亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android EasyPlayer聲音自動(dòng)停止、恢復(fù),一鍵靜音等功能

 更新時(shí)間:2017年03月09日 08:30:59   投稿:lqh  
這篇文章主要介紹了Android EasyPlayer聲音自動(dòng)停止、恢復(fù),一鍵靜音等功能的相關(guān)資料,需要的朋友可以參考下

Android EasyPlayer聲音自動(dòng)停止、恢復(fù),一鍵靜音等功能

我們?cè)陂_(kāi)發(fā)播放器時(shí),可能會(huì)需要靜音或者降低音量的功能。比如說(shuō)某款音樂(lè)播放器,當(dāng)在后臺(tái)播放時(shí),如果此時(shí)有另外的系統(tǒng)通知聲音發(fā)出,可能播放器會(huì)把音量降低,系統(tǒng)聲音結(jié)束后,再調(diào)高;如果有來(lái)電了,播放器可能會(huì)把音樂(lè)暫停,等通話結(jié)束后再繼續(xù)播放。還有,比方說(shuō)我們?cè)谀硞€(gè)場(chǎng)合放個(gè)視頻,不料音量很大,會(huì)引來(lái)很多目光(很尷尬),這時(shí)候可能我們需要一鍵靜音的功能。那這些功能我們應(yīng)該如何實(shí)現(xiàn)呢?

Android播放聲音的類為AudioTrack,播放器會(huì)先把音頻流demux出來(lái),再decode,之后,把音頻PCM數(shù)據(jù)通過(guò)AudioTrack類write到音頻設(shè)備中,從而通過(guò)話筒或者揚(yáng)聲器發(fā)出聲音。

為了方便地實(shí)現(xiàn)聲音控制,我們需要從應(yīng)用的最上層進(jìn)行操作(因?yàn)榈讓涌赡芤呀?jīng)被抽象成庫(kù)了),也就是要從AudioTrack來(lái)入手。讓我們看看AudioTrack的一些API吧。

int getPlayState ()
Returns the playback state of the AudioTrack instance.
獲取當(dāng)前的播放狀態(tài)。這個(gè)接口會(huì)返回PLAYSTATE_STOPPED、PLAYSTATE_PAUSED、PLAYSTATE_PLAYING
三種狀態(tài),分別表示未播放、暫停中、正在播放
void pause ()
Pauses the playback of the audio data. Data that has not been played back will not be discarded. Subsequent calls to play() will play this data back. See flush() to discard this data.
暫停播放音頻數(shù)據(jù)。已經(jīng)在緩沖區(qū)中的未播放數(shù)據(jù)將不會(huì)被丟棄,在下次play的時(shí)候繼續(xù)播放。調(diào)用flush則會(huì)丟棄緩沖數(shù)據(jù)。
void play ()
Starts playing an AudioTrack.
開(kāi)始播放
int setStereoVolume (float leftGain, 
        float rightGain)

Sets the specified left and right output gain values on the AudioTrack.
設(shè)置左右聲道的音量增益。

有了這幾個(gè)API,足以滿足我們的需求。實(shí)現(xiàn)起來(lái)就非常簡(jiǎn)單了。

首先我們做一鍵靜音功能。我們可以做個(gè)切換的按鈕,這個(gè)按鈕初始狀態(tài)是要顯示當(dāng)前的播放狀態(tài):正在播放音頻或未在播放音頻。播放狀態(tài)可以調(diào)用getPlayState ()來(lái)獲取到;然后按鈕按下后,再根據(jù)播放狀態(tài)進(jìn)行播放或暫停。

代碼如下:

mAudioEnable = mAudioTrack!=null && mAudioTrack.getPlayState()==PLAYSTATE_PLAYING;

public void setAudioEnable(boolean enable) {
   mAudioEnable = enable;
   AudioTrack at = mAudioTrack;
   if (at != null) {
     synchronized (at) {
       if (!enable) {
         at.pause();
         at.flush();
       } else {
         at.flush();
         at.play();
       }
     }
   }
 }

注意這里在pause之后,play之前都調(diào)用了flush接口。這樣可以確保在由暫停到播放切換時(shí),不會(huì)把暫停時(shí)未播放的“舊數(shù)據(jù)”播放出來(lái)。

