Android Framework学习笔记 -- 蓝牙设备播放流程
2017-11-12 10:54
489 查看
因为蓝牙通路与其他设备不同(多了一个蓝牙设备),因此播放的流程也与其他设备略有不同。
openOutput的流程跟其他Output的流程是一样的,最终在AudioFlinger建立了对应Output的Thread。DuplicateOutput使用openDuplicateOutput来打开,最终也是在AudioFlinger建立一个DuplicatingThread。
DuplicatingThread的addOutputTrack会创建对应thread的track(也就是生产者啦)
OutputThrack与AudioTrack类似,也是用obtainBuffer与releaseBuffer来驱动PlaybackThread
DuplicatingThread作用很明了,就是把一个output的流dup到其他output,这个一开始看名字就看出来了,就是不知道关联的是那个output,驱动其他两个thread的方式。
蓝牙设备的连接
从setDeviceConnectionState开始,AudioPolicyManager先注册Device后,再去打开设备对应的output,如果是duplicating类型的话,还要建一个DuplicateOutput,关联该output与mPrimaryOutput//--->frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name) { return setDeviceConnectionStateInt(device, state, device_address, device_name); } status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name) { ... sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(device, device_address, device_name); ... // handle output devices ... SortedVector <audio_io_handle_t> outputs; ssize_t index = mAvailableOutputDevices.indexOf(devDesc); mPreviousOutputs = mOutputs; ...(注册设备) if (index >= 0) { sp<HwModule> module = mHwModules.getModuleForDevice(device); if (module == 0) { mAvailableOutputDevices.remove(devDesc); return INVALID_OPERATION; } mAvailableOutputDevices[index]->attach(module); } else { return NO_MEMORY; } if (checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress) != NO_ERROR) { mAvailableOutputDevices.remove(devDesc); return INVALID_OPERATION; } ... } status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> devDesc, audio_policy_dev_state_t state, SortedVector<audio_io_handle_t>& outputs, const String8 address) { ... // 打开设备所对应的output for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) { sp<IOProfile> profile = profiles[profile_index]; ... status_t status = mpClientInterface->openOutput(profile->getModuleHandle(), &output, &config, &desc->mDevice, address, &desc->mLatency, desc->mFlags); } ... // 后续处理 if (output != AUDIO_IO_HANDLE_NONE) { addOutput(output, desc); ... else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && hasPrimaryOutput()) { ... // open a duplicating output thread for the new output and the primary output duplicatedOutput = mpClientInterface->openDuplicateOutput(output, mPrimaryOutput->mIoHandle); ... } } }
openOutput的流程跟其他Output的流程是一样的,最终在AudioFlinger建立了对应Output的Thread。DuplicateOutput使用openDuplicateOutput来打开,最终也是在AudioFlinger建立一个DuplicatingThread。
//--->frameworks/av/services/audiopolicy/service/AudioPolicyClientImpl.cpp // AudioPolicyService的转发 audio_io_handle_t AudioPolicyService::AudioPolicyClient::openDuplicateOut 4000 put( audio_io_handle_t output1, audio_io_handle_t output2) { sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); if (af == 0) { ALOGW("%s: could not get AudioFlinger", __func__); return 0; } return af->openDuplicateOutput(output1, output2); } //--->frameworks/av/services/audioflinger/AudioFlinger.cpp audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2) { // 这里两个output对应的thread都是MixerThread,意味着DuplicatingThread对应的线程是MixerThread?? Mutex::Autolock _l(mLock); MixerThread *thread1 = checkMixerThread_l(output1); MixerThread *thread2 = checkMixerThread_l(output2); ... audio_io_handle_t id = nextUniqueId(); DuplicatingThread *thread = new DuplicatingThread(this, thread1, id, mSystemReady); thread->addOutputTrack(thread2); mPlaybackThreads.add(id, thread); thread->ioConfigChanged(AUDIO_OUTPUT_OPENED); return id; } //--->frameworks/av/services/audioflinger/Threads.cpp AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, audio_io_handle_t id, bool systemReady) : MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->outDevice(), systemReady, DUPLICATING), mWaitTimeMs(UINT_MAX) { addOutputTrack(mainThread); }
DuplicatingThread的addOutputTrack会创建对应thread的track(也就是生产者啦)
//--->frameworks/av/services/audioflinger/Threads.cpp void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) { Mutex::Autolock _l(mLock); // The downstream MixerThread consumes thread->frameCount() amount of frames per mix pass. // Adjust for thread->sampleRate() to determine minimum buffer frame count. // Then triple buffer because Threads do not run synchronously and may not be clock locked. const size_t frameCount = 3 * sourceFramesNeeded(mSampleRate, thread->frameCount(), thread->sampleRate()); sp<OutputTrack> outputTrack = new OutputTrack(thread, this, mSampleRate, mFormat, mChannelMask, frameCount, IPCThreadState::self()->getCallingUid()); ... }
DuplicatingThread播放
普通的连蓝牙播放(音乐,触屏音等)还不会用到DuplicatingThread,只有在需要双设备播放的情况下(如闹铃,来电等),才会用到DuplicatingThread。DuplicatingThread跟别的PlaybackThread一样,也有prepareTrack_l和mix,就是write的时候不大一样。ssize_t AudioFlinger::DuplicatingThread::threadLoop_write() { // 对每个Tracks写数据 这里DuplicatingThread相当于生产者了 for (size_t i = 0; i < outputTracks.size(); i++) { outputTracks[i]->write(mSinkBuffer, writeFrames); } mStandby = false; return (ssize_t)mSinkBufferSize; }
OutputThrack与AudioTrack类似,也是用obtainBuffer与releaseBuffer来驱动PlaybackThread
bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) { ... while (waitTimeLeftMs) { ... status_t status = obtainBuffer(&mOutBuffer, waitTimeLeftMs); ... memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize); ... mClientProxy->releaseBuffer(&buf); } ... }
DuplicatingThread作用很明了,就是把一个output的流dup到其他output,这个一开始看名字就看出来了,就是不知道关联的是那个output,驱动其他两个thread的方式。
相关文章推荐
- Android Framework学习笔记 -- Audio调节音量流程
- Android usb学习笔记:Android AOA协议设备端 流程总结
- android中Mms学习笔记——短信(sms)接收流程(三)
- android 蓝牙学习笔记
- android 多媒体部分学习笔记十--简单视频播放
- android中Mms学习笔记——彩信(mms)发送流程和就收流程(四)
- Android 中的WiFi学习笔记(转载)----WIFI启动 代码流程走读---网络连接流程
- WebSocket 学习笔记--IE,IOS,Android等设备的兼容性问题与代码实现
- [API GUIDE 学习笔记]android MediaPlayer 播放视频
- Android 中的WiFi学习笔记(转载)----WIFI启动 代码流程走读---网络连接流程
- Android 学习笔记多媒体技术之 AsyncTask+实现音频播放...
- DirectSound学习笔记之 创建播放设备
- Android源码学习笔记1-短信发送流程分析
- Android应用开发学习笔记之播放视频
- Android游戏开发学习笔记(三):视频的播放
- android 蓝牙学习笔记
- WebSocket学习笔记–IE,IOS,Android等设备的兼容性问题与代码实现
- Android应用开发学习笔记之播放视频
- android中Mms学习笔记——短信(sms)发送流程(二)
- Android游戏开发学习笔记(二):音频的播放