Android Audio代码分析14 - testPlaybackHeadPositionIncrease

本文详细解析了在AudioTrack中通过play函数导致播放头位置增加的过程,包括初始化配置、测试流程以及验证结果。
继续啃AudioTrack的测试代码。


*****************************************源码*************************************************
//Test case 2: getPlaybackHeadPosition() increases after play() @LargeTest public void testPlaybackHeadPositionIncrease() throws Exception { // constants for test final String TEST_NAME = "testPlaybackHeadPositionIncrease"; final int TEST_SR = 22050; final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO; final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT; final int TEST_MODE = AudioTrack.MODE_STREAM; final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC; //-------- initialization -------------- int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT); AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT, minBuffSize, TEST_MODE); byte data[] = new byte[minBuffSize/2]; //-------- test -------------- assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED); track.write(data, 0, data.length); track.write(data, 0, data.length); track.play(); Thread.sleep(100); log(TEST_NAME, "position ="+ track.getPlaybackHeadPosition()); assertTrue(TEST_NAME, track.getPlaybackHeadPosition() > 0); //-------- tear down -------------- track.release(); }
**********************************************************************************************
源码路径:
frameworks\base\media\tests\mediaframeworktest\src\com\android\mediaframeworktest\functional\MediaAudioTrackTest.java


