高通音频架构(一)

您所在的位置:网站首页 高通音频技术怎么样 高通音频架构(一)

高通音频架构(一)

2024-07-17 09:38:31| 来源: 网络整理| 查看: 265

一、概述

音频是几乎是任何一个机器都是必备的一项功能,从早起的单纯发声的录音机,到后来的MP3,以及到现在的手机,它一直陪伴在我们的生活中,功能不变,形式却一直在变,包括它的架构也在变化。从早期的OSS到现在的ALSA,这个介绍在上篇文档是有介绍的,这里我们就着重说一下ALSA。首先高通的音频结构分为以下几个部分:

应用层,主要使用音频的用户主体架构层(framework),这一层主要是为应用层提供了相关处理接口,并且链接了HAL层硬件抽象(HAL)层,在音频开发中可能大部分主要逻辑都是放在这个层次来处理,链接了 framework层和kernel层,这里面还包含了ALSA库用于链接ALSA驱动内核(kernel)层,链接硬件的驱动程序硬件,包含MODEM,CODEC,ADSP

接下来分别介绍一下几个层,除了应用层

1.1 framework层

声音的播放方式有两种:MediaPlayer和Audiotrack,MediaPlayer能够播放多种格式的声音文件,比如MP3,AAC,WAV,OGG,MIDI等。MediaPlayer包含了AudioTrack。 AudioTrack仅仅能播放已经解码的PCM流。假设是文件的话仅仅支持wav格式的音频文件,由于wav格式的音频文件大部分都是PCM流。AudioTrack不创建解码器。所以仅仅能播放不须要解码的wav文件。

先从AudioTrack这方面来看,主要以下三个Java类开始:

AudioTrack.java 用于播放音频AudioRecord.java 用于录制音频AudioSystem.java 用于控制系统各种音频属性

他们的代码分别调用走向如下;

AuidoTrack.java → android_media_AudioTrack.cpp → AudioTrack.cpp → AudioFlinger.cpp

AudioRecord.java → android_media_AudioRecord.cpp → AudioRecord.cpp → AudioFlinger.cpp

AuidoSystem.java → android_media_AudioSystem.cpp → AudioSystem.cpp → AudioFlinger.cpp

从上面三个类的代码走向可以看出,他们最终都会走向同一个类AudioFlinger,它是音频管理器,我们也可以把它理解为代理,它代理了音频上层来的所有事物。它可以创造真正用于功能的track和recorder,那我们以track为例探究一下他是怎么走通这条路的。

首先了解一件事情,上层是怎么使用audiotrack 进行声音播放的,AudioTrack 有两种数据加载模式MODE_STREAM和MODE_STATIC,分别表示数据流加载和音频流类型,MODE_STREAM是通过不断的往AudioTrack内部buffer拷贝数据,这种方式会有一定的延迟,通常用来播放比较大的音频文件,MODE_STATIC则是把所有数据一次写入AudioTrack的内部缓冲区中,后续不再传入数据,这种模式通常用于占用内存小的文件播放。

新建一个Auiotrack对象,设置一些音频的参数调用.write写数据.play进行播放

第一步,新建AudioTrack对象时,AudioTrack.java本身有三个重载的构造方法,分别有不同的参数,但是最终多会用到参数最多的那个,看下它的代码做了什么

