Android的Audio音頻系統(tǒng).docx 免費下載
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、音頻系統(tǒng)JJJNNNIII初始化在 system_init(運行在 Simulator 上)或者 main_Mediaserver 中,AudioFlinger 被創(chuàng)建,會生成一個 AudioHardwareInterface 實例(Android 定義的音頻設備的一個抽象層),并且初始化音頻系統(tǒng)的模式和路由信息如下:mHardwareStatus = AUDIO_HW_IDLE; mAudioHardware = AudioHardwareInterface:create(); mHardwareStatus = AUDIO_HW_INIT;if (mAudioHardware-initCh
2、eck() = NO_ERROR) / open 16-bit output stream for s/w mixer mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;mOutput = mAudioHardware-openOutputStream(AudioSystem:PCM_16_BIT); mHardwareStatus = AUDIO_HW_IDLE;if (mOutput) mSampleRate = mOutput-sampleRate();mChannelCount = mOutput-channelCount();mFormat = mOutp
3、ut-format();mMixBufferSize = mOutput-bufferSize();mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t); mMixBuffer = new int16_tmFrameCount * mChannelCount; memset(mMixBuffer, 0, mMixBufferSize);mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);/ FIXME - this should come from settings
4、 setMasterVolume(1.0f);setRouting(AudioSystem:MODE_NORMAL, AudioSystem:ROUTE_SPEAKER,AudioSystem:ROUTE_ALL);setRouting(AudioSystem:MODE_RINGTONE,AudioSystem:ROUTE_SPEAKER, AudioSystem:ROUTE_ALL); setRouting(AudioSystem:MODE_IN_CALL, AudioSystem:ROUTE_EARPIECE,AudioSystem:ROUTE_ALL); setMode(AudioSys
5、tem:MODE_NORMAL); mMasterMute = false; else LOGE(Failed to initialize output stream); else LOGE(Couldnt even initialize the stubbed audio hardware!);在 SystemServer 啟動的時候,會生成一個 AudioService 的實例, try Log.i(TAG, Starting Audio Service);ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(c
6、ontext); catch (Throwable e) Log.e(TAG, Failure starting Volume Service, e);AudioService 的構造函數會讀取一些關于音頻的配置信息,比如 Ringer 和 vibrate 信息,private void readPersistedSettings() final ContentResolver cr = mContentResolver;mRingerMode=System.getInt(cr,System.MODE_RINGER,AudioManager.RINGER_MODE_NORMAL);mRinge
7、rModeAffectedStreams = System.getInt(mContentResolver,System.MODE_RINGER_STREAMS_AFFECTED,1AudioSystem.STREAM_RING);mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0);mMuteAffectedStreams = System.getInt(cr,System.MUTE_STREAMS_AFFECTED,(1 AudioSystem.STREAM_MUSIC)|(1 AudioSystem.STREAM_RING)|
8、(1 AudioSystem.STREAM_SYSTEM);/ Each stream will read its own persisted settings/ Broadcast the sticky intent broadcastRingerMode();/ Broadcast vibrate settings broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);同時也會從底層音頻系統(tǒng)讀取模式和
9、路由信息:private void readAudioSettings() synchronized (mSettingsLock) mMicMute = AudioSystem.isMicrophoneMuted();mMode = AudioSystem.getMode();for (int mode = 0; mode AudioSystem.NUM_MODES; mode+) mRoutesmode = AudioSystem.getRouting(mode);在 AudioSystem.cpp 第一次調用 get_audio_flinger 成功后,它會通過 binder 來監(jiān)聽運行
10、在 media_server 進程中的 AudioFlinger 是否活著。/ establish binder interface to AudioFlinger serviceconst sp& AudioSystem:get_audio_flinger()Mutex:Autolock _l(gLock); if (gAudioFlinger.get() = 0) sp sm = defaultServiceManager(); sp binder;do binder = sm-getService(String16(media.audio_flinger); if (binder !=
11、0)break;LOGW(AudioFlinger not published, waiting.);usleep(500000); / 0.5 s while(true);if (gDeathNotifier = NULL) gDeathNotifier = new DeathNotifier(); else if (gAudioErrorCallback) gAudioErrorCallback(NO_ERROR);binder-linkToDeath(gDeathNotifier);gAudioFlinger = interface_cast(binder);LOGE_IF(gAudio
12、Flinger=0, no AudioFlinger!?);return gAudioFlinger;到此,整個音頻系統(tǒng)初始化完畢。重新啟動如果 AudioFlinger 運行的 media_server 進程異常死掉,AudioSystem 會收到一個事件通知, void AudioSystem:DeathNotifier:binderDied(const wp& who) Mutex:Autolock _l(AudioSystem:gLock);AudioSystem:gAudioFlinger.clear();if (gAudioErrorCallback) gAudioErrorCal
13、lback(DEAD_OBJECT);LOGW(AudioFlinger server died!);從而調用 android_media_AudioSystem.cpp 注冊下來的回調函數,該函數又是通過 JNI 來調用 AudioService.java 注冊下來的回調函數,在該函數中會發(fā)送MSG_MEDIA_SERVER_DIED消息,AudioService 會監(jiān)聽這個消息,這樣 AudioService 就能知道 AudioFlinger 已不工作,它就接著調用 getMode 來嘗試連接到重啟后的 AudioFlinger。case MSG_MEDIA_SERVER_DIED:Lo
14、g.e(TAG, Media server died.);/ Force creation of new IAudioflinger interface mMediaServerOk = false; AudioSystem.getMode();break;當連接成功后,AudioFlinger 會調用 android_media_AudioSystem.cpp 注冊下來的回調函數,該函數又是通過 JNI 來調用 AudioService.java 注冊下來的回調函數,在該函數中會發(fā)送 MSG_MEDIA_SERVER_STARTED 消息。接著 AudioService 就去配置底層音頻系統(tǒng)
15、,包括模式、路由、每一路流的音量大小和 Ringer 狀態(tài)。case MSG_MEDIA_SERVER_STARTED:/ Restore audio routing and stream volumes applyAudioSettings();for (int streamType = AudioSystem.NUM_STREAMS - 1; streamType= 0; streamType-) int volume;VolumeStreamState streamState = mStreamStatesstreamType; if (streamState.muteCount() =
16、 0) volume = streamState.mVolumesstreamState.mIndex; else volume = streamState.mVolumes0;AudioSystem.setVolume(streamType, volume);setRingerMode();Note: AudioSystem 的 Native 實 現 在 device/libs/android_runtime/android_media_AudioSystem.cpp 中。模式初始的時候音頻系統(tǒng)是處于 MODE_NORMAL 模式的,下面是其模式狀態(tài)變遷圖:問題:當一個 Ringtone 放
17、完了之后,理論上系統(tǒng)是否要自動切換回 NORMAL 模式而不是必須要主動調用 stopRing?我沒找到相關 code。路由信息1. 當 HeadsetObserver 檢測到有耳機插上來的時候,它會把音頻系統(tǒng)的路由設置成均使用該耳機;當耳機被拔下來后,它會把音頻系統(tǒng)的路由設置成缺省配置(即都通過揚聲器)。private synchronized final void update(String newName, int newState) if (newName != mHeadsetName | newState != mHeadsetState) mHeadsetName = newNa
18、me; mHeadsetState = newState;AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);if (mHeadsetState = 1) audioManager.setRouting(AudioManager.MODE_NORMAL,AudioManager.ROUTE_HEADSET,AudioManager.ROUTE_ALL);audioManager.setRouting(AudioManager.MODE_RINGTONE,Audio
19、Manager.ROUTE_HEADSET|AudioManager.ROUTE_SPEAKER,AudioManager.ROUTE_ALL);audioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_HEADSET,AudioManager.ROUTE_ALL); else audioManager.setRouting(AudioManager.MODE_NORMAL,AudioManager.ROUTE_SPEAKER,AudioManager.ROUTE_ALL);audioManager.setRou
20、ting(AudioManager.MODE_RINGTONE, AudioManager.ROUTE_SPEAKER,AudioManager.ROUTE_ALL);audioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_EARPIECE,AudioManager.ROUTE_ALL);sendIntent();PhoneApp 會接收到一個 ACTION_HEADSET_PLUG 的 Intent,往自身發(fā)送一個消息,處理如下:只是在沒有藍牙耳機或者未使用藍牙耳機,而且該有線耳機是被拔掉的情況下,才把路由信
21、息設置成 MODE_IN_CALL 走 ROUTE_SPEAKER。 case EVENT_WIRED_HEADSET_PLUG:/ Since the presence of a wired headset or bluetooth affects the/ speakerphone, update the speaker state. We ONLY want to do/ this on the wired headset connect / disconnect events for now/ though,sowereonlytriggeringonEVENT_WIRED_HEADS
22、ET_PLUG.if (!isHeadsetPlugged() &(mBtHandsfree = null | !mBtHandsfree.isAudioOn() / is the state is not connected, restore the speaker state. PhoneUtils.restoreSpeakerMode(getApplicationContext();NotificationMgr.getDefault().updateSpeakerNotification(); break;問題:假設耳機插上來之前是通過藍牙耳機在接聽電話(或者聽音樂)的,耳機插上來的時
23、候系統(tǒng)就自動切換到使用耳機了,但是 PhoneApp 這個時候并不知道,它還以為在繼續(xù)使用藍牙耳機。但當耳機拔掉之后,怎么再切換回繼續(xù)使用藍牙耳機呢(系統(tǒng)默認是切換成EARPIECE)?這個時候 PhoneApp 的狀態(tài)應該是不對的。2. 當在 Setting 里面把藍牙耳機配對和 RFCOMM 連接上之后,BluetoothHeadsetService 會負責去和藍牙耳機建立 SCO 連接,當連接完成之后 BluetoothHandsfree 會調用AudioManager 的 setBluetoothScoOn 函數來通知音頻系統(tǒng)去切換 MODE_IN_CALL 路由信息到使用 ROUTE
24、_BLUETOOTH。/* Sets audio routing to the Bluetooth headset on or off.* param on set true to route SCO (voice) audio to/from Bluetooth* headset; false to route audio to/from phone earpiece*/public void setBluetoothScoOn(boolean on)setRouting(MODE_IN_CALL, on ? ROUTE_BLUETOOTH : ROUTE_EARPIECE, ROUTE_A
25、LL);當藍牙設備被關閉或者鏈接斷掉的時候,BluetoothHeadsetService 會收到一個 DISABLED_ACTION 的 Intent ,接著 BluetoothHandsfree 會調用 AudioManager 的 setBluetoothScoOn 函數來通知音頻系統(tǒng)去切換 MODE_IN_CALL 路由信息到ROUTE_EARPIECE。問題:setBluetoothScoOn 的實現在處理藍牙設備被關閉的時候,是直接把路由信息改成到ROUTE_EARPIECE,并沒有恢復到使用藍牙設備之前的信息狀態(tài)。Ringtone 是否需要在藍牙耳機上播放呢?音量控制對外接口是
26、AudioManager播放音頻系統(tǒng)對外的播放接口是 AudioTrack,每一路音頻會對應一個 AudioTrack 的實例,它會通過 iBinder 來遠程調用 AudioFlinger 的 createTrack 函數。/ create the tracksp track = audioFlinger-createTrack(getpid(),streamType, sampleRate, format, channelCount, bufferCount, flags);if (track = 0) LOGE(AudioFlinger could not create track);r
27、eturn NO_INIT;sp cblk = track-getCblk();if (cblk = 0) LOGE(Could not get control block);return NO_INIT;而 AudioFlinger 的 createTrack 又會在內部生成一個 Track 實例,再將其包裝成 TrackHandle 返回給 AudioTrack。track = new Track(this, client, streamType, sampleRate, format,channelCount,bufferCount,channelCount=1?mMixBufferSi
28、ze1:mMixBufferSize);mTracks.add(track);trackHandle = new TrackHandle(track);return trackHandle;所以 AudioTrack 和 AudioFlinger 實際操作的都是 Track 實例,AudioTrack 通過它來執(zhí)行控制操作(start/stop)和寫入操作(write),AudioFlinger 則負責管理多個 Track(包括調用 AudioMixer 來混音)。兩者之間的關系可以用生產者/消費者來類比,AudioTrack 是生產者, AudioFlinger 則是消費者。AudioTra
29、ckAudioTrack 的 start/stop 操作可以理解成一個開關,控制的是是否將與之對應的 Track 實例納入 AudioFlinger 的管理中去,下面僅以 start 操作為例。 void AudioTrack:start()LOGV(start);if (mAudioTrackThread != 0) mAudioTrackThread-mLock.lock();if (android_atomic_or(1, &mActive) = 0) setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);mActive =
30、 1;mAudioTrack-start();if (mAudioTrackThread != 0) mAudioTrackThread-run(AudioTrackThread,THREAD_PRIORITY_AUDIO_CLIENT);if (mAudioTrackThread != 0) mAudioTrackThread-mLock.unlock();status_t AudioFlinger:TrackHandle:start() return mTrack-start();status_t AudioFlinger:Track:start()LOGV(start(%d), mNam
31、e);mAudioFlinger-addTrack(this);return NO_ERROR;status_t AudioFlinger:addTrack(const sp& track)Mutex:Autolock _l(mLock);/ here the track could be either new, or restarted/ in both cases unstop the trackif (track-isPaused() track-mState = TrackBase:RESUMING; LOGV(PAUSED = RESUMING (%d), track-name();
32、 else track-mState = TrackBase:ACTIVE;LOGV(? = ACTIVE (%d), track-name();LOGV(mWaitWorkCV.broadcast);mWaitWorkCV.broadcast();if (mActiveTracks.indexOf(track) mFillingUpStatus = Track:FS_FILLING;mActiveTracks.add(track);return NO_ERROR;return ALREADY_EXISTS;AudioTrack 的 write 則是往 audio_track_cblk_t 結
33、構中寫入數據。ssize_t AudioTrack:write(const void* buffer, size_t userSize)LOGV(write %d bytes, mActive=%d, userSize, mActive);ssize_t written = 0;do if (mPosition = 0) status_t err = obtainBuffer(&mAudioBuffer, true);if (err 0) / out of buffers, return #bytes writtenif (err = status_t(NO_MORE_BUFFERS)brea
34、k;return ssize_t(err);size_t capacity = mAudioBuffer.size - mPosition;size_t toWrite = userSize capacity ? userSize : capacity;memcpy(mAudioBuffer.i8 + mPosition, buffer, toWrite);buffer = static_cast(buffer) + toWrite;mPosition += toWrite;userSize -= toWrite;capacity -= toWrite;written += toWrite;i
35、f (capacity = 0) mPosition = 0;releaseBuffer(&mAudioBuffer); while (userSize); return written;AudioFlingerAudioFlinger 對 Track 的管理是實現在 threadLoop 中的。先檢測進入 standby 的超時是否到了,超時的話 AudioFlinger 會調用 AudioHardwareInterface 的 standby,這個是為省電考慮的。nsecs_t standbyTime = systemTime();do enabledTracks = 0; / scope
36、 for the lock Mutex:Autolock _l(mLock);const SortedVector wp & activeTracks = mActiveTracks; / put audio hardware into standby after short delayif UNLIKELY(systemTime() standbyTime) / wait until we have something to do.LOGD(Audio hardware entering standbyn); mHardwareStatus = AUDIO_HW_STANDBY; if (!
37、mStandby) mAudioHardware-standby(); mStandby = true;mHardwareStatus = AUDIO_HW_IDLE;/ were about to wait, flush the binder command buffer IPCThreadState:self()-flushCommands(); mWaitWorkCV.wait(mLock);LOGD(Audio hardware exiting standbyn); standbyTime = systemTime() + kStandbyTimeInNsecs;continue;如果
38、未進 standby,接下來遍歷所有當前 Active 的 Track 實例。/ find out which tracks need to be processed size_t count = activeTracks.size();for (size_t i=0 ; icount ; i+) sp t = activeTmote(); if (t = 0) continue;Track* const track = t.get();audio_track_cblk_t* cblk = track-cblk();uint32_t u = cblk-user;uint32
39、_t s = cblk-server;/ The first time a track is added we wait/ for all its buffers to be filled before processing it audioMixer().setActiveTrack(track-name();當有某個 Track 的數據需要處理時(數據存儲在 audio_track_cblk_t 結構中,其 user 域表明當前寫入指針在 buffer 中的位置,server 域表明讀取指針在 buffer 中的位置,所以只有當 user 大于 server 的時候說明有數據要處理),先計
40、算該 Track 的 volume 信息,然后去配置針對該路 Track 的 Mixer 信息。if (u s) & (track-isReady(u, s) | track-isStopped() & !track-isPaused()/ compute volume for this track/ setup mixer needed information here AudioMixer& mixer(audioMixer(); mixer.setBufferProvider(track); mixer.enable(AudioMixer:MIXING);enabledTracks+;
41、else 最后進入真正的混音操作,再把混音過后的數據寫到 AudioHardwareInterface 生成的AudioOutputStream 中,由此整個音頻輸出完成。if (LIKELY(enabledTracks) / mix buffers.audioMixer().process(curBuf);/ output audio to hardware mLastWriteTime = systemTime(); mInWrite = true; mOutput-write(curBuf, mixBufferSize); mNumWrites+;mInWrite = false;mSt
42、andby = false;nsecs_t temp = systemTime();standbyTime = temp + kStandbyTimeInNsecs;nsecs_t delta = temp - mLastWriteTime;if (delta maxPeriod) LOGW(write blocked for %llu msecs, ns2ms(delta); mNumDelayedWrites+;sleepTime = kBufferRecoveryInUsecs; else 當所有 Active 的 Track 都沒有數據需要處理的時候,AudioFlinger 會 us
43、leep 一段時間從而進入 standby。/ There was nothing to mix this round, which means all/ active tracks were late. Sleep a little bit to give/ them another chance. If were too late, the audio/ hardware will zero-fill for us.LOGV(no buffers - usleep(%lu), sleepTime);usleep(sleepTime);if (sleepTime kMaxBufferReco
44、veryInUsecs) sleepTime += kBufferRecoveryInUsecs;錄制音頻系統(tǒng)對外的錄制接口是 AudioRecord,它會通過 iBinder 來遠程調用 AudioFlinger 的 openRecord 函數。/ open record channelsp record = audioFlinger-openRecord(getpid(), streamType, sampleRate, format, channelCount, bufferCount, flags);if (record = 0) return NO_INIT;sp cblk = re
45、cord-getCblk();if (cblk = 0) return NO_INIT;if (cbf != 0) mClientRecordThread = new ClientRecordThread(*this); if (mClientRecordThread = 0) return NO_INIT;而 AudioFlinger 的 openRecord 又會在內部先生成一個 AudioRecordThread 并且拿到AudioStreamIn,/ Create audio thread - take mutex to prevent race conditionMutex:Auto
46、lock _l(mLock);if (mAudioRecordThread != 0) LOGE(Record channel already open); goto Exit;thread = new AudioRecordThread(this); mAudioRecordThread = thread;/ Its safe to release the mutex here since the client doesnt get a/ handle until we return from this call/ open driver, initialize h/winput = mAu
47、dioHardware-openInputStream(AudioSystem:PCM_16_BIT, channelCount, sampleRate);再生成一個 RecordTrack 實例,將其包裝成 RecordTrackHandle 返回給 AudioRecord。 / create new record track and pass to record threadrecordTrack = new RecordTrack(this, client, streamType, sampleRate, format, channelCount, bufferCount, input-bufferSize();/ spin up record threadthread-open(recordTrack, input);thread-run(AudioRecordThread, PRIORITY_URGENT_AUDIO);/ return to handle to clientrecordHandle = new RecordHandle(recordTrack);所以 AudioRecord 和 AudioFlinger
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度采光井玻璃更換與維護合同3篇
- 二零二五年度氣象站氣象數據安全保障合同3篇
- 2024蘇州租賃合同含寵物飼養(yǎng)及養(yǎng)護服務條款3篇
- 2024版民間借貸合同范例
- 2025年度茶樓裝修工程消防設施合同范本4篇
- 2025年度10kv配電站施工期間質量檢測與驗收合同正規(guī)范本3篇
- 2025年度教育機構LOGO知識產權許可合同范本3篇
- 2025年度智能物流系統(tǒng)全國代理銷售合同4篇
- 2025年度廠房施工合同施工人員培訓協議(新版)3篇
- 2025年度智能工廠改造裝修合同模板3篇
- 小學四年級數學知識點總結(必備8篇)
- GB/T 893-2017孔用彈性擋圈
- GB/T 11072-1989銻化銦多晶、單晶及切割片
- GB 15831-2006鋼管腳手架扣件
- 醫(yī)學會自律規(guī)范
- 商務溝通第二版第4章書面溝通
- 950項機電安裝施工工藝標準合集(含管線套管、支吊架、風口安裝)
- 微生物學與免疫學-11免疫分子課件
- 《動物遺傳育種學》動物醫(yī)學全套教學課件
- 弱電工程自檢報告
- 民法案例分析教程(第五版)完整版課件全套ppt教學教程最全電子教案
評論
0/150
提交評論