Audio播放流程(三)---NuPlayer流程之setAudioStreamType以及prepare

1.setAudioStreamType的过程

frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp

status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type)
{
    ALOGE("[%d] setAudioStreamType(%d)", mConnId, type);
    // TODO: for hardware output, call player instead
    Mutex::Autolock l(mLock);
    if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
    return NO_ERROR;
}

这里的mAudioOutput是在Audio播放流程(二)—MediaPlayerService流程之setDataSource中创建的。

setDataSource_pre
	mAudioOutput = new AudioOutput(...)
	将AudioOutput设置为NuPlayer的Sink端
	static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);

继续

void MediaPlayerService::AudioOutput::setAudioStreamType(audio_stream_type_t streamType)
{
    Mutex::Autolock lock(mLock);
    // do not allow direct stream type modification if attributes have been set
    if (mAttributes == NULL) {
        mStreamType = streamType;
        // No attributes are set, for mediaPlayer playback, force populate attributes
        // This is done to ensure that we qualify for a direct output
        mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
        if (mAttributes != NULL) {
            stream_type_to_audio_attributes(mStreamType, mAttributes);
        }
    }
}
...
static void stream_type_to_audio_attributes(audio_stream_type_t streamType,
                                     audio_attributes_t *attr) {
    memset(attr, 0, sizeof(audio_attributes_t));

    switch (streamType) {
    case AUDIO_STREAM_DEFAULT:
    case AUDIO_STREAM_MUSIC:
        attr->content_type = AUDIO_CONTENT_TYPE_MUSIC;
        attr->usage = AUDIO_USAGE_MEDIA;
        break;
    case AUDIO_STREAM_VOICE_CALL:
        attr->content_type = AUDIO_CONTENT_TYPE_SPEECH;
        attr->usage = AUDIO_USAGE_VOICE_COMMUNICATION;
        break;
    case AUDIO_STREAM_ENFORCED_AUDIBLE:
        attr->flags  |= AUDIO_FLAG_AUDIBILITY_ENFORCED;
        // intended fall through, attributes in common with STREAM_SYSTEM
    case AUDIO_STREAM_SYSTEM:
        attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
        attr->usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION;
        break;
    case AUDIO_STREAM_RING:
        attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
        attr->usage = AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
        break;
    case AUDIO_STREAM_ALARM:
        attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
        attr->usage = AUDIO_USAGE_ALARM;
        break;
    case AUDIO_STREAM_NOTIFICATION:
        attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
        attr->usage = AUDIO_USAGE_NOTIFICATION;
        break;
    case AUDIO_STREAM_BLUETOOTH_SCO:
        attr->content_type = AUDIO_CONTENT_TYPE_SPEECH;
        attr->usage = AUDIO_USAGE_VOICE_COMMUNICATION;
        attr->flags |= AUDIO_FLAG_SCO;
        break;
    case AUDIO_STREAM_DTMF:
        attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
        attr->usage = AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
        break;
    case AUDIO_STREAM_TTS:
        attr->content_type = AUDIO_CONTENT_TYPE_SPEECH;
        attr->usage = AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
        break;
    default:
        ALOGE("invalid stream type %d when converting to attributes", streamType);
    }
}                          

这个API还是很简单的,就是设置音频的属性,例如:

case AUDIO_STREAM_MUSIC:
	attr->content_type = AUDIO_CONTENT_TYPE_MUSIC;
	attr->usage = AUDIO_USAGE_MEDIA;

2.prepareAsync的调用流程

frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp

status_t MediaPlayerService::Client::prepareAsync()
{
    ALOGE("[%d] prepareAsync", mConnId);
    sp<MediaPlayerBase> p = getPlayer();
    if (p == 0) return UNKNOWN_ERROR;
    status_t ret = p->prepareAsync();
#if CALLBACK_ANTAGONIZER
    ALOGD("start Antagonizer");
    if (ret == NO_ERROR) mAntagonizer->start();
#endif
    return ret;
}

frameworks\av\media\libmediaplayerservice\nuplayer\NuPlayerDriver.cpp

status_t NuPlayerDriver::prepareAsync() {
    ALOGV("prepareAsync(%p)", this);
    Mutex::Autolock autoLock(mLock);

    switch (mState) {
        case STATE_UNPREPARED:
            mState = STATE_PREPARING;
            mIsAsyncPrepare = true;
            mPlayer->prepareAsync();
            return OK;
        case STATE_STOPPED:
            // this is really just paused. handle as seek to start
            mAtEOS = false;
            mState = STATE_STOPPED_AND_PREPARING;
            mIsAsyncPrepare = true;
            mPlayer->seekToAsync(0, true /* needNotify */);
            return OK;
        default:
            return INVALID_OPERATION;
    };
}

frameworks\av\media\libmediaplayerservice\nuplayer\NuPlayer.cpp

void NuPlayer::prepareAsync() {
    (new AMessage(kWhatPrepare, this))->post();
}

这里使用了Native的Handle机制,这个机制原理上和JAVA端的是一致的。
先看处理这个handle的线程是在什么地方创建的,如下

frameworks\av\media\libmediaplayerservice\nuplayer\NuPlayerDriver.cpp

