/* * Copyright 2021 Rockchip Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif /* End of #ifdef __cplusplus */ #include #include #include #include #include #include #include #include #include #include #include "sample_comm.h" typedef struct _rkMpiCtx { SAMPLE_AI_CTX_S ai; SAMPLE_AENC_CTX_S aenc; } SAMPLE_MPI_CTX_S; static bool quit = false; static void sigterm_handler(int sig) { fprintf(stderr, "signal %d\n", sig); quit = true; } static RK_CODEC_ID_E code_type = RK_AUDIO_ID_MP2; #define MP3_PROFILE_LOW 1 typedef struct FreqIdx_ { RK_S32 u32SmpRate; RK_U8 u8FreqIdx; } FreqIdx; FreqIdx FreqIdxTbl[13] = {{96000, 0}, {88200, 1}, {64000, 2}, {48000, 3}, {44100, 4}, {32000, 5}, {24000, 6}, {22050, 7}, {16000, 8}, {12000, 9}, {11025, 10}, {8000, 11}, {7350, 12}}; static void GetHeader(RK_U8 *pu8Hdr, RK_S32 u32SmpRate, RK_U8 u8Channel, RK_U32 u32DataLen) { RK_U8 u8FreqIdx = 0; for (int i = 0; i < 13; i++) { if (u32SmpRate == FreqIdxTbl[i].u32SmpRate) { u8FreqIdx = FreqIdxTbl[i].u8FreqIdx; break; } } RK_U32 u32PacketLen = u32DataLen + 7; pu8Hdr[0] = 0xFF; pu8Hdr[1] = 0xF1; pu8Hdr[2] = ((MP3_PROFILE_LOW) << 6) + (u8FreqIdx << 2) + (u8Channel >> 2); pu8Hdr[3] = (((u8Channel & 3) << 6) + (u32PacketLen >> 11)); pu8Hdr[4] = ((u32PacketLen & 0x7FF) >> 3); pu8Hdr[5] = (((u32PacketLen & 7) << 5) + 0x1F); pu8Hdr[6] = 0xFC; } /****************************************************************************** * function : aenc thread ******************************************************************************/ static void *aenc_get_stream(void *pArgs) { SAMPLE_AENC_CTX_S *ctx = (SAMPLE_AENC_CTX_S *)(pArgs); RK_S32 s32Ret = RK_FAILURE; char name[256] = {0}; FILE *fp = RK_NULL; void *pData = RK_NULL; RK_S32 loopCount = 0; RK_U8 header[7]; if (ctx->dstFilePath) { snprintf(name, sizeof(name), "/%s/aenc_%d.bin", ctx->dstFilePath, ctx->s32ChnId); fp = fopen(name, "wb"); if (fp == RK_NULL) { printf("chn %d can't open %s file !\n", ctx->s32ChnId, ctx->dstFilePath); quit = true; return RK_NULL; } } while (!quit) { s32Ret = SAMPLE_COMM_AENC_GetStream(ctx, &pData); if (s32Ret == RK_SUCCESS) { // exit when complete if (ctx->s32loopCount > 0) { if (loopCount >= ctx->s32loopCount) { SAMPLE_COMM_AENC_ReleaseStream(ctx); quit = true; break; } } if (fp) { if (code_type == RK_AUDIO_ID_MP3) { GetHeader(header, ctx->stChnAttr.stCodecAttr.u32SampleRate, ctx->stChnAttr.stCodecAttr.u32Channels, ctx->stFrame.u32Len); fwrite(header, 1, 7, fp); } fwrite(pData, 1, ctx->stFrame.u32Len, fp); fflush(fp); } RK_LOGE("chn:%d, loopCount:%d wd:%d\n", ctx->s32ChnId, loopCount, ctx->stFrame.u32Len); SAMPLE_COMM_AENC_ReleaseStream(ctx); loopCount++; } usleep(1000); } if (fp) fclose(fp); return NULL; } static RK_CHAR optstr[] = "?::d:w:R:r:C:c:e:l:o:"; static void print_usage(const RK_CHAR *name) { printf("usage example:\n"); printf("\t%s -d default:CARD=rockchipes8388 -w 16bit -R 16000 -r 16000 -C 2 -c 2 -e " "mp2 -o /data/\n", name); printf("\t-d | --device_name: the sound name for open sound card, eg: " "default:CARD=rockchipes8388c Default(NULL)\n"); printf("\t-w | --bit_width: the bit width of open sound card, Default:16bit, " "Value:8bit, 16bit, 24bit\n"); printf("\t-R | --device_rate: the sample rate of open sound card, Default:16000\n"); printf("\t-r | --out_rate: the sample rate of out data, Default:16000\n"); printf("\t-C | --device_ch: the number of sound card channels, Default:2\n"); printf("\t-c | --out_ch: the channels of out data, Default:2\n"); printf("\t-e | --encode: encode type, Defaule:mp3, Value:mp3, mp2, g711a, g711u, " "g726\n"); printf("\t-l | --loop_count: loop running count, Default -1\n"); printf("\t-o | --output_path: encode save file path, Default /data/\n"); } int main(int argc, char *argv[]) { SAMPLE_MPI_CTX_S *ctx; MPP_CHN_S stSrcChn, stDestChn; RK_S32 s32DeviceChannel = 2; RK_S32 s32DeviceSampleRate = 16000; AUDIO_BIT_WIDTH_E bitWidth = AUDIO_BIT_WIDTH_16; RK_S32 s32SampleRate = 8000; AUDIO_SOUND_MODE_E soundMode = AUDIO_SOUND_MODE_STEREO; RK_S32 s32ChnCnt = 2; RK_S32 s32PeriodCount = 4; RK_S32 s32PeriodSize = 1024; RK_S32 s32loopCnt = -1; RK_CHAR *pCardName = NULL; RK_CHAR *pOutPath = NULL; int c; if (argc < 2) { print_usage(argv[0]); return 0; } ctx = (SAMPLE_MPI_CTX_S *)(malloc(sizeof(SAMPLE_MPI_CTX_S))); memset(ctx, 0, sizeof(SAMPLE_MPI_CTX_S)); signal(SIGINT, sigterm_handler); while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'd': pCardName = optarg; break; case 'r': s32SampleRate = atoi(optarg); break; case 'R': s32DeviceSampleRate = atoi(optarg); break; case 'c': s32ChnCnt = atoi(optarg); break; case 'C': s32DeviceChannel = atoi(optarg); break; case 'w': if (!strcmp(optarg, "8bit")) { bitWidth = AUDIO_BIT_WIDTH_8; } else if (!strcmp(optarg, "16bit")) { bitWidth = AUDIO_BIT_WIDTH_16; } else if (!strcmp(optarg, "24bit")) { bitWidth = AUDIO_BIT_WIDTH_24; } break; case 'o': pOutPath = optarg; break; case 'e': if (!strcmp(optarg, "mp2")) { code_type = RK_AUDIO_ID_MP2; } else if (!strcmp(optarg, "mp3")) { code_type = RK_AUDIO_ID_MP3; } else if (!strcmp(optarg, "g726")) { code_type = RK_AUDIO_ID_ADPCM_G726; } else if (!strcmp(optarg, "g711a")) { code_type = RK_AUDIO_ID_PCM_ALAW; } else if (!strcmp(optarg, "g711u")) { code_type = RK_AUDIO_ID_PCM_MULAW; } break; case 'l': s32loopCnt = atoi(optarg); break; case '?': default: print_usage(argv[0]); return 0; } } if (s32ChnCnt == 1) { soundMode = AUDIO_SOUND_MODE_MONO; } else if (s32ChnCnt == 2) { soundMode = AUDIO_SOUND_MODE_STEREO; } else { printf("%s channel = %d not support\n", __func__, s32ChnCnt); return 0; } printf("#Device: %s\n", pCardName); printf("#SampleRate: %d\n", s32SampleRate); printf("#Channel Count: %d\n", s32ChnCnt); printf("#Loop Count: %d\n", s32loopCnt); printf("#Output Path: %s\n", pOutPath); printf("#code_type: %d\n", code_type); RK_MPI_SYS_Init(); // Init AI[0] ctx->ai.s32DevId = 0; ctx->ai.s32ChnId = 0; ctx->ai.stAiAttr.soundCard.channels = s32DeviceChannel; ctx->ai.stAiAttr.soundCard.sampleRate = s32DeviceSampleRate; ctx->ai.stAiAttr.soundCard.bitWidth = bitWidth; ctx->ai.stAiAttr.enBitwidth = bitWidth; ctx->ai.stAiAttr.enSamplerate = (AUDIO_SAMPLE_RATE_E)s32SampleRate; ctx->ai.stAiAttr.enSoundmode = soundMode; ctx->ai.stAiAttr.u32FrmNum = s32PeriodCount; ctx->ai.stAiAttr.u32PtNumPerFrm = s32PeriodSize; ctx->ai.stAiAttr.u32EXFlag = 0; ctx->ai.stAiAttr.u32ChnCnt = s32ChnCnt; if (pCardName) { strcpy(ctx->ai.stAiAttr.u8CardName, pCardName); } SAMPLE_COMM_AI_CreateChn(&ctx->ai); // Init AENC[0] ctx->aenc.s32ChnId = 0; ctx->aenc.s32loopCount = s32loopCnt; ctx->aenc.stChnAttr.enType = code_type; ctx->aenc.stChnAttr.stCodecAttr.u32Channels = s32ChnCnt; ctx->aenc.stChnAttr.stCodecAttr.u32SampleRate = s32SampleRate; ctx->aenc.stChnAttr.stCodecAttr.enBitwidth = bitWidth; ctx->aenc.stChnAttr.u32BufCount = 4; ctx->aenc.dstFilePath = pOutPath; SAMPLE_COMM_AENC_CreateChn(&ctx->aenc); // Bind AI[0] and AENC[0] stSrcChn.enModId = RK_ID_AI; stSrcChn.s32DevId = ctx->ai.s32DevId; stSrcChn.s32ChnId = ctx->ai.s32ChnId; stDestChn.enModId = RK_ID_AENC; stDestChn.s32DevId = 0; stDestChn.s32ChnId = ctx->aenc.s32ChnId; SAMPLE_COMM_Bind(&stSrcChn, &stDestChn); pthread_t getStreamThread; pthread_create(&getStreamThread, NULL, aenc_get_stream, (void *)(&ctx->aenc)); printf("%s initial finish\n", __func__); while (!quit) { usleep(500000); } printf("%s exit!\n", __func__); pthread_join(getStreamThread, NULL); // UnBind AI[0] and AENC[0] stSrcChn.enModId = RK_ID_AI; stSrcChn.s32DevId = ctx->ai.s32DevId; stSrcChn.s32ChnId = ctx->ai.s32ChnId; stDestChn.enModId = RK_ID_AENC; stDestChn.s32DevId = 0; stDestChn.s32ChnId = ctx->aenc.s32ChnId; SAMPLE_COMM_UnBind(&stSrcChn, &stDestChn); // Destroy AENC[0] SAMPLE_COMM_AENC_DestroyChn(&ctx->aenc); // Destroy AI[0] SAMPLE_COMM_AI_DestroyChn(&ctx->ai); RK_MPI_SYS_Exit(); return 0; } #ifdef __cplusplus #if __cplusplus } #endif #endif /* End of #ifdef __cplusplus */