2012年10月9日星期二

Android4.1MediaPlayer无缝播放

Android4.1MediaPlayer无缝播放

  摘要:在Android4.1中,MediaPlayer实现两个完全独立的MediaPlayer类上执行无缝播放,这里介绍一下Android是如何实现无缝播放的。

  一、使用方法
  在第一个MediaPlayer类执行结束前的任何时间调用setNextMediaPlayer(MediaPlayer next)这个方法,该方法的参数是第二个文件创建的MediaPlayer实例。然后Android系统将会在您第一个停止的时候紧接着播放第二个文件。

  二、实现
  MediaPlayer类中的setNextMediaPlayer方法一路追踪JNI层的Android_Media_MediaPlayer.cpp,再到MediaPlayer.cpp,通过IMediaPlayer.cpp中的BnMediaPlayer到MediaPlayerService中的Client::setNextPlayer函数。

status_t MediaPlayerService::Client::setNextPlayer(const sp<IMediaPlayer>& player) {    ALOGV("setNextPlayer");    Mutex::Autolock l(mLock);    sp<Client> c = static_cast<Client*>(player.get());    mNextClient = c;    if (mAudioOutput != NULL && c != NULL) {        mAudioOutput->setNextOutput(c->mAudioOutput);    } else {        ALOGE("no current audio output");    }    return OK;}

  从MediaPlayerServie中的client获得另外一个track的AndroidOutput

void MediaPlayerService::AudioOutput::setNextOutput(const sp<AudioOutput>& nextOutput) {    mNextOutput = nextOutput;}

  设置好了mNextOutput后,AndroidOutput定义了另外一个重要的函数switchToNextOutput

void MediaPlayerService::AudioOutput::switchToNextOutput() {    ALOGV("switchToNextOutput");    if (mNextOutput != NULL) {        if (mCallbackData != NULL) {            mCallbackData->beginTrackSwitch();        }        delete mNextOutput->mCallbackData;        mNextOutput->mCallbackData = mCallbackData;        mCallbackData = NULL;        mNextOutput->mRecycledTrack = mTrack;        mTrack = NULL;        mNextOutput->mSampleRateHz = mSampleRateHz;        mNextOutput->mMsecsPerFrame = mMsecsPerFrame;        mNextOutput->mBytesWritten = mBytesWritten;        mNextOutput->mFlags = mFlags;    }}

  这个函数的调用是在notify函数中,

void MediaPlayerService::Client::notify(        void* cookie, int msg, int ext1, int ext2, const Parcel *obj){    Client* client = static_cast<Client*>(cookie);    {        Mutex::Autolock l(client->mLock);        if (msg == MEDIA_PLAYBACK_COMPLETE && client->mNextClient != NULL) {            client->mAudioOutput->switchToNextOutput();            client->mNextClient->start();            client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);        }    }    if (MEDIA_INFO == msg &&        MEDIA_INFO_METADATA_UPDATE == ext1) {        const media::Metadata::Type metadata_type = ext2;        if(client->shouldDropMetadata(metadata_type)) {            return;        }        // Update the list of metadata that have changed. getMetadata        // also access mMetadataUpdated and clears it.        client->addNewMetadataUpdate(metadata_type);    }    ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);    client->mClient->notify(msg, ext1, ext2, obj);}

  当前播放的client发出MEDIA_PLAYBACK_COMPLETE消息时,调用switchToNextOutput函数,从而实现了两个独立的MediaPlayer的无缝播放。

  三、总结
  无缝播放是android4.1添加的新的特性,支持音频流在一起播放而不产生停顿。这对需要在不同的音频文件无缝转换的App很有用。


TAG: