AudioTrack在Android系统中是用于PCM数据的混音、播放,并不涉及到音频的解码。因此MP3这类经过编码的音频格式文件不能直接通过AudioTrack正确地播放,AudioTrack只能播放PCM格式的音频数据,如wav格式的音频。

AudioTrack播放音频的实例如下:

  1. AudioTrack audio = new AudioTrack(
  2. AudioManager.STREAM_MUSIC, // stream mode
  3. 32000, // sample rate
  4. AudioFormat.CHANNEL_OUT_STEREO, // single or stereo
  5. AudioFormat.ENCODING_PCM_16BIT, // bit format
  6. AudioTrack.MODE_STREAM
  7. );
  8. audio.start();
  9. byte[] buffer = new buffer[4096];
  10. int count;
  11. while(true)
  12. {
  13. audio.write(buffer, 0, 4096);
  14. }

共有三个步骤:

  1. 构建AudioTrack对象,并且把PCM的参数传到对象里面
  2. 调用start
  3. 调用write

1. 构建AudioTrack对象

在AudioTrack构造方法内部仅调用了一个set函数

  1. AudioTrack::AudioTrack(
  2. audio_stream_type_t streamType,
  3. uint32_t sampleRate,
  4. audio_format_t format,
  5. audio_channel_mask_t channelMask,
  6. const sp<IMemory>& sharedBuffer,
  7. audio_output_flags_t flags,
  8. callback_t cbf,
  9. void* user,
  10. int notificationFrames,
  11. int sessionId,
  12. transfer_type transferType,
  13. const audio_offload_info_t *offloadInfo,
  14. int uid)
  15. : mStatus(NO_INIT),
  16. mIsTimed(false),
  17. mPreviousPriority(ANDROID_PRIORITY_NORMAL),
  18. mPreviousSchedulingGroup(SP_DEFAULT)
  19. {
  20. mStatus = set(streamType, sampleRate, format, channelMask,
  21. 0 /*frameCount*/, flags, cbf, user, notificationFrames,
  22. sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, uid);
  23. }

