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
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);
|
|
}
|