Wrap DefaultAudioSink to tolerate init errors.

main
Nicholas 2022-11-10 10:15:10 -05:00 zatwierdzone przez GitHub
rodzic 99f8ba5e0c
commit d678341399
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 68 dodań i 5 usunięć

Wyświetl plik

@ -0,0 +1,52 @@
package org.thoughtcrime.securesms.components.voice
import android.content.Context
import com.google.android.exoplayer2.audio.AudioCapabilities
import com.google.android.exoplayer2.audio.AudioSink
import com.google.android.exoplayer2.audio.DefaultAudioSink
import org.signal.core.util.logging.Log
import java.nio.ByteBuffer
/**
* Certain devices, including the incredibly popular Samsung A51, often fail to create a proper audio sink when switching from "media" mode to "communication" mode.
* It does eventually recover, but it needs to be given ample opportunity to.
* This class wraps the final DefaultAudioSink to provide exactly that functionality.
*/
class RetryableInitAudioSink(
context: Context,
enableFloatOutput: Boolean,
enableAudioTrackPlaybackParams: Boolean,
enableOffload: Boolean,
val delegate: AudioSink = DefaultAudioSink.Builder()
.setAudioCapabilities(AudioCapabilities.getCapabilities(context))
.setEnableFloatOutput(enableFloatOutput)
.setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams)
.setOffloadMode(if (enableOffload) DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED else DefaultAudioSink.OFFLOAD_MODE_DISABLED)
.build()
) : AudioSink by delegate {
private var retriesLeft = INITIAL_RETRY_COUNT
override fun handleBuffer(buffer: ByteBuffer, presentationTimeUs: Long, encodedAccessUnitCount: Int): Boolean {
return try {
val bufferHandled = delegate.handleBuffer(buffer, presentationTimeUs, encodedAccessUnitCount)
if (bufferHandled) {
retriesLeft = INITIAL_RETRY_COUNT
}
bufferHandled
} catch (e: AudioSink.InitializationException) {
Log.w(TAG, "Could not handle this buffer due to an initialization exception. $retriesLeft retries remaining.", e)
if (retriesLeft > 0) {
retriesLeft--
false
} else {
throw e
}
}
}
companion object {
private val TAG = Log.tag(RetryableInitAudioSink::class.java)
const val INITIAL_RETRY_COUNT = 5
}
}

Wyświetl plik

@ -4,16 +4,16 @@ import android.media.AudioManager
import android.os.Bundle
import android.os.ResultReceiver
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.PlaybackParameters
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.util.Util
import org.signal.core.util.logging.Log
class VoiceNotePlaybackController(
private val player: SimpleExoPlayer,
private val player: ExoPlayer,
private val voiceNotePlaybackParameters: VoiceNotePlaybackParameters
) : MediaSessionConnector.CommandReceiver {
@ -42,7 +42,6 @@ class VoiceNotePlaybackController(
player.playWhenReady = false
player.setAudioAttributes(attributes, newStreamType == AudioManager.STREAM_MUSIC)
if (newStreamType == AudioManager.STREAM_VOICE_CALL) {
player.playWhenReady = true
}

Wyświetl plik

@ -3,14 +3,17 @@ package org.thoughtcrime.securesms.components.voice
import android.content.Context
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.DefaultLoadControl
import com.google.android.exoplayer2.DefaultRenderersFactory
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.ForwardingPlayer
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.audio.AudioSink
import org.thoughtcrime.securesms.video.exo.SignalMediaSourceFactory
class VoiceNotePlayer @JvmOverloads constructor(
context: Context,
val internalPlayer: SimpleExoPlayer = SimpleExoPlayer.Builder(context)
val internalPlayer: ExoPlayer = ExoPlayer.Builder(context)
.setRenderersFactory(WorkaroundRenderersFactory(context))
.setMediaSourceFactory(SignalMediaSourceFactory(context))
.setLoadControl(
DefaultLoadControl.Builder()
@ -39,3 +42,12 @@ class VoiceNotePlayer @JvmOverloads constructor(
}
}
}
/**
* @see RetryableInitAudioSink
*/
class WorkaroundRenderersFactory(val context: Context) : DefaultRenderersFactory(context) {
override fun buildAudioSink(context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean, enableOffload: Boolean): AudioSink? {
return RetryableInitAudioSink(context, enableFloatOutput, enableAudioTrackPlaybackParams, enableOffload)
}
}