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很有用。

posted @ 2012-10-09 16:25  cerberspace  阅读(2397)  评论(0编辑  收藏  举报