接下來(lái)我們實(shí)現(xiàn)音頻資源被其它進(jìn)程占用(失去焦點(diǎn))時(shí),自動(dòng)降低聲音或者停止聲音;在音頻資源又被釋放(重新獲取到焦點(diǎn))時(shí)再恢復(fù)播放的功能。

我們需要通過(guò)AudioManager來(lái)判斷當(dāng)前音頻資源的狀態(tài),并且在音頻焦點(diǎn)更改時(shí)得到回調(diào)。其關(guān)鍵API接口有:

int requestAudioFocus (AudioManager.OnAudioFocusChangeListener l, 
        int streamType, 
        int durationHint)
Request audio focus. Send a request to obtain the audio focus
請(qǐng)求獲取音頻焦點(diǎn)。
第一個(gè)參數(shù)為音頻焦點(diǎn)更改時(shí)的回調(diào);
第二個(gè)參數(shù)為音頻類型,在我們調(diào)節(jié)音量時(shí)可以看到有若干種音量,就對(duì)應(yīng)的這里的streamType,這里我們基本用MUSIC,表示“媒體”。
第三個(gè)參數(shù)表示獲取焦點(diǎn)的“時(shí)長(zhǎng)”,有如下幾種情況:
AUDIOFOCUS_GAIN_TRANSIENT
表示僅僅為臨時(shí)獲取焦點(diǎn)。比如播放導(dǎo)航語(yǔ)音、通知聲音等,屬于時(shí)間很短暫的情況;
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
表示為DUCK模式,表示當(dāng)獲取焦點(diǎn)后,允許先前獲取過(guò)焦點(diǎn)的程序在降低輸出音量的前提下繼續(xù)播放。
AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
痛第一種情況類似,只是不允許系統(tǒng)再播放其他聲音。通常應(yīng)用在語(yǔ)音備忘、語(yǔ)音識(shí)別等情況;
AUDIOFOCUS_GAIN
表示要獲取焦點(diǎn)的時(shí)長(zhǎng)未知。比如播放音樂(lè)等等。

當(dāng)獲取到焦點(diǎn)時(shí),函數(shù)放回AUDIOFOCUS_REQUEST_GRANTED,當(dāng)獲取失敗時(shí),返回AUDIOFOCUS_REQUEST_FAILED

結(jié)合上面的API說(shuō)明,參考如下代碼以及解釋:

// 獲取AudioManager實(shí)例
final AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
AudioManager.OnAudioFocusChangeListener l = new AudioManager.OnAudioFocusChangeListener() {
  @Override
  public void onAudioFocusChange(int focusChange) {
    if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {// 焦點(diǎn)獲取到了,那繼續(xù)播放,并恢復(fù)音量。
      AudioTrack audioTrack = mAudioTrack;
      if (audioTrack != null) {
        audioTrack.setStereoVolume(1.0f, 1.0f);
        if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
          audioTrack.flush();
          audioTrack.play();
        }
      }
    } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {// 焦點(diǎn)丟失了,暫停播放。
       AudioTrack audioTrack = mAudioTrack;
      if (audioTrack != null) {
        if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
          audioTrack.pause();
        }
      }
    } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { // 焦點(diǎn)丟失了,但是允許在降低音量的前提下繼續(xù)播放,那么降低聲音。
      AudioTrack audioTrack = mAudioTrack;
      if (audioTrack != null) {
        audioTrack.setStereoVolume(0.5f, 0.5f);
      }
    }
  }
};
// 因?yàn)檫@里要獲得的焦點(diǎn)無(wú)法預(yù)知時(shí)長(zhǎng),因此用AUDIOFOCUS_GAIN模式。
int requestCode = am.requestAudioFocus(l, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (requestCode == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
  // 成功獲取到了焦點(diǎn)。那啟動(dòng)播放
  AudioTrack audioTrack = mAudioTrack;
  if (audioTrack != null) {
    audioTrack.setStereoVolume(1.0f, 1.0f);
    if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
      audioTrack.flush();
      audioTrack.play();
    }
  }
}else{ // 沒(méi)有獲取到音頻焦點(diǎn)。那不播放聲音
  AudioTrack audioTrack = mAudioTrack;
  if (audioTrack != null) {
    if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
      audioTrack.pause();
    }
  }
}

