首先需要注意的是,AudioPlayer处理的是已经解码后的数据。
1.创建AudioPlayer对象
(1)在 AwesomePlayer::play_l()函数中创建了AudioPlayer对象,并且在AwesomePlayer.cpp文件中,只在此函数中创建过AudioPlayer对象
if (mAudioSource != NULL) {
if (mAudioPlayer == NULL) {
if (mAudioSink != NULL) { // 只有mAudioSink参数不为空时,才会创建AudioPlayer对象,并作为第一个参数
mAudioPlayer = new AudioPlayer(mAudioSink, this);
mAudioPlayer->setSource(mAudioSource);
mTimeSource = mAudioPlayer;
// If there was a seek request before we ever started,
// honor the request now.
// Make sure to do this before starting the audio player
// to avoid a race condition.
seekAudioIfNecessary_l();
}
}
(2)在 AwesomePlayer::play_l()函数中创建了mAudioPlayer后,调用startAudioPlayer_l执行输出数据
status_t err = startAudioPlayer_l(
false /* sendErrorNotification */);
2. AwesomePlayer::startAudioPlayer_l
调用mAudioPlayer的start函数,开始输出数据
// We've already started the MediaSource in order to enable
// the prefetcher to read its data.
status_t err = mAudioPlayer->start(
true /* sourceAlreadyStarted */); // sourceAlreadyStarted参数为true
3.AudioPlayer::start
(1)由于sourceAlreadyStarted参数为true,所以不会再调用mSource->start()函数
(2)读取第一段解码后的数据
mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
(3)由于mAudioSink不为空,所以会执行下面的 mAudioSink->open函数,并注册了AudioSinkCallback函数,而不会执行新建AudioTrack,即不会注册AudioCallback函数
if (mAudioSink.get() != NULL) {
status_t err = mAudioSink->open(
mSampleRate, numChannels, AUDIO_FORMAT_PCM_16_BIT,
DEFAULT_AUDIOSINK_BUFFERCOUNT,
&AudioPlayer::AudioSinkCallback, this); // 注册的是AudioSinkCallback函数
if (err != OK) {
if (mFirstBuffer != NULL) {
mFirstBuffer->release();
mFirstBuffer = NULL;
}
if (!sourceAlreadyStarted) {
mSource->stop();
}
return err;
}
mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
mFrameSize = mAudioSink->frameSize();
mAudioSink->start(); // 实际调用AudioSink的实现类AudioOutput::start(), AudioOutput::start()又调用AudioTrack::start()开始输出数据
} else {
mAudioTrack = new AudioTrack(
AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT,
(numChannels == 2)
? AUDIO_CHANNEL_OUT_STEREO
: AUDIO_CHANNEL_OUT_MONO,
0, 0, &AudioCallback, this, 0); // 没有执行到新建AudioTrack函数,不会注册AudioCallback函数
4.AudioPlayer::AudioSinkCallback
在有数据到来时,循环调用此callback函数
调用fillBuffer函数进行填充数据
5.AudioPlayer::fillBuffer
(1)此函数的返回值size_done,代表已经处理的数据总大小,与传递进来的数据size(第二个参数)不一定相同
(2)获取解码后的数据
if (mInputBuffer == NULL) {
status_t err;
if (mIsFirstBuffer) { // 第一段数据,把mFirstBuffer赋给mInputBuffer
mInputBuffer = mFirstBuffer;
mFirstBuffer = NULL;
err = mFirstBufferResult;
mIsFirstBuffer = false;
} else { // 以后直接从MediaSource的实现类中读数据
err = mSource->read(&mInputBuffer, &options);
}
(3)取得一帧数据在媒体文件中存储的时间戳mPositionTimeMediaUs
CHECK(mInputBuffer->meta_data()->findInt64(
kKeyTime, &mPositionTimeMediaUs));
(4)计算一帧数据实际播放位置的时间戳
mPositionTimeRealUs =
((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
/ mSampleRate;
LOGV("buffer->size() = %d, "
"mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
mInputBuffer->range_length(),
mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
// 这两个时间戳,在AwesomePlayer::onVideoEvent()中,用于计算音视频同步的依据
int64_t realTimeUs, mediaTimeUs;
if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
}
(5)输出解码数据并释放已经使用的mInputBuffer
if (mInputBuffer->range_length() == 0) {
mInputBuffer->release();
mInputBuffer = NULL; // 释放mInputBuffer
continue;
}
size_t copy = size_remaining;
if (copy > mInputBuffer->range_length()) {
copy = mInputBuffer->range_length();
}
/// 把解码后的数据copy给输出buffer
memcpy((char *)data + size_done,
(const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
copy);
/// 每copy完一块数据后,重新设置剩余未copy数据的范围
mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
mInputBuffer->range_length() - copy);
size_done += copy;
size_remaining -= copy;