• 音频之Android NDK读写声卡


    通过Android NDK读写声卡通过 AudioRecord和AudioTrack两个类实现。

    AudioTrack:负责声音数据的输出
    AudioRecord:负责声音数据的采集

    • 相关头文件位置

     system/media/audio/include/system
     ├── audio-base.h
    ├── audio-base-utils.h
    ├── audio_effect-base.h
    ├── audio_effect.h
    ├── audio_effects
    ├── audio.h
    ├── audio_policy.h
    └── sound_trigger.h

    音频源:
    typedef enum {
        AUDIO_SOURCE_DEFAULT = 0, //默认输入源
        AUDIO_SOURCE_MIC = 1, //Microphone audio source 麦克风输入源
        AUDIO_SOURCE_VOICE_UPLINK = 2, //Voice call uplink (Tx) audio source 语音呼叫上行(Tx)输入源
        AUDIO_SOURCE_VOICE_DOWNLINK = 3, //Voice call downlink (Rx) audio source 语音呼叫下行(Rx)输入源
        AUDIO_SOURCE_VOICE_CALL = 4,     //Voice call uplink + downlink audio source 语音呼叫上下行输入源
        AUDIO_SOURCE_CAMCORDER = 5,      //Microphone audio source tuned for video recording 视频录制的麦克风音频源
        AUDIO_SOURCE_VOICE_RECOGNITION = 6, //Microphone audio source tuned for voice recognition 针对语音唤醒的输入源
        AUDIO_SOURCE_VOICE_COMMUNICATION = 7, //Microphone audio source tuned for voice communications such as VoIP 针对VOIP语音的输入源
        AUDIO_SOURCE_REMOTE_SUBMIX = 8,
        AUDIO_SOURCE_UNPROCESSED = 9,
        AUDIO_SOURCE_VOICE_PERFORMANCE = 10,
        AUDIO_SOURCE_ECHO_REFERENCE = 1997,
        AUDIO_SOURCE_FM_TUNER = 1998,
    #ifndef AUDIO_NO_SYSTEM_DECLARATIONS
        /**
         * A low-priority, preemptible audio source for for background software
         * hotword detection. Same tuning as VOICE_RECOGNITION.
         * Used only internally by the framework.
         */
        AUDIO_SOURCE_HOTWORD = 1999,
    #endif // AUDIO_NO_SYSTEM_DECLARATIONS
    } audio_source_t;


    typedef enum {
        AUDIO_SESSION_OUTPUT_STAGE = -1, // (-1)
        AUDIO_SESSION_OUTPUT_MIX = 0,
        AUDIO_SESSION_ALLOCATE = 0,
        AUDIO_SESSION_NONE = 0,
    } audio_session_t;

    //音频格式
    typedef enum {//省略部分定义
        AUDIO_FORMAT_INVALID             = 0xFFFFFFFFu,
        AUDIO_FORMAT_DEFAULT             = 0,
        AUDIO_FORMAT_PCM                 = 0x00000000u,
        AUDIO_FORMAT_MP3                 = 0x01000000u,
        AUDIO_FORMAT_AMR_NB              = 0x02000000u,
        /* Subformats */
        AUDIO_FORMAT_PCM_SUB_16_BIT        = 0x1u, 
        AUDIO_FORMAT_PCM_SUB_8_BIT         = 0x2u,
        AUDIO_FORMAT_PCM_SUB_32_BIT        = 0x3u,
        AUDIO_FORMAT_PCM_SUB_8_24_BIT      = 0x4u,
        AUDIO_FORMAT_PCM_SUB_FLOAT         = 0x5u,
        AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED = 0x6u,

        /* Aliases */
        AUDIO_FORMAT_PCM_16_BIT            = 0x1u,        // (PCM | PCM_SUB_16_BIT) //PCM16位
        AUDIO_FORMAT_PCM_8_BIT             = 0x2u,        // (PCM | PCM_SUB_8_BIT)  //PCM 8位
        AUDIO_FORMAT_PCM_32_BIT            = 0x3u,        // (PCM | PCM_SUB_32_BIT)
        AUDIO_FORMAT_PCM_8_24_BIT          = 0x4u,        // (PCM | PCM_SUB_8_24_BIT)
        AUDIO_FORMAT_PCM_FLOAT             = 0x5u,        // (PCM | PCM_SUB_FLOAT)
        AUDIO_FORMAT_PCM_24_BIT_PACKED     = 0x6u,        // (PCM | PCM_SUB_24_BIT_PACKED)
        AUDIO_FORMAT_AAC_MAIN              = 0x4000001u,  // (AAC | AAC_SUB_MAIN)
        AUDIO_FORMAT_AAC_LC                = 0x4000002u,  // (AAC | AAC_SUB_LC)
        AUDIO_FORMAT_AAC_SSR               = 0x4000004u,  // (AAC | AAC_SUB_SSR)
      
    } audio_format_t;


    enum {//省略部分定义
        AUDIO_CHANNEL_REPRESENTATION_POSITION   = 0x0u,
        AUDIO_CHANNEL_REPRESENTATION_INDEX      = 0x2u,
        AUDIO_CHANNEL_NONE                      = 0x0u,
        AUDIO_CHANNEL_INVALID                   = 0xC0000000u,

        AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1u,
        AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2u,
        AUDIO_CHANNEL_IN_TOP_RIGHT              = 0x400000u,
        AUDIO_CHANNEL_IN_VOICE_UPLINK           = 0x4000u,
        AUDIO_CHANNEL_IN_VOICE_DNLINK           = 0x8000u,
        AUDIO_CHANNEL_IN_MONO                   = 0x10u,     // IN_FRONT         //单声道
        AUDIO_CHANNEL_IN_STEREO                 = 0xCu,      // IN_LEFT | IN_RIGHT   立体声
        AUDIO_CHANNEL_IN_FRONT_BACK             = 0x30u,     // IN_FRONT | IN_BACK
        AUDIO_CHANNEL_IN_6                      = 0xFCu,     // IN_LEFT | IN_RIGHT | IN_FRONT | IN_BACK | IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED
        AUDIO_CHANNEL_IN_2POINT0POINT2          = 0x60000Cu, // IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT
        AUDIO_CHANNEL_IN_2POINT1POINT2          = 0x70000Cu, // IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY
        AUDIO_CHANNEL_IN_3POINT0POINT2          = 0x64000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT
        AUDIO_CHANNEL_IN_3POINT1POINT2          = 0x74000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY
        AUDIO_CHANNEL_IN_5POINT1                = 0x17000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY
        AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO      = 0x4010u,   // IN_VOICE_UPLINK | IN_MONO
        AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO      = 0x8010u,   // IN_VOICE_DNLINK | IN_MONO
        AUDIO_CHANNEL_IN_VOICE_CALL_MONO        = 0xC010u,   // IN_VOICE_UPLINK_MONO | IN_VOICE_DNLINK_MONO
    };


    typedef enum {
        AUDIO_INPUT_FLAG_NONE       = 0x0,
        AUDIO_INPUT_FLAG_FAST       = 0x1,
        AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2,
        AUDIO_INPUT_FLAG_RAW        = 0x4,
        AUDIO_INPUT_FLAG_SYNC       = 0x8,
        AUDIO_INPUT_FLAG_MMAP_NOIRQ = 0x10,
        AUDIO_INPUT_FLAG_VOIP_TX    = 0x20,
        AUDIO_INPUT_FLAG_HW_AV_SYNC = 0x40,
    #ifndef AUDIO_NO_SYSTEM_DECLARATIONS  // TODO: Expose at HAL interface, remove FRAMEWORK_FLAGS mask
        AUDIO_INPUT_FLAG_DIRECT     = 0x80,
        AUDIO_INPUT_FRAMEWORK_FLAGS = AUDIO_INPUT_FLAG_DIRECT,
    #endif
    } audio_input_flags_t;

        
    enum {
        AUDIO_IO_HANDLE_NONE = 0,
        AUDIO_MODULE_HANDLE_NONE = 0,
        AUDIO_PORT_HANDLE_NONE = 0,
        AUDIO_PATCH_HANDLE_NONE = 0,
    };


    TRANSFER_CALLBACK    通过回调函数传输数据
    TRANSFER_OBTAIN       
    TRANSFER_SYNC        
    TRANSFER_DEFAULT

    • demo源码:

    ├── Android.mk
    ├── include
    └── src
        └── audio_main.cpp

    audio_main.cpp:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. using namespace android;
    8. sp mAudioRecord;
    9. sp mAudioTrack;
    10. FILE *g_read_pcm = NULL;
    11. FILE *g_write_pcm = NULL;
    12. audio_channel_mask_t channelmask = AUDIO_CHANNEL_IN_MONO;
    13. audio_format_t audio_format = AUDIO_FORMAT_PCM_16_BIT;
    14. int sample_rate = 16000;
    15. int min_buf_size = 0;
    16. void read_audio_data(int event, void *user, void *info)
    17. {
    18. if (event != AudioRecord::EVENT_MORE_DATA) {
    19. printf("%s: event: %d\n", __FUNCTION__, event);
    20. return;
    21. }
    22. AudioRecord::Buffer *buffer = static_cast(info);
    23. if (buffer->size == 0) {
    24. return;
    25. }
    26. //printf("%s: buf size: %d\n", __FUNCTION__, buffer->size);
    27. fwrite(buffer->raw, buffer->size, 1, g_write_pcm);
    28. }
    29. //read from soundcard and write into file
    30. int ndk_audio_read()
    31. {
    32. int ret = 0;
    33. char file[256] = {'\0'};
    34. size_t frame_count = 0;
    35. int frame_size = 0;
    36. String16 strName = String16("reader");
    37. mAudioRecord = new AudioRecord(strName);
    38. mAudioRecord.get();
    39. status_t result = AudioRecord::getMinFrameCount(&frame_count, sample_rate,
    40. audio_format, channelmask);
    41. if (result == NO_ERROR) {
    42. int channel_count = popcount(channelmask);
    43. min_buf_size = frame_count * channel_count * (audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
    44. } else if (result == BAD_VALUE) {
    45. printf("Invalid param when get min frame count\n");
    46. return -1;
    47. } else {
    48. printf("Faield to get min frame count\n");
    49. return -1;
    50. }
    51. min_buf_size *= 2;// To prevent "buffer overflow" issue
    52. if (min_buf_size > 0) {
    53. printf("get min buf size[%d]\n", min_buf_size);
    54. } else {
    55. printf("get min buf size failed\n");
    56. return -1;
    57. }
    58. frame_size = popcount(channelmask) * (audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
    59. frame_count = min_buf_size / frame_size;
    60. ret = mAudioRecord->set(
    61. AUDIO_SOURCE_MIC,
    62. sample_rate,
    63. audio_format,
    64. channelmask,
    65. frame_count,
    66. read_audio_data,
    67. NULL,
    68. 0,
    69. false,
    70. AUDIO_SESSION_ALLOCATE,
    71. AudioRecord::TRANSFER_CALLBACK,
    72. AUDIO_INPUT_FLAG_FAST,
    73. getuid(),
    74. getpid(),
    75. NULL,
    76. AUDIO_PORT_HANDLE_NONE);
    77. if (ret != NO_ERROR) {
    78. printf("AudioRecord set failure\n");
    79. return -1;
    80. }
    81. else
    82. {
    83. printf("set success\n");
    84. }
    85. if (mAudioRecord->initCheck() != NO_ERROR) {
    86. printf("AudioRecord initialization failed!");
    87. return -1;
    88. }
    89. snprintf(file, 256, "/data/ndksound.pcm");
    90. g_write_pcm = fopen(file, "wb");
    91. ret = mAudioRecord->start();
    92. if (ret != NO_ERROR) {
    93. printf("Audio Record start failure ret: [%d]", ret);
    94. }
    95. return 0;
    96. }
    97. void write_audio_data(int event, void *user, void *info)
    98. {
    99. if (event != AudioTrack::EVENT_MORE_DATA) {
    100. printf("soundcard writer event: %d\n", event);
    101. return;
    102. }
    103. AudioTrack::Buffer *buffer = static_cast(info);
    104. if (buffer->size == 0) {
    105. return;
    106. }
    107. memset(buffer->raw, 0, buffer->size);
    108. int ret = fread(buffer->raw, 1, buffer->size, g_read_pcm);
    109. if (ret <= 0) {
    110. printf("%s: no more data:%d\n", __FUNCTION__, ret);
    111. exit(1);
    112. }
    113. }
    114. //read from file and write into soundcard
    115. int ndk_audio_write()
    116. {
    117. int ret = 0;
    118. char file[256] = {'\0'};
    119. size_t frame_count = 0;
    120. int frame_size = 0;
    121. mAudioTrack = new AudioTrack();
    122. mAudioTrack.get();
    123. status_t result = AudioTrack::getMinFrameCount(&frame_count, AUDIO_STREAM_DEFAULT,
    124. sample_rate);
    125. if (result == NO_ERROR) {
    126. int channel_count = popcount(channelmask);
    127. min_buf_size = frame_count * channel_count * (audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
    128. } else if (result == BAD_VALUE) {
    129. printf("Invalid param when get min frame count\n");
    130. return -1;
    131. } else {
    132. printf("Faield to get min frame count\n");
    133. return -1;
    134. }
    135. if (min_buf_size > 0) {
    136. printf("get min buf size[%d]\n", min_buf_size);
    137. } else {
    138. printf("get min buf size failed\n");
    139. return -1;
    140. }
    141. channelmask = AUDIO_CHANNEL_OUT_MONO;
    142. frame_size = popcount(channelmask) * (audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
    143. frame_count = min_buf_size / frame_size;
    144. ret = mAudioTrack->set(
    145. AUDIO_STREAM_VOICE_CALL,
    146. sample_rate,
    147. audio_format,
    148. channelmask,
    149. frame_count,
    150. AUDIO_OUTPUT_FLAG_FAST,
    151. write_audio_data,
    152. NULL,
    153. 0,
    154. 0,
    155. false,
    156. AUDIO_SESSION_ALLOCATE,
    157. AudioTrack::TRANSFER_CALLBACK,
    158. NULL,
    159. -1
    160. );
    161. if (ret != NO_ERROR) {
    162. printf("mAudioTrack set failure\n");
    163. return -1;
    164. }
    165. else
    166. {
    167. printf("set success\n");
    168. }
    169. if (mAudioTrack->initCheck() != NO_ERROR) {
    170. printf("mAudioTrack initialization failed!");
    171. return -1;
    172. }
    173. snprintf(file, 256, "/data/ndksound.pcm");
    174. g_read_pcm = fopen(file, "rb");
    175. if (!g_read_pcm) {
    176. printf("open file failed\n");
    177. return -1;
    178. }
    179. ret = mAudioTrack->start();
    180. if (ret != NO_ERROR) {
    181. printf("Audio Track start failure ret: [%d]", ret);
    182. return -1;
    183. }
    184. printf("start success\n");
    185. return 0;
    186. }
    187. int main(int argc, char *argv[])
    188. {
    189. int ret = 0;
    190. if (argc < 2) {
    191. printf("need 2 param\n");
    192. return -1;
    193. }
    194. if (0 == strcmp(argv[1], "read")) {
    195. printf("read soundcard\n");
    196. ret = ndk_audio_read();
    197. if (ret < 0) {
    198. exit(1);
    199. }
    200. } else {
    201. printf("write soundcard\n");
    202. ret = ndk_audio_write();
    203. if (ret < 0) {
    204. exit(1);
    205. }
    206. }
    207. while (1) {
    208. sleep(5);
    209. }
    210. if (g_read_pcm) {
    211. fclose(g_read_pcm);
    212. }
    213. if (g_write_pcm) {
    214. fclose(g_write_pcm);
    215. }
    216. return 0;
    217. }

    Android.mk

    1. LOCAL_PATH := $(call my-dir)
    2. include $(CLEAR_VARS)
    3. LOCAL_SRC_FILES += \
    4. src/audio_main.cpp
    5. LOCAL_C_INCLUDES += \
    6. bionic \
    7. external/stlport/stlport \
    8. external/libcxx/include \
    9. frameworks/av/include \
    10. frameworks/av/media/libaudioclient/include \
    11. frameworks/native/libs/nativebase/include \
    12. frameworks/native/libs/math/include \
    13. frameworks/av/media/ndk/include \
    14. system/core/include \
    15. system/core/libprocessgroup/include \
    16. system/core/base/include \
    17. system/core/libutils/include \
    18. LOCAL_CFLAGS := -DANDROID -Wall -Wno-implicit-function-declaration -Wl,--unresolved-symbols=ignore-all
    19. LOCAL_MODULE := ndk_audio
    20. LOCAL_LDLIBS := -lm -lmediandk -landroid -laudioclient -lstdc++ -lutils
    21. include $(BUILD_EXECUTABLE)
    • demo运行

    从声卡读声音数据写到文件: ./ndk_audio  read

    从文件读声音数据写到声卡: ./ndk_audio write

  • 相关阅读:
    【.net core】yisha框架单页面双列表联动效果示例
    pytest+allure生成测试报告
    一起Talk Android吧(第五百五十回:如何适配SplashScreen)
    C++从静态类型到单例模式
    零基础Linux_20(进程信号)内核态和用户态+处理信号+不可重入函数+volatile
    CSS - 移动端布局(二)移动端适配
    (undone) 如何计算 Hessian Matrix 海森矩阵 海塞矩阵
    【每日3题(3)】重新格式化电话号码
    TCP 和 UDP哪个更好
    Vue开发小注意点
  • 原文地址:https://blog.csdn.net/szkbsgy/article/details/126555114