Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.

feat: support for recording internal audio in rooted devices #284

Merged
merged 3 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission
android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
tools:ignore="ProtectedPermissions" />


<!-- Opt out for network permissions that are optional for the ExoPlayer -->
<uses-permission
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ enum class AudioDeviceSource(val value: Int) {
DEFAULT(MediaRecorder.AudioSource.DEFAULT),
MIC(MediaRecorder.AudioSource.MIC),
CAMCORDER(MediaRecorder.AudioSource.CAMCORDER),
UNPROCESSED(MediaRecorder.AudioSource.UNPROCESSED);
UNPROCESSED(MediaRecorder.AudioSource.UNPROCESSED),
REMOTE_SUBMIX(MediaRecorder.AudioSource.REMOTE_SUBMIX);

companion object {
fun fromInt(value: Int) = AudioDeviceSource.values().first { it.value == value }
Expand Down
36 changes: 34 additions & 2 deletions app/src/main/java/com/bnyro/recorder/ui/models/RecorderModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.widget.Toast
import androidx.activity.result.ActivityResult
import androidx.annotation.RequiresApi
import androidx.compose.runtime.getValue
Expand All @@ -18,7 +19,9 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModel
import com.bnyro.recorder.R
import com.bnyro.recorder.canvas_overlay.CanvasOverlay
import com.bnyro.recorder.enums.AudioDeviceSource
import com.bnyro.recorder.enums.AudioSource
import com.bnyro.recorder.enums.RecorderState
import com.bnyro.recorder.services.AudioRecorderService
Expand Down Expand Up @@ -75,8 +78,22 @@ class RecorderModel : ViewModel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
audioPermission.add(Manifest.permission.POST_NOTIFICATIONS)
}
val internalAudio = Preferences.prefs.getInt(
Preferences.audioDeviceSourceKey,
0
) == AudioDeviceSource.REMOTE_SUBMIX.value
if (internalAudio) {
audioPermission.add(Manifest.permission.CAPTURE_AUDIO_OUTPUT)
}

if (!PermissionHelper.checkPermissions(context, audioPermission.toTypedArray())) return
if (!PermissionHelper.checkPermissions(context, audioPermission.toTypedArray())) {
Toast.makeText(
context,
context.getString(R.string.no_sufficient_permissions), Toast.LENGTH_SHORT
)
.show()
return
}

val serviceIntent =
if (Preferences.prefs.getBoolean(Preferences.losslessRecorderKey, false)) {
Expand Down Expand Up @@ -161,12 +178,27 @@ class RecorderModel : ViewModel() {
Preferences.prefs.getInt(Preferences.audioSourceKey, 0) == AudioSource.MICROPHONE.value

if (recordAudio) requiredPermissions.add(Manifest.permission.RECORD_AUDIO)

val internalAudio = Preferences.prefs.getInt(
Preferences.audioDeviceSourceKey,
0
) == AudioDeviceSource.REMOTE_SUBMIX.value
if (internalAudio) requiredPermissions.add(Manifest.permission.CAPTURE_AUDIO_OUTPUT)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requiredPermissions.add(Manifest.permission.POST_NOTIFICATIONS)
}

if (requiredPermissions.isEmpty()) return true

return PermissionHelper.checkPermissions(context, requiredPermissions.toTypedArray())
val granted = PermissionHelper.checkPermissions(context, requiredPermissions.toTypedArray())
if (!granted) {
Toast.makeText(
context,
context.getString(R.string.no_sufficient_permissions), Toast.LENGTH_SHORT
)
.show()
}
return granted
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ fun SettingsScreen() {
R.string.default_audio,
R.string.microphone,
R.string.camcorder,
R.string.unprocessed
R.string.unprocessed,
R.string.internal_audio
).map {
stringResource(it)
},
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,6 @@
<string name="cant_access_selected_folder">Can\'t access selected folder!</string>
<string name="draw_mode">Draw Mode</string>
<string name="erase_mode">Erase Mode</string>
<string name="internal_audio">Internal Audio (Root)</string>
<string name="no_sufficient_permissions">No sufficient permissions to start recording</string>
</resources>
Loading