#######################说明################################
//Test case 2: getPlaybackHeadPosition() increases after play() // 在上一篇关于getPlaybackHeadPosition的分析中,没有调用play函数,就调用了getPlaybackHeadPosition,所以获取的position应该为0. // 而本例子中,在write之后就调用了play,然后sleep了100ms,才调用的getPlaybackHeadPosition。 // 也就是说,播放了100ms才去获取的位置,此时的位置当然应该大于0 @LargeTest public void testPlaybackHeadPositionIncrease() throws Exception { // constants for test final String TEST_NAME = "testPlaybackHeadPositionIncrease"; final int TEST_SR = 22050; final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO; final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT; final int TEST_MODE = AudioTrack.MODE_STREAM; final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC; //-------- initialization -------------- int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT); AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT, minBuffSize, TEST_MODE); byte data[] = new byte[minBuffSize/2]; //-------- test -------------- assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED); track.write(data, 0, data.length); track.write(data, 0, data.length); // 这次的引子是position如何被改变的 // 既然播放之后,获取的position为正,那么play函数的调用就应该会导致position的改变。 // 一起来看看play函数如何导致position改变的。 track.play(); // ++++++++++++++++++++++++++++++play++++++++++++++++++++++++++++++++++ /** * Starts playing an AudioTrack. * @throws IllegalStateException */ public void play() throws IllegalStateException { if (mState != STATE_INITIALIZED) { throw(new IllegalStateException("play() called on uninitialized AudioTrack.")); } synchronized(mPlayStateLock) { native_start(); // ++++++++++++++++++++++++++++++android_media_AudioTrack_start++++++++++++++++++++++++++++++++++ static void android_media_AudioTrack_start(JNIEnv *env, jobject thiz) { AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( thiz, javaAudioTrackFields.nativeTrackInJavaObj); if (lpTrack == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", "Unable to retrieve AudioTrack pointer for start()"); return; } lpTrack->start(); // ++++++++++++++++++++++++++++++AudioTrack::start++++++++++++++++++++++++++++++++++ void AudioTrack::start() { // mAudioTrackThread在函数AudioTrack::set中被赋值。 sp<AudioTrackThread> t = mAudioTrackThread; status_t status; LOGV("start %p", this); if (t != 0) { // 函数exitPending返回成员变量mExitPending if (t->exitPending()) { if (t->requestExitAndWait() == WOULD_BLOCK) { LOGE("AudioTrack::start called from thread"); return; } } t->mLock.lock(); } if (android_atomic_or(1, &mActive) == 0) { mNewPosition = mCblk->server + mUpdatePeriod; mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; mCblk->waitTimeMs = 0; mCblk->flags &= ~CBLK_DISABLED_ON; if (t != 0) { // 调用的是函数Thread::run t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); // +++++++++++++++++++++++++++++++Thread::run+++++++++++++++++++++++++++++++++ status_t Thread::run(const char* name, int32_t priority, size_t stack) { Mutex::Autolock _l(mLock); if (mRunning) { // thread already started return INVALID_OPERATION; } // reset status and exitPending to their default value, so we can // try again after an error happened (either below, or in readyToRun()) mStatus = NO_ERROR; // 在函数exitPending中会返回该成员变量 mExitPending = false; mThread = thread_id_t(-1); // hold a strong reference on ourself mHoldSelf = this; mRunning = true; bool res; // 我们调用函数AudioTrack::set的时候,将threadCanCallJava指定为了false if (mCanCallJava) { res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread); // +++++++++++++++++++++++++++++++createThreadEtc+++++++++++++++++++++++++++++++++ // Create thread with lots of parameters inline bool createThreadEtc(thread_func_t entryFunction, void *userData, const char* threadName = "android:unnamed_thread", int32_t threadPriority = PRIORITY_DEFAULT, size_t threadStackSize = 0, thread_id_t *threadId = 0) { return androidCreateThreadEtc(entryFunction, userData, threadName, threadPriority, threadStackSize, threadId) ? true : false; // +++++++++++++++++++++++++++++++++androidCreateThreadEtc+++++++++++++++++++++++++++++++ int androidCreateThreadEtc(android_thread_func_t entryFunction, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId) { // gCreateThreadFn被初始化为androidCreateRawThreadEtc。 // 函数androidSetCreateThreadFunc会对其赋值 return gCreateThreadFn(entryFunction, userData, threadName, threadPriority, threadStackSize, threadId); // ++++++++++++++++++++++++++++++androidSetCreateThreadFunc++++++++++++++++++++++++++++++++++ void androidSetCreateThreadFunc(android_create_thread_fn func) { gCreateThreadFn = func; } // 函数AndroidRuntime::startReg调用了函数androidSetCreateThreadFunc // +++++++++++++++++++++++++++++AndroidRuntime::startReg+++++++++++++++++++++++++++++++++++ /* * Register android native functions with the VM. */ /*static*/ int AndroidRuntime::startReg(JNIEnv* env) { /* * This hook causes all future threads created in this process to be * attached to the JavaVM. (This needs to go away in favor of JNI * Attach calls.) */ androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); // +++++++++++++++++++++++++++javaCreateThreadEtc+++++++++++++++++++++++++++++++++++++ /* * This is invoked from androidCreateThreadEtc() via the callback * set with androidSetCreateThreadFunc(). * * We need to create the new thread in such a way that it gets hooked * into the VM before it really starts executing. */ /*static*/ int AndroidRuntime::javaCreateThreadEtc( android_thread_func_t entryFunction, void* userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t* threadId) { void** args = (void**) malloc(3 * sizeof(void*)); // javaThreadShell must free int result; assert(threadName != NULL); args[0] = (void*) entryFunction; args[1] = userData; args[2] = (void*) strdup(threadName); // javaThreadShell must free // 如果可以从java层调用的话,就在thread外包了层壳 result = androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args, threadName, threadPriority, threadStackSize, threadId); return result; } // ---------------------------javaCreateThreadEtc------------------------------------- LOGV("--- registering native functions ---\n"); /* * Every "register" function calls one or more things that return * a local reference (e.g. FindClass). Because we haven't really * started the VM yet, they're all getting stored in the base frame * and never released. Use Push/Pop to manage the storage. */ env->PushLocalFrame(200); if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); //createJavaThread("fubar", quickTest, (void*) "hello"); return 0; } // 函数AndroidRuntime::start调用了函数AndroidRuntime::startReg。 // ++++++++++++++++++++++++++++++AndroidRuntime::start++++++++++++++++++++++++++++++++++ /* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". */ void AndroidRuntime::start(const char* className, const bool startSystemServer) { LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n", className != NULL ? className : "(unknown)"); char* slashClassName = NULL; char* cp; JNIEnv* env; blockSigpipe(); /* * 'startSystemServer == true' means runtime is obslete and not run from * init.rc anymore, so we print out the boot start event here. */ if (startSystemServer) { /* track our progress through the boot sequence */ const int LOG_BOOT_PROGRESS_START = 3000; LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } const char* rootDir = getenv("ANDROID_ROOT"); if (rootDir == NULL) { rootDir = "/system"; if (!hasDir("/system")) { LOG_FATAL("No root directory specified, and /android does not exist."); goto bail; } setenv("ANDROID_ROOT", rootDir, 1); } //const char* kernelHack = getenv("LD_ASSUME_KERNEL"); //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); /* start the virtual machine */ if (startVm(&mJavaVM, &env) != 0) goto bail; /* * Register android functions. */ if (startReg(env) < 0) { LOGE("Unable to register all android natives\n"); goto bail; } /* * We want to call main() with a String array with arguments in it. * At present we only have one argument, the class name. Create an * array to hold it. */ jclass stringClass; jobjectArray strArray; jstring classNameStr; jstring startSystemServerStr; stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(2, stringClass, NULL); assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); startSystemServerStr = env->NewStringUTF(startSystemServer ? "true" : "false"); env->SetObjectArrayElement(strArray, 1, startSystemServerStr); /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ jclass startClass; jmethodID startMeth; slashClassName = strdup(className); for (cp = slashClassName; *cp != '\0'; cp++) if (*cp == '.') *cp = '/'; startClass = env->FindClass(slashClassName); if (startClass == NULL) { LOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { LOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); #if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env); #endif } } LOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) LOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) LOGW("Warning: VM did not shut down cleanly\n"); bail: free(slashClassName); } // ------------------------------AndroidRuntime::start---------------------------------- // -----------------------------AndroidRuntime::startReg----------------------------------- // ------------------------------androidSetCreateThreadFunc---------------------------------- } // ---------------------------------androidCreateThreadEtc------------------------------- } // -------------------------------createThreadEtc--------------------------------- } else { res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); // +++++++++++++++++++++++++++++++androidCreateRawThreadEtc+++++++++++++++++++++++++++++++++ // 函数androidCreateRawThreadEtc有两种实现。 #if defined(HAVE_PTHREADS) int androidCreateRawThreadEtc(android_thread_func_t entryFunction, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #ifdef HAVE_ANDROID_OS /* valgrind is rejecting RT-priority create reqs */ if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) { // We could avoid the trampoline if there was a way to get to the // android_thread_id_t (pid) from pthread_t thread_data_t* t = new thread_data_t; t->priority = threadPriority; t->threadName = threadName ? strdup(threadName) : NULL; t->entryFunction = entryFunction; t->userData = userData; entryFunction = (android_thread_func_t)&thread_data_t::trampoline; userData = t; } #endif if (threadStackSize) { pthread_attr_setstacksize(&attr, threadStackSize); } errno = 0; pthread_t thread; int result = pthread_create(&thread, &attr, (android_pthread_entry)entryFunction, userData); if (result != 0) { LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n" "(android threadPriority=%d)", entryFunction, result, errno, threadPriority); return 0; } if (threadId != NULL) { *threadId = (android_thread_id_t)thread; // XXX: this is not portable } return 1; } #elif defined(HAVE_WIN32_THREADS) int androidCreateRawThreadEtc(android_thread_func_t fn, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId) { return doCreateThread( fn, userData, threadId); // ++++++++++++++++++++++++++++++doCreateThread++++++++++++++++++++++++++++++++++ /* * Create and run a new thread. */ static bool doCreateThread(android_thread_func_t fn, void* arg, android_thread_id_t *id) { HANDLE hThread; struct threadDetails* pDetails = new threadDetails; // must be on heap unsigned int thrdaddr; pDetails->func = fn; pDetails->arg = arg; #if defined(HAVE__BEGINTHREADEX) hThread = (HANDLE) _beginthreadex(NULL, 0, threadIntermediary, pDetails, 0, &thrdaddr); if (hThread == 0) #elif defined(HAVE_CREATETHREAD) hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) threadIntermediary, (void*) pDetails, 0, (DWORD*) &thrdaddr); if (hThread == NULL) #endif { LOG(LOG_WARN, "thread", "WARNING: thread create failed\n"); return false; } #if defined(HAVE_CREATETHREAD) /* close the management handle */ CloseHandle(hThread); #endif if (id != NULL) { *id = (android_thread_id_t)thrdaddr; } return true; } // ------------------------------doCreateThread---------------------------------- } #endif // -------------------------------androidCreateRawThreadEtc--------------------------------- } if (res == false) { mStatus = UNKNOWN_ERROR; // something happened! mRunning = false; mThread = thread_id_t(-1); mHoldSelf.clear(); // "this" may have gone away after this. return UNKNOWN_ERROR; } // Do not refer to mStatus here: The thread is already running (may, in fact // already have exited with a valid mStatus result). The NO_ERROR indication // here merely indicates successfully starting the thread and does not // imply successful termination/execution. return NO_ERROR; } // 在上面创建线程的时候,我们传入的是函数_threadLoop。 // ++++++++++++++++++++++++++++Thread::_threadLoop++++++++++++++++++++++++++++++++++++ int Thread::_threadLoop(void* user) { Thread* const self = static_cast<Thread*>(user); sp<Thread> strong(self->mHoldSelf); wp<Thread> weak(strong); self->mHoldSelf.clear(); #if HAVE_ANDROID_OS // this is very useful for debugging with gdb self->mTid = gettid(); #endif bool first = true; do { bool result; if (first) { first = false; self->mStatus = self->readyToRun(); result = (self->mStatus == NO_ERROR); if (result && !self->mExitPending) { // Binder threads (and maybe others) rely on threadLoop // running at least once after a successful ::readyToRun() // (unless, of course, the thread has already been asked to exit // at that point). // This is because threads are essentially used like this: // (new ThreadSubclass())->run(); // The caller therefore does not retain a strong reference to // the thread and the thread would simply disappear after the // successful ::readyToRun() call instead of entering the // threadLoop at least once. // 可见,最终调用的还是各thread的threadLoop函数 result = self->threadLoop(); // +++++++++++++++++++++++++++AudioTrack::AudioTrackThread::threadLoop+++++++++++++++++++++++++++++++++++++ bool AudioTrack::AudioTrackThread::threadLoop() { // 调用的其实是函数AudioTrack::processAudioBuffer return mReceiver.processAudioBuffer(this); // ++++++++++++++++++++++++++++AudioTrack::processAudioBuffer++++++++++++++++++++++++++++++++++++ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) { Buffer audioBuffer; uint32_t frames; size_t writtenSize; // Manage underrun callback if (mActive && (mCblk->framesReady() == 0)) { LOGV("Underrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags); if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { mCbf(EVENT_UNDERRUN, mUserData, 0); if (mCblk->server == mCblk->frameCount) { // 函数指针mCbf指向的是函数audioCallback mCbf(EVENT_BUFFER_END, mUserData, 0); // ++++++++++++++++++++++++++++audioCallback++++++++++++++++++++++++++++++++++++ static void audioCallback(int event, void* user, void *info) { if (event == AudioTrack::EVENT_MORE_DATA) { // set size to 0 to signal we're not using the callback to write more data AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info; pBuff->size = 0; } else if (event == AudioTrack::EVENT_MARKER) { audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user; JNIEnv *env = AndroidRuntime::getJNIEnv(); if (user && env) { env->CallStaticVoidMethod( callbackInfo->audioTrack_class, javaAudioTrackFields.postNativeEventInJava, callbackInfo->audioTrack_ref, event, 0,0, NULL); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } } } else if (event == AudioTrack::EVENT_NEW_POS) { audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user; JNIEnv *env = AndroidRuntime::getJNIEnv(); if (user && env) { env->CallStaticVoidMethod( callbackInfo->audioTrack_class, javaAudioTrackFields.postNativeEventInJava, callbackInfo->audioTrack_ref, event, 0,0, NULL); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } } } } // ----------------------------audioCallback------------------------------------ } mCblk->flags |= CBLK_UNDERRUN_ON; if (mSharedBuffer != 0) return false; } } // Manage loop end callback while (mLoopCount > mCblk->loopCount) { int loopCount = -1; mLoopCount--; if (mLoopCount >= 0) loopCount = mLoopCount; mCbf(EVENT_LOOP_END, mUserData, (void *)&loopCount); } // Manage marker callback if (!mMarkerReached && (mMarkerPosition > 0)) { if (mCblk->server >= mMarkerPosition) { mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition); mMarkerReached = true; } } // Manage new position callback if (mUpdatePeriod > 0) { while (mCblk->server >= mNewPosition) { mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition); mNewPosition += mUpdatePeriod; } } // If Shared buffer is used, no data is requested from client. if (mSharedBuffer != 0) { frames = 0; } else { frames = mRemainingFrames; } do { audioBuffer.frameCount = frames; // Calling obtainBuffer() with a wait count of 1 // limits wait time to WAIT_PERIOD_MS. This prevents from being // stuck here not being able to handle timed events (position, markers, loops). status_t err = obtainBuffer(&audioBuffer, 1); if (err < NO_ERROR) { if (err != TIMED_OUT) { LOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up."); return false; } break; } if (err == status_t(STOPPED)) return false; // Divide buffer size by 2 to take into account the expansion // due to 8 to 16 bit conversion: the callback must fill only half // of the destination buffer if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) { audioBuffer.size >>= 1; } size_t reqSize = audioBuffer.size; mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer); writtenSize = audioBuffer.size; // Sanity check on returned size if (ssize_t(writtenSize) <= 0) { // The callback is done filling buffers // Keep this thread going to handle timed events and // still try to get more data in intervals of WAIT_PERIOD_MS // but don't just loop and block the CPU, so wait usleep(WAIT_PERIOD_MS*1000); break; } if (writtenSize > reqSize) writtenSize = reqSize; if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) { // 8 to 16 bit conversion const int8_t *src = audioBuffer.i8 + writtenSize-1; int count = writtenSize; int16_t *dst = audioBuffer.i16 + writtenSize-1; while(count--) { *dst-- = (int16_t)(*src--^0x80) << 8; } writtenSize <<= 1; } audioBuffer.size = writtenSize; // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for // 8 bit PCM data: in this case, mCblk->frameSize is based on a sampel size of // 16 bit. audioBuffer.frameCount = writtenSize/mCblk->frameSize; frames -= audioBuffer.frameCount; releaseBuffer(&audioBuffer); } while (frames); if (frames == 0) { mRemainingFrames = mNotificationFramesAct; } else { mRemainingFrames = frames; } return true; } // ----------------------------AudioTrack::processAudioBuffer------------------------------------ } // ---------------------------AudioTrack::AudioTrackThread::threadLoop------------------------------------- } } else { result = self->threadLoop(); } if (result == false || self->mExitPending) { self->mExitPending = true; self->mLock.lock(); self->mRunning = false; // clear thread ID so that requestExitAndWait() does not exit if // called by a new thread using the same thread ID as this one. self->mThread = thread_id_t(-1); self->mThreadExitedCondition.broadcast(); self->mThread = thread_id_t(-1); // thread id could be reused self->mLock.unlock(); break; } // Release our strong reference, to let a chance to the thread // to die a peaceful death. strong.clear(); // And immediately, re-acquire a strong reference for the next loop strong = weak.promote(); } while(strong != 0); return 0; } // ----------------------------Thread::_threadLoop------------------------------------ // -------------------------------Thread::run--------------------------------- } else { setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT); } if (mCblk->flags & CBLK_INVALID_MSK) { LOGW("start() track %p invalidated, creating a new one", this); // no need to clear the invalid flag as this cblk will not be used anymore // force new track creation status = DEAD_OBJECT; } else { // mAudioTrack在函数AudioTrack::createTrack中被赋值,其最终指向的其实是一个TrackHandle对象 status = mAudioTrack->start(); // +++++++++++++++++++++++++++AudioFlinger::TrackHandle::start+++++++++++++++++++++++++++++++++++++ status_t AudioFlinger::TrackHandle::start() { return mTrack->start(); // +++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::Track::start+++++++++++++++++++++++++++++++++ status_t AudioFlinger::PlaybackThread::Track::start() { status_t status = NO_ERROR; LOGV("start(%d), calling thread %d session %d", mName, IPCThreadState::self()->getCallingPid(), mSessionId); sp<ThreadBase> thread = mThread.promote(); if (thread != 0) { Mutex::Autolock _l(thread->mLock); int state = mState; // here the track could be either new, or restarted // in both cases "unstop" the track if (mState == PAUSED) { mState = TrackBase::RESUMING; LOGV("PAUSED => RESUMING (%d) on thread %p", mName, this); } else { mState = TrackBase::ACTIVE; LOGV("? => ACTIVE (%d) on thread %p", mName, this); } if (!isOutputTrack() && state != ACTIVE && state != RESUMING) { thread->mLock.unlock(); status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType, mSessionId); // +++++++++++++++++++++++AudioSystem::startOutput+++++++++++++++++++++++++++++++++++++++++ status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; return aps->startOutput(output, stream, session); // ++++++++++++++++++++++++AudioPolicyService::startOutput++++++++++++++++++++++++++++++++++++++++ status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) { if (mpPolicyManager == NULL) { return NO_INIT; } LOGV("startOutput() tid %d", gettid()); Mutex::Autolock _l(mLock); return mpPolicyManager->startOutput(output, stream, session); // +++++++++++++++++++++++++++AudioPolicyManagerBase::startOutput+++++++++++++++++++++++++++++++++++++ status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) { LOGV("startOutput() output %d, stream %d, session %d", output, stream, session); // 函数AudioPolicyManagerBase::addOutput调用了函数mOutputs.add往mOutputs添加成员 ssize_t index = mOutputs.indexOfKey(output); // +++++++++++++++++++++++++++++AudioPolicyManagerBase::addOutput+++++++++++++++++++++++++++++++++++ void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc) { outputDesc->mId = id; mOutputs.add(id, outputDesc); } /* 类AudioPolicyManagerBase中有几处调用了函数AudioPolicyManagerBase::addOutput。 一般是调用mpClientInterface->openOutput函数后,会调用函数AudioPolicyManagerBase::addOutput将output添加到mOutputs。 (mpClientInterface其实是一个AudioPolicyService对象) 例如: 函数AudioPolicyManagerBase::getOutput和AudioPolicyManagerBase的构造函数。 创建AudioTrack对象的时候,在函数AudioTrack::set中会调用函数AudioPolicyManagerBase::getOutput。 AudioPolicyManagerBase对象是在AudioPolicyService的构造函数中被创建。*/ // -----------------------------AudioPolicyManagerBase::addOutput----------------------------------- if (index < 0) { LOGW("startOutput() unknow output %d", output); return BAD_VALUE; } // 在mOutputs中,output作为key,outputDesc作为value。 AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); // 函数getStrategy就是根据stream type返回特定的strategy。 routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); #ifdef WITH_A2DP if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) { setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput); // ++++++++++++++++++++++++++++AudioPolicyManagerBase::setStrategyMute++++++++++++++++++++++++++++++++++++ void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output, int delayMs) { LOGV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output); // 将strategy对应的stream全部mute for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { if (getStrategy((AudioSystem::stream_type)stream) == strategy) { setStreamMute(stream, on, output, delayMs); // +++++++++++++++++++++++++++++AudioPolicyManagerBase::setStreamMute+++++++++++++++++++++++++++++++++++ void AudioPolicyManagerBase::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs) { StreamDescriptor &streamDesc = mStreams[stream]; // ++++++++++++++++++++++++++++++StreamDescriptor++++++++++++++++++++++++++++++++++ // stream descriptor used for volume control class StreamDescriptor { public: StreamDescriptor() : mIndexMin(0), mIndexMax(1), mIndexCur(1), mCanBeMuted(true) {} void dump(char* buffer, size_t size); int mIndexMin; // min volume index int mIndexMax; // max volume index int mIndexCur; // current volume index bool mCanBeMuted; // true is the stream can be muted }; // ------------------------------StreamDescriptor---------------------------------- AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); // ++++++++++++++++++++++++++++++AudioOutputDescriptor++++++++++++++++++++++++++++++++++ // descriptor for audio outputs. Used to maintain current configuration of each opened audio output // and keep track of the usage of this output by each audio stream type. class AudioOutputDescriptor { public: AudioOutputDescriptor(); status_t dump(int fd); uint32_t device(); void changeRefCount(AudioSystem::stream_type, int delta); uint32_t refCount(); uint32_t strategyRefCount(routing_strategy strategy); bool isUsedByStrategy(routing_strategy strategy) { return (strategyRefCount(strategy) != 0);} bool isDuplicated() { return (mOutput1 != NULL && mOutput2 != NULL); } audio_io_handle_t mId; // output handle uint32_t mSamplingRate; // uint32_t mFormat; // uint32_t mChannels; // output configuration uint32_t mLatency; // AudioSystem::output_flags mFlags; // uint32_t mDevice; // current device this output is routed to uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output AudioOutputDescriptor *mOutput1; // used by duplicated outputs: first output AudioOutputDescriptor *mOutput2; // used by duplicated outputs: second output float mCurVolume[AudioSystem::NUM_STREAM_TYPES]; // current stream volume int mMuteCount[AudioSystem::NUM_STREAM_TYPES]; // mute request counter }; // ------------------------------AudioOutputDescriptor---------------------------------- LOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]); if (on) { if (outputDesc->mMuteCount[stream] == 0) { if (streamDesc.mCanBeMuted) { checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs); // ++++++++++++++++++++++++++++AudioPolicyManagerBase::checkAndSetVolume++++++++++++++++++++++++++++++++++++ status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force) { // do not change actual stream volume if the stream is muted if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) { LOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]); return NO_ERROR; } // do not change in call volume if bluetooth is connected and vice versa if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { LOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); return INVALID_OPERATION; } float volume = computeVolume(stream, index, output, device); // +++++++++++++++++++++++++++++++AudioPolicyManagerBase::computeVolume+++++++++++++++++++++++++++++++++ float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device) { float volume = 1.0; AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); StreamDescriptor &streamDesc = mStreams[stream]; if (device == 0) { device = outputDesc->device(); } int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); volume = AudioSystem::linearToLog(volInt); // +++++++++++++++++++++++++++++++AudioSystem::linearToLog+++++++++++++++++++++++++++++++++ float AudioSystem::linearToLog(int volume) { // float v = volume ? exp(float(100 - volume) * dBConvert) : 0; // LOGD("linearToLog(%d)=%f", volume, v); // return v; return volume ? exp(float(100 - volume) * dBConvert) : 0; } // -------------------------------AudioSystem::linearToLog--------------------------------- // if a headset is connected, apply the following rules to ring tones and notifications // to avoid sound level bursts in user's ears: // - always attenuate ring tones and notifications volume by 6dB // - if music is playing, always limit the volume to current music volume, // with a minimum threshold at -36dB so that notification is always perceived. if ((device & (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP | AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) && ((getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) || (stream == AudioSystem::SYSTEM)) && streamDesc.mCanBeMuted) { // Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB // #define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5 volume *= SONIFICATION_HEADSET_VOLUME_FACTOR; // when the phone is ringing we must consider that music could have been paused just before // by the music application and behave as if music was active if the last music track was // just stopped // 函数AudioPolicyManagerBase::setPhoneState中有对mLimitRingtoneVolume赋值 // ++++++++++++++++++++++++++++++mLimitRingtoneVolume++++++++++++++++++++++++++++++++++ // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE if (state == AudioSystem::MODE_RINGTONE && (hwOutputDesc->mRefCount[AudioSystem::MUSIC] || (systemTime() - mMusicStopTime) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) { mLimitRingtoneVolume = true; } else { mLimitRingtoneVolume = false; } // ------------------------------mLimitRingtoneVolume---------------------------------- if (outputDesc->mRefCount[AudioSystem::MUSIC] || mLimitRingtoneVolume) { float musicVol = computeVolume(AudioSystem::MUSIC, mStreams[AudioSystem::MUSIC].mIndexCur, output, device); float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ? musicVol : SONIFICATION_HEADSET_VOLUME_MIN; if (volume > minVol) { volume = minVol; LOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol); } } } return volume; } // -------------------------------AudioPolicyManagerBase::computeVolume--------------------------------- // We actually change the volume if: // - the float value returned by computeVolume() changed // - the force flag is set if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || force) { mOutputs.valueFor(output)->mCurVolume[stream] = volume; LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); if (stream == AudioSystem::VOICE_CALL || stream == AudioSystem::DTMF || stream == AudioSystem::BLUETOOTH_SCO) { // offset value to reflect actual hardware volume that never reaches 0 // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java) volume = 0.01 + 0.99 * volume; } mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); // +++++++++++++++++++++++++++++AudioPolicyService::setStreamVolume+++++++++++++++++++++++++++++++++++ status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs) { // mAudioCommandThread在AudioPolicyService的构造函数中被创建 return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs); // ++++++++++++++++++++++++++++++AudioPolicyService::AudioCommandThread::volumeCommand++++++++++++++++++++++++++++++++++ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs) { status_t status = NO_ERROR; AudioCommand *command = new AudioCommand(); command->mCommand = SET_VOLUME; VolumeData *data = new VolumeData(); data->mStream = stream; data->mVolume = volume; data->mIO = output; command->mParam = data; if (delayMs == 0) { command->mWaitStatus = true; } else { command->mWaitStatus = false; } Mutex::Autolock _l(mLock); insertCommand_l(command, delayMs); // +++++++++++++++++++++++++++++++++AudioPolicyService::AudioCommandThread::insertCommand_l+++++++++++++++++++++++++++++++ // insertCommand_l() must be called with mLock held void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs) { ssize_t i; Vector <AudioCommand *> removedCommands; command->mTime = systemTime() + milliseconds(delayMs); // acquire wake lock to make sure delayed commands are processed if (mName != "" && mAudioCommands.isEmpty()) { acquire_wake_lock(PARTIAL_WAKE_LOCK, mName.string()); } // check same pending commands with later time stamps and eliminate them // 如果command队列中,存在正在等待的相同的command,如果其延迟比新加入的还要晚,则删除这些command // 从后往前遍历 for (i = mAudioCommands.size()-1; i >= 0; i--) { AudioCommand *command2 = mAudioCommands[i]; // commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands // command在队列中是按照时间戳排序的,开头的时间戳最短 // 从后往前遍历,碰到比自己小的时间戳,说明前面所有command 的时间戳都比新command的时间戳要小,也就没必要再比较了 if (command2->mTime <= command->mTime) break; // 只比较相同的command类型 if (command2->mCommand != command->mCommand) continue; switch (command->mCommand) { // 如果是设置参数,因为要设置的参数比较多,只把要设置的相同类型的参数删掉 // 如果队列中command设置的所有的参数类型与新command的所有参数类型完全相同,则将原来的command删除 case SET_PARAMETERS: { ParametersData *data = (ParametersData *)command->mParam; ParametersData *data2 = (ParametersData *)command2->mParam; if (data->mIO != data2->mIO) break; LOGV("Comparing parameter command %s to new command %s", data2->mKeyValuePairs.string(), data->mKeyValuePairs.string()); AudioParameter param = AudioParameter(data->mKeyValuePairs); AudioParameter param2 = AudioParameter(data2->mKeyValuePairs); for (size_t j = 0; j < param.size(); j++) { String8 key; String8 value; param.getAt(j, key, value); for (size_t k = 0; k < param2.size(); k++) { String8 key2; String8 value2; param2.getAt(k, key2, value2); if (key2 == key) { param2.remove(key2); LOGV("Filtering out parameter %s", key2.string()); break; } } } // if all keys have been filtered out, remove the command. // otherwise, update the key value pairs if (param2.size() == 0) { removedCommands.add(command2); } else { data2->mKeyValuePairs = param2.toString(); } } break; // 如果是设置音量,比较它们是否是要设置同一个output上的相同的stream的音量 // 如果是,则删除原command case SET_VOLUME: { VolumeData *data = (VolumeData *)command->mParam; VolumeData *data2 = (VolumeData *)command2->mParam; if (data->mIO != data2->mIO) break; if (data->mStream != data2->mStream) break; LOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream); removedCommands.add(command2); } break; case START_TONE: case STOP_TONE: default: break; } } // remove filtered commands for (size_t j = 0; j < removedCommands.size(); j++) { // removed commands always have time stamps greater than current command for (size_t k = i + 1; k < mAudioCommands.size(); k++) { if (mAudioCommands[k] == removedCommands[j]) { LOGV("suppressing command: %d", mAudioCommands[k]->mCommand); mAudioCommands.removeAt(k); break; } } } removedCommands.clear(); // insert command at the right place according to its time stamp LOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size()); // 将command加入到队列mAudioCommands中,位置i是根据时间戳算出来的 // 函数AudioPolicyService::AudioCommandThread::threadLoop中会处理mAudioCommands中的command mAudioCommands.insertAt(command, i + 1); // +++++++++++++++++++++++++++++++++AudioPolicyService::AudioCommandThread::threadLoop+++++++++++++++++++++++++++++++ bool AudioPolicyService::AudioCommandThread::threadLoop() { nsecs_t waitTime = INT64_MAX; mLock.lock(); while (!exitPending()) { while(!mAudioCommands.isEmpty()) { nsecs_t curTime = systemTime(); // commands are sorted by increasing time stamp: execute them from index 0 and up if (mAudioCommands[0]->mTime <= curTime) { // 每次总是取第一个command进行处理,因为第一个command 的时间戳永远是最早的 AudioCommand *command = mAudioCommands[0]; mAudioCommands.removeAt(0); mLastCommand = *command; switch (command->mCommand) { case START_TONE: { mLock.unlock(); ToneData *data = (ToneData *)command->mParam; LOGV("AudioCommandThread() processing start tone %d on stream %d", data->mType, data->mStream); if (mpToneGenerator != NULL) delete mpToneGenerator; mpToneGenerator = new ToneGenerator(data->mStream, 1.0); mpToneGenerator->startTone(data->mType); delete data; mLock.lock(); }break; case STOP_TONE: { mLock.unlock(); LOGV("AudioCommandThread() processing stop tone"); if (mpToneGenerator != NULL) { mpToneGenerator->stopTone(); delete mpToneGenerator; mpToneGenerator = NULL; } mLock.lock(); }break; case SET_VOLUME: { VolumeData *data = (VolumeData *)command->mParam; LOGV("AudioCommandThread() processing set volume stream %d, \ volume %f, output %d", data->mStream, data->mVolume, data->mIO); command->mStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO); // ++++++++++++++++++++++++++++++AudioSystem::setStreamVolume++++++++++++++++++++++++++++++++++ status_t AudioSystem::setStreamVolume(int stream, float value, int output) { if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; af->setStreamVolume(stream, value, output); // ++++++++++++++++++++++++++++++AudioFlinger::setStreamVolume++++++++++++++++++++++++++++++++++ status_t AudioFlinger::setStreamVolume(int stream, float value, int output) { // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return BAD_VALUE; } AutoMutex lock(mLock); PlaybackThread *thread = NULL; if (output) { thread = checkPlaybackThread_l(output); if (thread == NULL) { return BAD_VALUE; } } mStreamTypes[stream].volume = value; // 如果没有找到output对应的playback thread,则将所有的playback thread中的对应stream的音量全部改变 // 否则只改变对应的playback thread中对应stream的音量 if (thread == NULL) { for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) { mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value); } } else { thread->setStreamVolume(stream, value); // ++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::setStreamVolume++++++++++++++++++++++++++++++++++ status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value) { #ifdef LVMX int audioOutputType = LifeVibes::getMixerType(mId, mType); if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { LifeVibes::setStreamVolume(audioOutputType, stream, value); } #endif // 只是改变了软件音量 // mStreamTypes中保存的音量,在函数AudioFlinger::MixerThread::prepareTracks_l中有被使用 mStreamTypes[stream].volume = value; // +++++++++++++++++++++++++++++mStreamTypes+++++++++++++++++++++++++++++++++++ // read original volumes with volume control float typeVolume = mStreamTypes[track->type()].volume; #ifdef LVMX bool streamMute=false; // read the volume from the LivesVibes audio engine. if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { LifeVibes::getStreamVolumes(audioOutputType, track->type(), &typeVolume, &streamMute); if (streamMute) { typeVolume = 0; } } #endif float v = masterVolume * typeVolume; vl = (uint32_t)(v * cblk->volume[0]) << 12; vr = (uint32_t)(v * cblk->volume[1]) << 12; va = (uint32_t)(v * cblk->sendLevel); } // Delegate volume control to effect in track effect chain if needed // 转换后的音量在此处有被使用 // chain->setVolume_l函数中不仅使用了音量,也有去改变音量 if (chain != 0 && chain->setVolume_l(&vl, &vr)) { // ++++++++++++++++++++++++++++++AudioFlinger::EffectChain::setVolume_l++++++++++++++++++++++++++++++++++ // setVolume_l() must be called with PlaybackThread::mLock held bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right) { uint32_t newLeft = *left; uint32_t newRight = *right; bool hasControl = false; int ctrlIdx = -1; size_t size = mEffects.size(); // first update volume controller for (size_t i = size; i > 0; i--) { if (mEffects[i - 1]->isProcessEnabled() && (mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL) { ctrlIdx = i - 1; hasControl = true; break; } } if (ctrlIdx == mVolumeCtrlIdx && *left == mLeftVolume && *right == mRightVolume) { if (hasControl) { *left = mNewLeftVolume; *right = mNewRightVolume; } return hasControl; } mVolumeCtrlIdx = ctrlIdx; mLeftVolume = newLeft; mRightVolume = newRight; // second get volume update from volume controller if (ctrlIdx >= 0) { mEffects[ctrlIdx]->setVolume(&newLeft, &newRight, true); // +++++++++++++++++++++++++++++AudioFlinger::EffectModule::setVolume+++++++++++++++++++++++++++++++++++ status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller) { Mutex::Autolock _l(mLock); status_t status = NO_ERROR; // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume // if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set) if (isProcessEnabled() && ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL || (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND)) { status_t cmdStatus; uint32_t volume[2]; uint32_t *pVolume = NULL; uint32_t size = sizeof(volume); volume[0] = *left; volume[1] = *right; if (controller) { pVolume = volume; } status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_VOLUME, size, volume, &size, pVolume); if (controller && status == NO_ERROR && size == sizeof(volume)) { *left = volume[0]; *right = volume[1]; } } return status; } // -----------------------------AudioFlinger::EffectModule::setVolume----------------------------------- mNewLeftVolume = newLeft; mNewRightVolume = newRight; } // then indicate volume to all other effects in chain. // Pass altered volume to effects before volume controller // and requested volume to effects after controller uint32_t lVol = newLeft; uint32_t rVol = newRight; for (size_t i = 0; i < size; i++) { if ((int)i == ctrlIdx) continue; // this also works for ctrlIdx == -1 when there is no volume controller if ((int)i > ctrlIdx) { lVol = *left; rVol = *right; } mEffects[i]->setVolume(&lVol, &rVol, false); } *left = newLeft; *right = newRight; return hasControl; } // ------------------------------AudioFlinger::EffectChain::setVolume_l---------------------------------- // Do not ramp volume if volume is controlled by effect param = AudioMixer::VOLUME; track->mHasVolumeController = true; } else { // force no volume ramp when volume controller was just disabled or removed // from effect chain to avoid volume spike if (track->mHasVolumeController) { param = AudioMixer::VOLUME; } track->mHasVolumeController = false; } // Convert volumes from 8.24 to 4.12 format int16_t left, right, aux; uint32_t v_clamped = (vl + (1 << 11)) >> 12; if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; left = int16_t(v_clamped); v_clamped = (vr + (1 << 11)) >> 12; if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; right = int16_t(v_clamped); if (va > MAX_GAIN_INT) va = MAX_GAIN_INT; aux = int16_t(va); #ifdef LVMX if ( tracksConnectedChanged || stateChanged ) { // only do the ramp when the volume is changed by the user / application param = AudioMixer::VOLUME; } #endif // XXX: these things DON'T need to be done each time mAudioMixer->setBufferProvider(track); mAudioMixer->enable(AudioMixer::MIXING); // setParameter函数将volume信息设置到track对象中 // 函数process__OneTrack16BitsStereoNoResampling中会根据音量对数据进行处理 mAudioMixer->setParameter(param, AudioMixer::VOLUME0, (void *)left); mAudioMixer->setParameter(param, AudioMixer::VOLUME1, (void *)right); mAudioMixer->setParameter(param, AudioMixer::AUXLEVEL, (void *)aux); // -----------------------------mStreamTypes----------------------------------- return NO_ERROR; } // ------------------------------AudioFlinger::PlaybackThread::setStreamVolume---------------------------------- } return NO_ERROR; } // ------------------------------AudioFlinger::setStreamVolume---------------------------------- return NO_ERROR; } // ------------------------------AudioSystem::setStreamVolume---------------------------------- if (command->mWaitStatus) { command->mCond.signal(); mWaitWorkCV.wait(mLock); } delete data; }break; case SET_PARAMETERS: { ParametersData *data = (ParametersData *)command->mParam; LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO); command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs); if (command->mWaitStatus) { command->mCond.signal(); mWaitWorkCV.wait(mLock); } delete data; }break; case SET_VOICE_VOLUME: { VoiceVolumeData *data = (VoiceVolumeData *)command->mParam; LOGV("AudioCommandThread() processing set voice volume volume %f", data->mVolume); // 这个命令会因函数AudioPolicyManagerBase::checkAndSetVolume中调用mpClientInterface->setVoiceVolume函数引起 // 这儿也展开看看 command->mStatus = AudioSystem::setVoiceVolume(data->mVolume); // ++++++++++++++++++++++++++++++AudioSystem::setVoiceVolume++++++++++++++++++++++++++++++++++ status_t AudioSystem::setVoiceVolume(float value) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; return af->setVoiceVolume(value); // ++++++++++++++++++++++++++++++AudioFlinger::setVoiceVolume++++++++++++++++++++++++++++++++++ status_t AudioFlinger::setVoiceVolume(float value) { // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_SET_VOICE_VOLUME; status_t ret = mAudioHardware->setVoiceVolume(value); // +++++++++++++++++++++++++++++AudioHardwareALSA::setVoiceVolume+++++++++++++++++++++++++++++++++++ status_t AudioHardwareALSA::setVoiceVolume(float volume) { /* could not set this params on SPDIF card, will return directly */ if (!strcmp(mCurCard,SPDIF)) return INVALID_OPERATION; // The voice volume is used by the VOICE_CALL audio stream. if (mMixer) return mMixer->setVolume(AudioSystem::DEVICE_OUT_EARPIECE, volume, volume); // +++++++++++++++++++++++++++++AudioFlinger::setVoiceVolume+++++++++++++++++++++++++++++++++++ status_t ALSAMixer::setVolume(uint32_t device, float left, float right) { for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++) if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) { mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo; if (!info || !info->elem) return INVALID_OPERATION; long minVol = info->min; long maxVol = info->max; // Make sure volume is between bounds. long vol = minVol + left * (maxVol - minVol); if (vol > maxVol) vol = maxVol; if (vol < minVol) vol = minVol; info->volume = vol; snd_mixer_selem_set_playback_volume_all (info->elem, vol); // +++++++++++++++++++++++++++++snd_mixer_selem_set_playback_volume_all+++++++++++++++++++++++++++++++++++ /** * \brief Set value of playback volume control for all channels of a mixer simple element * \param elem Mixer simple element handle * \param value control value * \return 0 on success otherwise a negative error code */ int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value) { snd_mixer_selem_channel_id_t chn; int err; for (chn = 0; chn < 32; chn++) { if (!snd_mixer_selem_has_playback_channel(elem, chn)) // +++++++++++++++++++++++++++++++snd_mixer_selem_has_playback_channel+++++++++++++++++++++++++++++++++ /** * \brief Get info about channels of playback stream of a mixer simple element * \param elem Mixer simple element handle * \param channel Mixer simple element channel identifier * \return 0 if channel is not present, 1 if present */ int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) { CHECK_BASIC(elem); return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_CHANNEL, (int)channel); } // -------------------------------snd_mixer_selem_has_playback_channel--------------------------------- continue; err = snd_mixer_selem_set_playback_volume(elem, chn, value); // +++++++++++++++++++++++++++++snd_mixer_selem_set_playback_volume+++++++++++++++++++++++++++++++++++ /** * \brief Set value of playback volume control of a mixer simple element * \param elem Mixer simple element handle * \param channel mixer simple element channel identifier * \param value control value * \return 0 on success otherwise a negative error code */ int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) { CHECK_BASIC(elem); CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); // #define sm_selem_ops(x)((sm_selem_t *)((x)->private_data))->ops return sm_selem_ops(elem)->set_volume(elem, SM_PLAY, channel, value); // +++++++++++++++++++++++++++++sm_selem_t+++++++++++++++++++++++++++++++++++ typedef struct _sm_selem { snd_mixer_selem_id_t *id; struct sm_elem_ops *ops; unsigned int caps; unsigned int capture_group; } sm_selem_t; // -----------------------------sm_selem_t----------------------------------- } // -----------------------------snd_mixer_selem_set_playback_volume----------------------------------- if (err < 0) return err; if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem)) // +++++++++++++++++++++++++++++++++snd_mixer_selem_has_playback_volume_joined+++++++++++++++++++++++++++++++ /** * \brief Return info about playback volume control of a mixer simple element * \param elem Mixer simple element handle * \return 0 if control is separated per channel, 1 if control acts on all channels together */ int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem) { CHECK_BASIC(elem); return COND_CAPS(elem, SM_CAP_PVOLUME_JOIN); } // ---------------------------------snd_mixer_selem_has_playback_volume_joined------------------------------- return 0; } return 0; } // -----------------------------snd_mixer_selem_set_playback_volume_all----------------------------------- } return NO_ERROR; } // -----------------------------AudioFlinger::setVoiceVolume----------------------------------- else return INVALID_OPERATION; } // -----------------------------AudioHardwareALSA::setVoiceVolume----------------------------------- mHardwareStatus = AUDIO_HW_IDLE; return ret; } // ------------------------------AudioFlinger::setVoiceVolume---------------------------------- } // ------------------------------AudioSystem::setVoiceVolume---------------------------------- if (command->mWaitStatus) { command->mCond.signal(); mWaitWorkCV.wait(mLock); } delete data; }break; default: LOGW("AudioCommandThread() unknown command %d", command->mCommand); } delete command; waitTime = INT64_MAX; } else { waitTime = mAudioCommands[0]->mTime - curTime; break; } } // release delayed commands wake lock if (mName != "" && mAudioCommands.isEmpty()) { release_wake_lock(mName.string()); } LOGV("AudioCommandThread() going to sleep"); mWaitWorkCV.waitRelative(mLock, waitTime); LOGV("AudioCommandThread() waking up"); } mLock.unlock(); return false; } // ---------------------------------AudioPolicyService::AudioCommandThread::threadLoop------------------------------- } // ---------------------------------AudioPolicyService::AudioCommandThread::insertCommand_l------------------------------- LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output); mWaitWorkCV.signal(); if (command->mWaitStatus) { command->mCond.wait(mLock); status = command->mStatus; mWaitWorkCV.signal(); } return status; } // ------------------------------AudioPolicyService::AudioCommandThread::volumeCommand---------------------------------- } // -----------------------------AudioPolicyService::setStreamVolume----------------------------------- } if (stream == AudioSystem::VOICE_CALL || stream == AudioSystem::BLUETOOTH_SCO) { float voiceVolume; // Force voice volume to max for bluetooth SCO as volume is managed by the headset if (stream == AudioSystem::VOICE_CALL) { voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; } else { voiceVolume = 1.0; } if (voiceVolume != mLastVoiceVolume && output == mHardwareOutput) { mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } } return NO_ERROR; } // ----------------------------AudioPolicyManagerBase::checkAndSetVolume------------------------------------ } } // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored outputDesc->mMuteCount[stream]++; } else { if (outputDesc->mMuteCount[stream] == 0) { LOGW("setStreamMute() unmuting non muted stream!"); return; } if (--outputDesc->mMuteCount[stream] == 0) { checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs); } } } // -----------------------------AudioPolicyManagerBase::setStreamMute----------------------------------- } } } // ----------------------------AudioPolicyManagerBase::setStrategyMute------------------------------------ } #endif // incremenent usage count for this stream on the requested output: // NOTE that the usage count is the same for duplicated output and hardware output which is // necassary for a correct control of hardware output routing by startOutput() and stopOutput() outputDesc->changeRefCount(stream, 1); setOutputDevice(output, getNewDevice(output)); // ++++++++++++++++++++++++++++AudioPolicyManagerBase::setOutputDevice++++++++++++++++++++++++++++++++++++ void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs) { LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs); AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); if (outputDesc->isDuplicated()) { setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); return; } #ifdef WITH_A2DP // filter devices according to output selected if (output == mA2dpOutput) { device &= AudioSystem::DEVICE_OUT_ALL_A2DP; } else { device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP; } #endif uint32_t prevDevice = (uint32_t)outputDesc->device(); // Do not change the routing if: // - the requestede device is 0 // - the requested device is the same as current device and force is not specified. // Doing this check here allows the caller to call setOutputDevice() without conditions if ((device == 0 || device == prevDevice) && !force) { LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output); return; } outputDesc->mDevice = device; // mute media streams if both speaker and headset are selected if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) { setStrategyMute(STRATEGY_MEDIA, true, output); // wait for the PCM output buffers to empty before proceeding with the rest of the command usleep(outputDesc->mLatency*2*1000); } // do the routing AudioParameter param = AudioParameter(); param.addInt(String8(AudioParameter::keyRouting), (int)device); mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs); // +++++++++++++++++++++++++++++AudioPolicyService::setParameters+++++++++++++++++++++++++++++++++++ void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs) { mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs); // +++++++++++++++++++++++++++++AudioPolicyService::AudioCommandThread::parametersCommand+++++++++++++++++++++++++++++++++++ status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs) { status_t status = NO_ERROR; AudioCommand *command = new AudioCommand(); command->mCommand = SET_PARAMETERS; ParametersData *data = new ParametersData(); data->mIO = ioHandle; data->mKeyValuePairs = keyValuePairs; command->mParam = data; if (delayMs == 0) { command->mWaitStatus = true; } else { command->mWaitStatus = false; } Mutex::Autolock _l(mLock); // 将command添加到队列 // command的处理还是在函数AudioPolicyService::AudioCommandThread::threadLoop中 // 这儿只摘取了set parameter的片段 insertCommand_l(command, delayMs); // ++++++++++++++++++++++++++++++++case SET_PARAMETERS++++++++++++++++++++++++++++++++ case SET_PARAMETERS: { ParametersData *data = (ParametersData *)command->mParam; LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO); command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs); // ++++++++++++++++++++++++++++++++AudioSystem::setParameters++++++++++++++++++++++++++++++++ status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; return af->setParameters(ioHandle, keyValuePairs); // ++++++++++++++++++++++++++++++++AudioFlinger::setParameters++++++++++++++++++++++++++++++++ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) { status_t result; LOGV("setParameters(): io %d, keyvalue %s, tid %d, calling tid %d", ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid()); // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } #ifdef LVMX AudioParameter param = AudioParameter(keyValuePairs); LifeVibes::setParameters(ioHandle,keyValuePairs); String8 key = String8(AudioParameter::keyRouting); int device; if (NO_ERROR != param.getInt(key, device)) { device = -1; } key = String8(LifevibesTag); String8 value; int musicEnabled = -1; if (NO_ERROR == param.get(key, value)) { if (value == LifevibesEnable) { mLifeVibesClientPid = IPCThreadState::self()->getCallingPid(); musicEnabled = 1; } else if (value == LifevibesDisable) { mLifeVibesClientPid = -1; musicEnabled = 0; } } #endif // ioHandle == 0 means the parameters are global to the audio hardware interface if (ioHandle == 0) { AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_SET_PARAMETER; // 函数setParameters其实是个空的,并没有实现。 // 类AudioHardwareALSA中没有实现,基类AudioHardwareBase中是个空的 result = mAudioHardware->setParameters(keyValuePairs); #ifdef LVMX if (musicEnabled != -1) { LifeVibes::enableMusic((bool) musicEnabled); } #endif mHardwareStatus = AUDIO_HW_IDLE; return result; } // hold a strong ref on thread in case closeOutput() or closeInput() is called // and the thread is exited once the lock is released sp<ThreadBase> thread; { Mutex::Autolock _l(mLock); thread = checkPlaybackThread_l(ioHandle); if (thread == NULL) { thread = checkRecordThread_l(ioHandle); } } if (thread != NULL) { result = thread->setParameters(keyValuePairs); // +++++++++++++++++++++++++++++++AudioFlinger::ThreadBase::setParameters+++++++++++++++++++++++++++++++++ status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs) { status_t status; LOGV("ThreadBase::setParameters() %s", keyValuePairs.string()); Mutex::Autolock _l(mLock); // checkForNewParameters_l函数会使用mNewParameters,如函数AudioFlinger::MixerThread::checkForNewParameters_l mNewParameters.add(keyValuePairs); // +++++++++++++++++++++++++++++++AudioFlinger::MixerThread::checkForNewParameters_l+++++++++++++++++++++++++++++++++ // checkForNewParameters_l() must be called with ThreadBase::mLock held bool AudioFlinger::MixerThread::checkForNewParameters_l() { bool reconfig = false; while (!mNewParameters.isEmpty()) { status_t status = NO_ERROR; String8 keyValuePair = mNewParameters[0]; AudioParameter param = AudioParameter(keyValuePair); int value; if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) { reconfig = true; } if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) { if (value != AudioSystem::PCM_16_BIT) { status = BAD_VALUE; } else { reconfig = true; } } if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) { if (value != AudioSystem::CHANNEL_OUT_STEREO) { status = BAD_VALUE; } else { reconfig = true; } } if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { // do not accept frame count changes if tracks are open as the track buffer // size depends on frame count and correct behavior would not be garantied // if frame count is changed after track creation if (!mTracks.isEmpty()) { status = INVALID_OPERATION; } else { reconfig = true; } } if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { // forward device change to effects that have requested to be // aware of attached audio device. mDevice = (uint32_t)value; for (size_t i = 0; i < mEffectChains.size(); i++) { mEffectChains[i]->setDevice_l(mDevice); } } if (status == NO_ERROR) { // mOutput在父类PlaybackThread的构造函数中被赋值,其值是通过构造函数参数传过去的 // MixerThread对象是在函数AudioFlinger::openOutput中创建的 // 其中的output是调用函数AudioHardwareALSA::openOutputStream得到的 // 其中setParameters函数的实现是调用父类ALSAStreamOps的setParameters函数。 status = mOutput->setParameters(keyValuePair); // ++++++++++++++++++++++++++++++AudioStreamOutALSA::setParameters++++++++++++++++++++++++++++++++++ virtual status_t setParameters(const String8& keyValuePairs) { return ALSAStreamOps::setParameters(keyValuePairs); // ++++++++++++++++++++++++++++++ALSAStreamOps::setParameters++++++++++++++++++++++++++++++++++ status_t ALSAStreamOps::setParameters(const String8& keyValuePairs) { AudioParameter param = AudioParameter(keyValuePairs); String8 key = String8(AudioParameter::keyRouting); status_t status = NO_ERROR; int device; LOGV("setParameters() %s", keyValuePairs.string()); if (param.getInt(key, device) == NO_ERROR) { // mParent其实是AudioHardwareALSA对象 // mALSADevice的赋值在AudioHardwareALSA的构造函数中 // 通过调用函数module->methods->open得到,真正调用的函数是s_device_open // mParent->mALSADevice->route其实是函数s_route mParent->mALSADevice->route(mHandle, (uint32_t)device, mParent->mode()); // ++++++++++++++++++++++++++++++s_route++++++++++++++++++++++++++++++++++ static status_t s_route(alsa_handle_t *handle, uint32_t devices, int mode) { status_t status = NO_ERROR; LOGD("route called for devices %08x in mode %d...", devices, mode); // below Always noting to do, so we open device every time. #if 0 if (handle->handle && handle->curDev == devices && handle->curMode == mode) ; // Nothing to do else if (handle->handle && (handle->devices & devices)) setAlsaControls(handle, devices, mode); else { LOGE("Why are we routing to a device that isn't supported by this object?!?!?!?!"); status = s_open(handle, devices, mode); } #else /* fix me if I was wrong here to judge the current sound card. In facat, in s_open, it will reconfig the controls */ setAlsaControls(handle, devices, mode); // +++++++++++++++++++++++++++++++++++setAlsaControls+++++++++++++++++++++++++++++ void setAlsaControls(alsa_handle_t *handle, uint32_t devices, int mode) { AlsaControlSet set = (AlsaControlSet) handle->modPrivate; const char *card = deviceName(handle, devices, mode, 0); set(devices, mode, card); } // -----------------------------------setAlsaControls----------------------------- status = s_open(handle, devices, mode); #endif return status; } // ------------------------------s_route---------------------------------- param.remove(key); } if (param.size()) { status = BAD_VALUE; } return status; } // ------------------------------ALSAStreamOps::setParameters---------------------------------- } // ------------------------------AudioStreamOutALSA::setParameters---------------------------------- if (!mStandby && status == INVALID_OPERATION) { mOutput->standby(); mStandby = true; mBytesWritten = 0; status = mOutput->setParameters(keyValuePair); } if (status == NO_ERROR && reconfig) { delete mAudioMixer; readOutputParameters(); // +++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::readOutputParameters+++++++++++++++++++++++++++++++++ void AudioFlinger::PlaybackThread::readOutputParameters() { mSampleRate = mOutput->sampleRate(); mChannels = mOutput->channels(); mChannelCount = (uint16_t)AudioSystem::popCount(mChannels); mFormat = mOutput->format(); mFrameSize = (uint16_t)mOutput->frameSize(); mFrameCount = mOutput->bufferSize() / mFrameSize; // FIXME - Current mixer implementation only supports stereo output: Always // Allocate a stereo buffer even if HW output is mono. if (mMixBuffer != NULL) delete[] mMixBuffer; mMixBuffer = new int16_t[mFrameCount * 2]; memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); // force reconfiguration of effect chains and engines to take new buffer size and audio // parameters into account // Note that mLock is not held when readOutputParameters() is called from the constructor // but in this case nothing is done below as no audio sessions have effect yet so it doesn't // matter. // create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains Vector< sp<EffectChain> > effectChains = mEffectChains; for (size_t i = 0; i < effectChains.size(); i ++) { mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this, false); } } // -------------------------------AudioFlinger::PlaybackThread::readOutputParameters--------------------------------- mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); for (size_t i = 0; i < mTracks.size() ; i++) { int name = getTrackName_l(); if (name < 0) break; mTracks[i]->mName = name; // limit track sample rate to 2 x new output sample rate if (mTracks[i]->mCblk->sampleRate > 2 * sampleRate()) { mTracks[i]->mCblk->sampleRate = 2 * sampleRate(); } } sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED); // ++++++++++++++++++++++++++++++++++AudioFlinger::ThreadBase::sendConfigEvent_l++++++++++++++++++++++++++++++ // sendConfigEvent_l() must be called with ThreadBase::mLock held void AudioFlinger::ThreadBase::sendConfigEvent_l(int event, int param) { ConfigEvent *configEvent = new ConfigEvent(); configEvent->mEvent = event; configEvent->mParam = param; // 函数AudioFlinger::ThreadBase::processConfigEvents会处理mConfigEvents中的event mConfigEvents.add(configEvent); // ++++++++++++++++++++++++++++++++++AudioFlinger::ThreadBase::processConfigEvents++++++++++++++++++++++++++++++ void AudioFlinger::ThreadBase::processConfigEvents() { mLock.lock(); while(!mConfigEvents.isEmpty()) { LOGV("processConfigEvents() remaining events %d", mConfigEvents.size()); ConfigEvent *configEvent = mConfigEvents[0]; mConfigEvents.removeAt(0); // release mLock before locking AudioFlinger mLock: lock order is always // AudioFlinger then ThreadBase to avoid cross deadlock mLock.unlock(); mAudioFlinger->mLock.lock(); audioConfigChanged_l(configEvent->mEvent, configEvent->mParam); // +++++++++++++++++++++++++++++++++++AudioFlinger::audioConfigChanged_l+++++++++++++++++++++++++++++ // audioConfigChanged_l() must be called with AudioFlinger::mLock held void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) { size_t size = mNotificationClients.size(); for (size_t i = 0; i < size; i++) { // 函数AudioFlinger::registerClient会往mNotificationClients中add 对象 mNotificationClients.valueAt(i)->client()->ioConfigChanged(event, ioHandle, param2); // ++++++++++++++++++++++++++++++++++AudioFlinger::registerClient++++++++++++++++++++++++++++++ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) { Mutex::Autolock _l(mLock); int pid = IPCThreadState::self()->getCallingPid(); if (mNotificationClients.indexOfKey(pid) < 0) { sp<NotificationClient> notificationClient = new NotificationClient(this, client, pid); LOGV("registerClient() client %p, pid %d", notificationClient.get(), pid); mNotificationClients.add(pid, notificationClient); sp<IBinder> binder = client->asBinder(); binder->linkToDeath(notificationClient); // the config change is always sent from playback or record threads to avoid deadlock // with AudioSystem::gLock for (size_t i = 0; i < mPlaybackThreads.size(); i++) { mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED); } for (size_t i = 0; i < mRecordThreads.size(); i++) { mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED); } } } // 函数AudioSystem::get_audio_flinger中调用了函数AudioFlinger::registerClient。 // +++++++++++++++++++++++++++++++AudioSystem::get_audio_flinger+++++++++++++++++++++++++++++++++ // establish binder interface to AudioFlinger service const sp<IAudioFlinger>& AudioSystem::get_audio_flinger() { Mutex::Autolock _l(gLock); if (gAudioFlinger.get() == 0) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { binder = sm->getService(String16("media.audio_flinger")); if (binder != 0) break; LOGW("AudioFlinger not published, waiting..."); usleep(500000); // 0.5 s } while(true); if (gAudioFlingerClient == NULL) { // 上面调用的函数ioConfigChanged其实是函数AudioSystem::AudioFlingerClient::ioConfigChanged gAudioFlingerClient = new AudioFlingerClient(); // ++++++++++++++++++++++++++++++AudioSystem::AudioFlingerClient::ioConfigChanged++++++++++++++++++++++++++++++++++ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) { LOGV("ioConfigChanged() event %d", event); OutputDescriptor *desc; uint32_t stream; if (ioHandle == 0) return; Mutex::Autolock _l(AudioSystem::gLock); switch (event) { case STREAM_CONFIG_CHANGED: if (param2 == 0) break; stream = *(uint32_t *)param2; LOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle); if (gStreamOutputMap.indexOfKey(stream) >= 0) { gStreamOutputMap.replaceValueFor(stream, ioHandle); } break; case OUTPUT_OPENED: { if (gOutputs.indexOfKey(ioHandle) >= 0) { LOGV("ioConfigChanged() opening already existing output! %d", ioHandle); break; } if (param2 == 0) break; desc = (OutputDescriptor *)param2; OutputDescriptor *outputDesc = new OutputDescriptor(*desc); gOutputs.add(ioHandle, outputDesc); LOGV("ioConfigChanged() new output samplingRate %d, format %d channels %d frameCount %d latency %d", outputDesc->samplingRate, outputDesc->format, outputDesc->channels, outputDesc->frameCount, outputDesc->latency); } break; case OUTPUT_CLOSED: { if (gOutputs.indexOfKey(ioHandle) < 0) { LOGW("ioConfigChanged() closing unknow output! %d", ioHandle); break; } LOGV("ioConfigChanged() output %d closed", ioHandle); gOutputs.removeItem(ioHandle); for (int i = gStreamOutputMap.size() - 1; i >= 0 ; i--) { if (gStreamOutputMap.valueAt(i) == ioHandle) { gStreamOutputMap.removeItemsAt(i); } } } break; // 我们上面添加的是这个event case OUTPUT_CONFIG_CHANGED: { int index = gOutputs.indexOfKey(ioHandle); if (index < 0) { LOGW("ioConfigChanged() modifying unknow output! %d", ioHandle); break; } if (param2 == 0) break; desc = (OutputDescriptor *)param2; LOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %d frameCount %d latency %d", ioHandle, desc->samplingRate, desc->format, desc->channels, desc->frameCount, desc->latency); OutputDescriptor *outputDesc = gOutputs.valueAt(index); delete outputDesc; outputDesc = new OutputDescriptor(*desc); gOutputs.replaceValueFor(ioHandle, outputDesc); } break; case INPUT_OPENED: case INPUT_CLOSED: case INPUT_CONFIG_CHANGED: break; } } // -------------------------------AudioSystem::AudioFlingerClient::ioConfigChanged--------------------------------- } else { if (gAudioErrorCallback) { gAudioErrorCallback(NO_ERROR); } } binder->linkToDeath(gAudioFlingerClient); gAudioFlinger = interface_cast<IAudioFlinger>(binder); gAudioFlinger->registerClient(gAudioFlingerClient); } LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?"); return gAudioFlinger; } // // -------------------------------AudioSystem::get_audio_flinger--------------------------------- // ----------------------------------AudioFlinger::registerClient------------------------------ } } // -----------------------------------AudioFlinger::audioConfigChanged_l----------------------------- mAudioFlinger->mLock.unlock(); delete configEvent; mLock.lock(); } mLock.unlock(); } // ----------------------------------AudioFlinger::ThreadBase::processConfigEvents------------------------------ LOGV("sendConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param); mWaitWorkCV.signal(); } // ----------------------------------AudioFlinger::ThreadBase::sendConfigEvent_l------------------------------ } } mNewParameters.removeAt(0); mParamStatus = status; mParamCond.signal(); mWaitWorkCV.wait(mLock); } return reconfig; } // -------------------------------AudioFlinger::MixerThread::checkForNewParameters_l--------------------------------- mWaitWorkCV.signal(); // wait condition with timeout in case the thread loop has exited // before the request could be processed if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) { status = mParamStatus; mWaitWorkCV.signal(); } else { status = TIMED_OUT; } return status; } // -------------------------------AudioFlinger::ThreadBase::setParameters--------------------------------- #ifdef LVMX if ((NO_ERROR == result) && (device != -1)) { LifeVibes::setDevice(LifeVibes::threadIdToAudioOutputType(thread->id()), device); } #endif return result; } return BAD_VALUE; } // --------------------------------AudioFlinger::setParameters-------------------------------- } // --------------------------------AudioSystem::setParameters-------------------------------- if (command->mWaitStatus) { command->mCond.signal(); mWaitWorkCV.wait(mLock); } delete data; }break; // --------------------------------case SET_PARAMETERS-------------------------------- LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs); mWaitWorkCV.signal(); if (command->mWaitStatus) { command->mCond.wait(mLock); status = command->mStatus; mWaitWorkCV.signal(); } return status; } // -----------------------------AudioPolicyService::AudioCommandThread::parametersCommand----------------------------------- } // -----------------------------AudioPolicyService::setParameters----------------------------------- // update stream volumes according to new device applyStreamVolumes(output, device, delayMs); // +++++++++++++++++++++++++++++AudioPolicyManagerBase::applyStreamVolumes+++++++++++++++++++++++++++++++++++ void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, uint32_t device, int delayMs) { LOGV("applyStreamVolumes() for output %d and device %x", output, device); for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, device, delayMs); } } // -----------------------------AudioPolicyManagerBase::applyStreamVolumes----------------------------------- // if changing from a combined headset + speaker route, unmute media streams if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) { setStrategyMute(STRATEGY_MEDIA, false, output, delayMs); } } // ----------------------------AudioPolicyManagerBase::setOutputDevice------------------------------------ // handle special case for sonification while in call if (isInCall()) { handleIncallSonification(stream, true, false); } // apply volume rules for current stream and device if necessary checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, outputDesc->device()); return NO_ERROR; } // ---------------------------AudioPolicyManagerBase::startOutput------------------------------------- } // -----------------------AudioPolicyService::startOutput----------------------------------------- } // -----------------------AudioSystem::startOutput----------------------------------------- thread->mLock.lock(); } if (status == NO_ERROR) { PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); playbackThread->addTrack_l(this); } else { mState = state; } } else { status = BAD_VALUE; } return status; } // ----------------------------AudioFlinger::PlaybackThread::Track::start------------------------------------ } // ---------------------------AudioFlinger::TrackHandle::start------------------------------------- } // 如果状态为DEAD_OBJECT,则创建一个AudioTrack对象,并调用其start函数 if (status == DEAD_OBJECT) { LOGV("start() dead IAudioTrack: creating a new one"); status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount, mFrameCount, mFlags, mSharedBuffer, getOutput(), false); if (status == NO_ERROR) { status = mAudioTrack->start(); if (status == NO_ERROR) { mNewPosition = mCblk->server + mUpdatePeriod; } } } if (status != NO_ERROR) { LOGV("start() failed"); android_atomic_and(~1, &mActive); if (t != 0) { t->requestExit(); } else { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); } } } if (t != 0) { t->mLock.unlock(); } } // ------------------------------AudioTrack::start---------------------------------- } // ------------------------------android_media_AudioTrack_start---------------------------------- mPlayState = PLAYSTATE_PLAYING; } } // ------------------------------play---------------------------------- Thread.sleep(100); log(TEST_NAME, "position ="+ track.getPlaybackHeadPosition()); assertTrue(TEST_NAME, track.getPlaybackHeadPosition() > 0); //-------- tear down -------------- track.release(); }
###########################################################

转载于:https://www.cnblogs.com/andriod-html5/archive/2011/10/18/2539553.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值