上面一篇最后提到Binder,我个人感觉Android系统需要申请内存空间基本上都是Binder完成的,
可以基本认知Binder:Binder在linux层是专门有一个binder驱动层的,这个驱动层可以用于分配设备内存空间.它同时提供接口给其他设备使用,用于分配内存和管理内存,其他设备需要申请内存都需要实现它的接口,通过它提供的接口分配内存和管理内存.
Android Audio 录播都需要分配内存用于存放音频数据,android Audio这个分配是在AudioFlinger核心部分完成的,但是看了很多网上面的说分配内存有两个地方,一个可以是AudioTrack,一个才是AudioFlinger,但是我个人看了很多次这部分源代码,没有发现AudioTrack分配内存的地方,也搜索了关键字 : heap()->allocate ,但是个人觉得AudioTrack应该不可能去申请内存空间,因为数据的操作和使用都是由AudioFlinger完成的---个人观点.
下面看看代码,我个人总是感觉AudioTrack.cpp部分看的不多,因为他最终都是"赖给"AudioFlinger去做事了,所以可以直接从AudioFlinger开始:
sp<IAudioTrack> AudioFlinger::createTrack(
pid_t pid,
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
int frameCount,
IAudioFlinger::track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t tid,
int *sessionId,
status_t *status)
{
从上面开始,这里面不涉及其他的,就看看内存分配,函数里面构造一个Track对象:
track = thread->createTrack_l(client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, &lStatus);
进入:这是一个PlaybackThread的内种类:
sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l
最终在这里:
if (!isTimed) {
track = new Track(this, client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, sessionId, flags);
} else {
track = TimedTrack::create(this, client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, sessionId);
}
无论isTimed是否成立,最终都会使用new Track(...)这个去构建.可以看下:
AudioFlinger::PlaybackThread::TimedTrack::TimedTrack(
PlaybackThread *thread,
const sp<Client>& client,
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId)
: Track(thread, client, streamType, sampleRate, format, channelMask,
frameCount, sharedBuffer, sessionId, IAudioFlinger::TRACK_TIMED),
最后两行.
到Track还没完,因为最终完成是TrackBase,可以看一下Track的构造体:
AudioFlinger::PlaybackThread::Track::Track(
PlaybackThread *thread,
const sp<Client>& client,
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId,
IAudioFlinger::track_flags_t flags)
: TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer, sessionId),
最后一行出现了TrackBase,然后继续跟踪:
if (client != NULL) {
mCblkMemory = client->heap()->allocate(size);
突然出现了一个client,怎么是它分配呢?回过头看看:
sp<IAudioTrack> AudioFlinger::createTrack(
pid_t pid,
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
int frameCount,
IAudioFlinger::track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t tid,
int *sessionId,
status_t *status)
{
sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
初始化:
client = registerPid_l(pid);
(这里面要注意函数名:createTrack和createTrack_l,名字非常相近,不知道android是怎么想的哈).
经过上面的一番折腾内存空间就给分配了.
但是可能又会问,分配内存不是Binder去搞定吗,怎么没看出来呀.
我们把下面这一句话继续展开:
mCblkMemory = client->heap()->allocate(size);
heap是谁的?看Client类:
sp<MemoryDealer> heap() const;
那么MemoryDealer又是什么?allocate又是如何处理的?
virtual sp<IMemory> allocate(size_t size);
终于到IMemory,只要多看一眼前面的createTrack等函数,就会发现它们构造体里面一直传递了一个IMemory的参数,不过这个传递进来的不是用来分配的,主要作用大概有两个:
<1> : 作为AudioTrack.cpp部分的回调;
<2> : 作为AudioTrack和AudioFlinger直接数据生产和消费,再就是协调数据进出有序的,FIFO.
继续allocate:
sp<IMemory> MemoryDealer::allocate(size_t size)
{
sp<IMemory> memory;
const ssize_t offset = allocator()->allocate(size);
if (offset >= 0) {
memory = new Allocation(this, heap(), offset, size);
}
return memory;
}
最后分配:
Allocation::Allocation(
const sp<MemoryDealer>& dealer,
const sp<IMemoryHeap>& heap, ssize_t offset, size_t size)
: MemoryBase(heap, offset, size), mDealer(dealer)
{
#ifndef NDEBUG
void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
memset(start_ptr, 0xda, size);
#endif
}
上面中的IMemoryHeap或者IMemory都是binder的接口,在IMemory.cpp文件中:大致有三点:
<1> : 前面程序会看到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;
}
size_t IMemory::size() const {
size_t size;
getMemory(NULL, &size);
return size;
}
ssize_t IMemory::offset() const {
ssize_t offset;
getMemory(&offset);
return offset;
}
这个是反馈分配的内存偏移量和内存大小,偏移量比较难理解的话,就可以勉强理解为分配的内存所在的位置.
<2> : Bn***,Bp***中的BpMemory 类:Bp全名:Binder Proxy : Binder代理
BpMemory::BpMemory(const sp<IBinder>& impl)
: BpInterface<IMemory>(impl), mOffset(0), mSize(0)
{
}
BpMemory::~BpMemory()
{
}
sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
{
if (mHeap == 0) {
Parcel data, reply;
data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
sp<IBinder> heap = reply.readStrongBinder();
ssize_t o = reply.readInt32();
size_t s = reply.readInt32();
if (heap != 0) {
mHeap = interface_cast<IMemoryHeap>(heap);
if (mHeap != 0) {
mOffset = o;
mSize = s;
}
}
}
}
if (offset) *offset = mOffset;
if (size) *size = mSize;
return mHeap;
}
其实这东西一两句话说不完,我自己的理解就是binder有货(内存空间,且分配好了的),你要"拿货",你找binder的代理(商),不要直接去找binder,当然binder也没有时间搭理你,另外binder自身分配的时候也不是同步的,所以如果同时直接去操作binder,就不知道有什么后果了.
<3> : BnMemory :这也是个好同志,将数据写入内存中,网上称为服务器端,但个人认为它是最终可以与binder linux节点交互的部分,上面BpMemory最终也是要和BnMemory交互的,至于binder详细,可以阅读:framework/base/libs/binder/下面的源代码.
BnMemory::BnMemory() {
}
BnMemory::~BnMemory() {
}
status_t BnMemory::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case GET_MEMORY: {
CHECK_INTERFACE(IMemory, data, reply);
ssize_t offset;
size_t size;
reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
reply->writeInt32(offset);
reply->writeInt32(size);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
最后还扯一个东西:AudioTrack和AudioFlinger,他们两在使用同一个内存区里面的数据时,怎么协调,AudioTrack把播放的数据缓存到binder分配的内存中,AudioFlinger如何调用的到那个内存中的数据,首先要清楚一点的是:
binder分配的内存区,提供了接口可以让多个设备共同读写同一个内存区,也就是说AudioTrack和AudioFlinger虽然在不同的进程,但是可以通过binder机制共同使用同一片内存数据.但是使用过程中,就会有一个协调的工作,不能出现差错,不然声音要么延迟,缎带,要么重复播放.它主要靠下面的结构体实现数据FIFO的协调工作:
// Important: do not add any virtual methods, including ~
struct audio_track_cblk_t
{
// The data members are grouped so that members accessed frequently and in the same context
// are in the same line of data cache.
Mutex lock; // sizeof(int)
Condition cv; // sizeof(int)
// next 4 are offsets within "buffers"
volatile uint32_t user;
volatile uint32_t server;
uint32_t userBase;
uint32_t serverBase;
// if there is a shared buffer, "buffers" is the value of pointer() for the shared
// buffer, otherwise "buffers" points immediately after the control block
void* buffers;
uint32_t frameCount;
// Cache line boundary
uint32_t loopStart;
uint32_t loopEnd; // read-only for server, read/write for client
int loopCount; // read/write for client
// Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
// Left channel is in [0:15], right channel is in [16:31].
// Always read and write the combined pair atomically.
// For AudioTrack only, not used by AudioRecord.
private:
uint32_t mVolumeLR;
public:
uint32_t sampleRate;
// NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
// 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of
// 16 bit because data is converted to 16 bit before being stored in buffer
// read-only for client, server writes once at initialization and is then read-only
uint8_t frameSize; // would normally be size_t, but 8 bits is plenty
uint8_t mName; // normal tracks: track name, fast tracks: track index
// used by client only
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
uint16_t waitTimeMs; // Cumulated wait time, used by client only
private:
// client write-only, server read-only
uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0
public:
volatile int32_t flags;
// Cache line boundary (32 bytes)
// Since the control block is always located in shared memory, this constructor
// is only used for placement new(). It is never used for regular new() or stack.
audio_track_cblk_t();
uint32_t stepUser(uint32_t frameCount); // called by client only, where
// client includes regular AudioTrack and AudioFlinger::PlaybackThread::OutputTrack
bool stepServer(uint32_t frameCount); // called by server only
void* buffer(uint32_t offset) const;
uint32_t framesAvailable();
uint32_t framesAvailable_l();
uint32_t framesReady(); // called by server only
bool tryLock();
// No barriers on the following operations, so the ordering of loads/stores
// with respect to other parameters is UNPREDICTABLE. That's considered safe.
// for AudioTrack client only, caller must limit to 0.0 <= sendLevel <= 1.0
void setSendLevel(float sendLevel) {
mSendLevel = uint16_t(sendLevel * 0x1000);
}
// for AudioFlinger only; the return value must be validated by the caller
uint16_t getSendLevel_U4_12() const {
return mSendLevel;
}
// for AudioTrack client only, caller must limit to 0 <= volumeLR <= 0x10001000
void setVolumeLR(uint32_t volumeLR) {
mVolumeLR = volumeLR;
}
// for AudioFlinger only; the return value must be validated by the caller
uint32_t getVolumeLR() const {
return mVolumeLR;
}
};
播放状态,播放位置(内存offset)...记录了播放过程中数据使用过程的所有状态和处理.这个地方千万要注意的是,AudioTrack和AudioFlinger两者通过传递这个结构实现数据同步的,读写内存本身是不能够同步进行的,需要人为去实现这个操作同步.
后面还有一个重采样的处理,以及后面的设备选择.