2024年1月2日发(作者:)

sp AudioFlinger::openRecord( audio_io_handle_t input, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t *frameCount, IAudioFlinger::track_flags_t *flags, pid_t tid, int *sessionId, size_t *notificationFrames, sp& cblk, sp& buffers, status_t *status){ sp recordTrack; sp recordHandle; sp client; status_t lStatus; int lSessionId; (); (); ... { Mutex::Autolock _l(mLock); RecordThread *thread = checkRecordThread_l(input); if (thread == NULL) { ALOGE("openRecord() checkRecordThread_l failed"); lStatus = BAD_VALUE; goto Exit; } pid_t pid = IPCThreadState::self()->getCallingPid(); ... // TODO: the uid should be passed in as a parameter to openRecord recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask, frameCount, lSessionId, notificationFrames, IPCThreadState::self()->getCallingUid(), flags, tid, &lStatus); LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));

} ... cblk = recordTrack->getCblk(); buffers = recordTrack->getBuffers(); // return handle to client recordHandle = new RecordHandle(recordTrack);Exit: *status = lStatus; return recordHandle;}重点分析:

if (event == AudioSystem::SYNC_EVENT_NONE) { recordTrack->clearSyncStartEvent(); } else if (event != AudioSystem::SYNC_EVENT_SAME) { recordTrack->mSyncStartEvent = mAudioFlinger->createSyncEvent(event, triggerSession, recordTrack->sessionId(), syncStartEventCallback, recordTrack); // Sync event can be cancelled by the trigger session if the track is not in a // compatible state in which case we start record immediately if (recordTrack->mSyncStartEvent->isCancelled()) { recordTrack->clearSyncStartEvent(); } else { // do not wait for the event for more than AudioSystem::kSyncRecordStartTimeOutMs recordTrack->mFramesToDrop = - ((AudioSystem::kSyncRecordStartTimeOutMs * recordTrack->mSampleRate) / 1000); } } { // This section is a rendezvous between binder thread executing start() and RecordThread AutoMutex lock(mLock); if (f(recordTrack) >= 0) { if (recordTrack->mState == TrackBase::PAUSING) { ALOGV("active record track PAUSING -> ACTIVE"); recordTrack->mState = TrackBase::ACTIVE; } else { ALOGV("active record track state %d", recordTrack->mState); } return status; } // TODO consider other ways of handling this, such as changing the state to :STARTING and // adding the track to mActiveTracks after returning from AudioSystem::startInput(), // or using a separate command thread recordTrack->mState = TrackBase::STARTING_1; (recordTrack); mActiveTracksGen++; status_t status = NO_ERROR; if (recordTrack->isExternalTrack()) { (); status = AudioSystem::startInput(mId, (audio_session_t)recordTrack->sessionId()); (); // FIXME should verify that recordTrack is still in mActiveTracks if (status != NO_ERROR) { (recordTrack); mActiveTracksGen++; recordTrack->clearSyncStartEvent(); ALOGV("RecordThread::start error %d", status); return status; } } // Catch up with current buffer indices if thread is already running. // This is what makes a new client discard all buffered data. If the track's mRsmpInFront // was initialized to some value closer to the thread's mRsmpInFront, then the track could // see previously buffered data before it called start(), but with greater risk of overrun. recordTrack->mRsmpInFront = mRsmpInRear; recordTrack->mRsmpInUnrel = 0; // FIXME why reset? if (recordTrack->mResampler != NULL) { recordTrack->mResampler->reset(); } recordTrack->mState = TrackBase::STARTING_2; // signal thread to start

{ ALOGV("setParameters(): io %d, keyvalue %s, calling pid %d", ioHandle, (), IPCThreadState::self()->getCallingPid()); // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } // AUDIO_IO_HANDLE_NONE means the parameters are global to the audio hardware interface if (ioHandle == AUDIO_IO_HANDLE_NONE) { Mutex::Autolock _l(mLock); status_t final_result = NO_ERROR; { AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_PARAMETER; for (size_t i = 0; i < (); i++) { audio_hw_device_t *dev = t(i)->hwDevice(); status_t result = dev->set_parameters(dev, ()); final_result = result ?: final_result; } mHardwareStatus = AUDIO_HW_IDLE; } // disable AEC and NS if the device is a BT SCO headset supporting those pre processings AudioParameter param = AudioParameter(keyValuePairs); String8 value; if ((String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) { bool btNrecIsOff = (value == AUDIO_PARAMETER_VALUE_OFF); if (mBtNrecIsOff != btNrecIsOff) { for (size_t i = 0; i < (); i++) { sp thread = t(i); audio_devices_t device = thread->inDevice(); bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff; // collect all of the thread's session IDs KeyedVector ids = thread->sessionIds(); // suspend effects associated with those session IDs for (size_t j = 0; j < (); ++j) { int sessionId = (j); thread->setEffectSuspended(FX_IID_AEC, suspend, sessionId); thread->setEffectSuspended(FX_IID_NS, suspend, sessionId); } } mBtNrecIsOff = btNrecIsOff; } } String8 screenState; if ((String8(AudioParameter::keyScreenState), screenState) == NO_ERROR) { bool isOff = screenState == "off"; if (isOff != (AudioFlinger::mScreenState & 1)) { AudioFlinger::mScreenState = ((AudioFlinger::mScreenState & ~1) + 2) | isOff; } } return final_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 thread; { Mutex::Autolock _l(mLock); thread = checkPlaybackThread_l(ioHandle); if (thread == 0) {