Android 系统播放声音,需要创建AudioTrack来和AudioFlinger通信,其创建过程如下
- 根据传入的声音属性得到output
- 通过得到的output,找到播放线程
- AudioFlinger在播放线程内,创建Track,和AudioTrack对应。后续通过它们进行通信
接下来分别看下其过程
找到output
在getOutputForAttr函数内,直接调用getOutputForAttrInt函数
//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::getOutputForAttrInt(
audio_attributes_t *resultAttr,
audio_io_handle_t *output,
audio_session_t session,
const audio_attributes_t *attr,
audio_stream_type_t *stream,
uid_t uid,
const audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
bool *isRequestedDeviceForExclusiveUse,
std::vector<sp<AudioPolicyMix>> *secondaryMixes,
output_type_t *outputType)
{
DeviceVector outputDevices;
const audio_port_handle_t requestedPortId = *selectedDeviceId;
DeviceVector msdDevices = getMsdAudioOutDevices();
const sp<DeviceDescriptor> requestedDevice =
mAvailableOutputDevices.getDeviceFromId(requestedPortId);
*outputType = API_OUTPUT_INVALID;
status_t status = getAudioAttributes(resultAttr, attr, *stream);//将attr赋值给resultAttr
//省略
outputDevices = mEngine->getOutputDevicesForAttributes(*resultAttr, requestedDevice, false);//根据resultAttr,找到device
//省略
if (*output == AUDIO_IO_HANDLE_NONE) {
*output = getOutputForDevices(outputDevices, session, *stream, config,
flags, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);//根据device,找到output
}
//省略
}
1,找到device
//frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
const sp<DeviceDescriptor> &preferredDevice,
bool fromCache) const
{
product_strategy_t strategy = getProductStrategyForAttributes(attributes);
//省略
return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
}
首先,通过声音属性,从mProductStrategies中找到strategy,然后根据strategy,找到对应的device。getDevicesForProductStrategy这个函数由厂商自定义,修改声音的音频策略,大多数情况下可以修改这个函数。
2,根据device,找到output
//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
audio_io_handle_t AudioPolicyManager::getOutputForDevices(
const DeviceVector &devices,
audio_session_t session,
audio_stream_type_t stream,
const audio_config_t *config,
audio_output_flags_t *flags,
bool forceMutingHaptic)
{
//省略
if (audio_is_linear_pcm(config->format)) {
SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
*flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
output = selectOutput(outputs, *flags, config->format, channelMask, config->sample_rate);
}
return output;
}
mOutputs中,支持该device的output可能有多个,通过getOutputsForDevices把它们找出来,然后调用selectOutput从中选择一个最符合的。怎么从中找到最合适的output,可以看其注释
// select one output among several that provide a path to a particular device or set of
// devices (the list was previously build by getOutputsForDevices()).
// The priority is as follows:
// 1: the output supporting haptic playback when requesting haptic playback
// 2: the output with the highest number of requested functional flags
// 3: the output supporting the exact channel mask
// 4: the output with a higher channel count than requested
// 5: the output with a higher sampling rate than requested
// 6: the output with the highest number of requested performance flags
// 7: the output with the bit depth the closest to the requested one
// 8: the primary output
// 9: the first output in the list
综上,找到output的流程为: audio_attributes_t >>> strategy >>> device >>> output
找到播放线程
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(audio_io_handle_t output) const
{
return mPlaybackThreads.valueFor(output).get();
}
根据output,从mPlaybackThreads中找到对应的播放线程
创建Track
//frameworks/av/services/audioflinger/Threads.cpp
sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(/*省略*/)
{
//省略
track = new Track(this, client, streamType, attr, sampleRate, format,
channelMask, frameCount,
nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
sessionId, creatorPid, uid, *flags, TrackBase::TYPE_DEFAULT, portId,
SIZE_MAX /*frameCountToBeReady*/, opPackageName);
//省略
mTracks.add(track);
//省略
}
AudioFlinger的PlaybackThread中有一个mTracks数组,先创建Track,然后将该Track保存到mTracks中。
总结
应用程序创建AudioTrack,导致在对应的播放线程内,创建Track和其对应。如何找到对应的播放线程?
- 根据传入的声音属性,找到strategy
- 根据strategy ,找到device
- 根据device找到output
- 根据output,从mPlaybackThreads中找到对应的播放线程