blob: 770ee4d5f25d4b9e17b7813c89c93fbccf267e8d [file] [log] [blame]
/*
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include "libaudiodev.h"
static unsigned int buffer_count;
static struct mutexed_buffer_s {
unsigned char *data;
pthread_mutex_t mutex;
pthread_cond_t has_data;
} *buffers;
/* Termination variable. */
static int terminate;
/* Buffer currently being captured to. */
static unsigned int buf_cap;
static void *play_loop(void *arg) {
audio_device_t * device = (audio_device_t *)arg;
unsigned int buf_play = 0;
while (!terminate) {
pthread_mutex_lock(&buffers[buf_play].mutex);
while (buf_cap == buf_play) {
pthread_cond_wait(&buffers[buf_play].has_data, &buffers[buf_play].mutex);
}
pcm_io(device, buffers[buf_play].data, chunk_size);
pthread_mutex_unlock(&buffers[buf_play].mutex);
buf_play = (buf_play + 1) % buffer_count;
}
return NULL;
}
static void *cap_loop(void *arg) {
audio_device_t *device = (audio_device_t *)arg;
int last;
while (!terminate) {
pthread_mutex_lock(&buffers[buf_cap].mutex);
pcm_io(device, buffers[buf_cap].data, chunk_size);
last = buf_cap;
buf_cap = (buf_cap + 1) % buffer_count;
pthread_cond_signal(&buffers[last].has_data);
pthread_mutex_unlock(&buffers[last].mutex);
}
return NULL;
}
static void signal_handler(int signal) {
printf("Signal Caught.\n");
terminate = 1;
}
static void dump_line(FILE *fp) {
int ch;
while ((ch = fgetc(fp)) != EOF && ch != '\n') {}
}
static void get_choice(char *direction_name, audio_device_list_t *list,
int *choice) {
int i;
while (1) {
printf("%s devices:\n", direction_name);
if (list->count == 0) {
printf("No devices :(\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < list->count; i++) {
printf("(%d)\nCard %d: %s, %s\n Device %d: %s [%s], %s", i + 1,
list->devs[i].card, list->devs[i].dev_id,
list->devs[i].dev_name, list->devs[i].dev_no,
list->devs[i].pcm_id, list->devs[i].pcm_name,
list->devs[i].hwdevname);
printf("\n");
}
printf("\nChoose one(1 - %d): ", list->count);
if (scanf("%d", choice) == 0) {
dump_line(stdin);
printf("\nThat was an invalid choice.\n");
} else if (*choice > 0 && *choice <= list->count) {
break;
} else {
printf("\nThat was an invalid choice.\n");
}
}
}
static void init_mutexed_buffers(int size) {
int i;
buffers = (struct mutexed_buffer_s *)malloc(buffer_count
* sizeof(struct mutexed_buffer_s));
if (!buffers) {
fprintf(stderr, "Error: Could not create audio buffer array.\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < buffer_count; i++) {
pthread_mutex_init(&buffers[i].mutex, NULL);
pthread_cond_init(&buffers[i].has_data, NULL);
buffers[i].data = (unsigned char *)malloc(size * sizeof(char));
if (!buffers[i].data) {
fprintf(stderr, "Error: Could not create audio buffers.\n");
exit(EXIT_FAILURE);
}
}
}
void test(int buffer_size, unsigned int ct, int pdev, int cdev) {
pthread_t capture_thread;
pthread_t playback_thread;
buffer_count = ct;
audio_device_list_t* playback_list = get_device_list(SND_PCM_STREAM_PLAYBACK);
audio_device_list_t* capture_list = get_device_list(SND_PCM_STREAM_CAPTURE);
if (pdev == -1) {
get_choice("playback", playback_list, &pdev);
} else if (pdev == 0 || pdev > playback_list->count) {
fprintf(stderr, "Invalid choice for playback device: %d\n", pdev);
return;
}
if (cdev == -1) {
get_choice("capture", capture_list, &cdev);
} else if (cdev == 0 || cdev > capture_list->count) {
fprintf(stderr, "Invalid ch oice for capture device: %d\n", cdev);
return;
}
init_mutexed_buffers(buffer_size);
terminate = 0;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGABRT, signal_handler);
if (create_sound_handle(&(playback_list->devs[pdev - 1]), buffer_size) ||
create_sound_handle(&(capture_list->devs[cdev - 1]), buffer_size))
exit(EXIT_FAILURE);
buf_cap = 0;
pthread_create(&playback_thread, NULL, play_loop,
&(playback_list->devs[pdev - 1]));
pthread_create(&capture_thread, NULL, cap_loop,
&(capture_list->devs[cdev - 1]));
pthread_join(capture_thread, NULL);
pthread_join(playback_thread, NULL);
close_sound_handle(&(playback_list->devs[pdev - 1]));
close_sound_handle(&(capture_list->devs[cdev - 1]));
free_device_list(playback_list);
free_device_list(capture_list);
printf("Exiting.\n");
}
int main(int argc, char **argv) {
int play_dev = -1;
int cap_dev = -1;
int count = 12;
int size = 512;
int arg;
while ((arg = getopt(argc, argv, "i:o:c:s:")) != -1) {
switch(arg) {
case 'i':
cap_dev = atoi(optarg);
break;
case 'o':
play_dev = atoi(optarg);
break;
case 'c':
count = atoi(optarg);
break;
case 's':
size = atoi(optarg);
break;
case '?':
if (optopt == 'i' || optopt == 'o' || optopt == 'c' || optopt == 's') {
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
} else {
fprintf(stderr, "Unknown Option -%c.\n", optopt);
}
default:
return 1;
}
}
test(size, count, play_dev, cap_dev);
return 0;
}