NuPlayerDriver::NuPlayerDriver(pid_t pid)
    : mState(STATE_IDLE),
      mIsAsyncPrepare(false),
      mAsyncResult(UNKNOWN_ERROR),
      mSetSurfaceInProgress(false),
      mDurationUs(-1),
      mPositionUs(-1),
      mSeekInProgress(false),
      mLooper(new ALooper),
      mPlayerFlags(0),
      mAtEOS(false),
      mLooping(false),
      mAutoLoop(false) {
    ALOGV("NuPlayerDriver(%p)", this);
    mLooper->setName("NuPlayerDriver Looper");
	//开启线程
    mLooper->start(
            false, /* runOnCallingThread */
            true,  /* canCallJava */
            PRIORITY_AUDIO);

    mPlayer = AVNuFactory::get()->createNuPlayer(pid);
    mLooper->registerHandler(mPlayer);

    mPlayer->setDriver(this);
}

如上,Looper会创建一个名为"NuPlayerDriver Looper"的线程,随后调用mLooper->start开启这个线程,之后循环等待是否有事件需要处理;

mLooper->registerHandler(mPlayer);

上面是为Looper设置handle(mPlayer继承自AHandler),之后AMessage将消息发送到Looper线程,随后线程回调AHandler的onMessageReceived方法去处理。这里需要注意的是onMessageReceived有可能会被AHandler的派生类重载。

AHandler的理论讲完了,回到NuPlayer::prepareAsync(),这里面通过AMessage将消息kWhatPrepare发送到了NuPlayer的onMessageReceived方法:

void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
...
        case kWhatPrepare:
        {
            mSource->prepareAsync();
            break;
        }
 ...
}

这里的mSource在上一步kWhatSetDataSource消息的处理中已经完成赋值了
这里的mSource指向的是GenericSource对象,因此prepareAsync会走向

frameworks\av\media\libmediaplayerservice\nuplayer\GenericSource.cpp

void NuPlayer::GenericSource::prepareAsync() {
    if (mLooper == NULL) {
        mLooper = new ALooper;
        mLooper->setName("generic");
        mLooper->start();

        mLooper->registerHandler(this);
    }

    sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
    msg->post();
}

如上GenericSource内部又开启了一个线程(“generic”),这个线程处理来自GenericSource的消息,因此,这条消息会继续发往GenericSource的onMessageReceived

void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
      case kWhatPrepareAsync:
      {
          onPrepareAsync();
          break;
      }
   ...
}
...
void NuPlayer::GenericSource::onPrepareAsync() {
	...
	创建DataSource
	mDataSource = new FileSource(mFd, mOffset, mLength);
	...
	//进行多媒体文件的格式探测和解析
	status_t err = initFromDataSource();
	// 上报流状态
	notifyFlagsChanged(
            (mIsSecure ? FLAG_SECURE : 0)
            | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
            | FLAG_CAN_PAUSE
            | FLAG_CAN_SEEK_BACKWARD
            | FLAG_CAN_SEEK_FORWARD
            | FLAG_CAN_SEEK);
	...
	//上报调用完成
	finishPrepareAsync();
	...
}  

我们重点关注initFromDataSource中的多媒体文件探测和解析

status_t NuPlayer::GenericSource::initFromDataSource() {
	...
	//创建多媒体探测器,这里会通过binder调度到MediaExtractor获取对应的解析器,例如MP3会使用MP3Extractor
	extractor = MediaExtractor::Create(mDataSource,
                mimeType.isEmpty() ? NULL : mimeType.string(),
                mIsStreaming ? 0 : AVNuUtils::get()->getFlags());
    //获取多媒体文件的元数据           
	mFileMeta = extractor->getMetaData();   
	//获取多媒体文件总共有多少个track
	size_t numtracks = extractor->countTracks();       
	for (size_t i = 0; i < numtracks; ++i) {
		//获取每一个track
		sp<IMediaSource> track = extractor->getTrack(i);
		//获取当前track的meta数据
		sp<MetaData> meta = extractor->getTrackMetaData(i);
		const char *mime;
		//从当前track的meta信息中得到,多媒体是audio还是video
		CHECK(meta->findCString(kKeyMIMEType, &mime));
		if (!strncasecmp(mime, "audio/", 6)) {
            if (mAudioTrack.mSource == NULL) {
                mAudioTrack.mIndex = i;
                mAudioTrack.mSource = track;
                mAudioTrack.mPackets =
                    new AnotherPacketSource(mAudioTrack.mSource->getFormat());

                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
                    mAudioIsVorbis = true;
                } else {
                    mAudioIsVorbis = false;
                }

                if (AVNuUtils::get()->isByteStreamModeEnabled(meta)) {
                    mIsByteMode = true;
                }
            }
        } else if (!strncasecmp(mime, "video/", 6)) {
        	....
        }
	}
	//获取时长
	if (meta->findInt64(kKeyDuration, &durationUs)) {
            if (durationUs > mDurationUs) {
                mDurationUs = durationUs;
            }
        }	
	...

一般对于音频的文件而言,track只有一个,如下:

size_t MP3Extractor::countTracks() {
    return mInitCheck != OK ? 0 : 1;
}

参考文章:
NuPlayer播放框架之GenericSource源码分析

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值