摘要:在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很有用。
努力工作 创造价值