set方法内部主要做了什么?

  1. status_t AudioTrack::set(
  2. audio_stream_type_t streamType,
  3. uint32_t sampleRate,
  4. audio_format_t format,
  5. audio_channel_mask_t channelMask,
  6. int frameCountInt,
  7. audio_output_flags_t flags,
  8. callback_t cbf,
  9. void* user,
  10. int notificationFrames,
  11. const sp<IMemory>& sharedBuffer,
  12. bool threadCanCallJava,
  13. int sessionId,
  14. transfer_type transferType,
  15. const audio_offload_info_t *offloadInfo,
  16. int uid)
  17. {
  18.  
  19. audio_io_handle_t output = AudioSystem::getOutput(
  20. streamType,
  21. sampleRate, format, channelMask,
  22. flags,
  23. offloadInfo);
  24.  
  25. if (cbf != NULL) {
  26. mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
  27. mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
  28. }
  29.  
  30. // create the IAudioTrack
  31. status_t status = createTrack_l(streamType,
  32. sampleRate,
  33. format,
  34. frameCount,
  35. flags,
  36. sharedBuffer,
  37. output,
  38. 0 /*epoch*/);

除了对参数的预处理以及保存之外,中间最主要的功能有三个:

  1. getOutput,获取输出设备并打开该设备
  2. 创建AudioTrackThread,并执行该线程
  3. 创建音轨,实际上是创建用户与Android系统的共享内存,用于传输音频数据

由于getOutput与createTrack_l的篇幅较大,我会在后面的章节在分析,这里分析一下AudioTrackThread。

AudioTrackThread主要用于反馈处理,会根据不同的buffer状态进行不同的操作,其中buffer状态包括下面几种:

  1. buffer的position有增长,说明buffer正在被填充;
  2. remainFrames减少说明buffer正在被消耗,即buffer内的Audio数据已被混音;
  3. loop_cycle说明buffer需要循环播放;
  4. loop_final说明buffer已经播放完毕;
  5. etc.

对于不同的状态,会调用到回调函数mCbf,该函数在set的时候被传入。回调函数mCbf的作用还是很大的,比如说能通知应用程序当前的播放状态,也能根据当前的状态继续进行下一步的操作。像AwesomePlayer中的音频处理模块AudioPlayer就能通过mCbf的回调自动填充buffer。

  1. bool AudioTrack::AudioTrackThread::threadLoop()
  2. {
  3.  
  4. nsecs_t ns = mReceiver.processAudioBuffer(this);
  5.  
  6. }
  7.  
  8. // -------------------------------------------------------------------------
  9.  
  10. nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
  11. {
  12.  
  13. mCbf(...);
  14.  
  15. }

2. 调用start

start方法是触发混音线程对当前音轨进行混音并输出,篇幅较大,会在后面章节分析

3. 调用write

write方法需要获得刚刚所创建的音轨,并且把PCM数据往音轨写入。由于音轨的大小有限,write也很有可能一次性不能写入全部数据,因此需要循环调用write方法

  1. // -------------------------------------------------------------------------
  2.  
  3. ssize_t AudioTrack::write(const void* buffer, size_t userSize)
  4. {
  5.  
  6. while (userSize >= mFrameSize) {
  7. audioBuffer.frameCount = userSize / mFrameSize;
  8.  
  9. status_t err = obtainBuffer(&audioBuffer, &ClientProxy::kForever);
  10.  
  11. memcpy(audioBuffer.i8, buffer, toWrite);
  12. }
  13. }

需要注意的就是AudioTrack除了初始化之外,write只是往音轨内写入PCM数据,这是Audio数据流动的第一步。

[Android] AudioTrack实例的更多相关文章

  1. Android HTTP实例 使用GET方法和POST方法发送请求

    Android HTTP实例 使用GET方法和POST方法发送请求 Web程序:使用GET和POST方法发送请求 首先利用MyEclispe+Tomcat写好一个Web程序,实现的功能就是提交用户信息 ...

  2. Android HTTP实例 发送请求和接收响应

    Android HTTP实例 发送请求和接收响应 Android Http连接 实例:发送请求和接收响应 添加权限 首先要在manifest中加上访问网络的权限: <manifest ... & ...

  3. Android图像处理实例教程

    Android图像处理实例教程 原始出处 http://vaero.blog.51cto.com/4350852/856750

  4. 一个简单的Android小实例

    原文:一个简单的Android小实例 一.配置环境 1.下载intellij idea15 2.安装Android SDK,通过Android SDK管理器安装或卸载Android平台   3.安装J ...

  5. android本地数据库,微信数据库WCDB for Android 使用实例

    android本地数据库,微信数据库WCDB for Android 使用实例 Home · Tencent/wcdb Wikihttps://github.com/Tencent/wcdb/wiki ...

  6. 【转】 Android常用实例—Alert Dialog的使用

    Android常用实例—Alert Dialog的使用 AlertDialog的使用很普遍,在应用中当你想要用户做出“是”或“否”或者其它各式各样的选择时,为了保持在同样的Activity和不改变用户 ...

  7. JSON的android应用实例

    JSON的android应用实例 Json在线解析器 下面是直接通过JUnit来测试直接通过API来解析Json数据 1.普通键值对象 2.Json数组对象 3.Json数组对象

  8. Android开发实例之miniTwitter登录界面的实现

    原文: http://www.jizhuomi.com/android/example/134.html 本文要演示的Android开发实例是如何完成一个Android中的miniTwitter登录界 ...

  9. android 教程实例系列

    用户界面部分学起来还真是无处下手哇,总不能一个控件发一篇文吧,略有点费时间啊...这个难道不是边用边学才给力吗..所以我打算从最实用的Button开始下手. 先贴几个链接,好东西: android用户 ...

随机推荐

  1. 关于kali安装vmware的坑,linux套路太深。

    http://www.linuxidc.com/Linux/2015-08/122240.htm 但是还有些坑 安装gcc5.4.1 apt-get install gcc-5 gcc-5所在目录 / ...

  2. VS2012 无法启动IIS Express Web服务器的解决方案

    本文转载:http://blog.csdn.net/hongleidy5000/article/details/22732621 打开VS2012解决方案资源管理器 -> 点选 Web 项目选择 ...

  3. Firemonkey的旁门左道[四]

    做开发,就是发现问题,解决问题,又发现问题...周而复始的循环 下面又应该是Firemonkey下的bug. 官方文档中描述: Using the FireMonkey TMenuBar's OSMe ...

  4. Linux的进程优先级-邹立巍

    http://liwei.life/2016/04/07/linux%E7%9A%84%E8%BF%9B%E7%A8%8B%E4%BC%98%E5%85%88%E7%BA%A7/

  5. cocos2d-x项目过程记录(跨平台iOS和Android)

    (原创作品,欢迎转载,注明出处,谢谢:http://www.cnblogs.com/binxindoudou/admin/EditPosts.aspx?postid=3205249) 1.配置环境,重 ...

  6. 关于cocostudio加载UI json CCUIHELPER未声明问题

    查看官方的文档,在文档的最后添加了如何加载项目.如下代码: UILayer* ul =UILayer::create(); ul->addWidget(CCUIHELPER->create ...

  7. HttpClient 发送图片

    var httpClient = new HttpClient(); using (FileStream fs = new FileStream("C:\\1.jpg", File ...

  8. js关于闭包的内存的问题--deep down

    js有一个东西叫做GC(garbage collection )垃圾回收机制;js中有两种类型:js基本数据类型,js引用类型; 当一个函数[对象]--引用类型被引用后,过后,出了它的功能之后,gc会 ...

  9. DownloadProvider调试

    由于身边的同事离职,最近又接手了一个模块,DownloadProvider, 也就是安卓中自带的下载管理.此模块的代码量比较少,但是最近阅读代码却发现还是由不少知识点的.之前同事在此模块做了一个关于D ...

  10. JavaScript_object基础

    之前写Java时老是有点蒙,大部分都是用jQuery,但原理还不是很清楚,最近一段时间在系统的学习JavaScript,有什么问题或错误请指出,多谢..................... Obje ...