初始化AudioTrace学习笔记------深入理解Android
来源:互联网 发布:java获取24小时制时间 编辑:程序博客网 时间:2024/06/05 15:14
AudioTrack类管理并播放Java应用的音频资源。它将PCM音频缓冲流传输到音频硬件播放。使用write(byte[], int, int)
和write(short[], int, int)
方法推送音频流到AudioTrace对象。
AudioTrace实例有两种工作方式:静态,流态
流态模式,应用将连续的数据流使用write()函数写入AudioTrack。数据流将阻塞,当数据从Java层传递到Native层后返回,并放入Playback队列。流态模式适用于播放音频数据块:
- 因声音播放时间过长而不适宜存储
- 因音频数据特性(高采样录、bits/s)而不适宜存储
- 之前的音频数据正在播放,同时接收或产生新的数据
根据创造方式,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.cppsp<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空间。
- 初始化AudioTrace学习笔记------深入理解Android
- 《深入理解Linux网络内幕》学习笔记二:网络设备初始化
- Binder学习笔记---深入理解Android
- 启动AudioFlinger学习笔记----深入理解Android
- 深入理解Android之Gradle学习笔记
- 【Android学习笔记】Android中pendingIntent的深入理解
- 《深入理解Linux网络内幕》学习笔记三:第七章 组件初始化内核架构
- 《深入理解Android内核设计思想》学习笔记
- 《疯狂Android讲义》学习笔记 -- 深入理解Activity
- 3深入理解Android之Gradle学习笔记
- 《深入理解计算机网络》学习笔记
- 深入理解计算机系统学习笔记
- 《深入理解Android》之笔记
- Android笔记----深入理解Activity
- 《深入理解 Android》笔记:ActivityManagerService
- java初始化深入理解
- 深入理解Android Telephony之PhoneApp的初始化
- 深入理解Android(03)——深入理解init初始化函数
- windows2000server下大文件上传限制问题
- java的静态代理
- 思绪---即将结束的项目
- rails 学习资源
- linux vi常用命令 提高编辑效率
- 初始化AudioTrace学习笔记------深入理解Android
- Gallery循环滑动原理
- html--message
- ORACLE PL/SQL编程之八: 把触发器说透
- VFP中控件如何随着窗体自动调整(经典,就一句!)
- java注解
- 将百度地图添加到页面中
- main执行之前与之后
- jxl Or poi 压缩导出 总结