androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.69k stars 405 forks source link

Сan't initialize Audio Effect with error code -3 #1261

Open mister-proger opened 7 months ago

mister-proger commented 7 months ago

Perhaps, similar problems: https://stackoverflow.com/questions/73911184/cannot-conect-audiotrack-to-audiofx-equalizer-in-kotlin https://github.com/GautamChibde/android-audio-visualizer/issues/9

Traceback:

2024-04-10 18:03:23.278 11549-11549 Token                   me.example.mediaplayer                 I  10788 // session ID
2024-04-10 18:03:23.283 11549-11549 AudioEffect             me.example.mediaplayer                 E  set(): AudioFlinger could not create effect 0bed4300-ddd6-11db-8f34-0002a5d5c51b / ec7178ec-e5e1-4432-a3f4-4657e6795210, status: -22
2024-04-10 18:03:23.283 11549-11549 AudioEffects-JNI        me.example.mediaplayer                 E  AudioEffect initCheck failed -3
2024-04-10 18:03:23.283 11549-11549 AudioEffect-JAVA        me.example.mediaplayer                 E  Error code -3 when initializing AudioEffect.
2024-04-10 18:03:23.294 11549-11549 AbstractFuture          me.example.mediaplayer                 E  RuntimeException while executing runnable me.example.mediaplayer.MainActivity$$ExternalSyntheticLambda4@dce6a30 with executor MoreExecutors.directExecutor()
                                                                                                    java.lang.RuntimeException: Cannot initialize effect engine for type: 0bed4300-ddd6-11db-8f34-0002a5d5c51b Error: -3
                                                                                                        at android.media.audiofx.AudioEffect.<init>(AudioEffect.java:545)
                                                                                                        at android.media.audiofx.AudioEffect.<init>(AudioEffect.java:503)
                                                                                                        at android.media.audiofx.AudioEffect.<init>(AudioEffect.java:477)
                                                                                                        at android.media.audiofx.Equalizer.<init>(Equalizer.java:139)
                                                                                                        at me.example.mediaplayer.effects.XEqualizer.<init>(AudioEffectUtils.kt:46)
                                                                                                        at me.example.mediaplayer.effects.AudioEffectManager.<init>(AudioEffectUtils.kt:13)
                                                                                                        at me.example.mediaplayer.views.PlayerPage.initializeAudioControllers$app_debug(MainPages.kt:354)
                                                                                                        at me.example.mediaplayer.views.PlayerPage.initializeAudioControllers$app_debug$default(MainPages.kt:340)

AudioEffectManage and Equalizer are wrappers over classes from your library.

That's how I get the token:

private val mediaSessionToken: SessionToken by lazy {
    SessionToken(
        this,
        ComponentName(this, MediaService::class.java)
    )
}
private val mediaControllerFuture by lazy {
    MediaController
        .Builder(this, mediaSessionToken)
        .buildAsync()
}
private var mediaController: MediaController? = null
private val audioManager: AudioManager by lazy {
    this@MainActivity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
}

My background service:

import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService

class MediaService : MediaSessionService() {
        private var mediaSession: MediaSession? = null

    override fun onCreate() {
        super.onCreate()
        mediaSession = MediaSession
            .Builder(
                this,
                ExoPlayer
                    .Builder(this)
                    .build()
            )
            .build()
    }

    override fun onDestroy() {
        mediaSession?.run {
            player.release()
            release()
            mediaSession = null
        }
        super.onDestroy()
    }

    override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) : MediaSession? =
        mediaSession
}

Listening to the creation of the controller:

mediaControllerFuture
    .addListener({
        pagesAdapter.initializeAudioControllers(
            mediaSessionToken.uid,
            mediaControllerFuture.get(),
            mediaSessionToken
        )
    }, MoreExecutors.directExecutor())

And connect effects:

fun initializeAudioControllers(
    audioSessionID: Int,
    audioController: MediaController,
    sessionToken: SessionToken,
) {
    this.audioController = audioController
    this.sessionToken = sessionToken

    Log.i("Token", audioSessionID.toString()) // 10788

    this@PlayerPage.effectsManager?.equalizer?.enabled = false // does not affect
    this@PlayerPage.effectsManager?.bassBoost?.enabled = false // does not affect

    this@PlayerPage.effectsManager = AudioEffectManager(audioSessionID) // exception
}

