Android N Audio播放四:start真面目

来源:互联网 发布:9860计算器怎么编程 编辑:程序博客网 时间:2024/06/07 06:06

  start是MusicDemo中播放音乐的最后一步,也是最重要的一步。这里我们就得把三步都打开了,后面为了看清楚,可以把前面两步的日志先过滤出去。
  

    private void play(){        try {            String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/Music/Test.mp3";            player.setDataSource(path);            Log.d("Jaychou","MusicDemo setDataSource");            player.prepare();            Log.d("Jaychou","MusicDemo Prepare");            player.start();            Log.d("Jaychou","MusicDemo start");        } catch (IOException e) {            e.printStackTrace();            Log.d("Jaychou","err when play");        }    }

1. start流程图
  和之前一样,还是先来看一看start的流程图,其实和setDataSource和prepare几乎是一样的。
  这里写图片描述

2. client端
如之前一样,MusicDemo, MediaPlayer.java和MediaPlayer.cpp都是属于Client端,它们是跑在同一个进程里面。
这里也简单用下图示例一下。

这里写图片描述

  从MusicDemo一直到MediaPlayer.cpp的start
  ./frameworks/av/media/libmedia/Mediaplayer.cpp#start
  

status_t MediaPlayer::start(){    ALOGV("start");    status_t ret = NO_ERROR;    Mutex::Autolock _l(mLock);    mLockThreadId = getThreadId();    if (mCurrentState & MEDIA_PLAYER_STARTED) {        ret = NO_ERROR;    } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {        mPlayer->setLooping(mLoop);        mPlayer->setVolume(mLeftVolume, mRightVolume);        mPlayer->setAuxEffectSendLevel(mSendLevel);        mCurrentState = MEDIA_PLAYER_STARTED;        ret = mPlayer->start();        if (ret != NO_ERROR) {            mCurrentState = MEDIA_PLAYER_STATE_ERROR;        } else {            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {                ALOGV("playback completed immediately following start()");            }        }    } else {        ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());        ret = INVALID_OPERATION;    }    mLockThreadId = 0;    return ret;}

可以看到,这里也没有做多少事情,就是调用server端来设置是否循环,音量等参数,当然,最重要的是调用server端的start。

以下是一些相关的日志可供参考。

02-17 17:51:59.379 V/MediaPlayer-JNI( 5974): start02-17 17:51:59.379 V/MediaPlayer( 5974): start02-17 17:51:59.380 V/MediaPlayerService(  642): [4] setLooping(0)02-17 17:51:59.380 V/MediaPlayerService(  642): [4] setVolume(1.000000, 1.000000)02-17 17:51:59.381 V/AudioSink(  642): setVolume(1.000000, 1.000000)02-17 17:51:59.382 V/MediaPlayerService(  642): [4] setAuxEffectSendLevel(0.000000)02-17 17:51:59.383 V/AudioSink(  642): setAuxEffectSendLevel(0.000000)

3. server端
  MediaPlayerService之后的类是跑在server端,它们在另一个进程中。
  

这里写图片描述

3.1 MediaPlayerService
./frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp#start

status_t MediaPlayerService::Client::start(){    ALOGV("[%d] start", mConnId);    sp<MediaPlayerBase> p = getPlayer();    if (p == 0) return UNKNOWN_ERROR;    p->setLooping(mLoop);    return p->start();}

这里非常简单,就是调用下一步NuPlayerDriver的start方法。

02-17 17:51:59.384 V/MediaPlayerService(  642): [4] start

3.2 NuPlayerDriver
./frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp#start

status_t NuPlayerDriver::start() {    ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);    Mutex::Autolock autoLock(mLock);    return start_l();}

./frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp#start_l

