初始化AudioTrace学习笔记------深入理解Android
2012-06-20 15:23
281 查看
AudioTrack类管理并播放Java应用的音频资源。它将PCM音频缓冲流传输到音频硬件播放。使用
AudioTrace实例有两种工作方式:静态,流态
流态模式,应用将连续的数据流使用write()函数写入AudioTrack。数据流将阻塞,当数据从Java层传递到Native层后返回,并放入Playback队列。流态模式适用于播放音频数据块:
因声音播放时间过长而不适宜存储
因音频数据特性(高采样录、bits/s)而不适宜存储
之前的音频数据正在播放,同时接收或产生新的数据
静态模式适用于可存储的很短的,播放延迟最小的声音。因此该模式适用于播放UI或者游戏中的声音。
根据创造方式,AudioTrack对象可决定是否初始化它的音频缓冲。缓冲的大小在构造时指定,并决定一个AudioTrack播放时间。
静态模式的AudioTrack,缓冲的大小是他可播放声音的最大长度。
流态模式的AudioTrack,数据将以长度小于总缓冲大小的小块写到硬件。
AuidoTrack->set()@AudioTrack.cpp
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l()
void AudioFlinger::PlaybackThread::readOutputParameters()
AuidoTrack->createTrack()函数最终经过AudioFlinger->createTrack()函数获得了AudioFlinger::TrackHandle。mAudioTrack记录下了TrackHandle,将来AudioTrack就靠它与下层AudioFlinger协作,调用start,stop等函数。
mCblkMemory记录下共享buffer首地址。
track->getCblk()
,%20int,%20int%29]write(byte[], int, int)和
write(short[], int, int)方法推送音频流到AudioTrace对象。
AudioTrace实例有两种工作方式:静态,流态
流态模式,应用将连续的数据流使用write()函数写入AudioTrack。数据流将阻塞,当数据从Java层传递到Native层后返回,并放入Playback队列。流态模式适用于播放音频数据块:
因声音播放时间过长而不适宜存储
因音频数据特性(高采样录、bits/s)而不适宜存储
之前的音频数据正在播放,同时接收或产生新的数据
静态模式适用于可存储的很短的,播放延迟最小的声音。因此该模式适用于播放UI或者游戏中的声音。
根据创造方式,AudioTrack对象可决定是否初始化它的音频缓冲。缓冲的大小在构造时指定,并决定一个AudioTrack播放时间。
静态模式的AudioTrack,缓冲的大小是他可播放声音的最大长度。
流态模式的AudioTrack,数据将以长度小于总缓冲大小的小块写到硬件。
AuidoTrack->set()@AudioTrack.cpp
status_t AudioTrack::set( int streamType, uint32_t sampleRate, int format, int channels, int frameCount, uint32_t flags, callback_t cbf, void* user, int notificationFrames, const sp<IMemory>& sharedBuffer, bool threadCanCallJava, int sessionId) { ...... uint32_t channelCount = AudioSystem::popCount(channels); audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType, sampleRate, format, channels, (AudioSystem::output_flags)flags); ...... mVolume[LEFT] = 1.0f; mVolume[RIGHT] = 1.0f; mSendLevel = 0; mFrameCount = frameCount; mNotificationFramesReq = notificationFrames; mSessionId = sessionId; mAuxEffectId = 0; // create the IAudioTrack status_t status = createTrack(streamType, sampleRate, format, channelCount,-------------------------------步骤1 frameCount, flags, sharedBuffer, output, true); ...... if (cbf != 0) { mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);----------------------------------步骤2 if (mAudioTrackThread == 0) { LOGE("Could not create callback thread"); return NO_INIT; } } ...... mSharedBuffer = sharedBuffer;--------------------------------------------------------------------------步骤3 ...... mCbf = cbf; mUserData = user; ...... mAudioSession = -1; return NO_ERROR; }AuidoTrack->createTrack()@AudioTrack.cpp
status_t AudioTrack::createTrack( int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount, uint32_t flags, const sp<IMemory>& sharedBuffer, audio_io_handle_t output, bool enforceFrameCount) { status_t status; const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();//获取AudioFlinger服务 ...... sp<IAudioTrack> track = audioFlinger->createTrack(getpid(), streamType, sampleRate, format, channelCount, frameCount, ((uint16_t)flags) << 16, sharedBuffer, output, &mSessionId, &status); ...... sp<IMemory> cblk = track->getCblk(); ...... mAudioTrack.clear(); mAudioTrack = track; mCblkMemory.clear(); mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());//获取AudioTrack共享buffer首地址 mCblk->flags |= CBLK_DIRECTION_OUT; if (sharedBuffer == 0) { mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); } else { mCblk->buffers = sharedBuffer->pointer(); // Force buffer full condition as data is already present in shared memory mCblk->stepUser(mCblk->frameCount); } ...... mAudioTrack->attachAuxEffect(mAuxEffectId); ...... return NO_ERROR; }AudioFlinger->createTrack()@AudioFlinger.cpp
sp<IAudioTrack> AudioFlinger::createTrack( pid_t pid, int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount, uint32_t flags, const sp<IMemory>& sharedBuffer, int output, int *sessionId, status_t *status) { sp<PlaybackThread::Track> track; sp<TrackHandle> trackHandle; sp<Client> client; wp<Client> wclient; status_t lStatus; int lSessionId; { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output);-----------------------获取output对应的playbackthread PlaybackThread *effectThread = NULL; if (thread == NULL) { LOGE("unknown output thread"); lStatus = BAD_VALUE; goto Exit; } wclient = mClients.valueFor(pid); if (wclient != NULL) { client = wclient.promote(); } else { client = new Client(this, pid);----------------------------------------------初始化1024*1024大小的memoryheap mClients.add(pid, client);----------------------------------------------------pid,client对 } LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);-------sessionId不为空 if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) { for (size_t i = 0; i < mPlaybackThreads.size(); i++) { sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); if (mPlaybackThreads.keyAt(i) != output) { // prevent same audio session on different output threads uint32_t sessions = t->hasAudioSession(*sessionId); if (sessions & PlaybackThread::TRACK_SESSION) { lStatus = BAD_VALUE; goto Exit; } // check if an effect with same session ID is waiting for a track to be created if (sessions & PlaybackThread::EFFECT_SESSION) { effectThread = t.get(); ` } } } lSessionId = *sessionId; } else { // if no audio session id is provided, create one here lSessionId = nextUniqueId();------------------------------------------------*sessionId赋值 if (sessionId != NULL) { *sessionId = lSessionId; } } track = thread->createTrack_l(client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, lSessionId, &lStatus); // move effect chain to this output thread if an effect on same session was waiting // for a track to be created if (lStatus == NO_ERROR && effectThread != NULL) { Mutex::Autolock _dl(thread->mLock); Mutex::Autolock _sl(effectThread->mLock); moveEffectChain_l(lSessionId, effectThread, thread, true); } } if (lStatus == NO_ERROR) { trackHandle = new TrackHandle(track);--------------------------------------------TrackHandle初始化 } else { // remove local strong reference to Client before deleting the Track so that the Client // destructor is called by the TrackBase destructor with mLock held client.clear(); track.clear(); } Exit: if(status) { *status = lStatus; } return trackHandle; }
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l()
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const { PlaybackThread *thread = NULL; if (mPlaybackThreads.indexOfKey(output) >= 0) { thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();-----------------mPlaybackThreads.add(id, thread)@openOutput;id为output号,thread为mixerthread } return thread; }class Client
AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) : RefBase(), mAudioFlinger(audioFlinger), mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")), mPid(pid) { // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer }PlaybackThread::createTrack_l()
sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l( const sp<AudioFlinger::Client>& client, int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId, status_t *status) { sp<Track> track; status_t lStatus; ...... { // scope for mLock Mutex::Autolock _l(mLock); // all tracks in same audio session must share the same routing strategy otherwise // conflicts will happen when tracks are moved from one output to another by audio policy // manager uint32_t strategy = AudioSystem::getStrategyForStream((AudioSystem::stream_type)streamType); for (size_t i = 0; i < mTracks.size(); ++i) { sp<Track> t = mTracks[i]; if (t != 0) { if (sessionId == t->sessionId() && strategy != AudioSystem::getStrategyForStream((AudioSystem::stream_type)t->type())) { lStatus = BAD_VALUE; goto Exit; } } } track = new Track(this, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, sessionId); ...... } lStatus = NO_ERROR; Exit: if(status) { *status = lStatus; } return track; }class Track
AudioFlinger::PlaybackThread::Track::Track( const wp<ThreadBase>& thread, const sp<Client>& client, int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId) : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId), mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL), mAuxEffectId(0), mHasVolumeController(false) { if (mCblk != NULL) { sp<ThreadBase> baseThread = thread.promote(); if (baseThread != 0) { PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get(); mName = playbackThread->getTrackName_l(); mMainBuffer = playbackThread->mixBuffer(); } ...... LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid()); if (mName < 0) { LOGE("no more track names available"); } ...... // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t); } ...... }AudioFlinger::ThreadBase::TrackBase::TrackBase
AudioFlinger::ThreadBase::TrackBase::TrackBase( const wp<ThreadBase>& thread, const sp<Client>& client, uint32_t sampleRate, int format, int channelCount, int frameCount, uint32_t flags, const sp<IMemory>& sharedBuffer, int sessionId) : RefBase(), mThread(thread), mClient(client), mCblk(0), mFrameCount(0), mState(IDLE), mClientTid(-1), mFormat(format), mFlags(flags & ~SYSTEM_FLAGS_MASK), mSessionId(sessionId) { LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); size_t size = sizeof(audio_track_cblk_t); size_t bufferSize = 0; if ( (format == AudioSystem::PCM_16_BIT) || (format == AudioSystem::PCM_8_BIT)) { bufferSize = frameCount*channelCount*sizeof(int16_t); } else if (format == AudioSystem::AMR_NB) { bufferSize = frameCount*channelCount*32; // full rate frame size } ...... if (sharedBuffer == 0) { size += bufferSize; } if (client != NULL) { mCblkMemory = client->heap()->allocate(size);------------------------------------------在已有的heap上分配空间 if (mCblkMemory != 0) { mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); if (mCblk) { // construct the shared structure in-place. new(mCblk) audio_track_cblk_t();-----------------------------------------------placement new,音频信息头 // clear all buffers mCblk->frameCount = frameCount; mCblk->sampleRate = sampleRate; mCblk->channelCount = (uint8_t)channelCount; if (sharedBuffer == 0) { mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);------------------------mBuffer音频数据的存储起始位置 // Change for Codec type if ( (format == AudioSystem::PCM_16_BIT) || (format == AudioSystem::PCM_8_BIT)) { memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); } else if (format == AudioSystem::AMR_NB) { memset(mBuffer, 0, frameCount*channelCount*32); // full rate frame size } ...... // Force underrun condition to avoid false underrun callback until first data is // written to buffer (other flags are cleared) mCblk->flags = CBLK_UNDERRUN_ON; } else { mBuffer = sharedBuffer->pointer(); } mBufferEnd = (uint8_t *)mBuffer + bufferSize;-----------------------------------音频数据的结束为止 } ...... } ...... } ...... }audio_track_cblk_t
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; Condition cv; volatile uint32_t user; volatile uint32_t server; uint32_t userBase; uint32_t serverBase; void* buffers; uint32_t frameCount; // Cache line boundary uint32_t loopStart; uint32_t loopEnd; int loopCount; volatile union { uint16_t volume[2]; uint32_t volumeLR; }; 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 uint8_t frameSize; uint8_t channelCount; uint16_t flags; uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger uint16_t waitTimeMs; // Cumulated wait time uint16_t sendLevel; uint16_t reserved; // Cache line boundary (32 bytes) audio_track_cblk_t(); uint32_t stepUser(uint32_t frameCount); bool stepServer(uint32_t frameCount); void* buffer(uint32_t offset) const; uint32_t framesAvailable(); uint32_t framesAvailable_l(); uint32_t framesReady(); };int AudioFlinger::MixerThread::getTrackName_l()
int AudioFlinger::MixerThread::getTrackName_l() { return mAudioMixer->getTrackName(); }int AudioMixer::getTrackName()
int AudioMixer::getTrackName() { uint32_t names = mTrackNames; uint32_t mask = 1; int n = 0; while (names & mask) { mask <<= 1; n++; } if (mask) { LOGV("add track (%d)", n); mTrackNames |= mask; return TRACK0 + n; } return -1; }int16_t *mixBuffer()
int16_t *mixBuffer() { return mMixBuffer; };mMixBuffer是在PlayBackThread的构造函数中调用readOutputParameters()中初始化的
void AudioFlinger::PlaybackThread::readOutputParameters()
void AudioFlinger::PlaybackThread::readOutputParameters() { ...... // FIXME - Current mixer implementation only supports stereo output: Always // Allocate a stereo buffer even if HW output is mono. if (mMixBuffer != NULL) delete[] mMixBuffer; mMixBuffer = new int16_t[mFrameCount * 2]; memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); ...... }class TrackHandle
AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track) : BnAudioTrack(), mTrack(track) { }TrackHandle使用Proxy模式,真正干活的AudioFlinger::PlaybackThread::Track,最终发给底层音频驱动设备。
AuidoTrack->createTrack()函数最终经过AudioFlinger->createTrack()函数获得了AudioFlinger::TrackHandle。mAudioTrack记录下了TrackHandle,将来AudioTrack就靠它与下层AudioFlinger协作,调用start,stop等函数。
mCblkMemory记录下共享buffer首地址。
track->getCblk()
sp<IMemory> AudioFlinger::TrackHandle::getCblk() const { return mTrack->getCblk(); }
sp<IMemory> AudioFlinger::EffectHandle::getCblk() const { return mCblkMemory; }mCblkMemory@TrackBase是在TrackBase构造函数中init的,mCblkMemory = client->heap()->allocate(size);。client也就是前面Client类中预先分配的1M的heap空间。
相关文章推荐
- Binder学习笔记---深入理解Android
- hongyang的博文深入理解Android中的自定义属性 学习笔记
- Android系统架构(简述)——《深入理解(I)》学习笔记1
- 3深入理解Android之Gradle学习笔记
- Java多线程高并发学习笔记(二)——深入理解ReentrantLock与Condition
- Android开发笔记之:深入理解Cursor相关的性能问题
- Html学习笔记 --- html 中深入理解语义化
- Hive学习笔记 --- 深入理解 HIVE 个各种存储模式
- 对于对象的深入理解(学习笔记)
- 《Java编程思想_ 深入理解java虚拟机_Thinking in java__Effiect java__设计模式》学习笔记7——泛型编程基础
- Android入门:深入学习理解 Handler HandlerThread AsyncQueryHandler 三者的关系
- 【深入理解Java虚拟机学习笔记】虚拟机类加载机制
- 深入理解JVM学习笔记-垃圾收集器和内存分配策略
- Android GPS学习笔记—GpsLP初始化
- 深入理解Java虚拟机---学习感悟以及笔记
- 《深入理解LINUX内存管理》学习笔记 (四)
- 【css学习笔记】深入理解之float
- 深入理解JVM虚拟机学习笔记(三)内存分配和回收策略
- 深入理解C#学习笔记之走出误区
- 深入理解JVM学习笔记-自动内存管理机制