当前位置:   article > 正文

11. Android native层使用TrackPlayer播放pcm_audioplayer_to_android.cpp

audioplayer_to_android.cpp


 

《<Android音频>Android native层使用TrackPlayer播放pcm_》

《<Android音频> 直接使用AudioFlinger播放pcm》

目录

一:概述

二:实现

环境

源码

编译

运行结果

可能问题:


一:概述

这是一个c语言demo程序,android源码环境,编译得到 bin文件,push到设备上在shell环境运行,播放pcm数据。如果是app java开发,没有系统源码,就不建议往下看了。

android native播放音频,可以使用Ndk层提供的Opensl es、AAudio。
  如果是在源码级别,可以随意改,比如这里使用framework内部的 TrackPlayer类,经研究源码发现android 对Opensl es 的支持,内部有条通路最后是通过 使用framework native层的TrackPlayer 类,来播放pcm数据。(有关opensl android分析在其他文章再叙述)

二:实现

上demo:(github**暂未上传)

环境

  • ubuntu22.04 编译 aosp11 源码,得到emulator 运行。 
  • 编译本demo 得到  out/target/product/generic_x86_64/system/bin/TrackPlayerDemo 可执行程序,push到 emulator上运行。
  • 程序需要一个 48K,16bit, 双通道立体声的pcm 数据文件作为源,(可使用ffmpeg制作)

源码

main.cpp

  1. /*
  2. * canok 20220629
  3. * android aosp 11
  4. * 参照 android中对opensl的支持 源码
  5. * 使用TrackPlayer 播放pcm
  6. * 需要源码环境下编译。
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <iostream>
  11. #include <atomic>
  12. #include <thread>
  13. #include <media/TrackPlayerBase.h>
  14. using namespace android;
  15. struct PlayerData
  16. {
  17. FILE *fp_in = nullptr;
  18. std::atomic<bool> bEnd = false;
  19. };
  20. // namespace android
  21. // {
  22. // 在callback中写数据。
  23. static void audioTrack_callBack_pullFromBuffQueue(int event, void *user, void *info)
  24. {
  25. // printf("track[%s%d]\n",__FUNCTION__,__LINE__);
  26. PlayerData *data = (PlayerData *)user;
  27. if (data == nullptr)
  28. {
  29. printf("[%s%d] data =null \n", __FUNCTION__, __LINE__);
  30. return;
  31. }
  32. FILE *fp_in = data->fp_in;
  33. if (fp_in == NULL)
  34. {
  35. printf("[%s%d] fp_in =null \n", __FUNCTION__, __LINE__);
  36. return;
  37. }
  38. switch (event)
  39. {
  40. case android::AudioTrack::EVENT_MORE_DATA:
  41. {
  42. android::AudioTrack::Buffer *pBuff = (android::AudioTrack::Buffer *)info;
  43. size_t availSink = pBuff->size;
  44. // void *pSrc =
  45. // memcpy(pBuff->raw, pSrc, availSink);
  46. size_t ret = fread(pBuff->raw, 1, pBuff->size, fp_in);
  47. pBuff->size = ret;
  48. if (ret < 0)
  49. {
  50. data->bEnd = true;
  51. }
  52. std::cout << "read :" << ret << std::endl;
  53. }
  54. break;
  55. default:
  56. break;
  57. }
  58. }
  59. int main(int argc, const char *argv[])
  60. {
  61. // 使用的是一个 callback 的传输方式, 在AudioTrack的callback中写数据。// AudioPlayer_to_android.cpp audioTrack_callBack_pullFromBuffQueue
  62. // threadCanCallJava 在AudioTrack构造函数中调用set() 时给的是false: 而transferType AudioTrack构造函数中为 默认值为 TRANSFER_DEFAULT
  63. // 在set() 函数中会判断根据参数,最终将 transfertype设置为 TRASNFER_CALLBACk. :: ssharedBuffer==0 cbf !=NULL threadCanCallJava==false
  64. // 将会在 cballck 中得到EVENT_MORE_DATA 消息,然后这里面写数据
  65. PlayerData data;
  66. data.fp_in = fopen("yk_48000_2_16.pcm", "r");
  67. if (data.fp_in == nullptr)
  68. {
  69. printf("[%s%d]fopen failed ! we need a pcm src file!!!!!!\n", __FUNCTION__, __LINE__);
  70. return -1;
  71. }
  72. sp<android::AudioTrack> pat = new android::AudioTrack(
  73. AUDIO_STREAM_MUSIC, // pAudioPlayer->mStreamType, // streamType
  74. 48000, // sampleRate,
  75. AUDIO_FORMAT_PCM_16_BIT, // sles_to_android_sampleFormat(df_pcm), // format
  76. AUDIO_CHANNEL_OUT_STEREO, // channelMask, // channel mask
  77. 0, // frameCount
  78. AUDIO_OUTPUT_FLAG_NONE, // policy, // flags
  79. audioTrack_callBack_pullFromBuffQueue, // callback
  80. (void *)&data, // (void *) pAudioPlayer, // user // 自定义的数据!!!!!会在callback中得到这个参数
  81. 0, // notificationFrames, // see comment above
  82. AUDIO_SESSION_ALLOCATE // pAudioPlayer->mSessionId
  83. );
  84. sp<TrackPlayerBase> player = new TrackPlayerBase();
  85. player->init(pat.get(), PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE, AUDIO_USAGE_MEDIA);
  86. player->start();
  87. player->setVolume(01.0);
  88. while (!data.bEnd)
  89. {
  90. std::this_thread::yield();
  91. }
  92. fclose(data.fp_in);
  93. return 0;
  94. }
  95. // }

Android.bp

  1. cc_binary {
  2. name: "TrackPlayerDemo",
  3. srcs: [
  4. "main.cpp",
  5. ],
  6. shared_libs: [
  7. "libaudioclient",
  8. "libaudioutils",
  9. "libutils",
  10. "libbinder",
  11. "libmediametrics",
  12. ],
  13. header_libs: [
  14. "libmedia_headers",
  15. ],
  16. include_dirs: [
  17. "frameworks/av/media/libnbaio/include_mono/",
  18. ],
  19. cflags: [
  20. "-Wall",
  21. "-Werror",
  22. "-Wno-error=deprecated-declarations",
  23. "-Wno-unused-parameter",
  24. "-Wno-unused-variable",
  25. ],
  26. }

编译

两文件放到framework 一个自定义目录下, 经source lunch 编译环境的配置后,到该自定义子目录 mm -j8

运行结果

 emulator虚拟机可以听到播放的音频:

 

可能问题:

  无声,先要确保emulator 自身能发声,比如去设置里面改一下铃声,看是否有声音。要确保宿主机ubuntu有声音,  ubuntu系统可以在设置里面选择输出到hdmi,

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/318868
推荐阅读
相关标签