Android音频子系统,音频流的回放(四)
来源:互联网 发布:java try的用法 编辑:程序博客网 时间:2024/06/02 09:25
Audiotrack被用于音频流的回放,用来传输数据。
AudioTrack支持两种数据模式:
一种是Static,静态就是指数据一次性交付给对方,简单高效,一次完成所有数据的传递。适用于铃声、系统提醒等对内存要求小的播放操作。
一种是streaming,流模式和基于网络的音频流回放类似,音频数据严格按照要求不断地传递给接收方,直到结束。通常适用于音频文件较大时;音频属相要求高,如采样率高、深度达的数据;音频数据时实时产生的。
源码中有Audiotrack的应用范例:用于测试立体声左右声道最大音量。
Framework/base/media/tests/../MediaAudioTrackTest.java
public void testSetStereoVolumeMax() throws Exception {final int TEST_SR = 22050; final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO; final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT; final int TEST_MODE = AudioTrack.MODE_STREAM;final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;// step1,计算最小缓冲区大小int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);//step2,生成audiotrack对象。AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT, minBuffSize, TEST_MODE);byte data[] = new byte[minBuffSize/2];// step3,写入音频数据track.write(data, 0, data.length);track.write(data, 0, data.length);// step4,开始播放音频track.play();//获取最大音量值。float maxVol = AudioTrack.getMaxVolume();track.release();}
上面的例子,包含了AudioTrack的常规操作
Step1,getMinBufferSize,获取最小的Buffer大小。函数实现如下:
AudioTrack.java
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {//获取音频的声道数属性。switch(channelConfig) {case AudioFormat.CHANNEL_OUT_MONO:channelCount = 1;break;case AudioFormat.CHANNEL_OUT_STEREO:channelCount = 2;break;}//检查音频采样深度。if (!AudioFormat.isPublicEncoding(audioFormat)) { return ERROR_BAD_VALUE; }//检查采样频率。if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) ||(sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) { return ERROR_BAD_VALUE; }//最小buffer的计算,取决于采样频率,声道数,采样深度这三个属性。具体计算在native层,android_media_audiotrack.cpp中。int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);}
Step2,有了minbuffersize,就可以创建一个audiotrack对象了。
转到audiotrack.java的构造函数
AudioTrack.java
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)throws IllegalArgumentException {// native initialization int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes, sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/);}
AudioTrack的一个重要任务是和Audioflinger建立联系,这是有native代码实现的。
android_media_AudioTrack.cpp
static jint android_media_AudioTrack_setup(…){//创建一个native层的audiotrack。lpTrack = new AudioTrack();//存储音频数据的地方lpJniStorage = new AudioTrackJniStorage();//调用Audiotrack的set函数,设置各种属性 status = lpTrack->set( AUDIO_STREAM_DEFAULT, sampleRateInHertz, format,// word length, PCM nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE, audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack0,//不同的内存模式,这个参数不一样,MODE_STREAM,这个值是0;MODE_STATIC,这个是:lpJniStorage->mMemBase 0,// shared mem true,// thread can call Java sessionId,// audio session ID AudioTrack::TRANSFER_SYNC, NULL, // default offloadInfo -1, -1, // default uid, pid values paa);}
接着看AudioTrack.cpp中的set函数的实现:
status_t AudioTrack::set(…){//默认刘类型是AUDIO_STREAM_MUSIC if (streamType == AUDIO_STREAM_DEFAULT) { streamType = AUDIO_STREAM_MUSIC;}//默认采样深度是16bit。 if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT;}在经过一些有效性检查后,Audiotrack就要使用底层的音频服务了,这里的底层服务是指audioflinger,audiopolicyservice等,android系统在Audiotrack和底层服务之间又加了audiosystem和Audioservice,这就降低了Audiotrack与底层服务间的耦合。就是说,即使不同版本Android的音频系统改动较大,但只要audioSystem,audioservice向上的接口不变,那么audiotrack就需要做任何修改。//step1,创建一个线程AudioTrackThreadmAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);//step2,创建一个IAudioTrack,createTrack_l函数中会经过Auidosystem,进一步调用到audiopolicyservice的服务接口。status_t status = createTrack_l();}
Step1,AudioTrackThread线程,一方面在Audiotrack和audioflinger之间做数据传输,作为客户端audiotrack用这个线程不断的传送数据,作为接收端的audioflinger也有一个线程(playbackthread)用于接收客户端发来的音频数据;另一方面,用于报告数据传输状态,Audiotrack中保存了mCbf变量,是callback_t类型的回调函数,用于回传音频传输过程中的状态给调用者。
Step2,createTrack_l中,会由audiosystem作为中转,调用audiopolicyservice,audioflinger实现的功能,如:getOutputForAttr,getFrameCount等;还有一个重要操作,是建立audiotrack与audioflinger之间跨进程沟通的桥梁IAudioTrack。
status_t AudioTrack::createTrack_l(){status = AudioSystem::getOutputForAttr(attr, &output,…);status = AudioSystem::getFrameCount(output, &mAfFrameCount);sp<IAudioTrack> track = audioFlinger->createTrack(streamType,…);}
AudioSystem::getOutputForAttr(…);这个功能实现,最终还是有AudioPolicyservice来完成的。Getoutput会在当前系统中寻找最适合audiotrack的audio interface,及output输出(由audioflinger通过openoutput打开的通道),然后audiotrack会向这个output申请一个track(PlaybackThread::Track),audiotrack在Audioflinger内部就是以这个track来管理的,因为audiotrack和Audioflinger之间是跨进程的,所以还创建了他们之间的桥梁是IaudioTrack。
createTrack中的关键步骤:
AudioFlinger.cpp
sp<IAudioTrack> AudioFlinger::createTrack(…){sp<PlaybackThread::Track> track;sp<TrackHandle> trackHandle;//这里的output (audio_io_handle_t),是在audioflinger::openoutput时产生的,这个值跟playbackthread是对应的。依据audio_io_handle_t全局标记值,找到匹配的playbackthread。然后在其内部创建playbacktrack::track对象,这个track的父类是trackBase,所有track对象都被添加到playbackthread:: mTracks中进行管理。TrackHandle就是Iaudiotrack.。PlaybackThread *thread = checkPlaybackThread_l(output);track = thread->createTrack_l(client, streamType, sampleRate, format,…);trackHandle = new TrackHandle(track);}
Tracks.cpp
在创建Track对象时,同时调用了父类Trackbase的构造函数:
AudioFlinger::PlaybackThread::Track::Track(…) : TrackBase(…){…}
在trackbase的构造函数中,申请了一块缓冲区,这块空间是可以跨进程共享的。AudioTrack通过track->getCblk();获取的就是这块内存空间,这块内存空间是针对mode_stream流模式下的音频数据的存放的。静态模式下音频数据的存放空间是由AudioTrackJniStorage来申请的。
AudioFlinger::ThreadBase::TrackBase::TrackBase(…){mCblkMemory = client->heap()->allocate(size);}
AudioTrack.cpp
status_t AudioTrack::createTrack_l(){sp<IAudioTrack> track = audioFlinger->createTrack(…);sp<IMemory> iMem = track->getCblk();}
下面是getCblk()的调用堆栈:
sp<IMemory> AudioFlinger::TrackHandle::getCblk() @Tracks.cppconst { return mTrack->getCblk();}sp<IMemory> getCblk()@TrackBase.h const { return mCblkMemory; }到这里,Audiotrack可以通过IaudioTrack调用audioflinger的服务,应用实例(前面的testSetStereoVolumeMax ()@MediaAudioTrackTest.java)可以通过不断写入音频数据(track.write(data, 0, data.length);)回放声音。
- Android音频子系统,音频流的回放(四)
- Android音频子系统,音频流(六)
- Android音频子系统,Audiopolicyservice音频策略的制定(五)
- Android音频子系统,音量的调节控制(七)
- android 音频子系统框架(一)
- android 音频子系统-AudioFlinger(二)
- Android音频子系统,AudioPolicyService(三)
- Android 音频子系统简要介绍
- Linux下的音频采集与回放
- Android java层音频相关的分析与理解(四)音频外设相关
- Android java层音频相关的分析与理解(四)音频外设相关
- Android音频子系统源码分析之AudioTrack的使用
- Android音频子系统源码分析之AudioFlinger的实现
- Android 音频子系统,音频系统跟应用层直接相关的部分(八)
- Android音频开发(5):音频数据的编解码
- Android音频开发(5):音频数据的编解码
- 截取android正在播放音乐的audio音频流(后台获取android音频流)
- java j2me 捕捉回放音频
- 机器学习入门--MNIST(一)
- IBM服务器引导盘serverguide 下载
- Somethings about the coding in Python
- UBoot:ENTRY等宏的展开,CPSR寄存器的设置(stat.S)
- sql排序问题
- Android音频子系统,音频流的回放(四)
- 【Java】【线程同步】sleep,join,yield,synchronized,wait,notify
- HDU 1029
- elasticsearch开发学习
- 【c#系列 三】从java到.net 高级
- js 去除空格、回车、换行
- Python之re方法
- equals的问题
- 11.15学习心得