xref: /OK3568_Linux_fs/external/rockit/mpi/example/mod/test_mpi_ai.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright 2020 Rockchip Electronics Co. LTD
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #include <stdio.h>
19 #include <errno.h>
20 #include <cstring>
21 #include <cstdlib>
22 #include <unistd.h>
23 #include <pthread.h>
24 #include <sys/poll.h>
25 #include "rk_defines.h"
26 #include "rk_debug.h"
27 #include "rk_mpi_ai.h"
28 #include "rk_mpi_sys.h"
29 #include "rk_mpi_mb.h"
30 
31 #include "test_comm_argparse.h"
32 
33 static RK_BOOL gAiExit = RK_FALSE;
34 #define TEST_AI_WITH_FD 0
35 
36 typedef struct _rkMpiAICtx {
37     const char *srcFilePath;
38     const char *dstFilePath;
39     RK_S32      s32LoopCount;
40     RK_S32      s32ChnNum;
41     RK_S32      s32DeviceSampleRate;
42     RK_S32      s32SampleRate;
43     RK_S32      s32DeviceChannel;
44     RK_S32      s32Channel;
45     RK_S32      s32BitWidth;
46     RK_S32      s32DevId;
47     RK_S32      s32PeriodCount;
48     RK_S32      s32PeriodSize;
49     char       *chCardName;
50     RK_S32      s32ChnIndex;
51     RK_S32      s32DevFd;
52 } TEST_AI_CTX_S;
53 
ai_find_sound_mode(RK_S32 ch)54 static AUDIO_SOUND_MODE_E ai_find_sound_mode(RK_S32 ch) {
55     AUDIO_SOUND_MODE_E channel = AUDIO_SOUND_MODE_BUTT;
56     switch (ch) {
57       case 1:
58         channel = AUDIO_SOUND_MODE_MONO;
59         break;
60       case 2:
61         channel = AUDIO_SOUND_MODE_STEREO;
62         break;
63       default:
64         RK_LOGE("channel = %d not support", ch);
65         return AUDIO_SOUND_MODE_BUTT;
66     }
67 
68     return channel;
69 }
70 
ai_find_bit_width(RK_S32 bit)71 static AUDIO_BIT_WIDTH_E ai_find_bit_width(RK_S32 bit) {
72     AUDIO_BIT_WIDTH_E bitWidth = AUDIO_BIT_WIDTH_BUTT;
73     switch (bit) {
74       case 8:
75         bitWidth = AUDIO_BIT_WIDTH_8;
76         break;
77       case 16:
78         bitWidth = AUDIO_BIT_WIDTH_16;
79         break;
80       case 24:
81         bitWidth = AUDIO_BIT_WIDTH_24;
82         break;
83       default:
84         RK_LOGE("bitwidth(%d) not support", bit);
85         return AUDIO_BIT_WIDTH_BUTT;
86     }
87 
88     return bitWidth;
89 }
90 
test_ai_poll_event(RK_S32 timeoutMsec,RK_S32 fd)91 RK_S32 test_ai_poll_event(RK_S32 timeoutMsec, RK_S32 fd) {
92     RK_S32 num_fds = 1;
93     struct pollfd pollFds[num_fds];
94     RK_S32 ret = 0;
95 
96     RK_ASSERT(fd > 0);
97     memset(pollFds, 0, sizeof(pollFds));
98     pollFds[0].fd = fd;
99     pollFds[0].events = (POLLPRI | POLLIN | POLLERR | POLLNVAL | POLLHUP);
100 
101     ret = poll(pollFds, num_fds, timeoutMsec);
102 
103     if (ret > 0 && (pollFds[0].revents & (POLLERR | POLLNVAL | POLLHUP))) {
104         RK_LOGE("fd:%d polled error", fd);
105         return -1;
106     }
107 
108     return ret;
109 }
110 
test_open_device_ai(TEST_AI_CTX_S * ctx)111 RK_S32 test_open_device_ai(TEST_AI_CTX_S *ctx) {
112     AUDIO_DEV aiDevId = ctx->s32DevId;
113     AUDIO_SOUND_MODE_E soundMode;
114 
115     AIO_ATTR_S aiAttr;
116     RK_S32 result;
117     memset(&aiAttr, 0, sizeof(AIO_ATTR_S));
118 
119     if (ctx->chCardName) {
120         snprintf(reinterpret_cast<char *>(aiAttr.u8CardName),
121                  sizeof(aiAttr.u8CardName), "%s", ctx->chCardName);
122     }
123 
124     aiAttr.soundCard.channels = ctx->s32DeviceChannel;
125     aiAttr.soundCard.sampleRate = ctx->s32DeviceSampleRate;
126     aiAttr.soundCard.bitWidth = AUDIO_BIT_WIDTH_16;
127 
128     AUDIO_BIT_WIDTH_E bitWidth = ai_find_bit_width(ctx->s32BitWidth);
129     if (bitWidth == AUDIO_BIT_WIDTH_BUTT) {
130         goto __FAILED;
131     }
132     aiAttr.enBitwidth = bitWidth;
133     aiAttr.enSamplerate = (AUDIO_SAMPLE_RATE_E)ctx->s32SampleRate;
134     soundMode = ai_find_sound_mode(ctx->s32Channel);
135     if (soundMode == AUDIO_SOUND_MODE_BUTT) {
136         goto __FAILED;
137     }
138     aiAttr.enSoundmode = soundMode;
139     aiAttr.u32FrmNum = ctx->s32PeriodCount;
140     aiAttr.u32PtNumPerFrm = ctx->s32PeriodSize;
141 
142     aiAttr.u32EXFlag = 0;
143     aiAttr.u32ChnCnt = 2;
144 
145     result = RK_MPI_AI_SetPubAttr(aiDevId, &aiAttr);
146     if (result != 0) {
147         RK_LOGE("ai set attr fail, reason = %d", result);
148         goto __FAILED;
149     }
150 
151     result = RK_MPI_AI_Enable(aiDevId);
152     if (result != 0) {
153         RK_LOGE("ai enable fail, reason = %d", result);
154         goto __FAILED;
155     }
156 
157     return RK_SUCCESS;
158 __FAILED:
159     return RK_FAILURE;
160 }
161 
test_init_mpi_ai(TEST_AI_CTX_S * params)162 RK_S32 test_init_mpi_ai(TEST_AI_CTX_S *params) {
163     RK_S32 result;
164 
165     result =  RK_MPI_AI_EnableChn(params->s32DevId, params->s32ChnIndex);
166     if (result != 0) {
167         RK_LOGE("ai enable channel fail, aoChn = %d, reason = %x", params->s32ChnIndex, result);
168         return RK_FAILURE;
169     }
170 
171 #if TEST_AI_WITH_FD
172     // open fd immediate after enable chn will be better.
173     params->s32DevFd = RK_MPI_AI_GetFd(params->s32DevId, params->s32ChnIndex);
174     RK_LOGI("ai (devId: %d, chnId: %d), selectFd:%d", params->s32DevId, params->s32ChnIndex, params->s32DevFd);
175 #endif
176 
177     result = RK_MPI_AI_EnableReSmp(params->s32DevId, params->s32ChnIndex,
178                                   (AUDIO_SAMPLE_RATE_E)params->s32SampleRate);
179     if (result != 0) {
180         RK_LOGE("ai enable channel fail, reason = %x, aoChn = %d", result, params->s32ChnIndex);
181         return RK_FAILURE;
182     }
183 
184     return RK_SUCCESS;
185 }
186 
test_deinit_mpi_ai(TEST_AI_CTX_S * params)187 RK_S32 test_deinit_mpi_ai(TEST_AI_CTX_S *params) {
188     RK_MPI_AI_DisableReSmp(params->s32DevId, params->s32ChnIndex);
189     RK_S32 result = RK_MPI_AI_DisableChn(params->s32DevId, params->s32ChnIndex);
190     if (result != 0) {
191         RK_LOGE("ai disable channel fail, reason = %d", result);
192         return RK_FAILURE;
193     }
194 
195     result =  RK_MPI_AI_Disable(params->s32DevId);
196     if (result != 0) {
197         RK_LOGE("ai disable fail, reason = %d", result);
198         return RK_FAILURE;
199     }
200 
201     return RK_SUCCESS;
202 }
203 
sendDataThread(void * ptr)204 void* sendDataThread(void * ptr) {
205     TEST_AI_CTX_S *params = reinterpret_cast<TEST_AI_CTX_S *>(ptr);
206 
207     RK_S32 result = 0;
208     RK_S32 s32MilliSec = -1;
209     AUDIO_FRAME_S frame;
210 
211     if (params->dstFilePath) {
212         AUDIO_SAVE_FILE_INFO_S save;
213         save.bCfg = RK_TRUE;
214         save.u32FileSize = 1024;
215         snprintf(save.aFilePath, sizeof(save.aFilePath), "%s", params->dstFilePath);
216         snprintf(save.aFileName, sizeof(save.aFileName), "%s", "cap_out.pcm");
217         RK_MPI_AI_SaveFile(params->s32DevId, params->s32ChnIndex, &save);
218     }
219 
220     while (!gAiExit) {
221 #if TEST_AI_WITH_FD
222         test_ai_poll_event(-1, params->s32DevFd);
223 #endif
224         result = RK_MPI_AI_GetFrame(params->s32DevId, params->s32ChnIndex, &frame, RK_NULL, s32MilliSec);
225         if (result == 0) {
226             void* data = RK_MPI_MB_Handle2VirAddr(frame.pMbBlk);
227             // get the length of valid data in this frame
228             RK_U64 len = RK_MPI_MB_GetLength(frame.pMbBlk);
229             RK_LOGV("data = %p, len = %lld", data, len);
230             RK_MPI_AI_ReleaseFrame(params->s32DevId, params->s32ChnIndex, &frame, RK_NULL);
231         }
232     }
233 
234     return RK_NULL;
235 }
236 
unit_test_mpi_ai(TEST_AI_CTX_S * ctx)237 RK_S32 unit_test_mpi_ai(TEST_AI_CTX_S *ctx) {
238     RK_S32 i = 0;
239     TEST_AI_CTX_S params[AI_MAX_CHN_NUM];
240     pthread_t tidSend[AI_MAX_CHN_NUM];
241     pthread_t tidComand[AI_MAX_CHN_NUM];
242 
243     if (test_open_device_ai(ctx) != RK_SUCCESS) {
244         goto __FAILED;
245     }
246 
247     for (i = 0; i < ctx->s32ChnNum; i++) {
248         memcpy(&(params[i]), ctx, sizeof(TEST_AI_CTX_S));
249         params[i].s32ChnIndex = i;
250         params[i].s32DevFd = -1;
251 
252         test_init_mpi_ai(&params[i]);
253         pthread_create(&tidSend[i], RK_NULL, sendDataThread, reinterpret_cast<void *>(&params[i]));
254     }
255 
256     for (i = 0; i < ctx->s32ChnNum; i++) {
257         pthread_join(tidSend[i], RK_NULL);
258         pthread_join(tidComand[i], RK_NULL);
259         test_deinit_mpi_ai(&params[i]);
260     }
261 
262     return RK_SUCCESS;
263 __FAILED:
264 
265     return RK_FAILURE;
266 }
267 
mpi_ai_test_show_options(const TEST_AI_CTX_S * ctx)268 static void mpi_ai_test_show_options(const TEST_AI_CTX_S *ctx) {
269     RK_PRINT("cmd parse result:\n");
270     RK_PRINT("input  file name      : %s\n", ctx->srcFilePath);
271     RK_PRINT("output file name      : %s\n", ctx->dstFilePath);
272     RK_PRINT("loop count            : %d\n", ctx->s32LoopCount);
273     RK_PRINT("channel number        : %d\n", ctx->s32ChnNum);
274     RK_PRINT("open sound rate       : %d\n", ctx->s32DeviceSampleRate);
275     RK_PRINT("record data rate      : %d\n", ctx->s32SampleRate);
276     RK_PRINT("sound card channel    : %d\n", ctx->s32DeviceChannel);
277     RK_PRINT("output channel        : %d\n", ctx->s32Channel);
278     RK_PRINT("bit_width             : %d\n", ctx->s32BitWidth);
279     RK_PRINT("period_count          : %d\n", ctx->s32PeriodCount);
280     RK_PRINT("period_size           : %d\n", ctx->s32PeriodSize);
281     RK_PRINT("sound card name       : %s\n", ctx->chCardName);
282     RK_PRINT("device id             : %d\n", ctx->s32DevId);
283 }
284 
285 static const char *const usages[] = {
286     "./rk_mpi_ai_test [--device_rate rate] [--device_ch ch] [--out_rate rate] [--out_ch ch]...",
287     NULL,
288 };
289 
main(int argc,const char ** argv)290 int main(int argc, const char **argv) {
291     RK_S32          i;
292     RK_S32          s32Ret;
293     TEST_AI_CTX_S  *ctx;
294 
295     ctx = reinterpret_cast<TEST_AI_CTX_S *>(malloc(sizeof(TEST_AI_CTX_S)));
296     memset(ctx, 0, sizeof(TEST_AI_CTX_S));
297 
298     ctx->srcFilePath        = RK_NULL;
299     ctx->dstFilePath        = RK_NULL;
300     ctx->s32LoopCount       = 1;
301     ctx->s32ChnNum          = 1;
302     ctx->s32BitWidth        = 16;
303     ctx->s32PeriodCount     = 4;
304     ctx->s32PeriodSize      = 1024;
305     ctx->chCardName         = RK_NULL;
306     ctx->s32DevId           = 0;
307 
308     struct argparse_option options[] = {
309         OPT_HELP(),
310         OPT_GROUP("basic options:"),
311 
312         OPT_INTEGER('\0', "device_rate", &(ctx->s32DeviceSampleRate),
313                     "the sample rate of open sound card.  <required>", NULL, 0, 0),
314         OPT_INTEGER('\0', "device_ch", &(ctx->s32DeviceChannel),
315                     "the number of sound card channels. <required>.", NULL, 0, 0),
316         OPT_INTEGER('\0', "out_ch", &(ctx->s32Channel),
317                     "the channels of out data. <required>", NULL, 0, 0),
318         OPT_INTEGER('\0', "out_rate", &(ctx->s32SampleRate),
319                     "the sample rate of out data. <required>", NULL, 0, 0),
320         OPT_STRING('o', "output", &(ctx->dstFilePath),
321                     "output file name, e.g.(./ai). default(NULL).", NULL, 0, 0),
322         OPT_INTEGER('n', "loop_count", &(ctx->s32LoopCount),
323                     "loop running count. can be any count. default(1)", NULL, 0, 0),
324         OPT_INTEGER('c', "channel_count", &(ctx->s32ChnNum),
325                     "the count of adec channel. default(1).", NULL, 0, 0),
326         OPT_INTEGER('\0', "bit", &(ctx->s32BitWidth),
327                     "the bit width of open sound card, range(8, 16, 24), default(16)", NULL, 0, 0),
328         OPT_INTEGER('\0', "period_size", &(ctx->s32PeriodSize),
329                     "the period size for open sound card, default(1024)", NULL, 0, 0),
330         OPT_INTEGER('\0', "period_count", &(ctx->s32PeriodCount),
331                     "the period count for open sound card, default(4)", NULL, 0, 0),
332         OPT_STRING('\0', "sound_card_name", &(ctx->chCardName),
333                     "the sound name for open sound card, default(NULL)", NULL, 0, 0),
334         OPT_END(),
335     };
336 
337     struct argparse argparse;
338     argparse_init(&argparse, options, usages, 0);
339     argparse_describe(&argparse, "\nselect a test case to run.",
340                                  "\nuse --help for details.");
341 
342     argc = argparse_parse(&argparse, argc, argv);
343     mpi_ai_test_show_options(ctx);
344 
345     if (ctx->s32Channel <= 0
346         || ctx->s32SampleRate <= 0
347         || ctx->s32DeviceSampleRate <= 0
348         || ctx->s32DeviceChannel <= 0) {
349         argparse_usage(&argparse);
350         goto __FAILED;
351     }
352 
353     RK_MPI_SYS_Init();
354 
355     for (i = 0; i < ctx->s32LoopCount; i++) {
356         RK_LOGI("start running loop count  = %d", i);
357         s32Ret = unit_test_mpi_ai(ctx);
358         if (s32Ret != RK_SUCCESS) {
359             goto __FAILED;
360         }
361         RK_LOGI("end running loop count  = %d", i);
362     }
363 
364 __FAILED:
365     if (ctx) {
366         free(ctx);
367         ctx = RK_NULL;
368     }
369 
370     RK_MPI_SYS_Exit();
371     return 0;
372 }
373