AudioManager вводит задержку в setMode(MODE_IN_COMMUNICATION)

Я пытаюсь воспроизвести звук через динамик, даже если наушники включены, НО, если в фоновом режиме воспроизводится музыка, я хочу, чтобы музыка воспроизводилась в наушниках до тех пор, пока звук не будет воспроизведен.

Поэтому я предпринимаю следующие шаги:

  • Перед воспроизведением звука я получаю audioFocus, поэтому вся фоновая музыка останавливается
  • После получения audioFocus я установил MODE_COMMUNICATION AudioManager, поэтому звук может быть воспроизведен на динамике.
  • После окончания звука я оставляю AudioFocus и возвращаюсь обратно MODE_NORMAL в AudioManager, поэтому фоновая музыка может продолжать играть в наушниках.

Странно то, что это зависит от устройства, на некоторых устройствах это нормально, но на устройствах Nexus 6P (Huawei) после установки MODE_COMMUNICATION Перед воспроизведением звука задерживается 3-4 секунды. Если я проигрываю звук без задержки, он не воспроизводится ни на динамике, ни на наушниках.

ВОПРОС

Как узнать, какую задержку установить до воспроизведения звука? Есть ли какой-нибудь слушатель, которого я могу подключить, так что можете уведомить меня об этом после установки MODE_COMMUNICATION звук готов к игре?

Я не хочу устанавливать задержку, даже если она не нужна!

Решение заключается не в установке режима в конструктор класса (чтобы пропустить задержку), потому что мне нужно, чтобы звук воспроизводился на динамике в определенный момент!

PS: я играю звук с AudioTrack, но я попробовал с MediaPlayer а также (настройка setAudioStreamType(MODE_IN_COMMUNICATION)), но безуспешно, задержка еще есть!

Так какие-нибудь предложения?

2 ответа

Если устройство поддерживает уровень API 31 или выше, можно использовать AudioManager.OnModeChangedListener для обнаружения изменения режима звука на MODE_IN_COMMUNICATION, примерно так:

      val am = getSystemService(AUDIO_SERVICE) as AudioManager
var audioModeChangedListener = AudioManager.OnModeChangedListener { mode ->
  if (mode == AudioManager.MODE_IN_COMMUNICATION) {
    Log.d(TAG, "Audio mode changed to MODE_IN_COMMUNICATION")
    if (audioModeChangedListener != null) {
      am.removeOnModeChangedListener(audioModeChangedListener!!)
      audioModeChangedListener = null
    }
    // start playing
  }
}
am.addOnModeChangedListener(mainExecutor, audioModeChangedListener!!)
Log.d(TAG, "Setting audio mode to MODE_IN_COMMUNICATION")
am.mode = AudioManager.MODE_IN_COMMUNICATION

Если кто-нибудь наткнется на этот пост, то, что сработало для меня, было позвонить AudioManager.setMode() а затем воссоздавая мой MediaPlayer (через конструктор, а не create()) и используя setAudioAttributes() для изменения источника вывода.

Kotlin фрагмент:

fun switchOutput(inCommunication: Boolean) {

    //STEP 1: Change the AudioManager's audio mode
    if(inCommunication) {
        audioManager.mode = AudioManager.MODE_IN_CALL
        audioManager.isSpeakerphoneOn = false
    } else {
        audioManager.mode = AudioManager.MODE_NORMAL
        audioManager.isSpeakerphoneOn = true
    }

    //STEP 2: Recreate the MediaPlayer
    if (player != null) {
        try {
            player?.stop()
        } catch (e: RuntimeException) {
        } finally {
            player?.reset()
            player?.release()
            player = null
        }
    }

    player = MediaPlayer()
    try {
        val streamType =
                if (inCommunication) AudioManager.STREAM_VOICE_CALL
                else AudioManager.STREAM_MUSIC
        player?.setDataSource(dataSource)
        player?.setAudioAttributes(AudioAttributes.Builder()
                .setLegacyStreamType(streamType)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build())
        player?.prepare()
        player?.start()
    } catch (e: java.lang.Exception) {}
}

Надеюсь это поможет:)

PS Обратите внимание, что я использовал MODE_IN_CALL вместо того MODE_IN_COMMUNICATION

Другие вопросы по тегам