日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

关于音频焦点的运用

發(fā)布時(shí)間:2024/4/17 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于音频焦点的运用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

引子

說 Audio Focus 前先說個(gè)很簡(jiǎn)單需求:來電時(shí)暫停正在播放的音樂,電話結(jié)束時(shí)恢復(fù)播放。

看到這個(gè)需求,第一反應(yīng)肯定是:監(jiān)聽用戶來電狀態(tài),作相應(yīng)操作。這里不多做介紹,這樣做有個(gè)不好的地方就是需要隱私權(quán)限!這樣做一點(diǎn)也不優(yōu)雅

后來搜索時(shí)看到一篇分析文章:Android來電時(shí)停止音樂播放的流程(順便說一嘴,這篇轉(zhuǎn)載居然不注明出處!!)。文章里的分析很明確的指出,系統(tǒng)在框架層就很好的幫我們處理了這個(gè)需求,問題是如何將音樂交給系統(tǒng)框架來處理呢?

音頻焦點(diǎn)

問題的解決方法就是:請(qǐng)求系統(tǒng)的音頻焦點(diǎn)(Request the Audio Focus)。

如果英文還行,強(qiáng)烈建議請(qǐng)看官方的原文:Managing Audio Playback,里面介紹的很清楚。以下為簡(jiǎn)單概述。

官方文檔指出Android?在處理音頻播放是分了多個(gè)“音頻流”的,如音樂流、音效流、電話聲音流等,使控制音量時(shí)可以互不干涉。多數(shù)情況下我們播放音樂都是使用?STREAM_MUSIC?音頻流。

另外,系統(tǒng)中可能會(huì)有多個(gè)應(yīng)用程序會(huì)播放音頻,所以需要考慮他們之間該如何協(xié)調(diào),為了避免同時(shí)播放音樂,Android 系統(tǒng)使用音頻焦點(diǎn)來進(jìn)行統(tǒng)一管理,即只有獲得了音頻焦點(diǎn)的應(yīng)用程序才可以播放音樂。

那么,播放音頻應(yīng)該這樣來做:

  • 獲取音頻焦點(diǎn) requestAudioFocus
  • 獲取成功后,開始播放音頻
  • 處理音頻焦點(diǎn)的丟失和“DUCK”
  • 播放完畢后取消焦點(diǎn)
  • 如此便可以完美的解決引子里的需求。

    一個(gè)簡(jiǎn)單的示例

    MusicService.java
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 public class MusicService extends Service { private AudioManager mAm; private boolean isPlaymusic; private String url; private MediaPlayer mediaPlayer; @Override public void onCreate() { super.onCreate(); mAm = (AudioManager) getSystemService(AUDIO_SERVICE); } @Override public void onStart(Intent intent, int startId) { if (intent != null) { Bundle bundle = intent.getExtras(); if (bundle != null) { isPlaymusic = bundle.getBoolean("isPlay", true); url = bundle.getString("url"); if (isPlaymusic) play(); else stop(); } } } OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) { // Pause playback pause(); } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Resume playback resume(); } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { // mAm.unregisterMediaButtonEventReceiver(RemoteControlReceiver); mAm.abandonAudioFocus(afChangeListener); // Stop playback stop(); } } }; private boolean requestFocus() { // Request audio focus for playback int result = mAm.requestAudioFocus(afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN); return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; } private void resume() { if (mediaPlayer != null) { mediaPlayer.start(); } } private void pause() { if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.pause(); } } OnCompletionListener completionListener = new OnCompletionListener() { @Override public void onCompletion(MediaPlayer player) { if(!player.isLooping()){ mAm.abandonAudioFocus(afChangeListener); } } }; private void play() { if (requestFocus()) { if (mediaPlayer == null) { try { mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(url); mediaPlayer.prepare(); mediaPlayer.setOnCompletionListener(completionListener); } catch (IOException e) { e.printStackTrace(); } } if (!mediaPlayer.isPlaying()) { mediaPlayer.start(); } } } @Override public void onDestroy() { super.onDestroy(); if (mediaPlayer != null) mediaPlayer.release(); } private void stop() { if (mediaPlayer != null) { mediaPlayer.stop(); } } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } }

    經(jīng)模擬器測(cè)試,當(dāng)來電時(shí)音頻焦點(diǎn)會(huì)給到鈴聲流,并打出日志:

    I/AudioService(1235): AudioFocus requestAudioFocus() from AudioFocus_For_Phone_Ring_And_Calls

    此時(shí)MusicService中的afChangeListener會(huì)得到AUDIOFOCUS_LOSS_TRANSIENT,于是會(huì)暫停播放音頻。當(dāng)通話結(jié)束或者掛掉電話,afChangeListener會(huì)得到AUDIOFOCUS_GAIN,于是恢復(fù)播放音頻。

    注意:

  • 播放完畢一定要禁止掉請(qǐng)求的音頻焦點(diǎn)abandonAudioFocus(afChangeListener),否則,如果播放完畢后的某個(gè)時(shí)段剛好有個(gè)通話結(jié)束,并且此時(shí)沒有其他的應(yīng)用占用了焦點(diǎn),系統(tǒng)會(huì)重新通知服務(wù)里的afChangeListener,導(dǎo)致音頻再次的播放。
  • 如果丟失的短暫音頻焦點(diǎn)允許DUCK狀態(tài)AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK,在這種情況下,應(yīng)用程序降低音量繼續(xù)播放,不需要暫停。再次獲取后,恢復(fù)原來的音量。
  • 總結(jié)

    以上是生活随笔為你收集整理的关于音频焦点的运用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。