AudioTrack.java private AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int mode, int sessionId, boolean offload, int encapsulationMode, @Nullable TunerConfiguration tunerConfiguration) throws IllegalArgumentException { super(attributes, AudioPlaybackConfiguration.PLAYER_TYPE_JAM_AUDIOTRACK); // mState already == STATE_UNINITIALIZED ...... // native initialization int initResult = native_setup(new WeakReference(this), mAttributes, ------> 1 sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat, mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/, offload, encapsulationMode, tunerConfiguration, getCurrentOpPackageName()); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing AudioTrack."); return; // with mState == STATE_UNINITIALIZED } ...... baseRegisterPlayer(mSessionId); native_setPlayerIId(mPlayerIId); // mPlayerIId now ready to send to native AudioTrack. ------> 2

我们着重看下1、2处,分别调用了native层的两个函数,即android_media_AudioTrack.cpp中,1 native_setup做了一些初始化的事情,新建了AudioTrack对象,并且根据不同的加载模式调用了AudioTrack set函数进行了不同的参数设置,2 纯粹设置了PLAYER ID

AudioTrack的构建函数中,并没有做太多事情,反而set函数中做了比较多的事情,看看set做了什么,set函数有两个重载参数差异,我们直接看最后调用的set

AudioTrack.cpp status_t AudioTrack::set( audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, audio_output_flags_t flags, callback_t cbf, void* user, int32_t notificationFrames, const sp& sharedBuffer, bool threadCanCallJava, audio_session_t sessionId, transfer_type transferType, const audio_offload_info_t *offloadInfo, const AttributionSourceState& attributionSource, const audio_attributes_t* pAttributes, bool doNotReconnect, float maxRequiredSpeed, audio_port_handle_t selectedDeviceId) { mThreadCanCallJava = threadCanCallJava; mSelectedDeviceId = selectedDeviceId; mSessionId = sessionId; ...... mSharedBuffer = sharedBuffer; mTransfer = transferType; mDoNotReconnect = doNotReconnect; ...... // handle default values first. if (streamType == AUDIO_STREAM_DEFAULT) { streamType = AUDIO_STREAM_MUSIC; } ...... mFormat = format; ...... mChannelMask = channelMask; channelCount = audio_channel_count_from_out_mask(channelMask); mChannelCount = channelCount; ...... mSampleRate = sampleRate; mOriginalSampleRate = sampleRate; mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; ...... mAuxEffectId = 0; mOrigFlags = mFlags = flags; mCbf = cbf; if (cbf != NULL) { mAudioTrackThread = new AudioTrackThread(*this); mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/); // thread begins in paused state, and will not reference us until start() } // create the IAudioTrack { AutoMutex lock(mLock); status = createTrack_l(); } ............ }

可以从上述截取的部分代码看出对一些重要的属性进行了设置,并且启动了一个重要线程AudioTrackTread,这个线程的作用后续会讲到。接着调用了createTrack_l(),这个函数主要是调用AudioFlinger.creaTrack()创建了一个Track,并且把它相关的属性保存在这边

status_t AudioTrack::createTrack_l() { status_t status; bool callbackAdded = false; const sp& audioFlinger = AudioSystem::get_audio_flinger(); 获取AudioFlinger if (audioFlinger == 0) { ALOGE("%s(%d): Could not get audioflinger", __func__, mPortId); status = NO_INIT; goto exit; } ...... IAudioFlinger::CreateTrackInput input; 组成input参数,这是要传递到AuioFlinger侧 if (mOriginalStreamType != AUDIO_STREAM_DEFAULT) { // Legacy: This is based on original parameters even if the track is recreated. input.attr = AudioSystem::streamTypeToAttributes(mOriginalStreamType); } else { input.attr = mAttributes; } input.config = AUDIO_CONFIG_INITIALIZER; ...... input.sharedBuffer = mSharedBuffer; 共享内存,这里是int值,表示的是共享内存的地址 input.notificationsPerBuffer = mNotificationsPerBufferReq; ...... media::CreateTrackResponse response; status = audioFlinger->createTrack(VALUE_OR_FATAL(input.toAidl()), response); IAudioFlinger::CreateTrackOutput output{}; if (status == NO_ERROR) { output = VALUE_OR_FATAL(IAudioFlinger::CreateTrackOutput::fromAidl(response)); 通过AIDL跨进程通信方式将参数传递到AudioFlinger并且返回值 } ...... // AudioFlinger now owns the reference to the I/O handle, // so we are no longer responsible for releasing it. // FIXME compare to AudioRecord std::optional sfr; output.audioTrack->getCblk(&sfr); 这里获得的audioTrack其实是个代理,获取共享内存 sp iMem = VALUE_OR_FATAL(aidl2legacy_NullableSharedFileRegion_IMemory(sfr)); if (iMem == 0) { ALOGE("%s(%d): Could not get control block", __func__, mPortId); status = NO_INIT; goto exit; } // TODO: Using unsecurePointer() has some associated security pitfalls // (see declaration for details). // Either document why it is safe in this case or address the // issue (e.g. by copying). void *iMemPointer = iMem->unsecurePointer(); if (iMemPointer == NULL) { ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId); status = NO_INIT; goto exit; } // invariant that mAudioTrack != 0 is true only after set() returns successfully if (mAudioTrack != 0) { IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this); mDeathNotifier.clear(); } mAudioTrack = output.audioTrack; 保存audiotrack和共享内存 mCblkMemory = iMem; IPCThreadState::self()->flushCommands(); audio_track_cblk_t* cblk = static_cast(iMemPointer); mCblk = cblk; ...... // Starting address of buffers in shared memory. If there is a shared buffer, buffers // is the value of pointer() for the shared buffer, otherwise buffers points // immediately after the control block. This address is for the mapping within client // address space. AudioFlinger::TrackBase::mBuffer is for the server address space. void* buffers; if (mSharedBuffer == 0) { buffers = cblk + 1; } else { // TODO: Using unsecurePointer() has some associated security pitfalls // (see declaration for details). // Either document why it is safe in this case or address the // issue (e.g. by copying). buffers = mSharedBuffer->unsecurePointer(); if (buffers == NULL) { ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId); status = NO_INIT; goto exit; } } mAudioTrack->attachAuxEffect(mAuxEffectId, &status); 绑定音效 ....... // update proxy if (mSharedBuffer == 0) { 根据是否使用共享内存创建了两个不同的client代理,这两个代理会与AudioFlinger中的server相配对 mStaticProxy.clear(); mProxy = new AudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize); } else { mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize); mProxy = mStaticProxy; } mProxy->setVolumeLR(gain_minifloat_pack( gain_from_float(mVolume[AUDIO_INTERLEAVE_LEFT]), gain_from_float(mVolume[AUDIO_INTERLEAVE_RIGHT]))); mProxy->setSendLevel(mSendLevel); const uint32_t effectiveSampleRate = adjustSampleRate(mSampleRate, mPlaybackRate.mPitch); const float effectiveSpeed = adjustSpeed(mPlaybackRate.mSpeed, mPlaybackRate.mPitch); const float effectivePitch = adjustPitch(mPlaybackRate.mPitch); mProxy->setSampleRate(effectiveSampleRate); AudioPlaybackRate playbackRateTemp = mPlaybackRate; playbackRateTemp.mSpeed = effectiveSpeed; playbackRateTemp.mPitch = effectivePitch; mProxy->setPlaybackRate(playbackRateTemp); mProxy->setMinimum(mNotificationFramesAct); ...... mDeathNotifier = new DeathNotifier(this); IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this); ...... }

第二步,write 数据,在AudioTrack.java中有好几个write的重载方法,分别用于写不同的数据类型:byte,short,float,long,nativebytes等,到android_media_AudioTrack.cpp中发现除了nativebytes其他都是指向同一个函数android_media_AudioTrack_writeArray

android_media_AudioTrack.cpp template static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz, T javaAudioData, jint offsetInSamples, jint sizeInSamples, jint javaAudioFormat, jboolean isWriteBlocking) { ...... jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */); envReleaseArrayElements(env, javaAudioData, cAudioData, 0); //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d", // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples); return samplesWritten; }

nativbytes指向了函数 android_media_AudioTrack_write_native_bytes

android_media_AudioTrack.cpp static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz, jobject javaByteBuffer, jint byteOffset, jint sizeInBytes, jint javaAudioFormat, jboolean isWriteBlocking) { ...... if (bytes == NULL) { ALOGE("Error retrieving source of audio data to play, can't play"); return (jint)AUDIO_JAVA_BAD_VALUE; } jint written = writeToTrack(lpTrack, javaAudioFormat, bytes, byteOffset, sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */); return written; }

可以看出两个函数虽然名字参数不一样但是最终都调用了writeToTrack函数,这个函数会根据AuioTrack.cpp 的shardBuffer,采用不同的方式写数据,shareBuffer是否为零根据上层使用的是MODE_STREAM还是MODE_STATIC,MODE_STATIC是会有sharedBuffer,然后写数据是直接写入sharedBuffer中,而MODE_STEREAM则是调用AudiaoTrack的write方式。

android_media_AudioTrack.cpp // ---------------------------------------------------------------------------- class AudioTrackJniStorage { public: sp mMemHeap; sp mMemBase; audiotrack_callback_cookie mCallbackData{}; sp mDeviceCallback; sp mAudioTrackCallback; bool allocSharedMem(int sizeInBytes) { mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base"); if (mMemHeap->getHeapID() ...... size_t written = 0; Buffer audioBuffer; while (userSize >= mFrameSize) { audioBuffer.frameCount = userSize / mFrameSize; status_t err = obtainBuffer(&audioBuffer, blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking); if (err break; } if (err == TIMED_OUT || err == -EINTR) { err = WOULD_BLOCK; } return ssize_t(err); } size_t toWrite = audioBuffer.size; memcpy(audioBuffer.i8, buffer, toWrite); buffer = ((const char *) buffer) + toWrite; userSize -= toWrite; written += toWrite; releaseBuffer(&audioBuffer); } if (written > 0) { mFramesWritten += written / mFrameSize; if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) { const sp t = mAudioTrackThread; if (t != 0) { // causes wake up of the playback thread, that will callback the client for // more data (with EVENT_CAN_WRITE_MORE_DATA) in processAudioBuffer() t->wake(); } } } return written; }

从AudioTrack::write 函数来看,这里是向ClientProxy申请了一个共享的buffer,然后把数据拷贝给这个buffer,可见stream模式最终也是通过共享内存来交换数据,最后在数据拷贝成功后,会唤醒AudioTrackThread 线程,这个线程他会将目前会循环的去获取当前的播放状态和事件,并且返回给上层

第三步,上层开始play

AudioTrack.java public void play() throws IllegalStateException { if (mState != STATE_INITIALIZED) { throw new IllegalStateException("play() called on uninitialized AudioTrack."); } //FIXME use lambda to pass startImpl to superclass final int delay = getStartDelayMs(); if (delay == 0) { startImpl(); -------- 1 } else { new Thread() { public void run() { try { Thread.sleep(delay); } catch (InterruptedException e) { e.printStackTrace(); } baseSetStartDelayMs(0); try { startImpl(); ------------ 1 } catch (IllegalStateException e) { // fail silently for a state exception when it is happening after // a delayed start, as the player state could have changed between the // call to start() and the execution of startImpl() } } }.start(); } } private void startImpl() { ------------- 1 synchronized (mRoutingChangeListeners) { if (!mEnableSelfRoutingMonitor) { mEnableSelfRoutingMonitor = testEnableNativeRoutingCallbacksLocked(); } } synchronized(mPlayStateLock) { baseStart(0); // unknown device at this point native_start(); ------------ 2 // FIXME see b/179218630 //baseStart(native_getRoutedDeviceId()); if (mPlayState == PLAYSTATE_PAUSED_STOPPING) { mPlayState = PLAYSTATE_STOPPING; } else { mPlayState = PLAYSTATE_PLAYING; mOffloadEosPending = false; } } }

在上层AudioTrack.java 调用play()之后,没有做太多的操作就是一个延迟开始和不延迟,实际上用到了native层native_start(),它对应android_media_AudioTrack.cpp中的android_media_AudioTrack_start()函数,我们直接看android_media_AudioTrack_start()

static void android_media_AudioTrack_start(JNIEnv *env, jobject thiz) { sp lpTrack = getAudioTrack(env, thiz); if (lpTrack == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Unable to retrieve AudioTrack pointer for start()"); return; } lpTrack->start(); }

直接跨度到了AudioTrack.cpp start()函数,这个start()函数比较长就不贴出来,主要做的事情就是将动作传递到了AudioFlinger那一侧的Track中,上面三步目前都已经走到了AudioFlinger 这里了,AudioFlinger到底做了什么,怎么来的,接下来就揭开其神秘面纱。

AudioFlinger:

首先从audioserver开始,audioserver是放在framework/av/media下面,它只有三个文件Andoird.bp,audioserver.rc,main_audioserver.cpp,从文件组成来看这个模块是开机就开始运行了,audioserver.rc 在开机的时候会被系统的init进程所加载,接着启动audioserver,也就是main_audioserver.cpp,然后在audioserver的main函数中就启动了AudioFlinger、AudioPolicyService,分别调用了它们的instantiate()函数,

AudioFlinger.cpp void AudioFlinger::instantiate() { sp sm(defaultServiceManager()); sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), -------- 1 new AudioFlingerServerAdapter(new AudioFlinger()), false, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT); } AudioFlinger::AudioFlinger() : mMediaLogNotifier(new AudioFlinger::MediaLogNotifier()), mPrimaryHardwareDev(NULL), mAudioHwDevs(NULL), mHardwareStatus(AUDIO_HW_IDLE), mMasterVolume(1.0f), mMasterMute(false), // mNextUniqueId(AUDIO_UNIQUE_ID_USE_MAX), mMode(AUDIO_MODE_INVALID), mBtNrecIsOff(false), mIsLowRamDevice(true), mIsDeviceTypeKnown(false), mTotalMemory(0), mClientSharedHeapSize(kMinimumClientSharedHeapSizeBytes), mGlobalEffectEnableTime(0), mPatchPanel(this), mDeviceEffectManager(this), mSystemReady(false) { // Move the audio session unique ID generator start base as time passes to limit risk of // generating the same ID again after an audioserver restart. // This is important because clients will reuse previously allocated audio session IDs // when reconnecting after an audioserver restart and newly allocated IDs may conflict with // active clients. // Moving the base by 1 for each elapsed second is a good compromise between avoiding overlap // between allocation ranges and not reaching wrap around too soon. timespec ts{}; clock_gettime(CLOCK_MONOTONIC, &ts); // zero ID has a special meaning, so start allocation at least at AUDIO_UNIQUE_ID_USE_MAX uint32_t movingBase = (uint32_t)std::max((long)1, ts.tv_sec); // unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum for (unsigned use = AUDIO_UNIQUE_ID_USE_UNSPECIFIED; use mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters", MemoryHeapBase::READ_ONLY); (void) pthread_once(&sMediaLogOnce, sMediaLogInit); } // reset battery stats. // if the audio service has crashed, battery stats could be left // in bad state, reset the state upon service start. BatteryNotifier::getInstance().noteResetAudio(); mDevicesFactoryHal = DevicesFactoryHalInterface::create(); -------- 2 mEffectsFactoryHal = EffectsFactoryHalInterface::create(); -------- 3 mMediaLogNotifier->run("MediaLogNotifier"); std::vector halPids; mDevicesFactoryHal->getHalPids(&halPids); TimeCheck::setAudioHalPids(halPids); // Notify that we have started (also called when audioserver service restarts) mediametrics::LogItem(mMetricsId) .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR) .record(); }

AuidoFlinger 的初始化,先是把自己包装之后加入到了servicemanager中,这里主要用于native 层通过binder和AudioFlinger进行数据交换,然后是初始化了两个很重要的接口,DevicesFactoryHalInterface和EffectsFactoryHalInterface,这两个接口是用于连接HAL层的主要接口类,负责与HAL层的数据交换,这里与HAL层的数据交换同样使用的Binder机制,学名HIDL一种跨进程通信方式,那先来看下他们做了什么,以DevicesFactoryHalInterface为例,窥探一下DevicesFactoryHalInterface.create后面的代码

DevicesFactoryHalInterface.cpp // static sp DevicesFactoryHalInterface::create() { 这里create 直接链接到下一个类的函数createPreferredImpl,传递了两个参数一个是包名另一个是AIDL 的代理类 return createPreferredImpl( "android.hardware.audio", "IDevicesFactory"); } -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- FactoryHalHidl.cpp void* createPreferredImpl(const std::string& package, const std::string& interface) { 这里显示遍历了一个保存HAL版本的数组,并判断当前处于哪个版本,如果找到有这个版本则创建这个版本的代理接口 for (auto version = detail::sAudioHALVersions; version != nullptr; ++version) { 遍历HAL版本数组 void* rawInterface = nullptr; if (hasHalService(package, *version, interface) 判断该版本号对应的HAL是否存在 && createHalService(*version, interface, &rawInterface)) { 创建对应版本的HAL代理接口 return rawInterface; } } return nullptr; } bool createHalService(const std::string& version, const std::string& interface, void** rawInterface) { const std::string libName = "libaudiohal@" + version + ".so"; 这里组装了一个[email protected]字符串,一个库,x.x就是刚才遍历到的版本储存在sAudioHALVersions中 const std::string factoryFunctionName = "create" + interface; 刚才穿进来的interface 是IDevicesFactory,这里组装成了createIDevicesFactory,像是一个函数 constexpr int dlMode = RTLD_LAZY; void* handle = nullptr; dlerror(); // clear handle = dlopen(libName.c_str(), dlMode); 加载库[email protected] if (handle == nullptr) { const char* error = dlerror(); ALOGE("Failed to dlopen %s: %s", libName.c_str(), error != nullptr ? error : "unknown error"); return false; } void* (*factoryFunction)(); *(void **)(&factoryFunction) = dlsym(handle, factoryFunctionName.c_str()); 获取库[email protected]中的createIDevicesFactory函数指针 if (!factoryFunction) { const char* error = dlerror(); ALOGE("Factory function %s not found in library %s: %s", factoryFunctionName.c_str(), libName.c_str(), error != nullptr ? error : "unknown error"); dlclose(handle); return false; } *rawInterface = (*factoryFunction)(); 这里则调用了createIDevicesFactory函数并返回了rawInterface,这个rawInterface最终是要返回到调用DevicesFactoryHalInterface.create的地方 ALOGW_IF(!*rawInterface, "Factory function %s from %s returned nullptr", factoryFunctionName.c_str(), libName.c_str()); return true; }

通过上面几段代码的一个跟踪和分析,发现DevicesFactoryHalInterface.create其实只是去打开了一个[email protected]的库,并且调用了它的函数createIDevicesFactory获取了其返回值,通过查找代码发现这个库的源码是在framewrok/av/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp

DevicesFactoryHalHybrid.cpp extern "C" __attribute__((visibility("default"))) void* createIDevicesFactory() { 这个函数的调用实际上是构建了DevicesFactoryHalHybrid并且把它返回给了调用者 auto service = hardware::audio::CPP_VERSION::IDevicesFactory::getService(); return service ? new CPP_VERSION::DevicesFactoryHalHybrid(service) : nullptr; } DevicesFactoryHalHybrid::DevicesFactoryHalHybrid(sp hidlFactory) DevicesFactoryHalHybrid构建初始化了两个类DevicesFactoryHalLocal和DevicesFactoryHalHidl从名字看一个是本地一个是HIDL代理者 : mLocalFactory(new DevicesFactoryHalLocal()), mHidlFactory(new DevicesFactoryHalHidl(hidlFactory)) { } status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp *device) { 打开HAL层的一些设备,这里设备有几种类型:primary,a2dp,usb,r_submix,stub,我们主要使用的是primary if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_HEARING_AID, name) != 0) { return mHidlFactory->openDevice(name, device); } return mLocalFactory->openDevice(name, device); } status_t DevicesFactoryHalHybrid::getHalPids(std::vector *pids) { if (mHidlFactory != 0) { return mHidlFactory->getHalPids(pids); } return INVALID_OPERATION; } status_t DevicesFactoryHalHybrid::setCallbackOnce(sp callback) { if (mHidlFactory) { return mHidlFactory->setCallbackOnce(callback); } return INVALID_OPERATION; }

