Android Audio Play Out Channel
1: 7嘴8舌
?
揚聲器, 耳機, 和聽筒
就是通過: audiomanager.setmode(AudioManager.MODE_IN_COMMUNICATION)
audiomanager.setSpeakerhponeOn(boolean value).這兩個來設置.不過有的好像不支持的.
米手機上切換 揚聲器和聽筒不能切換
?
Android AudioTrack音頻播放分析音頻資源在播放時,會經常出現沖突的情況,如在進行音樂播放時有電話呼入、
有新消息的提示音需要播放等,此類的并發處理就需要有一個統一的處理策略。在 Android系統開發中,通過為不同的場景配置不同的播放接口,在底層執行統一的并發策略,使得開發者可以將精力更集中在應用本身。
A udioTrack、MediaPlayer、SoundPool、Ringtone、JetPlayer等都是Android音頻處理中常用接口,本文將針對AudioTrack接口進行詳細說明。
AudioTrack AudioTrack用于管理單個的音頻資源。 在構造AudioTrack實例時,會涉及到流類型、采樣率、通道配置、音頻格式、緩沖大小、播放模式等因素。
AudioTrack支持STREAM_VOICE_CALL、STREAM_SYSTEM、STREAM_RING、STREAM_MUSIC和STREAM_ALARM等流類型。
AudioTrack支持44100Hz、22050Hz、11025Hz等采樣率。 AudioTrack支持單聲道(CHANNEL_OUT_MONO)、立體聲(CHANNEL_OUT_STEREO)等兩種通道。
AudioTrack支持ENCODING_PCM_16BIT、ENCODING_PCM_8BIT等兩種編碼格式。
AudioTrack支持兩種播放模式:靜態模式(static mode)和流模式(Streaming mode)。
其中靜態模式由于沒有從Java層向原生層傳遞數據造成的延遲,時延很小,當然受限于音頻緩沖的大小,通常在游戲場景中用于播放時長很短的音頻資源。
當音頻流較大不足以在音頻緩沖中一次寫入時,可采用流模式。
AudioTrack的播放狀態包括PLAYSTATE_STOPPED、PLAYSTATE_PAUSED、PLAYSTATE_PLAYING等。
AudioTrack實例的狀態包括STATE_INITIALIZED、STATE_NO_STATIC_DATA、STATE_UNINITIALIZED等。
向音頻緩沖中添加數據的方法為write()。
在設置音頻緩沖時,其大小與采樣率、通道和音頻格式有關。
其計算公式為: 緩沖大小=最小幀數×(通道==CHANNEL_OUT_STEREO?2:1)×(音頻格式== PCM16?2:1) 而最小幀數則受制于采樣率和音頻設備的延遲等因素。
另外,在Android 2.3中,還引入了會話的概念,便于對單曲的音效進行處理。相應的方法包括:attachAuxEffect()、getAudioSessionId()、setAuxEffectSendLevel()等。
通過AudioTrack.OnPlaybackPositionUpdateListener監聽器可以監聽播放進度。
下面是一個背景音頻的播放過程:
代碼10-3 AudioTrack播放音頻文件
public?class?BackgroundAudio?extends?Thread?{?public?static?final?int?SAMPLE_RATE?=?16000;? public?static?final?int?AUDIO_FORMAT?=?AudioFormat.ENCODING_PCM_16BIT;?public?static?final?int?BYTES_PER_SAMPLE?=?2;? public?static?final?int?PLAYBACK_STREAM?=?AudioManager.STREAM_MUSIC;?……? public?BackgroundAudio(byte[]?data)?{?//計算緩沖大小??final?int?minBufferSize?=?(BUFFER_TIME?*SAMPLE_RATE*BYTES_PER_SAMPLE)?/?1000;?//計算硬件的最小緩沖?final?int?minHardwareBufferSize?=?AudioTrack.getMinBufferSize(SAMPLE_RATE,AudioFormat.CHANNEL_OUT_MONO,AUDIO_FORMAT);?mBufferSize?=?Math.max(minHardwareBufferSize,?minBufferSize);????????
? mAudioTrack?=?new?AudioTrack(PLAYBACK_STREAM,?SAMPLE_RATE,?AudioFormat.CHANNEL_OUT_MONO,??AUDIO_FORMAT,?mBufferSize,?AudioTrack.MODE_STREAM);?????????
if?(mAudioTrack.getState()?==?AudioTrack.STATE_INITIALIZED)?{?????????????
writeAudio();?start();?//?啟動背景線程去推送音頻數據?????????????mAudioTrack.play();?????????}?else?{?Log.e(TAG,?"Error?initializing?audio?track.");?????????
}?}?……? private?void?writeAudio()?{????
int?len?=?mData.length;????
int?count;?int?maxBytes?=?Math.min(mBufferSize,?len?-?mPos);??count?=?mAudioTrack.write(mData,?mPos,?maxBytes);????
if?(count?<?0)?{?Log.e(TAG,?"Error?writing?looped?audio?data");????????
halt();????????
return;?????
}?mPos?+=?count;????
if?(mPos?==?len)?{?mPos?=?0;?//?Wraparound????
?}??}?} Media playback Supported Media Formats Audio Capture JetPlayer Camera 這次我先分享下Media Playback的中一些內容以及我學習中的感悟。 首先需要我們接觸到的最主要的兩個類分別是MediaPlayer、MediaManager。MediaPlayer是用來控制音頻/視頻流或者文件的播放的,需要我們注意的是MediaPlayer對象加上其支持的一些播放操作會形成一個狀態機,在不合適的狀態執行不合適的操作就會拋出異常,如果開發者不清楚自己創建的MediaPlayer對象當前處于哪個狀態,就很有可能調用錯誤的方法造成程序的異常,而且這些錯誤很難被察覺,所以錯誤處理在這個部分就顯得尤為重要。 下面要說的就是Audio Focus,舉個例子,當你在聽歌的時候,突然來了一條短信,如果不加處理,短信的聲音很可能被音樂的聲音湮沒,你就會察覺不到。我們希望發生什么事情呢?我們希望這個時候音樂的聲音較之前稍微降低些使得我們能夠聽到短信提示音,在短信提示音結束后音樂的聲音再次回到正常。這個過程就是獲取和釋放audio focus的過程。 在寫代碼的時候,我忽略了一點:Audio Focus is cooperative in nature. 申請audio focus [java] view plaincopyprint?AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); 處理focus change事件 [java] view plaincopyprint?class MyService extends Service implements AudioManager.OnAudioFocusChangeListener { // .... public void onAudioFocusChange(int focusChange) { // Do something based on focus change... } } class MyService extends Service implements AudioManager.OnAudioFocusChangeListener { // .... public void onAudioFocusChange(int focusChange) { // Do something based on focus change... } } 申請audio focus和處理focus change一定是互相配合實現的,我一開始寫了個service用來播放音樂,在start函數調用前并沒有申請audio focus,但是我實現了onAudioFocusChange函數。我期待這個service在focus change時停止播放,但是我發現,當另外一個service申請到audio focus時,之前的service不會出現音樂停止播放的情況。 android培訓,就選成都達內,最好的成都軟件培訓機構,如果你有“達內培訓需要多少錢”、“達內培訓怎么樣”等問題,詳情請咨詢達內客服(http://www.sctarena.com),我們會給你詳細的講解。
?
?android 聽筒播放音樂
AudioManager.setMode(AudioManager.MODE_IN_CALL) //設定為通話中即可 還是這一句代碼的事,不過記得要加上權限android.permission.MODIFY_AUDIO_SETTINGS還有一點需要注意的事,在播放完畢后需要AudioManager.setMode(AudioManager.MODE_NORMAL);不然其他軟件播放都聽筒發聲了
實際操作中,僅僅上述代碼并不能是實現需求:
| 榮耀:4..2.2 內核3.4.5 |
|
| Nexus 5 ??5.0.1 內核2.4.0 | audiomanager.setMode(AudioManager.MODE_IN_CALL);不能生效,即便添加該行仍然從揚聲器播出 ? ? |
| ? | ? |
| ? | ? |
| ? | ? |
| 設備 | audio path | media paly new | ? |
| ? | ? | ? | ? |
| ? | ? | ? | ? |
| ? | ? | ? | ? |
| ? | ? | ? | ? |
?
Actually you don't need audioManager.setSpeakerphoneOn(false); . And also, you need to create MediaPlayer not with static method MediaPlayer.create(), but you need to create it with new MediaPlayer()... – Andranik Jun 12 '14 at 18:40 up vote 16 down vote accepted Audio handling on Android is going to be pretty horrible for a while. The APIs are pretty weird, poorly documented, and keep changing/deprecating/breaking between versions. Even the AudioManager code has FIXMEs in it.Anyway, there are several stream types in Android (music, notifications, phone calls, etc.) and applications are meant to choose the appropriate one for playback. I imagine the majority of Android apps should use the music/media type (STREAM_TYPE_MUSIC). You set this on your MediaPlayer using the setAudioStreamType method.The SDK does allow you to set a single stream type as solo — causing all other streams to be muted — but I don't believe you can identify the audio being played back by particular applications and somehow pause/unpause it. Music applications in general will use the PhoneStateListener to pause themselves when a call comes in. So in your case, you could "borrow" the phone call stream for your MediaPlayer and use the method call AudioManager.setStreamSolo(AudioManager.STREAM_VOICE_CALL, true) when playback begins, then un-solo the stream with false when playback or your Activity is done.I can tell you that this works, but I can't remember offhand whether you need to also set the audio mode to MODE_IN_CALL when using the voice call stream (like this: AudioManager.setMode(AudioManager.MODE_IN_CALL)). If you find that is required, then you need to make sure you return the mode to MODE_NORMAL once playback completes, otherwise whenever you press the volume hard keys, it'll say "In-call volume"! However, if and when you do want to change back to MODE_NORMAL, you must check that a genuine phone call isn't happening at that time... Maybe you could use another stream type rather than the voice call one, but I'm just speaking from experience working on an app that could use either the speakerphone or the earpiece for audio playback, which requires the use of the voice call stream. Like I said, audio handling isn't particularly fun... ;)?
2:應用場景
?
Audio 輸出通道有很多,Speaker、headset、bluetooth A2DP等。
通話或播放音樂等使用Audio輸出過程中,可能發生Audio輸出通道的切換。比如,插入有線耳機播放音樂時,聲音是從耳機發出的;而此時拔出耳機,Audio輸出通道會發生切換。如果音樂播放器不做處理,Audio輸出是被切換到揚聲器的,聲音直接從Speaker發出。
Android中可以通過android.media.AudioManager查詢當前Audio輸出的情況,并且在Audio輸出發生變化時,捕獲并處理這種變化。
一、Audio輸出狀態查詢與控制
android.media.AudioManager提供的下列方法可以用來查詢當前Audio輸出的狀態:
?
- ?isBluetoothA2dpOn():檢查A2DPAudio是否通過藍牙耳機;
- ?isSpeakerphoneOn():檢查揚聲器是否打開;
- ?isWiredHeadsetOn():檢查線控耳機是否連著;注意這個方法只是用來判斷耳機是否是插入狀態,并不能用它的結果來判定當前的Audio是通過耳機輸出的,這還依賴于其他條件。
?
另外還有一些設置這些Audio輸出的setXYZ()方法,這些方法在一般使用Audio輸出的應用程序不要直接調用,他們由系統來管理,實現Audio輸出通道的自動切換。除非,界面提供給用戶切換的菜單或按鈕,而用戶選擇了卻換,比如要直接選擇揚聲器發聲,可直接調用setSpeakerphoneOn()。
?
二、Audio輸出通道切換的事件的捕獲與處理
因為耳機插拔、藍牙耳機的斷開,Audio輸出通路會自動切換。此時正在播放Audio的程序要獲得通知,知道這一事件的發生。Android中是通過廣播ACTION_AUDIO_BECOMING_NOISY這個Intent通知的。
處理廣播的較好的方式,是動態注冊/注銷自己所關心的廣播。下面代碼演示了,開始播放時注冊廣播的Receiver;停止播放時注銷廣播的Receiver。對Audio輸出通道切換的處理是暫停當前的播放,不直接從新的通道里發出聲來。
private class NoisyAudioStreamReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {// Pause the playback }} }private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);private void startPlayback() {registerReceiver(myNoisyAudioStreamReceiver(), intentFilter); }private void stopPlayback() {unregisterReceiver(myNoisyAudioStreamReceiver); }三、Audio輸出通道切換的典型場景—— 用耳機聽音樂時,拔出耳機
聽耳機聽音樂時,耳機別拔出的時序圖如下:
圖中:
?
- ?AudioNoisy Client注冊了偵聽廣播AudioManager.ACTION_AUDIO_BECOMING_NOISY[Step#1 ~ #2];
- ?用耳機一直在聽音樂;
- ?HeadsetObserver一直在監視耳機狀態的變化。檢測到耳機被拔出之后,發出廣播AudioManager.ACTION_AUDIO_BECOMING_NOISY[Step#3~4];
- ?AudioNoisy Client收到了廣播,發送暫停命令給MediaPaybackService去暫停當前的播放 [Step#5~6]。
?
?3:Android 文檔
Building Apps with Multimedia
These classes teach you how to create rich multimedia apps that behave the way users expect.
Managing Audio Playback
If your app plays audio, it’s important that your users can control the audio in a predictable manner. To ensure a great user experience, it’s also important that your app manages the audio focus to ensure multiple apps aren’t playing audio at the same time.After this class, you will be able to build apps that respond to hardware audio key presses, which request audio focus when playing audio, and which respond appropriately to changes in audio focus caused by the system or other applications. 為用戶提供便捷的音頻狀態控制對良好的用戶體驗是非常重要的。你可以構建響應物理音頻按鍵,獲取音頻播放焦點,以及適時的響應由于系統or其他應用引起的音頻焦點變化。?
?
How to respond to hardware audio key presses, request audio focus when playing audio, and respond appropriately to changes in audio focus.
?
引用:
http://blog.csdn.net/thl789/article/details/7423523
轉載于:https://www.cnblogs.com/conncui/p/4303795.html
總結
以上是生活随笔為你收集整理的Android Audio Play Out Channel的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#集合通论
- 下一篇: Android如果对APK进行加密,提高