我们还是从RecordHandle开始,它是IAudioRecord的服务端:
//frameworks/av/services/audioflinger/AudioFlinger.h
// server side of the client's IAudioRecord
class RecordHandle : public android::media::BnAudioRecord {
public:
explicit RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual binder::Status start(int /*AudioSystem::sync_event_t*/ event,
int /*audio_session_t*/ triggerSession);
virtual binder::Status stop();
virtual binder::Status getActiveMicrophones(
std::vector<media::MicrophoneInfoData>* activeMicrophones);
virtual binder::Status setPreferredMicrophoneDirection(
int /*audio_microphone_direction_t*/ direction);
virtual binder::Status setPreferredMicrophoneFieldDimension(float zoom);
virtual binder::Status shareAudioHistory(const std::string& sharedAudioPackageName,
int64_t sharedAudioStartMs);
private:
const sp<RecordThread::RecordTrack> mRecordTrack;
// for use from destructor
void stop_nonvirtual();
};
//frameworks/av/services/audioflinger/Tracks.cpp
binder::Status AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event,
int /*audio_session_t*/ triggerSession) {
ALOGV("%s()", __func__);
return binderStatusFromStatusT(
mRecordTrack->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession)); //调用RecordTrack的start函数
}
在RecordHandle的start函数中会调用mRecordTrack->start,也就是RecordTrack的start函数:
//frameworks/av/services/audioflinger/Threads.h
ActiveTracks<RecordTrack> mActiveTracks;
//frameworks/av/services/audioflinger/Tracks.cpp
status_t AudioFlinger::RecordThread::RecordTrack::start(AudioSystem::sync_event_t event,
audio_session_t triggerSession)
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
RecordThread *recordThread = (RecordThread *)thread.get(); //获取RecordThread
return recordThread->start(this, event, triggerSession); //RecordThread 的start函数
} else {
ALOGW("%s track %d: thread was destroyed", __func__, portId());
return DEAD_OBJECT;
}
}
status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack,
AudioSystem::sync_event_t event,
audio_session_t triggerSession)
{
ALOGV("RecordThread::start event %d, triggerSession %d", event, triggerSession);
sp<ThreadBase> strongMe = this;
status_t status = NO_ERROR;
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 = -(ssize_t)
((AudioSystem::kSyncRecordStartTimeOutMs * recordTrack->mSampleRate) / 1000);
}
}
{
// This section is a rendezvous between binder thread executing start() and RecordThread
AutoMutex lock(mLock);
if (recordTrack->isInvalid()) {
recordTrack->clearSyncStartEvent();
ALOGW("%s track %d: invalidated before startInput", __func__, recordTrack->portId());
return DEAD_OBJECT;
}
if (mActiveTracks.indexOf(recordTrack) >= 0) {
if (recordTrack->mState == TrackBase::PAUSING) {
// We haven't stopped yet (moved to PAUSED and not in mActiveTracks)
// so no need to startInput().
ALOGV("active record track PAUSING -> ACTIVE");
recordTrack->mState = TrackBase::ACTIVE;
} else {
ALOGV("active record track state %d", (int)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;
mActiveTracks.add(recordTrack); //mActiveTracks在RecordTrack中是RecordTrack,将当前recordTrack加入到RecordTrack中
status_t status = NO_ERROR;
if (recordTrack->isExternalTrack()) {
mLock.unlock();
status = AudioSystem::startInput(recordTrack->portId());
mLock.lock();
if (recordTrack->isInvalid()) {
recordTrack->clearSyncStartEvent();
if (status == NO_ERROR && recordTrack->mState == TrackBase::STARTING_1) {
recordTrack->mState = TrackBase::STARTING_2;
// STARTING_2 forces destroy to call stopInput.
}
ALOGW("%s track %d: invalidated after startInput", __func__, recordTrack->portId());
return DEAD_OBJECT;
}
if (recordTrack->mState != TrackBase::STARTING_1) {
ALOGW("%s(%d): unsynchronized mState:%d change",
__func__, recordTrack->id(), (int)recordTrack->mState);
// Someone else has changed state, let them take over,
// leave mState in the new state.
recordTrack->clearSyncStartEvent();
return INVALID_OPERATION;
}
// we're ok, but perhaps startInput has failed
if (status != NO_ERROR) {
ALOGW("%s(%d): startInput failed, status %d",
__func__, recordTrack->id(), status);
// We are in ActiveTracks if STARTING_1 and valid, so remove from ActiveTracks,
// leave in STARTING_1, so destroy() will not call stopInput.
mActiveTracks.remove(recordTrack);
recordTrack->clearSyncStartEvent();
return status;
}
sendIoConfigEvent_l(
AUDIO_CLIENT_STARTED, recordTrack->creatorPid(), recordTrack->portId()); //发送音频客户端已启动消息
}
recordTrack->logBeginInterval(patchSourcesToString(&mPatch)); // log to MediaMetrics
// 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->mResamplerBufferProvider->reset(); //reset 接收缓冲区
if (!recordTrack->isDirect()) {
// clear any converter state as new data will be discontinuous
recordTrack->mRecordBufferConverter->reset(); //reset重采样器
}
recordTrack->mState = TrackBase::STARTING_2;
// signal thread to start
mWaitWorkCV.broadcast(); //唤醒recordThread
return status;
}
}
这里重要的处理有四步,分别是:
-
调用mActiveTracks.add(recordTrack); 将当前recordTrack加入到RecordTrack中。
-
调用recordTrack->mResamplerBufferProvider->reset();函数,reset 接收缓冲区。
-
调用recordTrack->mRecordBufferConverter->reset();函数,reset 重采样器。
-
调用mWaitWorkCV.broadcast()函数,唤醒recordThread.
AudioFlinger RecordThread threadLoop
唤醒recordThread后,recordThread就会开始它自己的工作,thread_loop会动起来,不停的从AudioHAL读取数据,然后通过共享内存传给AudioRecord: