// Copyright 2020 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include #include #include #include #include #include #define MP3_NB_SAMPLES 1024 #define MP2_NB_SAMPLES 1152 //#define ALSA_PATH "default:CARD=rockchiprk809co" // get from "arecord -L" #define ALSA_PATH "hw:0,0" // get from "arecord -L" #define VQEFILE "/sdcard/RKAP_3A_Para.bin" static bool quit = false; static void sigterm_handler(int sig) { fprintf(stderr, "signal %d\n", sig); quit = true; } FILE *fp = NULL; static RK_U32 g_enWorkSampleRate = 16000; static RK_U32 g_s32VqeFrameSample = 256; // 20ms; static RK_U32 g_s32AiLayout = AI_LAYOUT_MIC_REF; static void audio_packet_cb(MEDIA_BUFFER mb) { printf("Get Audio Encoded packet:ptr:%p, fd:%d, size:%zu, mode:%d\n", RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetFD(mb), RK_MPI_MB_GetSize(mb), RK_MPI_MB_GetModeID(mb)); fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), fp); RK_MPI_MB_ReleaseBuffer(mb); } static RK_VOID AI_AO() { RK_MPI_SYS_Init(); MPP_CHN_S mpp_chn_ai, mpp_chn_ao; mpp_chn_ai.enModId = RK_ID_AI; mpp_chn_ai.s32ChnId = 0; mpp_chn_ao.enModId = RK_ID_AO; mpp_chn_ao.s32ChnId = 0; AI_CHN_ATTR_S ai_attr; ai_attr.pcAudioNode = ALSA_PATH; ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16; ai_attr.u32NbSamples = 1152; ai_attr.u32SampleRate = g_enWorkSampleRate; ai_attr.u32Channels = 1; ai_attr.enAiLayout = g_s32AiLayout; // chanel layout: [ref:mic]; remove // ref, output mic mono AO_CHN_ATTR_S ao_attr; ao_attr.pcAudioNode = ALSA_PATH; ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16; ao_attr.u32NbSamples = 1152; ao_attr.u32SampleRate = g_enWorkSampleRate; ao_attr.u32Channels = 1; // 1. create AI RK_MPI_AI_SetChnAttr(mpp_chn_ai.s32ChnId, &ai_attr); RK_MPI_AI_EnableChn(mpp_chn_ai.s32ChnId); RK_MPI_AI_SetVolume(mpp_chn_ai.s32ChnId, 100); // 2. create AO RK_MPI_AO_SetChnAttr(mpp_chn_ao.s32ChnId, &ao_attr); RK_MPI_AO_EnableChn(mpp_chn_ao.s32ChnId); RK_MPI_AO_SetVolume(mpp_chn_ao.s32ChnId, 100); // 3. bind AI-AO RK_MPI_SYS_Bind(&mpp_chn_ai, &mpp_chn_ao); printf("%s initial finish\n", __func__); signal(SIGINT, sigterm_handler); while (!quit) { usleep(500000); } printf("%s exit!\n", __func__); RK_MPI_SYS_UnBind(&mpp_chn_ai, &mpp_chn_ao); RK_MPI_AI_DisableChn(mpp_chn_ai.s32ChnId); RK_MPI_AO_DisableChn(mpp_chn_ao.s32ChnId); } static RK_VOID AI_AENC_FILE(char *file_path) { fp = fopen(file_path, "w+"); RK_MPI_SYS_Init(); MPP_CHN_S mpp_chn_ai, mpp_chn_aenc; mpp_chn_ai.enModId = RK_ID_AI; mpp_chn_ai.s32ChnId = 0; mpp_chn_aenc.enModId = RK_ID_AENC; mpp_chn_aenc.s32ChnId = 0; AI_CHN_ATTR_S ai_attr; ai_attr.pcAudioNode = ALSA_PATH; ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16; ai_attr.u32NbSamples = MP3_NB_SAMPLES; ai_attr.u32SampleRate = g_enWorkSampleRate; ai_attr.u32Channels = 1; ai_attr.enAiLayout = g_s32AiLayout; // chanel layout: [ref:mic]; remove // ref, output mic mono AENC_CHN_ATTR_S aenc_attr; aenc_attr.enCodecType = RK_CODEC_TYPE_MP3; aenc_attr.u32Bitrate = 64000; aenc_attr.u32Quality = 1; aenc_attr.stAencMP3.u32Channels = 1; aenc_attr.stAencMP3.u32SampleRate = g_enWorkSampleRate; // 1. create AI RK_MPI_AI_SetChnAttr(mpp_chn_ai.s32ChnId, &ai_attr); RK_MPI_AI_EnableChn(mpp_chn_ai.s32ChnId); // 2. create AENC RK_MPI_AENC_CreateChn(mpp_chn_aenc.s32ChnId, &aenc_attr); RK_U32 ret = RK_MPI_SYS_RegisterOutCb(&mpp_chn_aenc, audio_packet_cb); printf("ret = %d.\n", ret); // 3. bind AI-AENC RK_MPI_SYS_Bind(&mpp_chn_ai, &mpp_chn_aenc); printf("%s initial finish\n", __func__); signal(SIGINT, sigterm_handler); while (!quit) { usleep(500000); } RK_MPI_SYS_UnBind(&mpp_chn_ai, &mpp_chn_aenc); RK_MPI_AI_DisableChn(mpp_chn_ai.s32ChnId); RK_MPI_AENC_DestroyChn(mpp_chn_aenc.s32ChnId); fclose(fp); } static RK_VOID FILE_ADEC_AO(char *file_path) { CODEC_TYPE_E codec_type = RK_CODEC_TYPE_MP3; RK_U32 channels = 2; RK_U32 sample_rate = g_enWorkSampleRate; ADEC_CHN_ATTR_S stAdecAttr; AO_CHN_ATTR_S stAoAttr; stAdecAttr.enCodecType = codec_type; MPP_CHN_S mpp_chn_ao, mpp_chn_adec; mpp_chn_ao.enModId = RK_ID_AO; mpp_chn_ao.s32ChnId = 0; mpp_chn_adec.enModId = RK_ID_ADEC; mpp_chn_adec.s32ChnId = 0; stAoAttr.u32Channels = channels; stAoAttr.u32SampleRate = sample_rate; stAoAttr.u32NbSamples = 1024; stAoAttr.pcAudioNode = ALSA_PATH; switch (codec_type) { case RK_CODEC_TYPE_MP3: stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16; stAoAttr.u32NbSamples = 1024; break; case RK_CODEC_TYPE_MP2: stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16; stAoAttr.u32NbSamples = 1152; break; case RK_CODEC_TYPE_G711A: stAdecAttr.stAdecG711A.u32Channels = channels; stAdecAttr.stAdecG711A.u32SampleRate = sample_rate; stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16; break; case RK_CODEC_TYPE_G711U: stAdecAttr.stAdecG711U.u32Channels = channels; stAdecAttr.stAdecG711U.u32SampleRate = sample_rate; stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16; break; case RK_CODEC_TYPE_G726: stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16; break; default: printf("audio codec type error.\n"); return; } // init MPI RK_MPI_SYS_Init(); // create ADEC RK_MPI_ADEC_CreateChn(mpp_chn_adec.s32ChnId, &stAdecAttr); // create AO RK_MPI_AO_SetChnAttr(mpp_chn_ao.s32ChnId, &stAoAttr); RK_MPI_AO_EnableChn(mpp_chn_ao.s32ChnId); RK_MPI_SYS_Bind(&mpp_chn_adec, &mpp_chn_ao); RK_S32 buffer_size = 20480; FILE *read_file = fopen(file_path, "r"); if (!read_file) { printf("ERROR: open %s failed!\n", file_path); exit(0); } quit = true; while (quit) { MEDIA_BUFFER mb = RK_MPI_MB_CreateAudioBuffer(buffer_size, RK_FALSE); if (!mb) { printf("ERROR: no space left!\n"); break; } RK_S32 s32ReadSize = fread(RK_MPI_MB_GetPtr(mb), 1, buffer_size, read_file); RK_MPI_MB_SetSize(mb, s32ReadSize); RK_MPI_SYS_SendMediaBuffer(RK_ID_ADEC, mpp_chn_adec.s32ChnId, mb); RK_MPI_MB_ReleaseBuffer(mb); if (s32ReadSize != buffer_size) { printf("Get end of file!\n"); break; } } sleep(2); { // flush decoder printf("start flush decoder.\n"); MEDIA_BUFFER mb = RK_MPI_MB_CreateAudioBuffer(buffer_size, RK_FALSE); RK_MPI_MB_SetSize(mb, 0); RK_MPI_SYS_SendMediaBuffer(RK_ID_ADEC, mpp_chn_adec.s32ChnId, mb); RK_MPI_MB_ReleaseBuffer(mb); printf("end flush decoder.\n"); } sleep(10); } /* 0: close, 1: talk, 2: record */ static RK_U32 u32AiVqeType = 1; /* 0: close, 1: open */ static RK_U32 u32AoVqeType = 1; /****************************************************************************** * function : Ai ->VqeProcess-> Ao ******************************************************************************/ RK_S32 AI_VqeProcess_AO(RK_VOID) { AI_TALKVQE_CONFIG_S stAiVqeTalkAttr; AI_RECORDVQE_CONFIG_S stAiVqeRecordAttr; AO_VQE_CONFIG_S stAoVqeAttr; MPP_CHN_S mpp_chn_ai, mpp_chn_ao; if (1 == u32AiVqeType) { memset(&stAiVqeTalkAttr, 0, sizeof(AI_TALKVQE_CONFIG_S)); stAiVqeTalkAttr.s32WorkSampleRate = g_enWorkSampleRate; stAiVqeTalkAttr.s32FrameSample = g_s32VqeFrameSample; strcpy(stAiVqeTalkAttr.aParamFilePath, VQEFILE); stAiVqeTalkAttr.u32OpenMask = AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_AGC; } else if (2 == u32AiVqeType) { memset(&stAiVqeRecordAttr, 0, sizeof(AI_RECORDVQE_CONFIG_S)); stAiVqeRecordAttr.s32WorkSampleRate = g_enWorkSampleRate; stAiVqeRecordAttr.s32FrameSample = g_s32VqeFrameSample; stAiVqeRecordAttr.stAnrConfig.fPostAddGain = 0; stAiVqeRecordAttr.stAnrConfig.fGmin = -30; stAiVqeRecordAttr.stAnrConfig.fNoiseFactor = 0.98; stAiVqeRecordAttr.u32OpenMask = AI_RECORDVQE_MASK_ANR; } if (1 == u32AoVqeType) { memset(&stAoVqeAttr, 0, sizeof(AO_VQE_CONFIG_S)); stAoVqeAttr.s32WorkSampleRate = g_enWorkSampleRate; stAoVqeAttr.s32FrameSample = g_s32VqeFrameSample; strcpy(stAoVqeAttr.aParamFilePath, VQEFILE); stAoVqeAttr.u32OpenMask = AO_VQE_MASK_ANR | AO_VQE_MASK_AGC; } RK_MPI_SYS_Init(); mpp_chn_ai.enModId = RK_ID_AI; mpp_chn_ai.s32ChnId = 0; mpp_chn_ao.enModId = RK_ID_AO; mpp_chn_ao.s32ChnId = 0; AI_CHN_ATTR_S ai_attr; ai_attr.pcAudioNode = ALSA_PATH; ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16; ai_attr.u32NbSamples = 1024; ai_attr.u32SampleRate = g_enWorkSampleRate; ai_attr.u32Channels = 2; ai_attr.enAiLayout = g_s32AiLayout; // remove ref channel, and output mic mono AO_CHN_ATTR_S ao_attr; ao_attr.pcAudioNode = ALSA_PATH; ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16; ao_attr.u32NbSamples = 1024; ao_attr.u32SampleRate = g_enWorkSampleRate; ao_attr.u32Channels = 2; // 1. create AI RK_MPI_AI_SetChnAttr(mpp_chn_ai.s32ChnId, &ai_attr); RK_MPI_AI_EnableChn(mpp_chn_ai.s32ChnId); //RK_MPI_AI_SetVolume(mpp_chn_ai.s32ChnId, 100); if (1 == u32AiVqeType) { RK_MPI_AI_SetTalkVqeAttr(mpp_chn_ai.s32ChnId, &stAiVqeTalkAttr); RK_MPI_AI_EnableVqe(mpp_chn_ai.s32ChnId); } else if (2 == u32AiVqeType) { RK_MPI_AI_SetRecordVqeAttr(mpp_chn_ai.s32ChnId, &stAiVqeRecordAttr); RK_MPI_AI_EnableVqe(mpp_chn_ai.s32ChnId); } // 2. create AO RK_MPI_AO_SetChnAttr(mpp_chn_ao.s32ChnId, &ao_attr); RK_MPI_AO_EnableChn(mpp_chn_ao.s32ChnId); //RK_MPI_AO_SetVolume(mpp_chn_ao.s32ChnId, 100); if (1 == u32AoVqeType) { RK_MPI_AO_SetVqeAttr(mpp_chn_ao.s32ChnId, &stAoVqeAttr); RK_MPI_AO_EnableVqe(mpp_chn_ao.s32ChnId); } // 3. bind AI-AO RK_MPI_SYS_Bind(&mpp_chn_ai, &mpp_chn_ao); printf("%s initial finish\n", __func__); signal(SIGINT, sigterm_handler); while (!quit) { usleep(500000); } printf("%s exit!\n", __func__); RK_MPI_SYS_UnBind(&mpp_chn_ai, &mpp_chn_ao); RK_MPI_AI_DisableChn(mpp_chn_ai.s32ChnId); RK_MPI_AO_DisableChn(mpp_chn_ao.s32ChnId); return RK_SUCCESS; } static RK_VOID RKMEDIA_AUDIO_Usage() { printf("\n\n/Usage:./rkmdia_audio [filePath]/ " "[nbsamples] [ailayout]\n"); printf("\tindex and its function list below\n"); printf("\t0: start AI to AO loop\n"); printf("\t1: send audio frame to AENC channel from AI, save them\n"); printf("\t2: read audio stream from file, decode and send AO\n"); printf("\t3: start AI(VQE process), then send to AO\n"); // printf("\t4: start AI to Extern Resampler\n"); printf("\n"); printf("\tsampleRate list:\n"); printf("\t0 16000 22050 24000 32000 44100 48000\n"); printf("\n"); printf("\tfilePath represents the path of audio file to be decoded, only for " "sample 2.\n"); printf("\tdefault filePath: /userdata/out.mp2\n"); printf("\n"); printf("\tnbsamples, for example: 160 is 10ms at 16kHz\n"); printf("\n"); printf("\tailayout:\n"); printf("\t0: AI_LAYOUT_NORMAL\n"); printf("\t1: AI_LAYOUT_MIC_REF\n"); printf("\t2: AI_LAYOUT_REF_MIC\n"); printf("\t3: AI_LAYOUT_2MIC_REF_NONE\n"); printf("\t4: AI_LAYOUT_2MIC_NONE_REF\n"); printf("\t5: AI_LAYOUT_2MIC_2REF\n"); printf("\t6: AI_LAYOUT_BUTT\n"); printf("\n"); printf("\texample: ./rkmdia_audio 0 48000 480 1 /tmp/out_aiao.mp2\n"); } int main(int argc, char *argv[]) { RK_U32 u32Index; RK_CHAR *pFilePath = RK_NULL; if (!(argc >= 3 && argc <= 6)) { RKMEDIA_AUDIO_Usage(); return -1; } if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-?") == 0) { RKMEDIA_AUDIO_Usage(); return -1; } u32Index = atoi(argv[1]); g_enWorkSampleRate = atoi(argv[2]); switch (argc) { case 6: pFilePath = argv[5]; g_s32AiLayout = atoi(argv[4]); g_s32VqeFrameSample = atoi(argv[3]); break; case 5: g_s32AiLayout = atoi(argv[4]); g_s32VqeFrameSample = atoi(argv[3]); break; case 4: g_s32VqeFrameSample = atoi(argv[3]); break; default: pFilePath = (char *)"/tmp/out.mp2"; break; } switch (u32Index) { case 0: AI_AO(); break; case 1: AI_AENC_FILE(pFilePath); break; case 2: FILE_ADEC_AO(pFilePath); break; case 3: AI_VqeProcess_AO(); default: break; } return 0; }