The strangest thing is that this error occurred about two days ago, I fixed it by removing <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> from the manifest (but the effects were still not applied, or I do not know how to distinguish them). Now I was experimenting with the interface, and the error occurred again. I rolled back to the commit that I made as soon as the error disappeared (!), but it remained!

mister-proger commented 7 months ago

All traceback:

2024-04-10 18:30:37.003 12173-12173 AudioEffect             me.example.mediaplayer                 E  set(): AudioFlinger could not create effect 0bed4300-ddd6-11db-8f34-0002a5d5c51b / ec7178ec-e5e1-4432-a3f4-4657e6795210, status: -22
2024-04-10 18:30:37.003 12173-12173 AudioEffects-JNI        me.example.mediaplayer                 E  AudioEffect initCheck failed -3
2024-04-10 18:30:37.004 12173-12173 AudioEffect-JAVA        me.example.mediaplayer                 E  Error code -3 when initializing AudioEffect.
2024-04-10 18:30:37.005 12173-12173 AbstractFuture          me.example.mediaplayer                 E  RuntimeException while executing runnable me.example.mediaplayer.MainActivity$$ExternalSyntheticLambda4@378be2 with executor MoreExecutors.directExecutor()
                                                                                                    java.lang.RuntimeException: Cannot initialize effect engine for type: 0bed4300-ddd6-11db-8f34-0002a5d5c51b Error: -3
                                                                                                        at android.media.audiofx.AudioEffect.<init>(AudioEffect.java:545)
                                                                                                        at android.media.audiofx.AudioEffect.<init>(AudioEffect.java:503)
                                                                                                        at android.media.audiofx.AudioEffect.<init>(AudioEffect.java:477)
                                                                                                        at android.media.audiofx.Equalizer.<init>(Equalizer.java:139)
                                                                                                        at me.example.mediaplayer.effects.XEqualizer.<init>(AudioEffectUtils.kt:46)
                                                                                                        at me.example.mediaplayer.effects.AudioEffectManager.<init>(AudioEffectUtils.kt:13)
                                                                                                        at me.example.mediaplayer.effects.AudioEffectManager.<init>(AudioEffectUtils.kt:7)
                                                                                                        at me.example.mediaplayer.views.PlayerPage.initializeAudioControllers$app_debug(MainPages.kt:371)
                                                                                                        at me.example.mediaplayer.views.MainFragmentsAdapter.initializeAudioControllers(MainPages.kt:124)
                                                                                                        at me.example.mediaplayer.MainActivity.bindMediaService$lambda$9(MainActivity.kt:216)
                                                                                                        at me.example.mediaplayer.MainActivity.$r8$lambda$Lxbggj3KXT1Maq6pu8YUGeqraf4(Unknown Source:0)
                                                                                                        at me.example.mediaplayer.MainActivity$$ExternalSyntheticLambda4.run(D8$$SyntheticClass:0)
                                                                                                        at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:31)
                                                                                                        at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1286)
                                                                                                        at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:1055)
                                                                                                        at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:782)
                                                                                                        at androidx.media3.session.MediaControllerHolder.maybeSetFutureResult(MediaControllerHolder.java:62)
                                                                                                        at androidx.media3.session.MediaControllerHolder.onAccepted(MediaControllerHolder.java:52)
                                                                                                        at androidx.media3.session.MediaController.notifyAccepted(MediaController.java:1969)
                                                                                                        at androidx.media3.session.MediaControllerImplBase.onConnected(MediaControllerImplBase.java:2636)
                                                                                                        at androidx.media3.session.MediaControllerStub.lambda$onConnected$0(MediaControllerStub.java:98)
                                                                                                        at androidx.media3.session.MediaControllerStub$$ExternalSyntheticLambda12.run(D8$$SyntheticClass:0)
                                                                                                        at androidx.media3.session.MediaControllerStub.lambda$dispatchControllerTaskOnHandler$12(MediaControllerStub.java:349)
                                                                                                        at androidx.media3.session.MediaControllerStub$$ExternalSyntheticLambda5.run(D8$$SyntheticClass:0)
                                                                                                        at androidx.media3.common.util.Util.postOrRun(Util.java:824)
                                                                                                        at androidx.media3.session.MediaControllerStub.dispatchControllerTaskOnHandler(MediaControllerStub.java:341)
                                                                                                        at androidx.media3.session.MediaControllerStub.onConnected(MediaControllerStub.java:98)
                                                                                                        at androidx.media3.session.MediaSessionStub.lambda$connect$17$androidx-media3-session-MediaSessionStub(MediaSessionStub.java:546)
                                                                                                        at androidx.media3.session.MediaSessionStub$$ExternalSyntheticLambda44.run(D8$$SyntheticClass:0)
                                                                                                        at androidx.media3.common.util.Util.postOrRun(Util.java:824)
                                                                                                        at androidx.media3.session.MediaSessionStub.connect(MediaSessionStub.java:470)
                                                                                                        at androidx.media3.session.MediaSessionImpl.connectFromService(MediaSessionImpl.java:703)
                                                                                                        at androidx.media3.session.MediaSession.handleControllerConnectionFromService(MediaSession.java:1131)
                                                                                                        at androidx.media3.session.MediaSessionService$MediaSessionServiceStub.lambda$connect$0$androidx-media3-session-MediaSessionService$MediaSessionServiceStub(MediaSessionService.java:720)
                                                                                                        at androidx.media3.session.MediaSessionService$MediaSessionServiceStub$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:942)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:226)
                                                                                                        at android.os.Looper.loop(Looper.java:313)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8762)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
