From bd71fe8e472671eb938092bb53086523aa06e4b0 Mon Sep 17 00:00:00 2001 From: Joursoir Date: Mon, 1 Feb 2021 11:56:13 +0000 Subject: add code for work with device, functional arg --list-devices --- parecord/Makefile | 2 +- parecord/device.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++ parecord/device.h | 12 +++++ parecord/parecord.c | 32 +++++++++++- 4 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 parecord/device.c create mode 100644 parecord/device.h diff --git a/parecord/Makefile b/parecord/Makefile index 05ed2fc..6468280 100644 --- a/parecord/Makefile +++ b/parecord/Makefile @@ -1,6 +1,6 @@ CFLAGS = -Wall -g PULSEFLAGS = -lpulse -lpulse-simple -SOURCES = parecord.c audio_types.c +SOURCES = parecord.c audio_types.c device.c OBJECTS = ${SOURCES:.c=.o} EXECUTABLE = parecord diff --git a/parecord/device.c b/parecord/device.c new file mode 100644 index 0000000..24f94ba --- /dev/null +++ b/parecord/device.c @@ -0,0 +1,142 @@ +#include +#include +#include + +#include "device.h" + +static struct list_devices *g_input; // struct array +static int input_idx; +static int input_num; // size of struct array + +static void context_state_callback(pa_context *c, void *userdata) +{ + int *ready = userdata; + + switch(pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: { + *ready = 1; + break; + } + + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + default: { + *ready = 2; + // error + break; + } + } +} + +static void context_sourcelist_callback(pa_context *c, + const pa_source_info *i, int eol, void *userdata) +{ + // end of list + if(eol > 0) + return; + + if(input_idx >= input_num) + { + int i; + struct list_devices *tmp = malloc( + sizeof(struct list_devices) * (input_num+1)); + + for(i = 0; i < input_num; i++) { + tmp[i].name = g_input[i].name; + tmp[i].description = g_input[i].description; + } + input_num++; + free(g_input); + g_input = tmp; + } + g_input[input_idx].name + = malloc((strlen(i->name)+1)*sizeof(char)); + strcpy(g_input[input_idx].name, i->name); + + g_input[input_idx].description + = malloc((strlen(i->description)+1)*sizeof(char)); + strcpy(g_input[input_idx].description, i->description); + + input_idx++; +} + +struct list_devices *getInputDeviceList(int *len) +{ + pa_mainloop *ml; + pa_mainloop_api *ml_api; + pa_context *context; + pa_operation *operation; + int state = 0; + int ready = 0; + + if(!(ml = pa_mainloop_new())) + return NULL; + ml_api = pa_mainloop_get_api(ml); + context = pa_context_new(ml_api, NULL); + + // Connect the context + if(pa_context_connect(context, NULL, 0, NULL) < 0) + return NULL; + pa_context_set_state_callback(context, context_state_callback, &ready); + + input_idx = 0; + input_num = 3; + g_input = malloc( + sizeof(struct list_devices) * input_num); + + for(;;) { + if(ready == 0) { + pa_mainloop_iterate(ml, 1, NULL); + continue; + } + if(ready == 2) { + pa_context_disconnect(context); + pa_context_unref(context); + pa_mainloop_free(ml); + return NULL; + } + + switch(state) { + case 0: { + operation = pa_context_get_source_info_list( + context, context_sourcelist_callback, NULL); + + state++; + break; + } + case 1: { + if(pa_operation_get_state(operation) == PA_OPERATION_DONE) { + pa_operation_unref(operation); + pa_context_disconnect(context); + pa_context_unref(context); + pa_mainloop_free(ml); + *len = input_num; + return g_input; + } + break; + } + default: { + pa_mainloop_free(ml); + return NULL; + } + } + pa_mainloop_iterate(ml, 1, NULL); + } +} + +void freeDeviceList(struct list_devices *list, int len) +{ + int i; + for(i = 0; i < len; i++) + { + free(list[i].name); + free(list[i].description); + } + free(list); +} + diff --git a/parecord/device.h b/parecord/device.h new file mode 100644 index 0000000..3a520d6 --- /dev/null +++ b/parecord/device.h @@ -0,0 +1,12 @@ +#ifndef PAR_DEVICE_H +#define PAR_DEVICE_H + +struct list_devices { + char *name; + char *description; +}; + +struct list_devices *getInputDeviceList(int *len); +void freeDeviceList(struct list_devices *list, int len); + +#endif /* PAR_DEVICE_H */ diff --git a/parecord/parecord.c b/parecord/parecord.c index feda84b..e14cea9 100644 --- a/parecord/parecord.c +++ b/parecord/parecord.c @@ -10,6 +10,7 @@ #include #include "audio_types.h" +#include "device.h" #define PAR_RATE_MIN 2000U #define PAR_CHANNELS_MIN 1U @@ -63,6 +64,8 @@ int main(int argc, char *argv[]) off_t offset; const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, + {"device", required_argument, NULL, 'd'}, + {"list-devices", no_argument, NULL, 'D'}, {"file-type", required_argument, NULL, 't'}, {"file-types", no_argument, NULL, 'T'}, {"format", required_argument, NULL, 'f'}, @@ -72,7 +75,7 @@ int main(int argc, char *argv[]) {NULL, 0, NULL, 0} }; - while((result = getopt_long(argc, argv, "ht:Tf:Fc:r:", + while((result = getopt_long(argc, argv, "hd:Dt:Tf:Fc:r:", long_options, NULL)) != -1) { switch(result) { case 'h': { @@ -81,6 +84,12 @@ int main(int argc, char *argv[]) fprintf(stderr, "Option:\n\t-h, --help\n"); fprintf(stderr, "\t\tPrint this text.\n"); + fprintf(stderr, "\t-d, --device\n"); + fprintf(stderr, "\t\tIn development...\n"); + + fprintf(stderr, "\t-D, --list-devices\n"); + fprintf(stderr, "\t\tPrint all recorder audio devices\n"); + fprintf(stderr, "\t-t, --file-type\n"); fprintf(stderr, "\t\tFile type (pcm, wav). PCM is used by default\n"); @@ -100,6 +109,27 @@ int main(int argc, char *argv[]) fprintf(stderr, "\t\tSample rate in Hz. %d Hz is used by default. \n", STD_REC_RATE); return 0; } + case 'd': { + // ... + break; + } + case 'D': { + int i, list_devices_len; + struct list_devices *input_devices + = getInputDeviceList(&list_devices_len); + + if(!input_devices) + return 1; + + fprintf(stderr, "**** Input devices ****\n"); + for(i = 0; i < list_devices_len; i++) { + fprintf(stderr, "device %d: %s\n", i+1, input_devices[i].name); + fprintf(stderr, "\t%s\n", input_devices[i].description); + } + + freeDeviceList(input_devices, list_devices_len); + return 0; + } case 't': { file_type = checkAudioType(optarg); if(file_type != AUDIO_TYPE_NONE) break; -- cgit v1.2.3-18-g5258