Stagefright中关于audio的部分由AudioPlayer处理,输出使用AudioSink 或AudioTrack。
- status_t AwesomePlayer::play_l() {
- ...
- if (mAudioSource != NULL) {
- if (mAudioPlayer == NULL) {
- if (mAudioSink != NULL) {
- mAudioPlayer = new AudioPlayer(mAudioSink, this);
- mAudioPlayer->setSource(mAudioSource);
- ...
- }
- ...
- }
AwesomePlayer在initAudioDecoder方法中建立audio decoder
status_t AwesomePlayer::initAudioDecoder() {
...
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
mAudioSource = mAudioTrack;
} else {
mAudioSource = OMXCodec::Create(
mClient.interface(), mAudioTrack->getFormat(),
false, // createEncoder
mAudioTrack);
}
...
}
当调用play_l方法的时候建立AudioPlayer,并把Audio Decoder[mAudioSource]传递给它 AudioPlayer在调用start方法的时候会开启audioSink,并传递回调函数AudioSinkCallback
- status_t AudioPlayer::start(bool sourceAlreadyStarted) {
- ...
- if (mAudioSink.get() != NULL) {
- status_t err = mAudioSink->open(
- mSampleRate, numChannels, AudioSystem::PCM_16_BIT,
- DEFAULT_AUDIOSINK_BUFFERCOUNT,
- &AudioPlayer::AudioSinkCallback, this);
- ...
- mAudioSink->start();
- ...
- }
之后AudioSink会在需要Sample数据的时候回调AudioSinkCallback,要求将size大小Sample数据填充到buffer。这里调用fillBuffer函数从audio decoder读取解码后的Sample数据。
- size_t AudioPlayer::AudioSinkCallback(
- MediaPlayerBase::AudioSink *audioSink,
- void *buffer, size_t size, void *cookie) {
- AudioPlayer *me = (AudioPlayer *)cookie;
-
- LOGI("[%s:%d]_____ enter AudioPlayer::AudioSinkCallback size = %d"
- , __FUNCTION__, __LINE__, size);
-
- return me->fillBuffer(buffer, size);
- }
-
- void AudioPlayer::AudioCallback(int event, void *info) {
- if (event != AudioTrack::EVENT_MORE_DATA) {
- return;
- }
- AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
- size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
- buffer->size = numBytesWritten;
- }
-
- size_t AudioPlayer::fillBuffer(void *data, size_t size) {
- ...
- size_t size_done = 0;
- size_t size_remaining = size;
- while (size_remaining > 0) {
- ...
- err = mSource->read(&mInputBuffer, &options);
- ...
- memcpy((char *)data + size_done,
- (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
- copy);
- mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
- mInputBuffer->range_length() - copy);
- size_done += copy;
- size_remaining -= copy;
- ...
- }
- ...
- }
这里的mSource实际上是decoder,其read方法会调用mAudioTrack的read方法获取DataSource的未解码数据,然后解码,返回解码后的数据。 总流程如下
- AudioSink
- |
- +- AudioPlayer#AudioSinkCallback
- |
- +- AudioDecoder#read
- |
- +- Extractor::MediaSource#read
参考
使用AudioTrack播放PCM音频数
MediaPlayer只能对完整的音频文件进行操作,而不能直接对纯PCM音频数据操作。假如我们通过解码得到PCM数据源,又当如何将它们播放?没错,就是用 AudioTrack这个类(MediaPlayer内部也是调用该类进行真正的播放音频流操作)下面这个DEMO演示了如何使用AudioTrack
Android的 MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用 MediaPlayer实现的。MediaPlayer在底层是基于OpenCore(PacketVideo)的库实现的,为了构建一个 MediaPlayer程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。 但是该类只能对完整的音频文件进行操作,而不能直接对纯PCM音频数据操作。假如我们通过解码得到PCM数据源,又当如何将它们播放?没错,就是用 AudioTrack这个类(MediaPlayer内部也是调用该类进行真正的播放音频流操作)下面这个DEMO演示了如何使用AudioTrack 不啰嗦,上图先 
以下这个类对AudioTrack做了简单封装:
- public class MyAudioTrack {
- int mFrequency;
- int mChannel;
- int mSampBit;
- AudioTrack mAudioTrack;
- public MyAudioTrack(int frequency, int channel, int sampbit){
- mFrequency = frequency;
- mChannel = channel;
- mSampBit = sampbit;
- }
- public void init(){
- if (mAudioTrack != null){
- release();
- }
-
-
- int minBufSize = AudioTrack.getMinBufferSize(mFrequency,
- mChannel, mSampBit);
-
-
-
-
-
-
- mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
- mFrequency,mChannel,mSampBit,minBufSize, AudioTrack.MODE_STREAM);
-
-
- mAudioTrack.play();
- }
- public void release(){
- if (mAudioTrack != null){
- mAudioTrack.stop();
- mAudioTrack.release();
- }
- }
-
- public void playAudioTrack(byte []data, int offset, int length){
- if (data == null || data.length == 0){return ;}
- try {
- mAudioTrack.write(data, offset, length);
- } catch (Exception e) {
- Log.i("MyAudioTrack", "catch exception...");
- }
- }
-
- public int getPrimePlaySize(){
- int minBufSize = AudioTrack.getMinBufferSize(mFrequency,
- mChannel, mSampBit);
- return minBufSize * 2;
- }
- }
mAudioTrack.write(data, offset, length);该函数正是将数据写入硬件播放的关键! |
|