marcbaechinger commented 7 months ago

Thanks for your report!

From the stack trace above, it looks like the exception is coming from classes of the app without any library involvement:

...
at me.example.mediaplayer.effects.XEqualizer.<init>(AudioEffectUtils.kt:46)
at me.example.mediaplayer.effects.AudioEffectManager.<init>(AudioEffectUtils.kt:13)
at me.example.mediaplayer.effects.AudioEffectManager.<init>(AudioEffectUtils.kt:7)
at me.example.mediaplayer.views.PlayerPage.initializeAudioControllers$app_debug(MainPages.kt:371)
at me.example.mediaplayer.views.MainFragmentsAdapter.initializeAudioControllers(MainPages.kt:124)
at me.example.mediaplayer.MainActivity.bindMediaService$lambda$9(MainActivity.kt:216)

This looks like a problem that can't be fixed from the library side I'm afraid. If you think this is related to the library, please add some more information how you think this is the case. Else we are probably unable to help you with fixing this.

mister-proger commented 7 months ago

The 'XEqualizerandXBassBoost` classes:

class XEqualizer(
    priority: Int,
    audioSessionId: Int,
) : Equalizer(priority, audioSessionId) {

    private val enableStatusListeners = mutableListOf<(Boolean) -> Unit>()
    private val propertiesChangeListeners = mutableListOf<(Settings?) -> Unit>()
    private val bandChangeListeners = mutableListOf<(band: Short, level: Short) -> Unit>()

    private var currPreset: Short = currentPreset
        private set

    fun addEnableStatusChangeListener(listener: (Boolean) -> Unit) {
        enableStatusListeners.add(listener)
    }

    fun removeEnableStatusChangeListener(listener: (Boolean) -> Unit) {
        enableStatusListeners.remove(listener)
    }

    fun addPropertiesChangeListener(listener: (Settings?) -> Unit) {
        propertiesChangeListeners.add(listener)
    }

    fun removePropertiesChangeListener(listener: (Settings?) -> Unit) {
        propertiesChangeListeners.remove(listener)
    }

    fun addBandChangeListeners(listener: (band: Short, level: Short) -> Unit) {
        bandChangeListeners.add(listener)
    }

    fun removeBandChangeListeners(listener: (band: Short, level: Short) -> Unit) {
        bandChangeListeners.remove(listener)
    }

    override fun usePreset(preset: Short) {
        super.usePreset(preset)
        currPreset = preset
    }

    override fun release() {
        try {
            super.release()
        } finally {
            bandChangeListeners.clear()
            propertiesChangeListeners.clear()
            enableStatusListeners.clear()
        }
    }

    override fun setEnabled(enabled: Boolean): Int {
        try {
            return super.setEnabled(enabled)
        } finally {
            enableStatusListeners.forEach {
                it(enabled)
            }
        }
    }

    override fun setProperties(settings: Settings?) {
        try {
            super.setProperties(settings)
        } finally {
            propertiesChangeListeners.forEach {
                it(settings)
            }
        }
    }

    override fun setBandLevel(band: Short, level: Short) {
        try {
            super.setBandLevel(band, level)
        } finally {
            bandChangeListeners.forEach {
                it(band, level)
            }
        }
    }
}