至此,我們便實(shí)現(xiàn)了EasyPlayer的聲音自動(dòng)停止、恢復(fù),一鍵靜音的功能的實(shí)現(xiàn)??雌饋?lái)挺麻煩對(duì)嗎?其實(shí)做一個(gè)app很容易,但是要想做的好,各種情況都兼顧了,卻是很不容易的。我們不防多看些系統(tǒng)APP的實(shí)現(xiàn),或者Google官方的一些DEMO,它們往往都看似功能很簡(jiǎn)單,會(huì)讓我們覺(jué)得:“如果是我做的話,幾行代碼即可搞定。?!?,但是它們的代碼量卻很大,因?yàn)樗鼈兗骖櫫烁鞣N細(xì)節(jié)。而往往我們開(kāi)發(fā)出來(lái)絕大多數(shù)app的都只能算是半成品,都有繼續(xù)優(yōu)化的余地。

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • 讀寫(xiě)Android中assets目錄下的文件的方法詳解

    讀寫(xiě)Android中assets目錄下的文件的方法詳解

    這篇文章主要介紹了讀寫(xiě)Android中assets目錄下的文件的方法詳解,assets和res/raw工程目錄下都可以放一些文件,這些文件將被打包到APK中應(yīng)用使用,需要的朋友可以參考下
    2016-04-04
  • Android游戲開(kāi)發(fā)學(xué)習(xí)之引擎用法實(shí)例詳解

    Android游戲開(kāi)發(fā)學(xué)習(xí)之引擎用法實(shí)例詳解

    這篇文章主要介紹了Android游戲開(kāi)發(fā)學(xué)習(xí)之引擎用法,較為詳細(xì)的分析了Android游戲開(kāi)發(fā)中所常用的JBox2D引擎功能及相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • Android開(kāi)發(fā)實(shí)現(xiàn)圖片切換APP

    Android開(kāi)發(fā)實(shí)現(xiàn)圖片切換APP

    這篇文章主要介紹了Android開(kāi)發(fā)實(shí)現(xiàn)圖片切換APP,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • Android Studio手動(dòng)配置Gradle的方法

    Android Studio手動(dòng)配置Gradle的方法

    Gradle:Gradle是一個(gè)基于Apache Ant和Apache Maven概念的項(xiàng)目自動(dòng)化建構(gòu)工具。它使用一種基于Groovy的特定領(lǐng)域語(yǔ)言(DSL)來(lái)聲明項(xiàng)目設(shè)置,拋棄了基于XML的各種繁瑣配置,本文給大家介紹Android Studio手動(dòng)配置Gradle的方法,一起看看吧
    2017-11-11
  • Android 對(duì)話框(Dialog)大全詳解及示例代碼

    Android 對(duì)話框(Dialog)大全詳解及示例代碼

    本文主要介紹Android 對(duì)話框的知識(shí),這里整理了詳細(xì)資料及實(shí)現(xiàn)示例代碼及實(shí)現(xiàn)效果圖,有興趣的小伙伴可以參考下
    2016-09-09
  • Android RecyclerView多類型布局卡片解決方案

    Android RecyclerView多類型布局卡片解決方案

    這篇文章主要介紹了Android RecyclerView多類型布局卡片解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-03-03
  • Android開(kāi)發(fā)Compose框架使用開(kāi)篇

    Android開(kāi)發(fā)Compose框架使用開(kāi)篇

    這篇文章主要為大家介紹了Android開(kāi)發(fā)Compose框架使用開(kāi)篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 詳解Android MVP開(kāi)發(fā)模式

    詳解Android MVP開(kāi)發(fā)模式

    這篇文章主要為大家介紹了Android MVP開(kāi)發(fā)模式的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • 橫豎屏切換導(dǎo)致頁(yè)面頻繁重啟screenLayout解析

    橫豎屏切換導(dǎo)致頁(yè)面頻繁重啟screenLayout解析

    這篇文章主要為大家介紹了橫豎屏切換導(dǎo)致頁(yè)面頻繁重啟screenLayout解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Android自定義荷載進(jìn)度的兩種方法

    Android自定義荷載進(jìn)度的兩種方法

    進(jìn)度條在App中非常常見(jiàn),例如下載進(jìn)度、加載圖片、打開(kāi)文章、打開(kāi)網(wǎng)頁(yè)等等……本篇文章主要介紹了Android自定義荷載進(jìn)度的兩種方法,有需要的朋友可以了解一下。
    2016-10-10

最新評(píng)論