一、Android Audio Play Out Channel
揚聲器、耳機、聽筒,通過這兩個來設(shè)置,不過有的好像不支持的
/frameworks/base/media/java/android/media/AudioManager.java audiomanager.setmode(AudioManager.MODE_IN_COMMUNICATION) audiomanager.setSpeakerhponeOn(booleanvalue)
音頻資源在播放時,會經(jīng)常出現(xiàn)沖突的情況,如在進行音樂播放時有電話呼入、有新消息的提示音需要播放等,此類的并發(fā)處理就需要有一個統(tǒng)一的處理策略。
在Android系統(tǒng)開發(fā)中,通過為不同的場景配置不同的播放接口,在底層執(zhí)行統(tǒng)一的并發(fā)策略,使得開發(fā)者可以將精力更集中在應(yīng)用本身。
AudioTrack、MediaPlayer、SoundPool、Ringtone、JetPlayer等都是Android音頻處理中常用接口
針對AudioTrack接口進行詳細說明
(1).AudioTrack、AudioTrack用于管理單個的音頻資源。在構(gòu)造AudioTrack實例時,會涉及到流類型、采樣率、通道配置、音頻格式、緩沖大小、播放模式等因素。
(2).AudioTrack支持STREAM_VOICE_CALL、STREAM_SYSTEM、STREAM_RING、STREAM_MUSIC和STREAM_ALARM等流類型。
(3).AudioTrack支持44100Hz、22050Hz、11025Hz等采樣率。
(4).AudioTrack支持單聲道(CHANNEL_OUT_MONO)、
立體聲(CHANNEL_OUT_STEREO)等兩種通道。
(5).AudioTrack支持ENCODING_PCM_16BIT、ENCODING_PCM_8BIT等兩種編碼格式。
(6).AudioTrack支持兩種播放模式
靜態(tài)模式(static mode)
流模式(Streaming mode)
其中靜態(tài)模式由于沒有從Java層向原生層傳遞數(shù)據(jù)造成的延遲,時延很小,當(dāng)然受限于音頻緩沖的大小,通常在游戲場景中用于播放時長很短的音頻資源。
當(dāng)音頻流較大不足以在音頻緩沖中一次寫入時,可采用流模式。
AudioTrack的播放狀態(tài)包括
PLAYSTATE_STOPPED
PLAYSTATE_PAUSED
PLAYSTATE_PLAYING等
AudioTrack實例的狀態(tài)包括
STATE_INITIALIZED
STATE_NO_STATIC_DATA
STATE_UNINITIALIZED等
向音頻緩沖中添加數(shù)據(jù)的方法為write()
在設(shè)置音頻緩沖時,其大小與采樣率、通道和音頻格式有關(guān),其計算公式為:
緩沖大小 = 最小幀數(shù) × (通道==CHANNEL_OUT_STEREO?2:1) × (音頻格式== PCM16?2:1)
而最小幀數(shù)則受制于采樣率和音頻設(shè)備的延遲等因素
另外,在Android2.3中,還引入了會話的概念,便于對單曲的音效進行處理。相應(yīng)的方法包括:
attachAuxEffect()
getAudioSessionId()
setAuxEffectSendLevel()等
通過AudioTrack.OnPlaybackPositionUpdateListener監(jiān)聽器可以監(jiān)聽播放進度
當(dāng)在聽歌的時候,突然來了一條短信,如果不加處理,短信的聲音很可能被音樂的聲音湮沒,就會察覺不到。
獲取和釋放audio focus的過程
(1).申請audio focus
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); intresult=audioManager.requestAudioFocus(this,AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN);
(2).處理focus change事件
class MyService extends Service implements AudioManager.OnAudioFocusChangeListener { // .... public void onAudioFocusChange(int focusChange) { // Do something based on focus change... } }
申請audio focus和處理focus change一定是互相配合實現(xiàn)的
android聽筒播放音樂
AudioManager.setMode(AudioManager.MODE_IN_CALL)//設(shè)定為通話中即可 添加權(quán)限 android.permission.MODIFY_AUDIO_SETTINGS 播放完畢后需要 AudioManager.setMode(AudioManager.MODE_NORMAL);
不然其他軟件播放都聽筒發(fā)聲,實際操作中,僅僅上述代碼并不能是實現(xiàn)需求
Android 5.0.1 audiomanager.setMode(AudioManager.MODE_IN_CALL); //不能生效,即便添加該行仍然從揚聲器播出
應(yīng)用場景
Audio輸出通道有很多,Speaker、headset、bluetooth A2DP等
Android中的Audio播放(控制Audio輸出通道切換)
通話或播放音樂等使用Audio輸出過程中,可能發(fā)生Audio輸出通道的切換
例如:
插入有線耳機播放音樂時,聲音是從耳機發(fā)出的;而此時拔出耳機,Audio輸出通道會發(fā)生切換。如果音樂播放器不做處理,Audio輸出是被切換到揚聲器的,聲音直接從Speaker發(fā)出。
Android中可以通過android.media.AudioManager查詢當(dāng)前Audio輸出的情況,并且在Audio輸出發(fā)生變化時,捕獲并處理這種變化。
(1).Audio輸出狀態(tài)查詢與控制
android.media.AudioManager提供的下列方法可以用來查詢當(dāng)前Audio輸出的狀態(tài)
isBluetoothA2dpOn() //檢查A2DPAudio是否通過藍牙耳機
isSpeakerphoneOn() //檢查揚聲器是否打開
isWiredHeadsetOn() //檢查線控耳機是否連著,注意這個方法只是用來判斷耳機是否是插入狀態(tài),并不能用它的結(jié)果來判定當(dāng)前的Audio是通過耳機輸出的,這還依賴于其他條件。
另外還有一些設(shè)置這些Audio輸出的setXYZ()方法,這些方法在一般使用Audio輸出的應(yīng)用程序不要直接調(diào)用,他們由系統(tǒng)來管理,實現(xiàn)Audio輸出通道的自動切換。除非,界面提供給用戶切換的菜單或按鈕,而用戶選擇了卻換
例如:
要直接選擇揚聲器發(fā)聲,可直接調(diào)用setSpeakerphoneOn()
(2).Audio輸出通道切換的事件的捕獲與處理
因為耳機插拔、藍牙耳機的斷開,Audio輸出通路會自動切換。此時正在播放Audio的程序要獲得通知,知道這一事件的發(fā)生。
Android中是通過廣播ACTION_AUDIO_BECOMING_NOISY這個Intent通知的。
處理廣播的較好的方式,是動態(tài)注冊/注銷自己所關(guān)心的廣播。
開始播放時注冊廣播的Receiver,停止播放時注銷廣播的Receiver。對Audio輸出通道切換的處理是暫停當(dāng)前的播放,不直接從新的通道里發(fā)出聲來
private class NoisyAudioStreamReceiver extends BroadcastReceiver { @Override public 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); }
(3).Audio輸出通道切換的典型場景——用耳機聽音樂時,拔出耳機
AudioNoisy Client注冊了偵聽廣播
AudioManager.ACTION_AUDIO_BECOMING_NOISY
用耳機一直在聽音樂
HeadsetObserver一直在監(jiān)視耳機狀態(tài)的變化。檢測到耳機被拔出之后,發(fā)出廣播AudioManager.ACTION_AUDIO_BECOMING_NOISY
frameworks/base/services/java/com/android/server/HeadsetObserver.java
AudioNoisy Client收到了廣播,發(fā)送暫停命令給MediaPaybackService去暫停當(dāng)前的播放
Managing Audio Playback
提供便捷的音頻狀態(tài)控制
可以構(gòu)建響應(yīng)物理音頻按鍵,獲取音頻播放焦點,以及適時的響應(yīng)由于系統(tǒng)或其他應(yīng)用引起的音頻焦點變化
三個AudioCommandThread線程分別是ApmTone、ApmAudio、ApmOutput
ApmTone用于播放tone音
ApmAudio用于執(zhí)行audio命令
ApmOutput用于執(zhí)行輸出命令
在AudioPolicyManager創(chuàng)建過程中會通過加載audio_policy.conf配置文件來加載音頻設(shè)備,Android為每種音頻接口定義了對應(yīng)的硬件抽象層。硬件抽象層代碼
hardware/libhardware/modules/audio external/bluetooth/bluedroid/audio_a2dp_hw/audio.a2dp.default.so hardware/libhardware/modules/audio/audio.primary.default.so hardware/libhardware/modules/usbaudio/audio.usb.default.so
原文鏈接: https://www.shuzhiduo.com/A/1O5EDokGJ7/ https://blog.csdn.net/thl789/article/details/7423523 https://www.shuzhiduo.com/A/Gkz1Lj3GdR/
二、Android上播放視頻時沒有聲音的問題
(1).如果在android上播放視頻時遇到?jīng)]有聲音的問題,要么是android手機上有問題,要么就是視頻本身有問題。無論那種情況,都有相對應(yīng)的解決方案。
(2).在Android Audio相關(guān)開發(fā)過程中,可能會遇到播放ringtone時無聲,但播放Music可以聽到聲音,關(guān)于無聲問題的分析。
三、Android設(shè)備上播放有聲視頻的技巧
(1).始終保持揚聲器清潔
(2).未經(jīng)驗證的應(yīng)用程序不應(yīng)安裝在設(shè)備上
(3).手機的音頻端口。這是因為一旦拔出耳機,某些設(shè)備就會卡在耳機模式
(4).還應(yīng)檢查聽筒
四、Android Audio遇到播放無聲時的分析思路
(1).在音量控制面板中確認該音頻流對應(yīng)的Volume_index大小是否等于0
(2).若Volume_index != 0時,看user space的logcat與kernel log中有無明顯的Audio Fail項,比如設(shè)備是否選擇正確以及對應(yīng)的路徑是否有配通
(3).在hardware層,在audio_hw.cpp文件中的out_write函數(shù)中添加log,判斷是否有數(shù)據(jù)寫入(QCOM MSM8939)
/hardware/libhardware/modules/audio_remote_submix/audio_hw.cpp 785 static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, 786 size_t bytes)
(4).通過dumpsys media.audio_policy命令來查看對應(yīng)音頻流是否被mute住,若被mute,需要分析AudioPolicyManager.cpp文件
/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
(5).看當(dāng)前音源檔本身的音量是否為0
其中1與5之間的區(qū)別在于:
在播放某音源檔時,在AudioTrack::set()函數(shù)里,先將音源數(shù)據(jù)的左右聲道的Volume設(shè)置為1.0,即為最大聲。而通過音量按鍵或則在VolumePanel中調(diào)節(jié)音量則是在最大音量基礎(chǔ)上做衰減操作
/frameworks/av/media/libaudioclient/AudioTrack.cpp 326 status_t AudioTrack::set( 327 audio_stream_type_t streamType, 328 uint32_t sampleRate, 329 audio_format_t format, 330 audio_channel_mask_t channelMask, 331 size_t frameCount, 332 audio_output_flags_t flags, 333 callback_t cbf, 334 void* user, 335 int32_t notificationFrames, 336 const sp& sharedBuffer, 337 bool threadCanCallJava, 338 audio_session_t sessionId, 339 transfer_type transferType, 340 const audio_offload_info_t *offloadInfo, 341 uid_t uid, 342 pid_t pid, 343 const audio_attributes_t* pAttributes, 344 bool doNotReconnect, 345 float maxRequiredSpeed, 346 audio_port_handle_t selectedDeviceId)
/frameworks/base/services/core/java/com/android/server/audio/AudioService.java mVolumeControlStream VolumePanel /frameworks/base/media/java/android/media/AudioManager.java VolumePanel
(6).在Android開發(fā)中可以通過AudioManager來判斷是否有聲音在播放
/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java /frameworks/base/media/java/android/media/AudioManager.java 2046 public boolean isMusicActive() { 2047 return AudioSystem.isStreamActive(STREAM_MUSIC, 0); 2048 }
(7).Android中的Audio播放(分析控制Audio輸出通道切換設(shè)置)
檢查Android Audio音頻setMode()的默認設(shè)置 AudioManager.setMode(AudioManager.MODE_NORMAL);
Android各版本系統(tǒng)源碼在線閱讀地址
http://aospxref.com/ http://androidxref.com https://aosp.opersys.com https://wiki.lineageos.org/devices/ https://wiki.pixelexperience.org/devices/
審核編輯:劉清
-
PCM
+關(guān)注
關(guān)注
1文章
196瀏覽量
53318 -
編碼器
+關(guān)注
關(guān)注
45文章
3663瀏覽量
135024 -
JAVA
+關(guān)注
關(guān)注
19文章
2973瀏覽量
104944 -
Android系統(tǒng)
+關(guān)注
關(guān)注
0文章
56瀏覽量
13534
原文標題:Android10以上系統(tǒng)Audio音頻遇到播放視頻無聲時的分析方法
文章出處:【微信號:哆啦安全,微信公眾號:哆啦安全】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論