如何在Android API O中设置音频焦点ChangeListener?

14

由于在API O中requestAudioFocus(AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint)已被弃用,那么如何使用AudioFocusRequest设置音频焦点变更监听器呢?


我查看了这个链接,但它似乎并没有被弃用。而且在AndroidStudio中也没有任何弃用警告。 - Koorosh
请查看此处 https://developer.android.com/reference/android/media/AudioManager.html#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int)。 - Xera12
5个回答

22

https://developer.android.com/guide/topics/media-apps/audio-focus此为资源的官方链接

 AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        mAudioManager.requestAudioFocus(new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                .setAudioAttributes(
                        new AudioAttributes.Builder()
                                .setUsage(AudioAttributes.USAGE_GAME)
                                .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                                .build()
                )
                .setAcceptsDelayedFocusGain(true)
                .setOnAudioFocusChangeListener(new AudioManager.OnAudioFocusChangeListener() {
                    @Override
                    public void onAudioFocusChange(int focusChange) {
                       //Handle Focus Change 
                    }
                }).build()
        );
    } else {

        mAudioManager.requestAudioFocus(focusChange -> {

                   //Handle Focus Change for earliest version of oreo
                },
                AudioManager.STREAM_MUSIC,
                AudioManager.AUDIOFOCUS_GAIN);
    }

6
另一个选项是使用AudiomanagerCompat,AudioAttributesCompat和AudioRequestCompat与Jetpack(androidx)兼容性库一起使用:https://developer.android.com/reference/androidx/media/AudioManagerCompat 这样,您可以在Android O+和之前的版本中使用相同的代码(无需对API版本进行条件检查)。但是,此方法的一个缺点是您无法使用.setAcceptsDelayedFocusGain(true)。
如果您选择此方法,则必须使用requestAudioFocus(mAudioManager, mFocusRequest)和 abandonAudioFocusRequest(mAudioManager, mFocusRequest)来获取和释放音频焦点。
部分示例代码(使用Kotlin编写): (注意:如果您不使用Timber进行记录,请用标准的Log函数替换它)
class MyClass : AudioManager.OnAudioFocusChangeListener {

    internal var audioManager: AudioManager? = null
    private var focusRequest: AudioFocusRequestCompat? = null
    private var playbackAttributes : AudioAttributesCompat? = null

    // Create AudioManager and other audio related objects
    audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager?
    playbackAttributes = AudioAttributesCompat.Builder()
                .setUsage(AudioAttributesCompat.USAGE_MEDIA)
                .setContentType(AudioAttributesCompat.CONTENT_TYPE_SPEECH)
                .build()

    focusRequest = AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN)
                .setAudioAttributes(playbackAttributes ?: return)
                .setWillPauseWhenDucked(false)
                .setOnAudioFocusChangeListener(this)
                .build()

    // Request audio focus and check if it was granted to us
    if (requestAudioFocus(audioManager!!, focusRequest!!) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
         // We obtained audio focus

    }
    else {
        // We could not obtain audio focus

    }

    // And to remove audio focus
    if (audioManager != null && focusRequest != null)
            abandonAudioFocusRequest(audioManager!!, focusRequest!!)



    // Implementation of OnAudioFocusChangeListener
    override fun onAudioFocusChange(focusState: Int) {

        // Invoked when the audio focus of the system is updated.
        when (focusState) {
            AudioManager.AUDIOFOCUS_GAIN -> {
                // We recovered audio focus.
                Timber.d("Audio Focus obtained")
            }
            AudioManager.AUDIOFOCUS_LOSS -> {
                // Lost focus for an unbounded amount of time
                Timber.d("Audio Focus lost")
            }
            AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
                // Lost focus for a short time, but it's ok to keep playing at an attenuated level
                Timber.d("Audio Focus transient loss - can duck")
            }
            AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
                // Lost focus for a short time
                Timber.d("Audio Focus transient loss - cannot duck")
            }
        }
    }
}

4

我在官方文档中发现了以下内容:

请求音频焦点:您的服务可以使用requestAudioFocus()方法提交更精细的请求,以接收设备范围内的音频焦点。传递一个AudioFocusRequest对象,您可以使用AudioFocusRequest.Builder创建该对象。在这个构建器类中,您可以指定以下选项:

您希望获得的焦点类型,例如AUDIOFOCUS_GAIN_TRANSIENT或AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK。当另一个音频服务接管设备焦点时,您的服务是否应该继续更安静地播放或完全暂停。您的服务是否可以等待直到设备准备好才能获得焦点。

注意:当构建您的AudioFocusRequest实例时,如果您通过调用setAcceptsDelayedFocusGain()表示您的服务可以等待产生声音,则还必须调用setOnAudioFocusChangeListener(),以便您的服务知道何时可以开始产生声音。

正如@kelebro63所提到的,以下示例显示如何使用AudioFocusRequest.Builder构建AudioFocusRequest并请求和放弃音频焦点:

mAudioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
mPlaybackAttributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_GAME)
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .build();
mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
        .setAudioAttributes(mPlaybackAttributes)
        .setAcceptsDelayedFocusGain(true)
        .setOnAudioFocusChangeListener(mMyFocusListener, mMyHandler)
        .build();
mMediaPlayer = new MediaPlayer();
final Object mFocusLock = new Object();

boolean mPlaybackDelayed = false;
boolean mPlaybackNowAuthorized = false;

// ...
int res = mAudioManager.requestAudioFocus(mFocusRequest);
synchronized(mFocusLock) {
    if (res == AUDIOFOCUS_REQUEST_FAILED) {
        mPlaybackNowAuthorized = false;
    } else if (res == AUDIOFOCUS_REQUEST_GRANTED) {
        mPlaybackNowAuthorized = true;
        playbackNow();
    } else if (res == AUDIOFOCUS_REQUEST_DELAYED) {
       mPlaybackDelayed = true;
       mPlaybackNowAuthorized = false;
    }
}

// ...
@Override
public void onAudioFocusChange(int focusChange) {
    switch (focusChange) {
        case AudioManager.AUDIOFOCUS_GAIN:
            if (mPlaybackDelayed || mResumeOnFocusGain) {
                synchronized(mFocusLock) {
                    mPlaybackDelayed = false;
                    mResumeOnFocusGain = false;
                }
                playbackNow();
            } 
            break;
        case AudioManager.AUDIOFOCUS_LOSS:
            synchronized(mFocusLock) {
                mResumeOnFocusGain = false;
                mPlaybackDelayed = false;
            }
            pausePlayback();
            break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            synchronized(mFocusLock) {
                mResumeOnFocusGain = true;
                mPlaybackDelayed = false;
            }
            pausePlayback();
            break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
            // ... pausing or ducking depends on your application
            break;
        }
    }
}

参考资料:

音频焦点增强功能

Android O 特性和 API


因为@kelebro63只是提供了一个链接,但是该链接可能会被移动、更改或者其他问题,所以我提供了更多的解释和代码,以防止可能出现的问题。 - Koorosh
你的代码中的mMyHandler是什么?它从未被声明过。它是用来做什么的? - qkx

1

要获得焦点,请使用以下代码(它会暂停其他播放器):

 mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);       
 mAudioManager.requestAudioFocus(null,AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

要取消焦点,请使用以下内容(这将恢复该播放器):

   mAudioManager.abandonAudioFocus(null);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接