Preferred way to attach AudioEffect to global mix?
Asked Answered
G

3

16

In Android, AudioEffect API, all of the builtin effects such as Equalizer come with a warning

"NOTE: attaching an Equalizer to the global audio output mix by use of session 0 is deprecated. "

If this is deprecated, then what is the replacement API? My goal is to attach an effect to the global output mix...

Groundmass answered 22/2, 2012 at 23:16 Comment(0)
H
6

Yes it is deprecated, because of side-effects isues.

The Android Developers website states that the second parameter of the Equalizer class should be :

A system wide unique audio session identifier. The Equalizer will be attached to the MediaPlayer or AudioTrack in the same audio session.

You should use this instead :

MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource( _your_data_source_ );
Equalizer equalizer = new Equalizer(0, mediaPlayer.getAudioSessionId());
equalizer.setEnabled(true);
/* Do your stuff ... */
mediaPlayer.start();
Hankins answered 5/4, 2013 at 10:55 Comment(3)
As mentioned in one of the comments on your link, this is not a work around, in the case where you want to apply Equalizer or other effect to an existing stream, or all streams.Groundmass
For now you can potentially still use the global audio session with the Equalizer. There is no replacement, deprecation doesn't always come with replacement. They just figured that this does not appear to be working well and decided to keep a support for this until further Android releases. The workaround in your case is to attach an Equalizer to each MediaPlayer instances across your apps. If not, taking the risk of keeping an Equalizer attached to the global audio session knowing that it will certainly not run on further releases.Hankins
Hello Halim, How to attach eqaulizer to each MediaPlayer instances? Please share more info on that. Also What is alternative to attach effect globally in ICS?Insolent
M
5

There is no alternative to attach an AudioEffect to the global output. What you should do instead is register a broadcast receiver that receives all audio sessions, so you can apply audio effects to that. An example can be found here. The intent containing the session ID is obtained in this BroadcastReceiver. Remember that this only works if you registered the receiver in the manifest. Alternatively you could register a receiver programmatically like this in your service onCreate():

IntentFilter()
    .apply { addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) }
    .apply { addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION) }
    .run { registerReceiver(mAudioSessionReceiver, this) } `

where mAudioSessionReceiver looks something like this:

private val mAudioSessionReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent == null || context == null) {
            return
        }

        val sessionStates = arrayOf(
            AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION,
            AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION
        )
        if (sessionStates.contains(intent.action)) {
            val service = Intent(context, WaveletService::class.java)
            val sessionID = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION, AudioEffect.ERROR)
            service
                .apply { action = intent.action }
                .apply { putExtra(AudioEffect.EXTRA_AUDIO_SESSION, sessionID) }
            context.startService(service)
        }
    }
}`

Then, you can obtain the intent in onStartCommand:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    if (intent == null)
        return START_STICKY

    val sessionID = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION, AudioEffect.ERROR)

    when (intent.action) {
        AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION -> {
            // create new instance of the AudioEffect using the sessionID
        }
        AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION -> {
            // Release instance of the AudioEffect connected to this sessionID 
        }
    }

    return START_REDELIVER_INTENT
}`

Lastly, don't forget to unregister the receiver in onDestroy():

unregisterReceiver(mAudioSessionReceiver)`
Marvamarve answered 24/11, 2019 at 22:57 Comment(0)
M
1

According to Android, you can use ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION to receive the id of a playing audio session:

Intent to signal to the effect control application or service that a new audio session is opened and requires audio effects to be applied.

I tried adding the constant in the manifest, but it didn't work:

<receiver android:name=".receivers.AudioSessionReceiver">
        <intent-filter>
            <action android:name="android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"/>
        </intent-filter>
</receiver>

If you figure out how to use the constant, the intent will contain the audio session id, which you can use to apply the equalizer settings you want. (If you found a work-around in all those years, would you mind sharing?)

Marabout answered 3/10, 2019 at 21:16 Comment(2)
This is only working with Spotify, did you get any clue about this?Mahratta
Initially I was confused by why this app works despite global mix being deprecated, then I realized that global mix was simply still working on my OnePlus phone by making a test app. I tried decompiling some apks but didn't find anything. Developers have to explicitly fire the OPEN action, it isn't done by default.Sarena

© 2022 - 2024 — McMap. All rights reserved.