diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioPlayer.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioPlayer.kt index 65727a25d..92b681ee6 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioPlayer.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioPlayer.kt @@ -3,6 +3,7 @@ package com.yunqiinnovation.azure_speech.tools import android.content.Context import android.media.AudioAttributes import android.media.AudioDeviceInfo +import android.media.AudioFocusRequest import android.media.AudioFormat import android.media.AudioManager import android.media.AudioTrack @@ -49,6 +50,20 @@ class SimpleAudioPlayer(private val context: Context? = null) { // 推送流 private var pushOutputStream: PushAudioOutputStream? = null + + // AudioFocus + private var audioFocusRequest: AudioFocusRequest? = null + private val audioFocusChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange -> + when (focusChange) { + AudioManager.AUDIOFOCUS_LOSS, + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { + lock.withLock { audioTrack?.pause() } + } + AudioManager.AUDIOFOCUS_GAIN -> { + lock.withLock { if (isPlaying) audioTrack?.play() } + } + } + } // 自定义推送流回调 private inner class AudioOutputCallback : PushAudioOutputStreamCallback() { @@ -235,10 +250,13 @@ class SimpleAudioPlayer(private val context: Context? = null) { configureAudioRouting(isBluetoothConnected) } + // 请求 AudioFocus,让外部音乐暂停 + requestAudioFocus() + // 开始播放 audioTrack?.play() isPlaying = true - + FileLogger.d(TAG, "AudioTrack开始播放") } } catch (e: Exception) { @@ -257,7 +275,8 @@ class SimpleAudioPlayer(private val context: Context? = null) { audioTrack?.pause() audioTrack?.flush() isPlaying = false - + abandonAudioFocus() + FileLogger.d(TAG, "AudioTrack停止播放") } } catch (e: Exception) { @@ -298,7 +317,10 @@ class SimpleAudioPlayer(private val context: Context? = null) { isPlaying = false isReleased = true - + + // 放弃 AudioFocus,让外部音乐恢复 + abandonAudioFocus() + FileLogger.d(TAG, "AudioTrack释放资源") } } catch (e: Exception) { @@ -310,7 +332,41 @@ class SimpleAudioPlayer(private val context: Context? = null) { * 是否正在播放 */ fun isPlaying(): Boolean = isPlaying - + + private fun requestAudioFocus() { + val am = audioManager ?: return + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val attrs = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) + .build() + val req = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) + .setAudioAttributes(attrs) + .setOnAudioFocusChangeListener(audioFocusChangeListener) + .build() + audioFocusRequest = req + am.requestAudioFocus(req) + } else { + @Suppress("DEPRECATION") + am.requestAudioFocus( + audioFocusChangeListener, + AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK + ) + } + } + + private fun abandonAudioFocus() { + val am = audioManager ?: return + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + audioFocusRequest?.let { am.abandonAudioFocusRequest(it) } + audioFocusRequest = null + } else { + @Suppress("DEPRECATION") + am.abandonAudioFocus(audioFocusChangeListener) + } + } + /** * 写入音频数据 * 内部方法,由PushAudioOutputStreamCallback调用 diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt index cc72aa389..1c09b84d7 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt @@ -58,6 +58,9 @@ class SimpleAudioReceiver(private val context: Context) { private var audioManager: AudioManager? = null private var originalAudioMode = AudioManager.MODE_NORMAL + // AudioFocus + private var audioFocusRequest: AudioFocusRequest? = null + // 录音文件处理 var recordfile: RecordFile? = null var isRecord =false @@ -251,19 +254,7 @@ fun startAudioRecord(audioSourceType: AudioSourceType, callback: AudioDataCallba Log.d("AudioMode", "检测到蓝牙设备,使用蓝牙音频") } - // 请求音频焦点 - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) - .setAudioAttributes( - AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) - .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) - .build() - ) - .build() - - audioManager?.requestAudioFocus(focusRequest) - } + // Honor 专属:请求音频焦点(已移至 requestAudioFocus() 统一处理) Log.d("AudioMode", "通话音频模式已设置: MODE_IN_COMMUNICATION") @@ -296,6 +287,8 @@ fun startAudioRecord(audioSourceType: AudioSourceType, callback: AudioDataCallba try { Log.d(TAG, "前台服务已启动,开始音频录制") + // 请求 AudioFocus,让外部音乐暂停(所有设备) + requestAudioFocus() // 根据手机品牌决定是否设置通话音频模式 if (isHonorDevice()) { Log.d(TAG, "检测到荣耀设备,启用通话音频模式") @@ -412,10 +405,11 @@ fun startAudioRecord(audioSourceType: AudioSourceType, callback: AudioDataCallba // 停止录音 audioRecord?.stop() - + abandonAudioFocus() + // 恢复音频模式 这里会导致关闭麦克风卡住待优化 //restoreCommunicationAudioMode() - + } catch (e: Exception) { Log.e(TAG, "停止麦克风捕获失败: ${e.message}") } @@ -497,6 +491,38 @@ fun startAudioRecord(audioSourceType: AudioSourceType, callback: AudioDataCallba return isWriting.get() } + private fun requestAudioFocus() { + val am = audioManager ?: (context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager)?.also { audioManager = it } ?: return + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val req = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) + .setAudioAttributes( + AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) + .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) + .build() + ) + .build() + audioFocusRequest = req + am.requestAudioFocus(req) + } else { + @Suppress("DEPRECATION") + am.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) + } + Log.d(TAG, "AudioFocus 已请求") + } + + private fun abandonAudioFocus() { + val am = audioManager ?: return + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + audioFocusRequest?.let { am.abandonAudioFocusRequest(it) } + audioFocusRequest = null + } else { + @Suppress("DEPRECATION") + am.abandonAudioFocus(null) + } + Log.d(TAG, "AudioFocus 已释放") + } + /** * 连续识别回调接口 */