从DevicesFactoryHalHybrid.cpp上面的代码可以看出,它的主要处理是交给了mHidlFactory也就是DevicesFactoryHalHidl。

介绍完了AudioFlinger的初始化,我们再看一下上层调用的三步到达AudioFlinger之后做了什么

第一步,代码到达了AudioFlinger.createTrack

status_t AudioFlinger::createTrack(const media::CreateTrackRequest& _input, media::CreateTrackResponse& _output) { // Local version of VALUE_OR_RETURN, specific to this method's calling conventions. CreateTrackInput input = VALUE_OR_RETURN_STATUS(CreateTrackInput::fromAidl(_input)); CreateTrackOutput output; sp track; sp trackHandle; sp client; status_t lStatus; audio_stream_type_t streamType; audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE; std::vector secondaryOutputs; ...... output.sessionId = sessionId; output.outputId = AUDIO_IO_HANDLE_NONE; output.selectedDeviceId = input.selectedDeviceId; lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType, adjAttributionSource, &input.config, input.flags, &output.selectedDeviceId, &portId, &secondaryOutputs); ------------------ 1 ...... { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output.outputId); 获取playback数组 if (thread == NULL) { ALOGE("no playback thread found for output handle %d", output.outputId); lStatus = BAD_VALUE; goto Exit; } ...... ALOGV("createTrack() sessionId: %d", sessionId); output.sampleRate = input.config.sample_rate; output.frameCount = input.frameCount; output.notificationFrameCount = input.notificationFrameCount; output.flags = input.flags; output.streamType = streamType; track = thread->createTrack_l(client, streamType, localAttr, &output.sampleRate, input.config.format, input.config.channel_mask, &output.frameCount, &output.notificationFrameCount, input.notificationsPerBuffer, input.speed, input.sharedBuffer, sessionId, &output.flags, callingPid, adjAttributionSource, input.clientInfo.clientTid, &lStatus, portId, input.audioTrackCallback); LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0)); // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless output.afFrameCount = thread->frameCount(); output.afSampleRate = thread->sampleRate(); output.afLatencyMs = thread->latency(); output.portId = portId; ...... setAudioHwSyncForSession_l(thread, sessionId); } ...... output.audioTrack = new TrackHandle(track); _output = VALUE_OR_FATAL(output.toAidl()); Exit: if (lStatus != NO_ERROR && output.outputId != AUDIO_IO_HANDLE_NONE) { AudioSystem::releaseOutput(portId); } return lStatus; }

整个createTrack代码很长总结来说就是先获取传过来的参数input ,根据input在调用PlaybackThread创建Track,然后返回output,并且返回的audioTrack并不是真的Track而是TrackHandle代理,从名字看这是一个回放的线程,它的代码非常的长,主要目的就是创建Track,并且保存在了一个数组中,在上面代码中标记1处,这个函数是获取我们的Output,它首先是通过AudioSystem中转调用AudioPolicyInterfaceImpl中的getOutputForAttr,然后再到AudioPolicyManager的getOutputForAttrInt,直接看AudioPolicyManager

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 *secondaryMixes, output_type_t *outputType) { DeviceVector outputDevices; const audio_port_handle_t requestedPortId = *selectedDeviceId; DeviceVector msdDevices = getMsdAudioOutDevices(); const sp requestedDevice = mAvailableOutputDevices.getDeviceFromId(requestedPortId); *outputType = API_OUTPUT_INVALID; status_t status = getAudioAttributes(resultAttr, attr, *stream); if (status != NO_ERROR) { return status; } if (auto it = mAllowedCapturePolicies.find(uid); it != end(mAllowedCapturePolicies)) { resultAttr->flags = static_cast(resultAttr->flags | it->second); } *stream = mEngine->getStreamTypeForAttributes(*resultAttr); ALOGV("%s() attributes=%s stream=%s session %d selectedDeviceId %d", __func__, toString(*resultAttr).c_str(), toString(*stream).c_str(), session, requestedPortId); // The primary output is the explicit routing (eg. setPreferredDevice) if specified, // otherwise, fallback to the dynamic policies, if none match, query the engine. // Secondary outputs are always found by dynamic policies as the engine do not support them sp primaryMix; status = mPolicyMixes.getOutputForAttr(*resultAttr, uid, *flags, primaryMix, secondaryMixes); if (status != OK) { return status; } // Explicit routing is higher priority then any dynamic policy primary output bool usePrimaryOutputFromPolicyMixes = requestedDevice == nullptr && primaryMix != nullptr; // FIXME: in case of RENDER policy, the output capabilities should be checked if ((usePrimaryOutputFromPolicyMixes || (secondaryMixes != nullptr && !secondaryMixes->empty())) && !audio_is_linear_pcm(config->format)) { ALOGD("%s: rejecting request as dynamic audio policy only support pcm", __func__); return BAD_VALUE; } if (usePrimaryOutputFromPolicyMixes) { sp deviceDesc = mAvailableOutputDevices.getDevice(primaryMix->mDeviceType, primaryMix->mDeviceAddress, AUDIO_FORMAT_DEFAULT); sp policyDesc = primaryMix->getOutput(); if (deviceDesc != nullptr && (policyDesc == nullptr || (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT))) { audio_io_handle_t newOutput; status = openDirectOutput( --------------------- 1 *stream, session, config, (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT), DeviceVector(deviceDesc), &newOutput); if (status != NO_ERROR) { policyDesc = nullptr; } else { policyDesc = mOutputs.valueFor(newOutput); primaryMix->setOutput(policyDesc); } } if (policyDesc != nullptr) { policyDesc->mPolicyMix = primaryMix; *output = policyDesc->mIoHandle; *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE; ALOGV("getOutputForAttr() returns output %d", *output); if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) { *outputType = API_OUT_MIX_PLAYBACK; } else { *outputType = API_OUTPUT_LEGACY; } return NO_ERROR; } } // Virtual sources must always be dynamicaly or explicitly routed if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) { ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE"); return BAD_VALUE; } // explicit routing managed by getDeviceForStrategy in APM is now handled by engine // in order to let the choice of the order to future vendor engine outputDevices = mEngine->getOutputDevicesForAttributes(*resultAttr, requestedDevice, false); if ((resultAttr->flags & AUDIO_FLAG_HW_AV_SYNC) != 0) { *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC); } // Set incall music only if device was explicitly set, and fallback to the device which is // chosen by the engine if not. // FIXME: provide a more generic approach which is not device specific and move this back // to getOutputForDevice. // TODO: Remove check of AUDIO_STREAM_MUSIC once migration is completed on the app side. if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX) && (*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) && audio_is_linear_pcm(config->format) && isCallAudioAccessible()) { if (requestedPortId != AUDIO_PORT_HANDLE_NONE) { *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC; *isRequestedDeviceForExclusiveUse = true; } } ALOGV("%s() device %s, sampling rate %d, format %#x, channel mask %#x, flags %#x stream %s", __func__, outputDevices.toString().c_str(), config->sample_rate, config->format, config->channel_mask, *flags, toString(*stream).c_str()); *output = AUDIO_IO_HANDLE_NONE; if (!msdDevices.isEmpty()) { *output = getOutputForDevices(msdDevices, session, *stream, config, flags); ------------ 2 if (*output != AUDIO_IO_HANDLE_NONE && setMsdOutputPatches(&outputDevices) == NO_ERROR) { ALOGV("%s() Using MSD devices %s instead of devices %s", __func__, msdDevices.toString().c_str(), outputDevices.toString().c_str()); } else { *output = AUDIO_IO_HANDLE_NONE; } } if (*output == AUDIO_IO_HANDLE_NONE) { *output = getOutputForDevices(outputDevices, session, *stream, config, ------------- 3 flags, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC); } if (*output == AUDIO_IO_HANDLE_NONE) { return INVALID_OPERATION; } *selectedDeviceId = getFirstDeviceId(outputDevices); for (auto &outputDevice : outputDevices) { if (outputDevice->getId() == getConfig().getDefaultOutputDevice()->getId()) { *selectedDeviceId = outputDevice->getId(); break; } } if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX)) { *outputType = API_OUTPUT_TELEPHONY_TX; } else { *outputType = API_OUTPUT_LEGACY; } ALOGV("%s returns output %d selectedDeviceId %d", __func__, *output, *selectedDeviceId); return NO_ERROR; }

整个这些代码目的就一个获取output,上面代码标记的三处分别对应的不同情况,最终都是要用到openDirectOutput,看一下openDirectOutput

status_t AudioPolicyManager::openDirectOutput(audio_stream_type_t stream, audio_session_t session, const audio_config_t *config, audio_output_flags_t flags, const DeviceVector &devices, audio_io_handle_t *output) { *output = AUDIO_IO_HANDLE_NONE; // skip direct output selection if the request can obviously be attached to a mixed output // and not explicitly requested if (((flags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && audio_is_linear_pcm(config->format) && config->sample_rate channel_mask) profile = getProfileForOutput( devices, config->sample_rate, config->format, config->channel_mask, flags, true /* directOnly */); } if (profile == nullptr) { return NAME_NOT_FOUND; } if (!(flags & AUDIO_OUTPUT_FLAG_DIRECT) && (profile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT)) { ALOGI("%s rejecting direct profile as was not requested ", __func__); profile = nullptr; return NAME_NOT_FOUND; } sp outputDesc = nullptr; // check if direct output for pcm/track offload or compress offload already exist bool directSessionInUse = false; bool offloadSessionInUse = false; // exclusive outputs for MMAP and Offload are enforced by different session ids. if (!(property_get_bool("vendor.audio.offload.multiple.enabled", false) && ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) && (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0)) { for (size_t i = 0; i outputDesc = desc; // reuse direct output if currently open by the same client // and configured with same parameters if ((config->sample_rate == desc->getSamplingRate()) && (config->format == desc->getFormat()) && (config->channel_mask == desc->getChannelMask()) && (session == desc->mDirectClientSession)) { desc->mDirectOpenCount++; ALOGI("%s reusing direct output %d for session %d", __func__, mOutputs.keyAt(i), session); *output = mOutputs.keyAt(i); return NO_ERROR; } if (desc->mFlags == AUDIO_OUTPUT_FLAG_DIRECT) { directSessionInUse = true; ALOGV("%s Direct PCM already in use", __func__); } if (desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { offloadSessionInUse = true; ALOGV("%s Compress Offload already in use", __func__); } } } if (outputDesc != nullptr && ((flags == AUDIO_OUTPUT_FLAG_DIRECT && directSessionInUse) || ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && offloadSessionInUse))) { if (session != outputDesc->mDirectClientSession) { ALOGV("getOutput() do not reuse direct pcm output because current client (%d) " "is not the same as requesting client (%d) for different output conf", outputDesc->mDirectClientSession, session); return NAME_NOT_FOUND; } else { ALOGV("%s close previous output on same client session %d ", __func__, session); closeOutput(outputDesc->mIoHandle); } } } if (!profile->canOpenNewIo()) { return NAME_NOT_FOUND; } 上面是处理一些找不到的情况,进行一个过滤 outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface); ---------- 新建一个SwAudioOutputDescriptor,这个是包装output的类 // An MSD patch may be using the only output stream that can service this request. Release // all MSD patches to prioritize this request over any active output on MSD. releaseMsdOutputPatches(devices); status_t status = outputDesc->open(config, devices, stream, flags, output); ----------这里才是真正的打开output // only accept an output with the requested parameters if (status != NO_ERROR || (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) || (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) || (config->channel_mask != 0 && config->channel_mask != outputDesc->getChannelMask())) { ALOGV("%s failed opening direct output: output %d sample rate %d %d," "format %d %d, channel mask %04x %04x", __func__, *output, config->sample_rate, outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(), config->channel_mask, outputDesc->getChannelMask()); if (*output != AUDIO_IO_HANDLE_NONE) { outputDesc->close(); } // fall back to mixer output if possible when the direct output could not be open if (audio_is_linear_pcm(config->format) && config->sample_rate audio_module_handle_t module = VALUE_OR_RETURN_STATUS( aidl2legacy_int32_t_audio_module_handle_t(request.module)); audio_config_t config = VALUE_OR_RETURN_STATUS( aidl2legacy_AudioConfig_audio_config_t(request.config)); sp device = VALUE_OR_RETURN_STATUS( aidl2legacy_DeviceDescriptorBase(request.device)); audio_output_flags_t flags = VALUE_OR_RETURN_STATUS( aidl2legacy_int32_t_audio_output_flags_t_mask(request.flags)); audio_io_handle_t output; uint32_t latencyMs; ALOGI("openOutput() this %p, module %d Device %s, SamplingRate %d, Format %#08x, " "Channels %#x, flags %#x", this, module, device->toString().c_str(), config.sample_rate, config.format, config.channel_mask, flags); audio_devices_t deviceType = device->type(); const String8 address = String8(device->address().c_str()); if (deviceType == AUDIO_DEVICE_NONE) { return BAD_VALUE; } Mutex::Autolock _l(mLock); sp thread = openOutput_l(module, &output, &config, deviceType, address, flags); openoutput核心处理在这里 if (thread != 0) { if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) { PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); latencyMs = playbackThread->latency(); // notify client processes of the new output creation playbackThread->ioConfigChanged(AUDIO_OUTPUT_OPENED); // the first primary output opened designates the primary hw device if no HW module // named "primary" was already loaded. AutoMutex lock(mHardwareLock); if ((mPrimaryHardwareDev == nullptr) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) { ALOGI("Using module %d as the primary audio interface", module); mPrimaryHardwareDev = playbackThread->getOutput()->audioHwDev; mHardwareStatus = AUDIO_HW_SET_MODE; mPrimaryHardwareDev->hwDevice()->setMode(mMode); mHardwareStatus = AUDIO_HW_IDLE; } } else { MmapThread *mmapThread = (MmapThread *)thread.get(); mmapThread->ioConfigChanged(AUDIO_OUTPUT_OPENED); } response->output = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output)); response->config = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_config_t_AudioConfig(config)); response->latencyMs = VALUE_OR_RETURN_STATUS(convertIntegral(latencyMs)); response->flags = VALUE_OR_RETURN_STATUS( legacy2aidl_audio_output_flags_t_int32_t_mask(flags)); return NO_ERROR; } return NO_INIT; } sp AudioFlinger::openOutput_l(audio_module_handle_t module, audio_io_handle_t *output, audio_config_t *config, audio_devices_t deviceType, const String8& address, audio_output_flags_t flags) { AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType); 寻找并加载对应的HAL层module,也就是链接HAL侧接口 if (outHwDev == NULL) { return 0; } if (*output == AUDIO_IO_HANDLE_NONE) { *output = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT); } else { // Audio Policy does not currently request a specific output handle. // If this is ever needed, see openInput_l() for example code. ALOGE("openOutput_l requested output handle %d is not AUDIO_IO_HANDLE_NONE", *output); return 0; } mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; // FOR TESTING ONLY: // This if statement allows overriding the audio policy settings // and forcing a specific format or channel mask to the HAL/Sink device for testing. if (!(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) { // Check only for Normal Mixing mode if (kEnableExtendedPrecision) { // Specify format (uncomment one below to choose) //config->format = AUDIO_FORMAT_PCM_FLOAT; //config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED; //config->format = AUDIO_FORMAT_PCM_32_BIT; //config->format = AUDIO_FORMAT_PCM_8_24_BIT; // ALOGV("openOutput_l() upgrading format to %#08x", config->format); } if (kEnableExtendedChannels) { // Specify channel mask (uncomment one below to choose) //config->channel_mask = audio_channel_out_mask_from_count(4); // for USB 4ch //config->channel_mask = audio_channel_mask_from_representation_and_bits( // AUDIO_CHANNEL_REPRESENTATION_INDEX, (1 openOutputStream( &outputStream, *output, deviceType, flags, config, address.string()); 这里调用HAL层的openoutputStream正式打通和HAL层的通道 mHardwareStatus = AUDIO_HW_IDLE; if (status == NO_ERROR) { 下面就对应几种情况分别建立了playbackThread if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) { sp thread = new MmapPlaybackThread(this, *output, outHwDev, outputStream, mSystemReady); ------------- 1 mMmapThreads.add(*output, thread); ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p", *output, thread.get()); return thread; } else { sp thread; if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { thread = new OffloadThread(this, outputStream, *output, mSystemReady); -------------- 2 ALOGV("openOutput_l() created offload output: ID %d thread %p", *output, thread.get()); } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) || !isValidPcmSinkFormat(config->format) || !isValidPcmSinkChannelMask(config->channel_mask)) { thread = new DirectOutputThread(this, outputStream, *output, mSystemReady); --------------- 3 ALOGV("openOutput_l() created direct output: ID %d thread %p", *output, thread.get()); } else { thread = new MixerThread(this, outputStream, *output, mSystemReady); --------------- 4 ALOGV("openOutput_l() created mixer output: ID %d thread %p", *output, thread.get()); } mPlaybackThreads.add(*output, thread); 添加到了数组中 struct audio_patch patch; mPatchPanel.notifyStreamOpened(outHwDev, *output, &patch); if (thread->isMsdDevice()) { thread->setDownStreamPatch(&patch); } return thread; } } return 0; }

至此,mPlaybackThreads的神秘面纱就揭开了,它所保存的几种thread 分别有不用的场景应用,具体如下图 在这里插入图片描述看完playbackthread接着往下看Track的创建

AudioFlinger::PlaybackThread::Track::Track( PlaybackThread *thread, const sp& client, audio_stream_type_t streamType, const audio_attributes_t& attr, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, void *buffer, size_t bufferSize, const sp& sharedBuffer, audio_session_t sessionId, pid_t creatorPid, const AttributionSourceState& attributionSource, audio_output_flags_t flags, track_type type, audio_port_handle_t portId, size_t frameCountToBeReady, float speed) : TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount, // TODO: Using unsecurePointer() has some associated security pitfalls // (see declaration for details). // Either document why it is safe in this case or address the // issue (e.g. by copying). (sharedBuffer != 0) ? sharedBuffer->unsecurePointer() : buffer, (sharedBuffer != 0) ? sharedBuffer->size() : bufferSize, sessionId, creatorPid, VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)), true /*isOut*/, (type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK, type, portId, std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + std::to_string(portId)), 这个地方调用了父类的构造函数,利用父类做了一些事情 mFillingUpStatus(FS_INVALID), // mRetryCount initialized later when needed mSharedBuffer(sharedBuffer), mStreamType(streamType), mMainBuffer(thread->sinkBuffer()), mAuxBuffer(NULL), mAuxEffectId(0), mHasVolumeController(false), mFrameMap(16 /* sink-frame-to-track-frame map memory */), mVolumeHandler(new media::VolumeHandler(sampleRate)), mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(attributionSource, attr, id(), streamType)), // mSinkTimestamp mFastIndex(-1), mCachedVolume(1.0), /* The track might not play immediately after being active, similarly as if its volume was 0. * When the track starts playing, its volume will be computed. */ mFinalVolume(0.f), mResumeToStopping(false), mFlushHwPending(false), mFlags(flags), mSpeed(speed) { 持有了各种状态属性 // client == 0 implies sharedBuffer == 0 ALOG_ASSERT(!(client == 0 && sharedBuffer != 0)); ALOGV_IF(sharedBuffer != 0, "%s(%d): sharedBuffer: %p, size: %zu", __func__, mId, sharedBuffer->unsecurePointer(), sharedBuffer->size()); if (mCblk == NULL) { return; } uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)); if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) { ALOGE("%s(%d): no more tracks available", __func__, mId); releaseCblk(); // this makes the track invalid. return; } if (sharedBuffer == 0) { 根据是否有共享内存创建了两个server代理,和AudioTrack中的client相配对 mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount, mFrameSize, !isExternalTrack(), sampleRate); } else { mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount, mFrameSize, sampleRate); } mServerProxy = mAudioTrackServerProxy; mServerProxy->setStartThresholdInFrames(frameCountToBeReady); // update the Cblk value // only allocate a fast track index if we were able to allocate a normal track name if (flags & AUDIO_OUTPUT_FLAG_FAST) { // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential // race with setSyncEvent(). However, if we call it, we cannot properly start // static fast tracks (SoundPool) immediately after stopping. //mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); ALOG_ASSERT(thread->mFastTrackAvailMask != 0); int i = __builtin_ctz(thread->mFastTrackAvailMask); ALOG_ASSERT(0 supportsHapticPlayback()) { // If the track is attached to haptic playback thread, it is potentially to have // HapticGenerator effect, which will generate haptic data, on the track. In that case, // external vibration is always created for all tracks attached to haptic playback thread. mAudioVibrationController = new AudioVibrationController(this); std::string packageName = attributionSource.packageName.has_value() ? attributionSource.packageName.value() : ""; mExternalVibration = new os::ExternalVibration( mUid, packageName, mAttr, mAudioVibrationController); } // Once this item is logged by the server, the client can add properties. const char * const traits = sharedBuffer == 0 ? "" : "static"; mTrackMetrics.logConstructor(creatorPid, uid, id(), traits, streamType); }

第二步,写数据,这里是将上层要播放的数据写进了共享内存里,这里的关键方法是obtainBuffer,这个函数是用来获取共享内存的,没有太多操作不细讲

第三步,play进行到了AudioTrak.start 调用了AudioFlinger侧的TrackHandle start,这只是一个传递代码真正是到了Track start(),然后看看Track start 做了什么

status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event __unused, audio_session_t triggerSession __unused) { status_t status = NO_ERROR; ALOGV("%s(%d): calling pid %d session %d", __func__, mId, IPCThreadState::self()->getCallingPid(), mSessionId); sp thread = mThread.promote(); if (thread != 0) { if (isOffloaded()) { Mutex::Autolock _laf(thread->mAudioFlinger->mLock); Mutex::Autolock _lth(thread->mLock); sp ec = thread->getEffectChain_l(mSessionId); if (thread->mAudioFlinger->isNonOffloadableGlobalEffectEnabled_l() || (ec != 0 && ec->isNonOffloadableEnabled())) { invalidate(); return PERMISSION_DENIED; } } Mutex::Autolock _lth(thread->mLock); track_state state = mState; // here the track could be either new, or restarted // in both cases "unstop" the track // initial state-stopping. next state-pausing. // What if resume is called ? if (state == FLUSHED) { // avoid underrun glitches when starting after flush reset(); } // clear mPauseHwPending because of pause (and possibly flush) during underrun. mPauseHwPending = false; if (state == PAUSED || state == PAUSING) { if (mResumeToStopping) { // happened we need to resume to STOPPING_1 mState = TrackBase::STOPPING_1; ALOGV("%s(%d): PAUSED => STOPPING_1 on thread %d", __func__, mId, (int)mThreadIoHandle); } else { mState = TrackBase::RESUMING; ALOGV("%s(%d): PAUSED => RESUMING on thread %d", __func__, mId, (int)mThreadIoHandle); } } else { mState = TrackBase::ACTIVE; ALOGV("%s(%d): ? => ACTIVE on thread %d", __func__, mId, (int)mThreadIoHandle); } // states to reset position info for non-offloaded/direct tracks if (!isOffloaded() && !isDirect() && (state == IDLE || state == STOPPED || state == FLUSHED)) { mFrameMap.reset(); } PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); 获取playbackThread if (isFastTrack()) { // refresh fast track underruns on start because that field is never cleared // by the fast mixer; furthermore, the same track can be recycled, i.e. start // after stop. mObservedUnderruns = playbackThread->getFastTrackUnderruns(mFastIndex); 这里是监测underrun状态 } status = playbackThread->addTrack_l(this); 将当前track加入到playbackThread中 if (status == INVALID_OPERATION || status == PERMISSION_DENIED) { triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); // restore previous state if start was rejected by policy manager if (status == PERMISSION_DENIED) { mState = state; } } // Audio timing metrics are computed a few mix cycles after starting. { mLogStartCountdown = LOG_START_COUNTDOWN; mLogStartTimeNs = systemTime(); mLogStartFrames = mAudioTrackServerProxy->getTimestamp() .mPosition[ExtendedTimestamp::LOCATION_KERNEL]; mLogLatencyMs = 0.; } if (status == NO_ERROR || status == ALREADY_EXISTS) { // for streaming tracks, remove the buffer read stop limit. mAudioTrackServerProxy->start(); } // track was already in the active list, not a problem if (status == ALREADY_EXISTS) { status = NO_ERROR; } else { // Acknowledge any pending flush(), so that subsequent new data isn't discarded. // It is usually unsafe to access the server proxy from a binder thread. // But in this case we know the mixer thread (whether normal mixer or fast mixer) // isn't looking at this track yet: we still hold the normal mixer thread lock, // and for fast tracks the track is not yet in the fast mixer thread's active set. // For static tracks, this is used to acknowledge change in position or loop. ServerProxy::Buffer buffer; buffer.mFrameCount = 1; (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/); } } else { status = BAD_VALUE; } if (status == NO_ERROR) { forEachTeePatchTrack([](auto patchTrack) { patchTrack->start(); }); } return status; }

上面的代码我们主要看playbackThread,我们播放音频的发动机,主要核心线程,playbackThread是保存在mPlaybackThreads数组中,再看看playbackThread→addTrack_l

status_t AudioFlinger::PlaybackThread::addTrack_l(const sp& track) { status_t status = ALREADY_EXISTS; if (mActiveTracks.indexOf(track) TrackBase::track_state state = track->mState; mLock.unlock(); status = AudioSystem::startOutput(track->portId()); 这边实际上是调用到了AudioOutputDescriptor中,增加了mPorfile->curActiveCount的计数 mLock.lock(); // abort track was stopped/paused while we released the lock if (state != track->mState) { if (status == NO_ERROR) { mLock.unlock(); AudioSystem::stopOutput(track->portId()); mLock.lock(); } return INVALID_OPERATION; } // abort if start is rejected by audio policy manager if (status != NO_ERROR) { return PERMISSION_DENIED; } #ifdef ADD_BATTERY_DATA // to track the speaker usage addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStart); #endif sendIoConfigEvent_l(AUDIO_CLIENT_STARTED, track->creatorPid(), track->portId()); } // set retry count for buffer fill if (track->isOffloaded()) { if (track->isStopping_1()) { track->mRetryCount = kMaxTrackStopRetriesOffload; } else { track->mRetryCount = kMaxTrackStartupRetriesOffload; } track->mFillingUpStatus = mStandby ? Track::FS_FILLING : Track::FS_FILLED; } else { track->mRetryCount = kMaxTrackStartupRetries; track->mFillingUpStatus = track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING; } sp chain = getEffectChain_l(track->sessionId()); if (mHapticChannelMask != AUDIO_CHANNEL_NONE && ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE || (chain != nullptr && chain->containsHapticGeneratingEffect_l()))) { // Unlock due to VibratorService will lock for this call and will // call Tracks.mute/unmute which also require thread's lock. mLock.unlock(); const int intensity = AudioFlinger::onExternalVibrationStart( track->getExternalVibration()); mLock.lock(); track->setHapticIntensity(static_cast(intensity)); // Haptic playback should be enabled by vibrator service. if (track->getHapticPlaybackEnabled()) { // Disable haptic playback of all active track to ensure only // one track playing haptic if current track should play haptic. for (const auto &t : mActiveTracks) { t->setHapticPlaybackEnabled(false); } } // Set haptic intensity for effect if (chain != nullptr) { chain->setHapticIntensity_l(track->id(), intensity); } } track->mResetDone = false; track->resetPresentationComplete(); mActiveTracks.add(track); if (chain != 0) { ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), track->sessionId()); chain->incActiveTrackCnt(); } track->logBeginInterval(patchSinksToString(&mPatch)); // log to MediaMetrics status = NO_ERROR; } onAddNewTrack_l(); ----------- 1 return status; } void AudioFlinger::PlaybackThread::onAddNewTrack_l() 1 ------------- 这里是对我们playbackThread进行了唤醒 { ALOGV("signal playback thread"); broadcast_l(); }

addTrack_l之后playbackThread会被唤醒,然后就会开始它自己的工作,thread_loop会动起来,这里面包含集合函数:threadloop_mix、threadloop_write、threadloop_standby,分别是对音频进行混音、通过数据流将数据写到HAL层、暂停,上层play之后就会开始往HAL层写数据,然后就放出了了我们听到的音乐,这个track在framework层的使命就算是成功完成了,然后处理的事情就交给了HAL层和kernel及ALSA



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


    图片新闻

    实验室药品柜的特性有哪些
    实验室药品柜是实验室家具的重要组成部分之一,主要
    小学科学实验中有哪些教学
    计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
    实验室各种仪器原理动图讲
    1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
    高中化学常见仪器及实验装
    1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
    微生物操作主要设备和器具
    今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
    浅谈通风柜使用基本常识
     众所周知,通风柜功能中最主要的就是排气功能。在

    专题文章

      CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