/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2020-2021. All rights reserved. * Description: alsa_capture sample * Author: audio * Create: 2020-04-03 */ #include #include #include #include #include #include #include #include #include #include "adp_common_ext.h" #include "securec.h" #include "karaoke.h" #include "uapi_sound.h" #define MIC_BUF_MAX_SIZE 1000 #define DEV_LEN 128 #define BAKE_100 100 #define BAKE_1000 1000 #define BAKE_S_TO_US 1000000LLU #define MIXER_FRAME_TIME 5 /* 5ms */ #define INTERVAL_TIME 10000 #define INTERVAL_COUNT 5000 static snd_pcm_t* chandle = TD_NULL; static td_s32 usb_mic_set_attr(snd_pcm_t* chandle, snd_pcm_hw_params_t* hardware_params, td_u32 *requested_rate, snd_pcm_uframes_t *buffer_size) { td_s32 ret; /* Set the interleaved read and write format. */ ret = snd_pcm_hw_params_set_access(chandle, hardware_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (ret < 0) { printf("Unable to configure PCM read/write format\n"); return -1; } ret = snd_pcm_hw_params_set_format(chandle, hardware_params, SND_PCM_FORMAT_S16_LE); if (ret < 0) { printf("Unable to configure PCM format\n"); return -1; } ret = snd_pcm_hw_params_set_channels(chandle, hardware_params, CHANNELS_2); if (ret < 0) { printf("Unable to set channel count to 1\n"); return -1; } printf("set channel count to 2\n"); ret = snd_pcm_hw_params_set_rate_near(chandle, hardware_params, requested_rate, 0); if (ret < 0) { printf("Unable to set sample rate to %u\n", *requested_rate); return -1; } else { printf("Set sample rate to %u HZ\n", *requested_rate); } ret = snd_pcm_hw_params_set_buffer_size_near(chandle, hardware_params, buffer_size); if (ret < 0) { printf("Unable to set buffer size to %d\n", (int)*buffer_size); return -1; } return TD_SUCCESS; } td_s32 usb_mic_dev_init(unsigned int card) { td_s32 ret; snd_pcm_hw_params_t* hardware_params = TD_NULL; td_u32 latency = 0; td_u32 period_time = 0; td_u32 requested_rate = UAPI_AUDIO_SAMPLE_RATE_48K; snd_pcm_uframes_t buffer_size = UAPI_AUDIO_SAMPLE_RATE_48K / BAKE_100 * sizeof(td_s16); td_char dev_name[DEV_LEN]; memset_s(dev_name, DEV_LEN *sizeof(td_char), 0, DEV_LEN); strcat_s(dev_name, sizeof(dev_name), "plughw:"); ret = strcat_s(dev_name, sizeof(dev_name), (card == 0) ? "0" : "1"); if (ret != 0) { return -1; } ret = snd_pcm_open(&chandle, dev_name, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC); if (ret != 0) { printf("snd_pcm_open failed\n"); return -1; } if (snd_pcm_hw_params_malloc(&hardware_params) < 0) { printf("Failed to allocate ALSA hardware parameters!"); return -1; } ret = snd_pcm_hw_params_any(chandle, hardware_params); if (ret < 0) { return -1; } ret = usb_mic_set_attr(chandle, hardware_params, &requested_rate, &buffer_size); if (ret != TD_SUCCESS) { return -1; } ret = snd_pcm_hw_params_get_buffer_time(hardware_params, &latency, NULL); if (ret < 0) { return -1; } buffer_size = latency / 4; /* 4 is num */ ret = snd_pcm_hw_params_set_period_time_near(chandle, hardware_params, &period_time, NULL); if (ret < 0) { return -1; } snd_pcm_hw_params(chandle, hardware_params); return 0; } td_void usb_mic_dev_deinit(td_void) { snd_pcm_close(chandle); } static td_void pcm_read(snd_pcm_t* chandle, char *mic_buf, td_u32 max_len) { td_s32 n; td_s32 frames = UAPI_AUDIO_SAMPLE_RATE_48K / BAKE_1000 * MIXER_FRAME_TIME; if (frames > max_len) { printf("invalid frames\n"); return; } do { n = snd_pcm_readi(chandle, mic_buf, frames); if (n < frames) { if (n < 0) { printf("snd_pcm_recover\n"); n = snd_pcm_recover(chandle, n, 0); } else { printf("snd_pcm_prepare, seem to not enough data \n"); n = snd_pcm_prepare(chandle); } } } while (n == -EAGAIN); } static td_void *alsa_capture_thread(td_void *args) { td_u64 start_time; td_u64 cur_time; td_u64 cost_time; td_u64 tmp; td_u64 total_cnt = 0; char mic_buf[MIC_BUF_MAX_SIZE]; sample_capture_ctx *ctx = (sample_capture_ctx *)args; td_u64 thread_time_a; td_u64 thread_time_b; struct timeval st_time_start, st_time_cur; struct timeval st_time_thread_a; gettimeofday(&st_time_start, NULL); start_time = st_time_start.tv_sec * BAKE_S_TO_US + st_time_start.tv_usec; thread_time_b = start_time; ctx->ao_frame.pcm_buffer = (td_s32 *)mic_buf; while (ctx->stop == TD_FALSE) { pcm_read(chandle, mic_buf, MIC_BUF_MAX_SIZE); gettimeofday(&st_time_thread_a, NULL); thread_time_a = st_time_thread_a.tv_sec * BAKE_S_TO_US + st_time_thread_a.tv_usec; if (thread_time_a - thread_time_b > INTERVAL_TIME) { printf("[%llu]Mic Test Waring: Waiting too long(%llu) for alsa data!\n", total_cnt, thread_time_a - thread_time_b); } thread_time_b = thread_time_a; uapi_snd_send_track_data(ctx->track_id, &ctx->ao_frame); total_cnt++; if (total_cnt % INTERVAL_COUNT == 0) { gettimeofday(&st_time_cur, NULL); cur_time = st_time_cur.tv_sec * BAKE_S_TO_US + st_time_cur.tv_usec; cost_time = cur_time - start_time; tmp = total_cnt * MIXER_FRAME_TIME * BAKE_1000; printf("total_cnt = %llu data time = %llu cost time = %llu Delta=%lld\n", total_cnt, tmp, cost_time, cost_time - tmp); } } usb_mic_dev_deinit(); return TD_NULL; } td_void capture_sample_start(sample_capture_ctx *ctx) { if (ctx == TD_NULL) { return; } ctx->stop = TD_FALSE; pthread_create(&ctx->thread, TD_NULL, alsa_capture_thread, ctx); } td_void capture_sample_stop(sample_capture_ctx *ctx) { if (ctx == TD_NULL) { return; } ctx->stop = TD_TRUE; pthread_join(ctx->thread, TD_NULL); }