class XBassBoost(
    priority: Int,
    audioSessionId: Int,
) : BassBoost(priority, audioSessionId) {

    private val maxRecommendedStrength = 19

    private val enableStatusListeners = mutableListOf<(Boolean) -> Unit>()
    private val propertiesChangeListeners = mutableListOf<(Settings?) -> Unit>()
    private val strengthChangeListeners = mutableListOf<(Short) -> Unit>()

    fun addEnableStatusChangeListener(listener: (Boolean) -> Unit) {
        enableStatusListeners.add(listener)
    }

    fun removeEnableStatusChangeListener(listener: (Boolean) -> Unit) {
        enableStatusListeners.remove(listener)
    }

    fun addPropertiesChangeListener(listener: (Settings?) -> Unit) {
        propertiesChangeListeners.add(listener)
    }

    fun removePropertiesChangeListener(listener: (Settings?) -> Unit) {
        propertiesChangeListeners.remove(listener)
    }

    fun addBandChangeListeners(listener: (Short) -> Unit) {
        strengthChangeListeners.add(listener)
    }

    fun removeBandChangeListeners(listener: (Short) -> Unit) {
        strengthChangeListeners.remove(listener)
    }

    override fun setStrength(strength: Short) {
        try {
            super.setStrength((1000F / maxRecommendedStrength * strength).toInt().toShort())
        } finally {
            strengthChangeListeners.forEach {
                it(strength)
            }
        }
    }

    override fun getRoundedStrength(): Short {
        return (super.getRoundedStrength() / (1000F / maxRecommendedStrength)).toInt().toShort()
    }

    override fun release() {
        try {
            super.release()
        } finally {
            strengthChangeListeners.clear()
            propertiesChangeListeners.clear()
            enableStatusListeners.clear()
        }
    }

    override fun setEnabled(enabled: Boolean): Int {
        try {
            return super.setEnabled(enabled)
        } finally {
            enableStatusListeners.forEach {
                it(enabled)
            }
        }
    }

    override fun setProperties(settings: Settings?) {
        try {
            super.setProperties(settings)
        } finally {
            propertiesChangeListeners.forEach {
                it(settings)
            }
        }
    }
}

Manager:

class AudioEffectManager(
    audioSessionId: Int,
    initialState: Boolean = true,
) {
    private var releaseListeners = mutableListOf<() -> Unit>()

    var equalizer: XEqualizer = XEqualizer(Integer.MAX_VALUE, audioSessionId)
        private set

    var bassBoost: XBassBoost = XBassBoost(Integer.MAX_VALUE, audioSessionId)
        private set

    init {
        bassBoost.enabled = initialState
        equalizer.enabled = initialState
    }

    fun addReleaseListener(listener: () -> Unit) {
        releaseListeners.add(listener)
    }

    fun removeReleaseListener(listener: () -> Unit) {
        releaseListeners.remove(listener)
    }

    fun release() {
        try {
            equalizer.release()
            bassBoost.release()
        } finally {
            releaseListeners.forEach { it() }
            releaseListeners.clear()
        }
    }
}
mister-proger commented 7 months ago

I forgot to mention that this code is located in the activity fields `MainActivity'.

private val mediaSessionToken: SessionToken by lazy {
    SessionToken(
        this,
        ComponentName(this, MediaService::class.java)
    )
}
private val mediaControllerFuture by lazy {
    MediaController
        .Builder(this, mediaSessionToken)
        .buildAsync()
}
private var mediaController: MediaController? = null
private val audioManager: AudioManager by lazy {
    this@MainActivity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
}