#include #include #include struct rt_hwparams { snd_pcm_format_t format; unsigned int channels; unsigned int rate; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; }; pthread_t play_thread; pthread_t capture_thread; pthread_attr_t play_thread_attr; struct sched_param play_schedule_param; pthread_attr_t capture_thread_attr; struct sched_param capture_schedule_param; void *func_play_demo(void *arg); void *func_play_hub_demo(void *arg); void *func_capture_demo(void *arg); void *func_capture_sync_demo(void *arg); int main(void) { pthread_attr_init(&play_thread_attr); play_schedule_param.sched_priority = 88; pthread_attr_setinheritsched(&play_thread_attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(&play_thread_attr, SCHED_RR); pthread_attr_setschedparam(&play_thread_attr, &play_schedule_param); pthread_attr_init(&capture_thread_attr); capture_schedule_param.sched_priority = 88; pthread_attr_setinheritsched(&capture_thread_attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(&capture_thread_attr, SCHED_RR); pthread_attr_setschedparam(&capture_thread_attr, &capture_schedule_param); // pthread_create(&play_thread, &play_thread_attr, func_play_demo, &play_schedule_param); pthread_create(&play_thread, &play_thread_attr, func_play_hub_demo, &play_schedule_param); // pthread_create(&capture_thread, &capture_thread_attr, func_capture_demo, &capture_schedule_param); pthread_create(&capture_thread, &capture_thread_attr, func_capture_sync_demo, &capture_schedule_param); pthread_join(play_thread, NULL); pthread_join(capture_thread, NULL); printf("main exit\n"); return 0; } static int rt_snd_pcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, snd_pcm_hw_params_t *hw_params, struct rt_hwparams *hwparams) { int ret; ret = snd_pcm_open(pcmp, name, stream, mode); if (ret < 0) { printf("snd_pcm_open failed: %d.\n", ret); goto err_pcm_open; } ret = snd_pcm_hw_params_any(*pcmp, hw_params); if (ret < 0) { printf("snd_pcm_hw_params_any failed: %d.\n", ret); goto err_pcm_hw_params; } ret = snd_pcm_hw_params_set_access(*pcmp, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (ret < 0) { printf("snd_pcm_hw_params_set_access failed: %d.\n", ret); goto err_pcm_hw_params; } ret = snd_pcm_hw_params_set_format(*pcmp, hw_params, hwparams->format); if (ret < 0) { printf("snd_pcm_hw_params_set_format failed: %d.\n", ret); goto err_pcm_hw_params; } ret = snd_pcm_hw_params_set_channels(*pcmp, hw_params, hwparams->channels); if (ret < 0) { printf("snd_pcm_hw_params_set_channels failed: %d.\n", ret); goto err_pcm_hw_params; } ret = snd_pcm_hw_params_set_rate(*pcmp, hw_params, hwparams->rate, 0); if (ret < 0) { printf("snd_pcm_hw_params_set_rate failed: %d.\n", ret); goto err_pcm_hw_params; } ret = snd_pcm_hw_params_set_buffer_size(*pcmp, hw_params, hwparams->buffer_size); if (ret < 0) { printf("snd_pcm_hw_params_set_buffer_size failed: %d.\n", ret); goto err_pcm_hw_params; } ret = snd_pcm_hw_params_set_period_size(*pcmp, hw_params, hwparams->period_size, 0); if (ret < 0) { printf("snd_pcm_hw_params_set_period_size failed: %d.\n", ret); goto err_pcm_hw_params; } ret = snd_pcm_hw_params(*pcmp, hw_params); if (ret < 0) { printf("snd_pcm_hw_params failed: %d.\n", ret); goto err_pcm_hw_params; } return 0; err_pcm_hw_params: snd_pcm_close(*pcmp); err_pcm_open: return -1; } static void rt_snd_pcm_close(snd_pcm_t *pcmp) { if (pcmp) snd_pcm_close(pcmp); } static int rt_mixer_cset(const char *card_name, const char *str, const char *value) { int i, err; static char card[64] = "default"; static snd_ctl_t *handle = NULL; snd_ctl_elem_info_t *info; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *control; snd_ctl_elem_info_alloca(&info); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_value_alloca(&control); i = snd_card_get_index(card_name); if (i >= 0 && i < 32) sprintf(card, "hw:%i", i); else { fprintf(stderr, "Invalid card number.\n"); return -EINVAL; } if (snd_ctl_ascii_elem_id_parse(id, str)) { fprintf(stderr, "Wrong control identifier: %s\n", str); return -EINVAL; } if (handle == NULL && (err = snd_ctl_open(&handle, card, 0)) < 0) { printf("Control %s open error: %s\n", card, snd_strerror(err)); return err; } snd_ctl_elem_info_set_id(info, id); if ((err = snd_ctl_elem_info(handle, info)) < 0) { printf("Cannot find the given element from control %s\n", card); snd_ctl_close(handle); handle = NULL; return err; } snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */ snd_ctl_elem_value_set_id(control, id); if ((err = snd_ctl_elem_read(handle, control)) < 0) { snd_ctl_close(handle); handle = NULL; return err; } err = snd_ctl_ascii_value_parse(handle, control, info, value); if (err < 0) { snd_ctl_close(handle); handle = NULL; return err; } if ((err = snd_ctl_elem_write(handle, control)) < 0) { snd_ctl_close(handle); handle = NULL; return err; } snd_ctl_close(handle); handle = NULL; return 0; } /* base. * 1. card -> audiocodec * 2. asound.conf -> default card should be audiocodec, and hooks to open the playback control * * process. * 1. open pcm file * 2. open and set hw_params audiocodec card * 3. read pcm file data and write to audiocodec card pcm device * 4. close audiocodec card * * ex. * channel -> 1 * sample bit -> 16 * sample rate -> 16K * period size -> 1024 * period count -> 4 */ void *func_play_demo(void *arg) { int ret; FILE *fp_play = NULL; size_t fp_read_size; size_t fp_read_num; snd_pcm_t *play_handle = NULL; char *data = NULL; snd_pcm_sframes_t num_write; snd_pcm_hw_params_t *hw_params = NULL; struct rt_hwparams rt_hwparam = { .channels = 1, .format = SND_PCM_FORMAT_S16_LE, .rate = 16000, .buffer_size = 4096, .period_size = 1024, }; fp_play = fopen("play_mono_16k.pcm","rb"); if (!fp_play) { printf("fopen _failed.\n"); goto err_fopen; } printf("play start\n"); ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) { printf("snd_pcm_hw_params_malloc failed: %d.\n", ret); goto err_pcm_hw_params_malloc; } ret = rt_snd_pcm_open(&play_handle, "default", SND_PCM_STREAM_PLAYBACK, 0, hw_params, &rt_hwparam); if (ret < 0) { printf("rt_snd_pcm_open failed: %d.\n", ret); goto err_rt_snd_pcm_open; } fp_read_size = snd_pcm_frames_to_bytes(play_handle, rt_hwparam.period_size); data = (char *)malloc(fp_read_size); if (data == NULL) { printf("malloc failed\n"); goto err_malloc; } do { fp_read_num = fread(data, 1, fp_read_size, fp_play); if (fp_read_num < fp_read_size) { printf("fread failed: %zu\n", fp_read_num); goto err_pcm_writei; } num_write = snd_pcm_writei(play_handle, data, rt_hwparam.period_size); if (num_write < 0) { printf("snd_pcm_writei failed: %s\n", snd_strerror(num_write)); goto err_pcm_writei; } } while (!feof(fp_play)); snd_pcm_drain(play_handle); err_pcm_writei: if (data) free(data); err_malloc: rt_snd_pcm_close(play_handle); err_rt_snd_pcm_open: snd_pcm_hw_params_free(hw_params); err_pcm_hw_params_malloc: if(fp_play) fclose(fp_play); err_fopen: printf("play exit\n"); pthread_exit(NULL); } /* base. * 1. card -> audiocodec * 2. asound.conf -> default card should be audiocodec, and hooks to open the capture control * * process. * 1. open new pcm file * 2. open and set hw_params audiocodec card * 4. read audiocodec card pcm device data and write to pcm file * 5. close audiocodec card * * ex. * channel -> 1 * sample bit -> 16 * sample rate -> 16K * period size -> 1024 * period count -> 4 */ void *func_capture_demo(void *arg) { int i, ret; FILE *fp_capture = NULL; size_t fp_write_size; size_t fp_write_num; snd_pcm_t *capture_handle = NULL; char *data = NULL; snd_pcm_sframes_t num_read; snd_pcm_hw_params_t *hw_params = NULL; struct rt_hwparams rt_hwparam = { .channels = 1, .format = SND_PCM_FORMAT_S16_LE, .rate = 16000, .buffer_size = 4096, .period_size = 1024, }; unsigned int capture_time = 500; fp_capture = fopen("capture_mono_16k.pcm","wb"); if (!fp_capture) { printf("fopen _failed.\n"); goto err_fopen; } printf("capture start\n"); ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) { printf("snd_pcm_hw_params_malloc failed: %d.\n", ret); goto err_pcm_hw_params_malloc; } ret = rt_snd_pcm_open(&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 0, hw_params, &rt_hwparam); if (ret < 0) { printf("rt_snd_pcm_open failed: %d.\n", ret); goto err_rt_snd_pcm_open; } fp_write_size = snd_pcm_frames_to_bytes(capture_handle, rt_hwparam.period_size); data = (char *)malloc(fp_write_size); if (data == NULL) { printf("malloc failed\n"); goto err_malloc; } for (i = 0; i < capture_time; i++) { num_read = snd_pcm_readi(capture_handle, data, rt_hwparam.period_size); if (num_read < 0) { printf("snd_pcm_readi failed: %s\n", snd_strerror(num_read)); goto err_pcm_readi; } fp_write_num = fwrite(data, 1, fp_write_size, fp_capture); if (fp_write_num != fp_write_size) { printf("fwrite failed: %zu\n", fp_write_num); goto err_pcm_readi; } } snd_pcm_drain(capture_handle); err_pcm_readi: if (data) free(data); err_malloc: err_rt_snd_pcm_open: snd_pcm_hw_params_free(hw_params); err_pcm_hw_params_malloc: if(fp_capture) fclose(fp_capture); err_fopen: printf("capture exit\n"); pthread_exit(NULL); } /* base. * 1. card -> audiocodec & snddaudio0 * 2. card func -> audiocodec & snddaudio0 whit "tx hub mode" controls * 3. asound.conf -> default card should be audiocodec, and hooks to open the playback control * * process. * 1. open pcm file * 2. set audiocodec & snddaudio0 card "tx hub mode" control to "On" * 3. open and set hw_params audiocodec & snddaudio0 card * 4. read pcm file data and write to audiocodec card pcm device * 5. close audiocodec & snddaudio0 card * * ex. * channel -> 1 * sample bit -> 16 * sample rate -> 16K * period size -> 1024 * period count -> 4 */ void *func_play_hub_demo(void *arg) { int ret; FILE *fp_play = NULL; size_t fp_read_size; size_t fp_read_num; snd_pcm_t *play_handle = NULL; snd_pcm_t *play_hub_handle = NULL; char *data = NULL; snd_pcm_sframes_t num_write; snd_pcm_hw_params_t *hw_params = NULL; struct rt_hwparams rt_hwparam = { .channels = 1, .format = SND_PCM_FORMAT_S16_LE, .rate = 16000, .buffer_size = 4096, .period_size = 1024, }; fp_play = fopen("play_mono_16k.pcm","rb"); if (!fp_play) { printf("fopen _failed.\n"); goto err_fopen; } printf("capture control set start\n"); ret = rt_mixer_cset("audiocodec", "name='tx hub mode'", "On"); if (ret < 0) { printf("rt_mixer_cset failed: %d.\n", ret); goto err_mixer_cset; } ret = rt_mixer_cset("snddaudio0", "name='tx hub mode'", "On"); if (ret < 0) { printf("rt_mixer_cset failed: %d.\n", ret); goto err_mixer_cset; } printf("capture control set exit\n"); printf("play start\n"); ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) { printf("snd_pcm_hw_params_malloc failed: %d.\n", ret); goto err_pcm_hw_params_malloc; } ret = rt_snd_pcm_open(&play_handle, "default", SND_PCM_STREAM_PLAYBACK, 0, hw_params, &rt_hwparam); if (ret < 0) { printf("rt_snd_pcm_open failed: %d.\n", ret); goto err_rt_snd_pcm_open; } ret = rt_snd_pcm_open(&play_hub_handle, "hw:snddaudio0,0", SND_PCM_STREAM_PLAYBACK, 0, hw_params, &rt_hwparam); if (ret < 0) { printf("rt_snd_pcm_open failed: %d.\n", ret); goto err_rt_snd_pcm_open; } fp_read_size = snd_pcm_frames_to_bytes(play_handle, rt_hwparam.period_size); data = (char *)malloc(fp_read_size); if (data == NULL) { printf("malloc failed\n"); goto err_malloc; } do { fp_read_num = fread(data, 1, fp_read_size, fp_play); if (fp_read_num < fp_read_size) { printf("fread failed: %zu\n", fp_read_num); goto err_pcm_writei; } num_write = snd_pcm_writei(play_handle, data, rt_hwparam.period_size); if (num_write < 0) { printf("snd_pcm_writei failed: %s\n", snd_strerror(num_write)); goto err_pcm_writei; } } while (!feof(fp_play)); snd_pcm_drain(play_handle); err_pcm_writei: if (data) free(data); err_malloc: rt_snd_pcm_close(play_hub_handle); rt_snd_pcm_close(play_handle); err_rt_snd_pcm_open: snd_pcm_hw_params_free(hw_params); err_pcm_hw_params_malloc: err_mixer_cset: if(fp_play) fclose(fp_play); err_fopen: printf("play exit\n"); pthread_exit(NULL); } /* base. * 1. card -> audiocodec & snddaudio0 * 2. card func -> audiocodec & snddaudio0 whit "rx sync mode" controls * 3. asound.conf -> default card should be multi audiocodec & snddaudio0, and hooks to open the capture control; * * process. * 1. open pcm file * 2. set audiocodec & snddaudio0 card "rx sync mode" control to "On" * 3. open and set hw_params default card * 4. read default card pcm device data and write to pcm file * 5. close default card * * ex. * channel -> 2 * sample bit -> 16 * sample rate -> 16K * period size -> 1024 * period count -> 4 */ void *func_capture_sync_demo(void *arg) { int i, ret; FILE *fp_capture = NULL; size_t fp_write_size; size_t fp_write_num; snd_pcm_t *capture_handle = NULL; char *data = NULL; snd_pcm_sframes_t num_read; snd_pcm_hw_params_t *hw_params = NULL; struct rt_hwparams rt_hwparam = { .channels = 2, .format = SND_PCM_FORMAT_S16_LE, .rate = 16000, .buffer_size = 4096, .period_size = 1024, }; unsigned int capture_time = 500; fp_capture = fopen("capture_stereo_16k.pcm","wb"); if (!fp_capture) { printf("fopen _failed.\n"); goto err_fopen; } printf("capture control set start\n"); ret = rt_mixer_cset("audiocodec", "name='rx sync mode'", "On"); if (ret < 0) { printf("rt_mixer_cset failed: %d.\n", ret); goto err_mixer_cset; } ret = rt_mixer_cset("snddaudio0", "name='rx sync mode'", "On"); if (ret < 0) { printf("rt_mixer_cset failed: %d.\n", ret); goto err_mixer_cset; } printf("capture control set exit\n"); printf("capture start\n"); ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) { printf("snd_pcm_hw_params_malloc failed: %d.\n", ret); goto err_pcm_hw_params_malloc; } ret = rt_snd_pcm_open(&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 0, hw_params, &rt_hwparam); if (ret < 0) { printf("rt_snd_pcm_open failed: %d.\n", ret); goto err_rt_snd_pcm_open; } fp_write_size = snd_pcm_frames_to_bytes(capture_handle, rt_hwparam.period_size); data = (char *)malloc(fp_write_size); if (data == NULL) { printf("malloc failed\n"); goto err_malloc; } for (i = 0; i < capture_time; i++) { num_read = snd_pcm_readi(capture_handle, data, rt_hwparam.period_size); if (num_read < 0) { printf("snd_pcm_readi failed: %s\n", snd_strerror(num_read)); goto err_pcm_readi; } fp_write_num = fwrite(data, 1, fp_write_size, fp_capture); if (fp_write_num != fp_write_size) { printf("fwrite failed: %zu\n", fp_write_num); goto err_pcm_readi; } } snd_pcm_drain(capture_handle); err_pcm_readi: if (data) free(data); err_malloc: err_rt_snd_pcm_open: snd_pcm_hw_params_free(hw_params); err_pcm_hw_params_malloc: err_mixer_cset: if(fp_capture) fclose(fp_capture); err_fopen: printf("capture exit\n"); pthread_exit(NULL); }