You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
6.4 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd. 2020-2021. All rights reserved.
* Description: alsa_capture sample
* Author: audio
* Create: 2020-04-03
*/
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#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);
}