MediaPlayer那边就不看了,从AudioTrack开始研究。
1、AudioTrack::write函数
调用函数obtainBuffer获取到一块buffer,然后把传入的数据copy到获取的buffer中。
2、AudioTrack::obtainBuffer函数
该函数的主要功能就是对传入的audioBuffer进行赋值。
看看audioBuffer的类型:
class Buffer
{
public:
enum {
MUTE = 0x00000001
};
uint32_t flags;
int channelCount;
int format;
size_t frameCount;
size_t size;
union {
void* raw;
short* i16;
int8_t* i8;
};
};
其中存放数据的是下面这个东东:
union {
void* raw;
short* i16;
int8_t* i8;
};
对这块东东赋值的代码如下:
audioBuffer->raw = (int8_t *)cblk->buffer(u);
先看其中cblk的来历:
audio_track_cblk_t* cblk = mCblk;
mCblk的赋值在函数AudioTrack::createTrack中:
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
cblk的由来:
sp<IMemory> cblk = track->getCblk();
track的由来:
sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
streamType,
sampleRate,
format,
channelCount,
frameCount,
((uint16_t)flags) << 16,
sharedBuffer,
output,
&mSessionId,
&status);
函数AudioFlinger::createTrack返回的是一个TrackHandle对象:
trackHandle = new TrackHandle(track);
return trackHandle;
track的由来:
track = thread->createTrack_l(client, streamType, sampleRate, format,
channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);
函数AudioFlinger::PlaybackThread::createTrack_l返回的是一个Track对象:
track = new Track(this, client, streamType, sampleRate, format,
channelCount, frameCount, sharedBuffer, sessionId);
return track;
看看函数TrackHandle::getCblk() :
return mTrack->getCblk();
mTrack就是作为构造函数传入的track对象。
函数AudioFlinger::ThreadBase::TrackBase::getCblk() 的实现:
return mCblkMemory;
mCblkMemory的赋值在构造函数AudioFlinger::ThreadBase::TrackBase::TrackBase中:
mCblkMemory = client->heap()->allocate(size);
mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); // 这个成员变量也很重要
client是构造函数参数:
const sp<Client>& client
函数AudioFlinger::Client::heap:
return mMemoryDealer;
mMemoryDealer的赋值在函数AudioFlinger::Client::Client中:
mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client"))
看看函数MemoryDealer::allocate:
sp<IMemory> MemoryDealer::allocate(size_t size)
{
sp<IMemory> memory;
// allocator()直接返回mAllocator
// mAllocator的赋值在构造函数中:mAllocator(new SimpleBestFitAllocator(size))
/× 函数SimpleBestFitAllocator::allocate的实现:
size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
{
Mutex::Autolock _l(mLock);
// 暂止
ssize_t offset = alloc(size, flags);
return offset;
}
×/
const ssize_t offset = allocator()->allocate(size);
if (offset >= 0) {
// heap()直接返回mHeap
// mHeap的赋值在构造函数中:mHeap(new MemoryHeapBase(size, 0, name))
memory = new Allocation(this, heap(), offset, size);
}
return memory;
}
可见前面的mCblkMemory其实就是一个Allocation对象。
可见AudioTrack的成员变量mCblk和AudioFlinger::ThreadBase::TrackBase的成员变量mCblk的值相同,
都是:static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())。
函数IMemory::pointer的实现:
void* IMemory::pointer() const {
ssize_t offset;
sp<IMemoryHeap> heap = getMemory(&offset);
void* const base = heap!=0 ? heap->base() : MAP_FAILED;
if (base == MAP_FAILED)
return 0;
return static_cast<char*>(base) + offset;
}
回头过去,看看函数audio_track_cblk_t::buffer:
return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;
可见audio_track_cblk_t的主要作用是申请了一块内存空间。
调用函数AudioTrack::write的时候,会先将数据写到这个内存空间中。
3、数据写入到了audio_track_cblk_t中,谁又会来使用这些数据呢?
看代码可知,函数AudioTrack::obtainBuffer中会先调用audio_track_cblk_t::framesAvailable。
同时,我们发现还有一个函数audio_track_cblk_t::framesReady。
单从字面上也可以看出来,这是告诉用户准备好了多少数据。
搜搜哪儿调用了函数audio_track_cblk_t::framesReady吧。
搜了下,发现有三个函数中调用了它,分别是:
AudioFlinger::MixerThread::prepareTracks_l函数
AudioFlinger::DirectOutputThread::threadLoop函数
AudioFlinger::PlaybackThread::Track::getNextBuffer函数
4、先看看函数AudioFlinger::MixerThread::prepareTracks_l函数。
字面上看,应该是准备提供数据的Tracks。
果然不错,函数中调用AudioMixer::setBufferProvider将Track设置到mAudioMixer(AudioMixer)中。
函数AudioMixer::setBufferProvider实现:
status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
{
mState.tracks[ mActiveTrack ].bufferProvider = buffer;
return NO_ERROR;
}
然后调用函数AudioMixer::setParameter将Track的main buffer也设置到mAudioMixer(AudioMixer)中。
函数AudioMixer::setParameter中与main buffer相关的部分代码:
if (name == MAIN_BUFFER) {
if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) {
mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
invalidateState(1<<mActiveTrack);
}
return NO_ERROR;
}
类函数AudioMixer中是如何来使用bufferProvider的呢?
AudioMixer中的以process__为前缀的几个函数都是有到了bufferProvider。
但从数据传输上来说,这几个函数是类似的。
我们只看其中的AudioMixer::process__OneTrack16BitsStereoNoResampling函数。
函数中有代码:
t.bufferProvider->getNextBuffer(&b);
我们知道,bufferProvider其实就是Track,而我们探讨的是音频播放,所以就跳到了函数:AudioFlinger::PlaybackThread::Track::getNextBuffer,
也就是前面我们搜到的,调用audio_track_cblk_t::framesReady的三个函数之一。
函数AudioFlinger::PlaybackThread::Track::getNextBuffer是从audio_track_cblk_t中取得已准备好的音频数据,
写到什么地方去,下面我们开始研究。
回到函数process__OneTrack16BitsStereoNoResampling中,我们知道,调用AudioFlinger::PlaybackThread::Track::getNextBuffer获取的地址赋值给了in:
int16_t const *in = b.i16;
后来取in的数据给了rl:
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
然后将rl赋值给out:
*out++ = (r<<16) | (l & 0xFFFF);
由此可见,我们刚才疑惑的“写到什么地方去”,其实就是写到out里了。
out的来历:
int32_t* out = t.mainBuffer;
这不就是函数AudioMixer::setParameter中赋值的main buffer么???
搞了一圈,原来AudioMixer的功能就是将Track里audio_track_cblk_t中的数据,赋值给Track里的mainBuffer。
下面好好看看这个main buffer的来历吧。
由前面的分析可知,调用函数AudioMixer::setParameter,来设置main buffer的地方是函数AudioFlinger::MixerThread::prepareTracks_l。
回过去看看对函数AudioMixer::setParameter的调用:
mAudioMixer->setParameter(
AudioMixer::TRACK,
AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
函数mainBuffer()实现:
return mMainBuffer;
mMainBuffer的赋值在函数setMainBuffer中:
setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
看看谁调用了函数setMainBuffer吧。
有三个地方调用了函数setMainBuffer:
a、AudioFlinger::PlaybackThread::createTrack_l函数
b、AudioFlinger::PlaybackThread::addEffectChain_l函数
c、AudioFlinger::PlaybackThread::removeEffectChain_l函数
b和c类似,都是将PlaybackThread的mMixBuffer赋值给了main buffer。
先看看a.
track->setMainBuffer(chain->inBuffer());
作为main buffer的是chain->inBuffer()这个东东。
inBuffer()函数实现:return mInBuffer;
mInBuffer中函数setInBuffer中被赋值:
mInBuffer = buffer;
看看调用setInBuffer函数的地方:
AudioFlinger::PlaybackThread::addEffectChain_l函数
AudioFlinger::EffectChain::addEffect_l函数
先看看AudioFlinger::PlaybackThread::addEffectChain_l函数中的处理,
函数中根据是否为DIRECT output thread,有两种处理方式:
一种是处理direct output thread:
调用函数setMainBuffer将PlaybackThread的mMixBuffer告诉给Track,即告诉Track,在AudioMixer中往PlaybackThread的mMixBuffer中copy数据。
然后将effect chain的input buffer和output buffer都设置为PlaybackThread的mMixBuffer。
(目的是让该effect chain不起作用?存在注释“Only one effect chain can be present in direct output thread and it usesthe mix buffer as input”)
另一种是处理非direct output thread:
new一段buffer出来。
调用函数setMainBuffer将新buffer告诉给Track,即告诉Track,在AudioMixer中往新buffer中copy数据。
调用函数setInBuffer来实装chain的input buffer。(发现函数AudioFlinger::PlaybackThread::createTrack_l中其实有将chain的input buffer赋值给Track的main buffer)。
然后将PlaybackThread的mMixBuffer赋值给chain的output buffer。
也就是说,Track将数据copy到自己的main buffer(即effect chain的input buffer),
effect chain对数据进行处理,然后将处理过的数据赋值给自己的output buffer(即PlaybackThread的mMixBuffer)
mMixBuffer是如何被使用的呢?
函数AudioFlinger::MixerThread::threadLoop中调用函数AudioStreamOutALSA::write(HAL侧)。
函数AudioStreamOutALSA::write中调用了函数snd_pcm_mmap_writei或者snd_pcm_writei。
函数snd_pcm_mmap_writei或者snd_pcm_writei将mMixBuffer中的数据写入到底层。
分享到:
相关推荐
Android实时音频采集,通过网络传输到客户端,客户端直接获取数据流后直接进行播放。
android 实时传输摄像头内容到服务器,服务器支持查看
通过组播,socket,将android实时采集的音频数据进行g711编码, 发送,然后接收再进行g711解码,实时播放采集的声音
Audio系统在Android中负责音频方面的数据流传输和控制功能,也负责音频设备的管理。
参考别人的代码,然后自己优化后的Android加Speex编码,然后利用RTP传输数据的实时语音DEMO,亲测在两台手机上可用,一个说的话效果还不错,如果2个人同时说回音还是有点大,有需要的可以参考下。
4. jrtplib库进行视频音频数据发送,本项目修改jrtplib库,添加了大数据切片功能,方便进行网络传输 5. ffmpeg对接收到的数据进行解码,利用ffmpeg软解码的原因是减少延时,Android硬解码由于机制问题,会存在 缓冲...
Android扫描蓝牙设备,连接蓝牙设备,读取设备数据,向设备写入数据的方法类。
----------------------------------- Android 编程基础 1 封面----------------------------------- Android 编程基础 2 开放手机联盟 --Open --Open --Open --Open Handset Handset Handset Handset Alliance ...
Android 4.0 全面而又细致的讲解Blutooth 4.0 OPP 相关的部分。值得一看。
小程序蓝牙传输,递归调用方便大数据量传输的情况,ios,android使用
优化音视频播放模块,音视频同步更精准,缩短...优化服务器缓冲区管理机制,提高服务器流媒体数据传输效率; 修正部分网络环境下操作UPNP设备时程序长时间被阻塞的Bug; 修正GetSDKOption接口获取部分参数失败的Bug。
3.4.3 使用relay实现内核到用户空间的数据传输 66 3.5 三类驱动程序 70 3.5.1 字符设备驱动程序 70 3.5.2 块设备驱动程序 79 3.5.3 网络设备驱动程序 82 第4章 hal层深入分析 84 4.1 ...
3.4.3 使用relay实现内核到用户空间的数据传输 66 3.5 三类驱动程序 70 3.5.1 字符设备驱动程序 70 3.5.2 块设备驱动程序 79 3.5.3 网络设备驱动程序 82 第4章 hal层深入分析 84 4.1 ...
基于rtp协议封装的数据收发sdk可用于android工程或修改后用于java项目,对于大量数据实时传输的应用。目前采用pcm格式语音数据做的测试,数据收发稳定
Audio 系统在 Android 中负责音频方面的数据流传输和控制功能,也负责音频设备的管理。这个部分作为 Android 的 Audio 系统的输入/输出层次,一般负责播放 PCM 声音输出和从外部获取 PCM 声音,以及管理声音设备和设置...
Android平台做的文件管理器可以通过WIFI和电脑传数据,加上3D的背景切换
音频流媒体实时音频流Android应用程序,使用户可以将音频记录和流式传输到本地服务器,并进行简单的分析。概括这是一个示例应用程序,可让用户录制音频并将其实时流式传输到本地服务器。 作为回报,服务器分析音频并...
想要在Android平台下实现音视频通信,最快捷的方法是寻找开源项目或调用其他公司封装好的API
这款Android数据恢复工具可以恢复手机或从其它设备传输的任何照片与视频,除了音乐,文件,档案外,还包括存储在您的Android手机上的SD卡中的资料。进行扫描,检查和恢复,3步即可完成。 下面是一些主要特点: - 从...