AudioManager MODE_IN_COMMUNICATION снижает качество звука и вызывает треск/треск

Описание проблемы:

Когда приложение подключено через наушники Bluetooth, я запускаюaudioManager.startBluetoothSco(). Вы можете проверить код ниже. Соединение работает хорошо, но у меня проблема с потрескивающими звуками, которые воспроизводит MediaPlayer. Всякий раз, когда воспроизводится звук действия, качество плохое или слышен треск. (например, R.raw.record_start, R.raw.success_action, R.raw.failure_action)

Устройства, которые я использовал для тестирования:

  • OpenComm от AfterShokx и Jabra Evolve 65
  • Samsung A52, Samsung A50, Пиксель 3, OnePlus 6 Pro

Что я пробовал до сих пор?

  1. я пытался изменитьaudioManager.mode = AudioManager.MODE_IN_COMMUNICATIONв AudioManager.MODE_IN_CALL или AudioManager.MODE_NORMAL.
  • Изменение на MODE_IN_CALL не меняет . Значение остается равным 0, что соответствует MODE_NORMAL.
  1. Изменение на MODE_NORMAL работает только на Samsung A52. Никаких потрескиваний не слышно все работает отлично. Вот чего я хочу добиться,
  • НО все остальные телефоны переключаются на другой поток или что-то еще; вот почему я не СЛЫШУ никаких звуков мультимедиа.
  • Допустим, я использую Pixel 3 и подключен к Jabra Evolve 65 в режиме MODE_NORMAL. Я больше не слышу никаких звуков мультимедиа, включая звуки других приложений, таких как Youtube, Spotify и системные звуки, но в режиме MODE_IN_COMMUNICATION он работает с потрескивающим звуком.
  1. Я пытался изменить AudioAttributes MediaPlayer, но все равно плохое качество.

            val actionSound = if (triggerErrorEarcon) R.raw.failure_action else if (longRecordingBreak) R.raw.success_action else R.raw.record_start
    val md = MediaPlayer.create(context, actionSound)
    val streamType = if (audioDeviceManager.headsetConnected) AudioManager.STREAM_VOICE_CALL else AudioManager.STREAM_MUSIC
    md.setAudioAttributes(
            AudioAttributes.Builder()
                .setLegacyStreamType(streamType)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build())
    md.play()
    

Возможные решения?

  • не знаю как, но исправляюaudioManager.modeили некоторые другие свойства audioManager.
  • Продолжайте использовать MODE_IN_COMMUNICATION, но исправьте свойства MediaPlayer, чтобы отключить плохое качество звука на устройстве Bluetooth.
  • Я не могу думать ни о чем другом с этого момента. Я надеюсь, что вы могли бы помочь мне с этой проблемой, спасибо заранее.

AudioDeviceManager.kt:

      class AudioDeviceManager(val context: Context) {
    internal val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    internal val headsetConnectedSubject = BehaviorSubject.createDefault(false)
    internal val headsetConnected: Boolean get() = headsetConnectedSubject.value ?: false
    private val intentFilter = IntentFilter().apply { addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED) }
    private val audioDeviceCallback = object: AudioDeviceCallback() {
        override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
            super.onAudioDevicesAdded(addedDevices)
            updateBluetoothHeadsetState()
        }

        override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) {
            super.onAudioDevicesRemoved(removedDevices)
            updateBluetoothHeadsetState()
        }
    }
    private val scoReceiver = object: BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1) == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
                // SCO now connected
                audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
                audioManager.isSpeakerphoneOn = false
                audioManager.isBluetoothScoOn = true
            }
        }
    }

    fun start() {
        if (headsetConnected.not())
            audioManager.registerAudioDeviceCallback(audioDeviceCallback, null)
    }

    fun stop(unregisterAudioDeviceCallback: Boolean = false) {
        if (unregisterAudioDeviceCallback)
            unregisterDeviceCallback()
        audioManager.mode = AudioManager.MODE_NORMAL
        audioManager.isSpeakerphoneOn = true
        audioManager.isBluetoothScoOn = false
        audioManager.stopBluetoothSco()
    }

    private fun unregisterDeviceCallback() = audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)

    fun updateBluetoothHeadsetState() {
        val headset = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)?.firstOrNull { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO }
        val headsetConnected = headset != null
        headsetConnectedSubject.onNext(headsetConnected)

        if (headsetConnected) {
            audioManager.startBluetoothSco()
            context.registerReceiver(scoReceiver, intentFilter)
        } else {
            audioManager.mode = AudioManager.MODE_NORMAL
            audioManager.isSpeakerphoneOn = true
            audioManager.isBluetoothScoOn = false
            audioManager.stopBluetoothSco()
        }
    }
}

Воспроизведение звука действия в приложении:

       MediaPlayer.create(context, R.raw.record_start)
            .play()
            .subscribe()
            .addTo(disposable)

Функция расширения:

      fun MediaPlayer.play(): Completable {
    return Completable.create { emitter ->

        var isCancelled = false
        emitter.setCancellable {
            isCancelled = true
        }
        setOnCompletionListener {
            GlobalScope.launch {
                // release the sound a bit later. Listener is triggering so fast!
                delay(3000)
                it.release()
            }
            if (isCancelled) { return@setOnCompletionListener }
            emitter.onComplete()
        }
        start()
    }
}

0 ответов