@@ -283,6 +283,10 @@ class RecordingService : MediaBrowserService() {
283283 // Request audio focus only when actually recording
284284 requestRecordingFocus()
285285
286+ // Start Bluetooth SCO routing if a headset is connected.
287+ // We don't wait for SCO to fully connect — we start recording immediately.
288+ // The system will route audio through the BT mic as soon as SCO is ready.
289+ // At worst, the very first ~200-500ms may come from the phone mic.
286290 startBluetoothRouting()
287291
288292 mediaRecorder = createMediaRecorder(outputFile).apply {
@@ -291,6 +295,7 @@ class RecordingService : MediaBrowserService() {
291295 start()
292296 startTime = System .currentTimeMillis()
293297 totalPausedMillis = 0
298+ Log .d(" RecordingService" , " startRecording: recording started to ${outputFile.absolutePath} " )
294299 updatePlaybackState(true )
295300 startForegroundWithType(createNotification(" Capturing thought..." ))
296301 } catch (e: Exception ) {
@@ -372,10 +377,12 @@ class RecordingService : MediaBrowserService() {
372377
373378 private fun createMediaRecorder (file : File ): MediaRecorder {
374379 val hasHeadset = bluetoothChecker.isHeadsetConnected()
380+ val audioSource = if (hasHeadset) MediaRecorder .AudioSource .VOICE_COMMUNICATION else MediaRecorder .AudioSource .MIC
381+ Log .d(" RecordingService" , " createMediaRecorder: hasHeadset=$hasHeadset , audioSource=$audioSource , isScoStarted=$isScoStarted , scoOn=${audioManager.isBluetoothScoOn} " )
375382 return (if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .S ) MediaRecorder (this )
376383 else @Suppress(" DEPRECATION" ) MediaRecorder ()).apply {
377384 // Using VOICE_COMMUNICATION source is generally better for Bluetooth SCO routing
378- setAudioSource(if (hasHeadset) MediaRecorder . AudioSource . VOICE_COMMUNICATION else MediaRecorder . AudioSource . MIC )
385+ setAudioSource(audioSource )
379386 setOutputFormat(MediaRecorder .OutputFormat .MPEG_4 )
380387 setAudioEncoder(MediaRecorder .AudioEncoder .AAC_ELD )
381388 setAudioEncodingBitRate(128_000 )
@@ -393,12 +400,11 @@ class RecordingService : MediaBrowserService() {
393400
394401 private fun startBluetoothRouting () {
395402 if (bluetoothChecker.isHeadsetConnected()) {
396- if (Build .VERSION .SDK_INT < Build .VERSION_CODES .P ) {
397- Log .d(" RecordingService" , " Starting Bluetooth SCO for legacy API" )
398- audioManager.startBluetoothSco()
399- audioManager.isBluetoothScoOn = true
400- isScoStarted = true
401- }
403+ Log .d(" RecordingService" , " Starting Bluetooth SCO routing" )
404+ audioManager.mode = AudioManager .MODE_IN_COMMUNICATION
405+ audioManager.startBluetoothSco()
406+ audioManager.isBluetoothScoOn = true
407+ isScoStarted = true
402408 }
403409 }
404410
@@ -407,16 +413,20 @@ class RecordingService : MediaBrowserService() {
407413 Log .d(" RecordingService" , " Stopping Bluetooth SCO" )
408414 audioManager.stopBluetoothSco()
409415 audioManager.isBluetoothScoOn = false
416+ audioManager.mode = AudioManager .MODE_NORMAL
410417 isScoStarted = false
411418 }
412419 }
413420
414421 private fun getBluetoothAudioDevice (): AudioDeviceInfo ? {
415422 val devices = audioManager.getDevices(AudioManager .GET_DEVICES_INPUTS )
416- return devices.find {
423+ Log .d(" RecordingService" , " Available input devices: ${devices.map { " ${it.productName} (type=${it.type} )" }} " )
424+ val btDevice = devices.find {
417425 it.type == AudioDeviceInfo .TYPE_BLUETOOTH_SCO ||
418426 (Build .VERSION .SDK_INT >= Build .VERSION_CODES .S && it.type == AudioDeviceInfo .TYPE_BLE_HEADSET )
419427 }
428+ Log .d(" RecordingService" , " Bluetooth audio device: ${btDevice?.productName ? : " none" } " )
429+ return btDevice
420430 }
421431
422432 private fun createNotification (contentText : String ): Notification {
0 commit comments