音频之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:

#include <stdio.h>
#include <pthread.h>
#include <math.h>
#include <system/audio.h>
#include <media/AudioRecord.h>
#include <media/AudioTrack.h>

using namespace android;

sp<AudioRecord> mAudioRecord;
sp<AudioTrack> mAudioTrack;
FILE *g_read_pcm = NULL;
FILE *g_write_pcm = NULL;
audio_channel_mask_t channelmask = AUDIO_CHANNEL_IN_MONO;
audio_format_t audio_format = AUDIO_FORMAT_PCM_16_BIT;
int sample_rate = 16000;
int min_buf_size = 0;

void read_audio_data(int event, void *user, void *info)
{
    if (event != AudioRecord::EVENT_MORE_DATA) {
        printf("%s: event: %d\n", __FUNCTION__, event);
        return;
    }

    AudioRecord::Buffer *buffer = static_cast<AudioRecord::Buffer *>(info);
    if (buffer->size == 0) {
        return;
    }

    //printf("%s: buf size: %d\n", __FUNCTION__, buffer->size);
    fwrite(buffer->raw, buffer->size, 1, g_write_pcm);
}

//read from soundcard and write into file
int ndk_audio_read()
{
    int ret = 0;
    char file[256] = {'\0'};
    size_t frame_count = 0;
    int frame_size = 0;
    String16  strName = String16("reader");

    mAudioRecord = new AudioRecord(strName);

    mAudioRecord.get();

    status_t result = AudioRecord::getMinFrameCount(&frame_count, sample_rate,
                    audio_format, channelmask);
    if (result == NO_ERROR) {
        int channel_count = popcount(channelmask);
        min_buf_size = frame_count * channel_count * (audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
    } else if (result == BAD_VALUE) {
        printf("Invalid param when get min frame count\n");
        return -1;
    } else {
        printf("Faield to get min frame count\n");
        return -1;
    }

    min_buf_size *= 2;// To prevent "buffer overflow" issue

    if (min_buf_size > 0) {
        printf("get min buf size[%d]\n", min_buf_size);
    } else {
        printf("get min buf size failed\n");
        return -1;
    }

    frame_size = popcount(channelmask) * (audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
    frame_count = min_buf_size / frame_size;

    ret = mAudioRecord->set(
        AUDIO_SOURCE_MIC,
        sample_rate,
        audio_format,
        channelmask,
        frame_count,
        read_audio_data,
        NULL,
        0,
        false,
        AUDIO_SESSION_ALLOCATE,
        AudioRecord::TRANSFER_CALLBACK,
        AUDIO_INPUT_FLAG_FAST,
        getuid(),
        getpid(),
        NULL,
        AUDIO_PORT_HANDLE_NONE);
    if (ret != NO_ERROR) {
        printf("AudioRecord set failure\n");
        return -1;
    }
    else
    {
        printf("set success\n");
    }

    if (mAudioRecord->initCheck() != NO_ERROR) {
        printf("AudioRecord initialization failed!");
        return -1;
    }

    snprintf(file, 256, "/data/ndksound.pcm");
    g_write_pcm = fopen(file, "wb");

    ret = mAudioRecord->start();
    if (ret != NO_ERROR) {
        printf("Audio Record start failure ret: [%d]", ret);
    }

    return 0;
}

void write_audio_data(int event, void *user, void *info)
{
    if (event != AudioTrack::EVENT_MORE_DATA) {
        printf("soundcard writer event: %d\n", event);
        return;
    }

    AudioTrack::Buffer *buffer = static_cast<AudioTrack::Buffer *>(info);
    if (buffer->size == 0) {
        return;
    }
    memset(buffer->raw, 0, buffer->size);

    int ret = fread(buffer->raw, 1, buffer->size, g_read_pcm);
    if (ret <= 0) {
        printf("%s: no more data:%d\n", __FUNCTION__, ret);
        exit(1);
    }
}

//read from file and write into soundcard
int ndk_audio_write()
{
    int ret = 0;
    char file[256] = {'\0'};
    size_t frame_count = 0;
    int frame_size = 0;

    mAudioTrack = new AudioTrack();
    mAudioTrack.get();

    status_t result = AudioTrack::getMinFrameCount(&frame_count, AUDIO_STREAM_DEFAULT,
                    sample_rate);
    if (result == NO_ERROR) {
        int channel_count = popcount(channelmask);
        min_buf_size = frame_count * channel_count * (audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
    } else if (result == BAD_VALUE) {
        printf("Invalid param when get min frame count\n");
        return -1;
    } else {
        printf("Faield to get min frame count\n");
        return -1;
    }

    if (min_buf_size > 0) {
        printf("get min buf size[%d]\n", min_buf_size);
    } else {
        printf("get min buf size failed\n");
        return -1;
    }

    channelmask = AUDIO_CHANNEL_OUT_MONO;
    frame_size = popcount(channelmask) * (audio_format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
    frame_count = min_buf_size / frame_size;

    ret = mAudioTrack->set(
            AUDIO_STREAM_VOICE_CALL,
            sample_rate,
            audio_format,
            channelmask,
            frame_count,
            AUDIO_OUTPUT_FLAG_FAST,
            write_audio_data,
            NULL,
            0,
            0,
            false,
            AUDIO_SESSION_ALLOCATE,
            AudioTrack::TRANSFER_CALLBACK,
            NULL,
            -1
        );
    if (ret != NO_ERROR) {
        printf("mAudioTrack set failure\n");
        return -1;
    }
    else
    {
        printf("set success\n");
    }

    if (mAudioTrack->initCheck() != NO_ERROR) {
        printf("mAudioTrack initialization failed!");
        return -1;
    }

    snprintf(file, 256, "/data/ndksound.pcm");
    g_read_pcm = fopen(file, "rb");
    if (!g_read_pcm) {
        printf("open file failed\n");
        return -1;
    }

    ret = mAudioTrack->start();
    if (ret != NO_ERROR) {
        printf("Audio Track start failure ret: [%d]", ret);
        return -1;
    }

    printf("start success\n");
    return 0;
}

int main(int argc, char *argv[])
{
    int ret = 0;

    if (argc < 2) {
        printf("need 2 param\n");
        return -1;
    }
    if (0 == strcmp(argv[1], "read")) {
        printf("read soundcard\n");
        ret = ndk_audio_read();
        if (ret < 0) {
            exit(1);
        }
    } else {
        printf("write soundcard\n");
        ret = ndk_audio_write();
        if (ret < 0) {
            exit(1);
        }
    }

    while (1) {
        sleep(5);
    }

    if (g_read_pcm) {
        fclose(g_read_pcm);
    }

    if (g_write_pcm) {
        fclose(g_write_pcm);
    }

	return 0;
}

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES += \
    src/audio_main.cpp

LOCAL_C_INCLUDES += \
    bionic \
    external/stlport/stlport \
    external/libcxx/include \
    frameworks/av/include \
    frameworks/av/media/libaudioclient/include \
    frameworks/native/libs/nativebase/include \
    frameworks/native/libs/math/include \
    frameworks/av/media/ndk/include \
    system/core/include \
    system/core/libprocessgroup/include \
    system/core/base/include \
    system/core/libutils/include \

LOCAL_CFLAGS := -DANDROID -Wall -Wno-implicit-function-declaration  -Wl,--unresolved-symbols=ignore-all


LOCAL_MODULE := ndk_audio
LOCAL_LDLIBS := -lm -lmediandk -landroid -laudioclient -lstdc++ -lutils

include $(BUILD_EXECUTABLE)
  • demo运行

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

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪游东戴河

你就是这个世界的唯一

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值