status_t NuPlayerDriver::start_l() {    switch (mState) {        case STATE_UNPREPARED:        {            status_t err = prepare_l();            if (err != OK) {                return err;            }            CHECK_EQ(mState, STATE_PREPARED);            // fall through        }        case STATE_PAUSED:        case STATE_STOPPED_AND_PREPARED:        case STATE_PREPARED:        {            mPlayer->start();            // fall through        }        case STATE_RUNNING:        {            if (mAtEOS) {                mPlayer->seekToAsync(0);                mAtEOS = false;                mPositionUs = -1;            }            break;        }        default:            return INVALID_OPERATION;    }    mState = STATE_RUNNING;    return OK;}

这里mState是STATE_PREPARED,这是在prepare的时候把状态置成STATE_PREPARED的。看来也没干啥,就是调用Nuplayer的start方法。

02-17 17:51:59.385 D/NuPlayerDriver(  642): start(0xee80c600), state is 4, eos is 0

3.3 NuPlayer
./frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp#start

void NuPlayer::start() {    (new AMessage(kWhatStart, this))->post();}

通过AMessage post出去。最终调用onStart

02-17 17:51:59.385 E/NuPlayer(  642): Nuplayer  onMessageReceived msg is AMessage(what = 'strt', target = 7) = {02-17 17:51:59.385 E/NuPlayer(  642): }02-17 17:51:59.385 V/NuPlayer(  642): kWhatStart

./frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp#onStart
这段代码较多,只列出关键。

void NuPlayer::onStart(int64_t startPositionUs) {    //1.调用GenericSource的start    if (!mSourceStarted) {        mSourceStarted = true;        mSource->start();    }    ......    //2.创建renderer    mRenderer = AVNuFactory::get()->createRenderer(mAudioSink, notify, flags);    mRendererLooper = new ALooper;    mRendererLooper->setName("NuPlayerRenderer");    mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);    mRendererLooper->registerHandler(mRenderer);    status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);    if (err != OK) {        mSource->stop();        mSourceStarted = false;        notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);        return;    }    ......    //3.调用postScanSources, 这里面会创建解码器。    ALOGE("onStart  postScanSources");    postScanSources();}

3.3.1 调用GenericSource的start

./frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp#startvoid NuPlayer::GenericSource::start() {    ALOGI("start");    mStopRead = false;    if (mAudioTrack.mSource != NULL) {        ALOGI("start  mAudioTrack.mSource not null");        postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);    }    if (mVideoTrack.mSource != NULL) {        ALOGI("start  mVideoTrack.mSource not null");        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);    }    setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);    mStarted = true;    (new AMessage(kWhatStart, this))->post();}

这里有一步比较重要的是postReadBuffer(MEDIA_TRACK_TYPE_AUDIO),这里会去读取audio 的buffer, 具体的操作我们在后面会有单独的文章来介绍,这里暂时不详说。

接着发送kWhatStart消息,最后到

void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() {    Mutex::Autolock _l(mLock);    if (mIsStreaming) {        cancelPollBuffering_l();        onPollBuffering_l();    }}

这个主要是流媒体相关的,这里就先不介绍了。

02-17 17:51:59.385 I/GenericSource(  642): start02-17 17:51:59.386 I/GenericSource(  642): start  mAudioTrack.mSource not null02-17 17:51:59.386 E/GenericSource(  642): GenericSource  onMessageReceived msg is AMessage(what = 0x0000000c, target = 8) = {02-17 17:51:59.386 E/GenericSource(  642):   int32_t trackType = 202-17 17:51:59.386 E/GenericSource(  642): }

what = 0x0000000c代表的是kWhatReadBuffer消息。

3.3.2 创建renderer
这里的渲染, 我们放在以后的文章中来介绍。

3.3.3 调用postScanSources, 这里面会创建解码器

./frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp#postScanSources

void NuPlayer::postScanSources() {    if (mScanSourcesPending) {        return;    }    sp<AMessage> msg = new AMessage(kWhatScanSources, this);    msg->setInt32("generation", mScanSourcesGeneration);    msg->post();    mScanSourcesPending = true;}

./frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp#onMessageReceived

void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {    ALOGE("Nuplayer  onMessageReceived msg is %s", msg->debugString().c_str());    switch (msg->what()) {    ......    case kWhatScanSources:        {            int32_t generation;            CHECK(msg->findInt32("generation", &generation));            if (generation != mScanSourcesGeneration) {                // Drop obsolete msg.                break;            }            mScanSourcesPending = false;            ALOGV("scanning sources haveAudio=%d, haveVideo=%d",                 mAudioDecoder != NULL, mVideoDecoder != NULL);            bool mHadAnySourcesBefore =                (mAudioDecoder != NULL) || (mVideoDecoder != NULL);            bool rescan = false;            // initialize video before audio because successful initialization of            // video may change deep buffer mode of audio.            if (mSurface != NULL) {                if (instantiateDecoder(false, &mVideoDecoder) == -EWOULDBLOCK) {                    rescan = true;                }            }            // Don't try to re-open audio sink if there's an existing decoder.            if (mAudioSink != NULL && mAudioDecoder == NULL) {                if (instantiateDecoder(true, &mAudioDecoder) == -EWOULDBLOCK) {                    rescan = true;                }            }            if (!mHadAnySourcesBefore                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {                // This is the first time we've found anything playable.                if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {                    schedulePollDuration();                }            }            status_t err;            if ((err = mSource->feedMoreTSData()) != OK) {                if (mAudioDecoder == NULL && mVideoDecoder == NULL) {                    // We're not currently decoding anything (no audio or                    // video tracks found) and we just ran out of input data.                    if (err == ERROR_END_OF_STREAM) {                        notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);                    } else {                        notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);                    }                }                break;            }            if (rescan) {                msg->post(100000ll);                mScanSourcesPending = true;            }            break;        }        ....     }}

这里会通过instantiateDecoder创建音视频的解码器,我们将在之后的文章讨论这个问题。

4. server端到Client端的notify
同prepare一样,当start开始以后,会一层层往上通知当前的状态。

02-17 17:51:59.761 D/NuPlayerDriver(  642): notifyListener_l(0xee80c600), (6, 0, 0), loop setting(0, 0)02-17 17:51:59.761 V/MediaPlayerService(  642): [4] notify (0xf004f540, 6, 0, 0)02-17 17:51:59.763 E/MediaPlayer-JNI( 5974): JNIMediaPlayerListener notify

5. 总结
可以看到,start的流程和prepare几乎都是一样的。

这里写图片描述

但start开始以后,是怎么读取audio数据,是如何解码的等等问题,我们在接下来的文章中会慢慢介绍。

0 0
原创粉丝点击