status_tAwesomePlayer::play_l(){ modifyFlags(SEEK_PREVIEW, CLEAR); mMediaRenderingStartGeneration = ++mStartGeneration; if (!(mFlags & PREPARED)) { status_t err = prepare_l(); } modifyFlags(PLAYING, SET); modifyFlags(FIRST_FRAME, SET); if (mAudioSource != NULL) { if (mAudioPlayer == NULL) { createAudioPlayer_l(); } CHECK(!(mFlags & AUDIO_RUNNING)); if (mVideoSource == NULL) { // We don't want to post an error notification at this point, // the error returned from MediaPlayer::start() will suffice. status_t err = startAudioPlayer_l( false/* sendErrorNotification */); } } if (mFlags & AT_EOS) { // Legacy behaviour, if a stream finishes playing and then // is started again, we play from the start... seekTo_l(0); } return OK; }
void AwesomePlayer::createAudioPlayer_l() { mAudioPlayer = newAudioPlayer(mAudioSink, flags, this); mAudioPlayer->setSource(mAudioSource); // If there was a seek request before we ever started, // honor the request now. // Make sure to do this before starting the audio player // to avoid a race condition. //如果在开始播放之前有一个seek的请求那么需要在启动audio player之前进行seek seekAudioIfNecessary_l(); }
if (!(mFlags & AUDIOPLAYER_STARTED)) { bool wasSeeking = mAudioPlayer->isSeeking(); // We've already started the MediaSource in order to enable // the prefetcher to read its data. err = mAudioPlayer->start(true/* sourceAlreadyStarted */); return err; } modifyFlags(AUDIOPLAYER_STARTED, SET); if (wasSeeking) { CHECK(!mAudioPlayer->isSeeking()); // We will have finished the seek while starting the audio player. postAudioSeekComplete(); } else { notifyIfMediaStarted_l(); } } return err; }
status_t MediaPlayerService::AudioOutput::open( uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask, audio_format_t format, int bufferCount, AudioCallback cb, void *cookie, audio_output_flags_t flags, constaudio_offload_info_t *offloadInfo, bool doNotReconnect, uint32_t suggestedFrameCount) { sp<AudioTrack> t; CallbackData *newcbd = NULL; //将回调函数保存在 mCallback mCallback = cb; mCallbackCookie = cookie; // We don't attempt to create a new track if we are recycling an // offloaded track. But, if we are recycling a non-offloaded or we // are switching where one is offloaded and one isn't then we create // the new track in advance so that we can read additional stream info if (!(reuse && bothOffloaded)) { ALOGV("creating new AudioTrack"); if (mCallback != NULL) { newcbd = newCallbackData(this); //new 一个AudioTrack t = newAudioTrack( mStreamType, sampleRate, format, channelMask, frameCount, flags, //audiotrack需要数据的时候,就会调用此函数 CallbackWrapper, newcbd, 0, // notification frames mSessionId, AudioTrack::TRANSFER_CALLBACK, offloadInfo, mUid, mPid, mAttributes, doNotReconnect); } else { //……………………………………… } } mCallbackData = newcbd; //将 new出来的AudioTrack保存到mTrack中 mTrack = t; return res; }
nsecs_tAudioTrack::processAudioBuffer() { if (waitStreamEnd) { // FIXME: Instead of blocking in proxy->waitStreamEndDone(), Callback thread // should wait on proxy futex and handle CBLK_STREAM_END_DONE within this function // (and make sure we don't callback for more data while we're stopping). // This helps with position, marker notifications, and track invalidation. structtimespec timeout; timeout.tv_sec = WAIT_STREAM_END_TIMEOUT_SEC; timeout.tv_nsec = 0;
status_t status = proxy->waitStreamEndDone(&timeout); switch (status) { case NO_ERROR: case DEAD_OBJECT: case TIMED_OUT: mCbf(EVENT_STREAM_END, mUserData, NULL); { AutoMutex lock(mLock); // The previously assigned value of waitStreamEnd is no longer valid, // since the mutex has been unlocked and either the callback handler // or another thread could have re-started the AudioTrack during that time. waitStreamEnd = mState == STATE_STOPPING; if (waitStreamEnd) { mState = STATE_STOPPED; mReleased = 0; } } break; } return0; } if (newUnderrun) { mCbf(EVENT_UNDERRUN, mUserData, NULL); } while (loopCountNotifications > 0) { mCbf(EVENT_LOOP_END, mUserData, NULL); --loopCountNotifications; } if (flags & CBLK_BUFFER_END) { mCbf(EVENT_BUFFER_END, mUserData, NULL); } if (markerReached) { mCbf(EVENT_MARKER, mUserData, &markerPosition); } while (newPosCount > 0) { size_t temp = newPosition; mCbf(EVENT_NEW_POS, mUserData, &temp); newPosition += updatePeriod; newPosCount--; } if (mObservedSequence != sequence) { mObservedSequence = sequence; mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL); // for offloaded tracks, just wait for the upper layers to recreate the track if (isOffloadedOrDirect()) { return NS_INACTIVE; } }
void MediaPlayerService::AudioOutput::CallbackWrapper( int event, void *cookie, void *info) { //ALOGV("callbackwrapper"); CallbackData *data = (CallbackData*)cookie; // lock to ensure we aren't caught in the middle of a track switch. data->lock(); AudioOutput *me = data->getOutput(); AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; switch(event) { case AudioTrack::EVENT_MORE_DATA: { size_t actualSize = (*me->mCallback)( me, buffer->raw, buffer->size, me->mCallbackCookie, CB_EVENT_FILL_BUFFER); // Log when no data is returned from the callback. // (1) We may have no data (especially with network streaming sources). // (2) We may have reached the EOS and the audio track is not stopped yet. // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS. // NuPlayerRenderer will return zero when it doesn't have data (it doesn't block to fill). // // This is a benign busy-wait, with the next data request generated 10 ms or more later; // nevertheless for power reasons, we don't want to see too many of these. me->mBytesWritten += actualSize; // benign race with reader. buffer->size = actualSize; } break;
case AudioTrack::EVENT_STREAM_END: // currently only occurs for offloaded callbacks ALOGV("callbackwrapper: deliver EVENT_STREAM_END"); (*me->mCallback)(me, NULL /* buffer */, 0/* size */, me->mCallbackCookie, CB_EVENT_STREAM_END); break;
case AudioTrack::EVENT_NEW_IAUDIOTRACK : ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN"); (*me->mCallback)(me, NULL /* buffer */, 0/* size */, me->mCallbackCookie, CB_EVENT_TEAR_DOWN); break; case AudioTrack::EVENT_UNDERRUN: // This occurs when there is no data available, typically // when there is a failure to supply data to the AudioTrack. It can also // occur in non-offloaded mode when the audio device comes out of standby. // // If an AudioTrack underruns it outputs silence. Since this happens suddenly // it may sound like an audible pop or glitch. // // The underrun event is sent once per track underrun; the condition is reset // when more data is sent to the AudioTrack. break; default: ALOGE("received unknown event type: %d inside CallbackWrapper !", event); } data->unlock(); }