summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2020-02-12 17:57:42 +0100
committerWim Taymans <wtaymans@redhat.com>2020-02-12 17:57:42 +0100
commitfe85a3b817c926e1901033e2d7460eeff64cff97 (patch)
tree2919673b78161ad9c9c5567aa8ea60ead672e46b
parente5bdb04b3ad4273c4a03664d7b9a4f3303e99d1c (diff)
pw-cat: refactor a bit
Try to keep the sndfile code in one place
-rw-r--r--src/tools/pw-cat.c352
1 files changed, 183 insertions, 169 deletions
diff --git a/src/tools/pw-cat.c b/src/tools/pw-cat.c
index ea658125..76ff2dc4 100644
--- a/src/tools/pw-cat.c
+++ b/src/tools/pw-cat.c
@@ -106,12 +106,14 @@ struct data {
const char *media_type;
const char *media_category;
const char *media_role;
+ const char *channel_map;
+ const char *format;
const char *target;
const char *latency;
+ struct pw_properties *props;
const char *filename;
SNDFILE *file;
- SF_INFO info;
unsigned int rate;
int channels;
@@ -477,13 +479,13 @@ static unsigned int find_channel(const char *name)
return SPA_AUDIO_CHANNEL_UNKNOWN;
}
-static int parse_channelmap(const char *channelmap, struct channelmap *map)
+static int parse_channelmap(const char *channel_map, struct channelmap *map)
{
int i, nch;
char **ch;
for (i = 0; i < (int) SPA_N_ELEMENTS(maps); i++) {
- if (strcmp(maps[i].name, channelmap) == 0) {
+ if (strcmp(maps[i].name, channel_map) == 0) {
map->n_channels = maps[i].channels;
spa_memcpy(map->channels, &maps[i].values,
map->n_channels * sizeof(unsigned int));
@@ -491,7 +493,7 @@ static int parse_channelmap(const char *channelmap, struct channelmap *map)
}
}
- ch = pw_split_strv(channelmap, ",", SPA_AUDIO_MAX_CHANNELS, &nch);
+ ch = pw_split_strv(channel_map, ",", SPA_AUDIO_MAX_CHANNELS, &nch);
if (ch == NULL)
return -1;
@@ -913,6 +915,135 @@ static void show_usage(const char *name, bool is_error)
"\n");
}
+static int setup_sndfile(struct data *data)
+{
+ SF_INFO info;
+ const char *s;
+ unsigned int nom = 0;
+
+ /* for record, you fill in the info first */
+ if (data->mode == mode_record) {
+ memset(&info, 0, sizeof(info));
+ info.samplerate = data->rate;
+ info.channels = data->channels;
+ info.format = sf_str_to_fmt(data->format);
+ if (info.format == -1) {
+ fprintf(stderr, "error: unknown format \"%s\"\n", data->format);
+ return -EINVAL;
+ }
+ }
+
+ data->file = sf_open(data->filename,
+ data->mode == mode_playback ? SFM_READ : SFM_WRITE,
+ &info);
+ if (!data->file) {
+ fprintf(stderr, "error: failed to open audio file \"%s\": %s\n",
+ data->filename, sf_strerror(NULL));
+ return -EIO;
+ }
+
+ if (data->verbose)
+ printf("opened file \"%s\" format %08x\n", data->filename, info.format);
+
+ if (data->mode == mode_playback) {
+ data->rate = info.samplerate;
+
+ if (data->channels > 0 && info.channels != data->channels) {
+ printf("given channels (%u) don't match file channels (%d)\n",
+ data->channels, info.channels);
+ return -EINVAL;
+ }
+
+ data->channels = info.channels;
+
+ if (data->channelmap.n_channels == 0) {
+ bool def = false;
+
+ if (sf_command(data->file, SFC_GET_CHANNEL_MAP_INFO,
+ data->channelmap.channels,
+ sizeof(data->channelmap.channels[0]) * data->channels)) {
+ data->channelmap.n_channels = data->channels;
+ if (channelmap_from_sf(&data->channelmap) < 0)
+ data->channelmap.n_channels = 0;
+ }
+ if (data->channelmap.n_channels == 0) {
+ channelmap_default(&data->channelmap, data->channels);
+ def = true;
+ }
+ if (data->verbose) {
+ printf("using %s channel map: ", def ? "default" : "file");
+ channelmap_print(&data->channelmap);
+ printf("\n");
+ }
+ }
+ }
+ data->samplesize = sf_format_samplesize(info.format);
+ data->stride = data->samplesize * data->channels;
+ data->spa_format = sf_format_to_pw(info.format);
+ data->fill = data->mode == mode_playback ?
+ sf_fmt_playback_fill_fn(info.format) :
+ sf_fmt_record_fill_fn(info.format);
+
+ data->latency_unit = unit_none;
+
+ s = data->latency;
+ while (*s && isdigit(*s))
+ s++;
+ if (!*s)
+ data->latency_unit = unit_samples;
+ else if (!strcmp(s, "none"))
+ data->latency_unit = unit_none;
+ else if (!strcmp(s, "s") || !strcmp(s, "sec") || !strcmp(s, "secs"))
+ data->latency_unit = unit_sec;
+ else if (!strcmp(s, "ms") || !strcmp(s, "msec") || !strcmp(s, "msecs"))
+ data->latency_unit = unit_msec;
+ else if (!strcmp(s, "us") || !strcmp(s, "usec") || !strcmp(s, "usecs"))
+ data->latency_unit = unit_usec;
+ else if (!strcmp(s, "ns") || !strcmp(s, "nsec") || !strcmp(s, "nsecs"))
+ data->latency_unit = unit_nsec;
+ else {
+ fprintf(stderr, "error: bad latency value %s (bad unit)\n", data->latency);
+ return -EINVAL;
+ }
+ data->latency_value = atoi(data->latency);
+ if (!data->latency_value) {
+ fprintf(stderr, "error: bad latency value %s (is zero)\n", data->latency);
+ return -EINVAL;
+ }
+
+ switch (data->latency_unit) {
+ case unit_sec:
+ nom = data->latency_value * data->rate;
+ break;
+ case unit_msec:
+ nom = nearbyint((data->latency_value * data->rate) / 1000.0);
+ break;
+ case unit_usec:
+ nom = nearbyint((data->latency_value * data->rate) / 1000000.0);
+ break;
+ case unit_nsec:
+ nom = nearbyint((data->latency_value * data->rate) / 1000000000.0);
+ break;
+ case unit_samples:
+ nom = data->latency_value;
+ break;
+ default:
+ nom = 0;
+ break;
+ }
+
+ if (data->verbose)
+ printf("rate=%u channels=%u fmt=%s samplesize=%u stride=%u latency=%u (%.3fs)\n",
+ data->rate, data->channels,
+ sf_fmt_to_str(info.format),
+ data->samplesize,
+ data->stride, nom, (double)nom/data->rate);
+ if (nom)
+ pw_properties_setf(data->props, PW_KEY_NODE_LATENCY, "%u/%u", nom, data->rate);
+
+ return 0;
+}
+
int main(int argc, char *argv[])
{
struct data data = { 0, };
@@ -920,11 +1051,8 @@ int main(int argc, char *argv[])
const struct spa_pod *params[1];
uint8_t buffer[1024];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
- const char *prog, *channelmap = NULL;
- int exit_code = EXIT_FAILURE, c, format = 0, ret;
- struct pw_properties *props = NULL;
- const char *s;
- unsigned int nom = 0;
+ const char *prog;
+ int exit_code = EXIT_FAILURE, c, ret;
struct target *target, *target_default;
enum pw_stream_flags flags = 0;
@@ -1037,15 +1165,11 @@ int main(int argc, char *argv[])
break;
case OPT_CHANNELMAP:
- channelmap = optarg;
+ data.channel_map = optarg;
break;
case OPT_FORMAT:
- format = sf_str_to_fmt(optarg);
- if (format == -1) {
- fprintf(stderr, "error: unknown format \"%s\"\n", optarg);
- goto error_usage;
- }
+ data.format = optarg;
break;
case OPT_VOLUME:
@@ -1083,9 +1207,9 @@ int main(int argc, char *argv[])
data.latency = DEFAULT_LATENCY;
if (!data.rate)
data.rate = DEFAULT_RATE;
- if (channelmap != NULL) {
- if (parse_channelmap(channelmap, &data.channelmap) < 0) {
- fprintf(stderr, "error: can parse channel-map \"%s\"\n", channelmap);
+ if (data.channel_map != NULL) {
+ if (parse_channelmap(data.channel_map, &data.channelmap) < 0) {
+ fprintf(stderr, "error: can parse channel-map \"%s\"\n", data.channel_map);
goto error_usage;
} else {
@@ -1096,12 +1220,12 @@ int main(int argc, char *argv[])
data.channels = data.channelmap.n_channels;
}
}
- if (!data.channels)
- data.rate = DEFAULT_CHANNELS;
+ if (data.channels == 0)
+ data.channels = DEFAULT_CHANNELS;
if (data.volume < 0)
data.volume = DEFAULT_VOLUME;
- if (data.mode == mode_record && !format)
- format = sf_str_to_fmt(DEFAULT_FORMAT);
+ if (data.mode == mode_record && data.format == NULL)
+ data.format = DEFAULT_FORMAT;
if (!data.list_targets && optind >= argc) {
fprintf(stderr, "error: filename argument missing\n");
@@ -1109,120 +1233,18 @@ int main(int argc, char *argv[])
}
data.filename = argv[optind++];
- /* for record, you fill in the info first */
- if (data.mode == mode_record) {
- memset(&data.info, 0, sizeof(data.info));
- data.info.samplerate = data.rate;
- data.info.channels = data.channels;
- data.info.format = format;
- }
-
- if (!data.list_targets) {
- data.file = sf_open(data.filename,
- data.mode == mode_playback ? SFM_READ : SFM_WRITE,
- &data.info);
- if (!data.file) {
- fprintf(stderr, "error: failed to open audio file \"%s\": %s\n",
- data.filename, sf_strerror(NULL));
- goto error_open_file;
- }
-
- if (data.verbose)
- printf("opened file \"%s\" format %08x\n", data.filename, data.info.format);
-
- format = data.info.format;
- if (data.mode == mode_playback) {
- data.rate = data.info.samplerate;
-
- if (data.channels > 0 && data.info.channels != data.channels) {
- printf("given channels (%u) don't match file channels (%d)\n",
- data.channels, data.info.channels);
- goto error_bad_file;
- }
-
- data.channels = data.info.channels;
-
- if (data.channelmap.n_channels == 0) {
- bool def = false;
-
- if (sf_command(data.file, SFC_GET_CHANNEL_MAP_INFO,
- data.channelmap.channels,
- sizeof(data.channelmap.channels[0]) * data.channels)) {
- data.channelmap.n_channels = data.channels;
- if (channelmap_from_sf(&data.channelmap) < 0)
- data.channelmap.n_channels = 0;
- }
- if (data.channelmap.n_channels == 0) {
- channelmap_default(&data.channelmap, data.channels);
- def = true;
- }
- if (data.verbose) {
- printf("using %s channel map: ", def ? "default" : "file");
- channelmap_print(&data.channelmap);
- printf("\n");
- }
- }
- }
- data.samplesize = sf_format_samplesize(format);
- data.stride = data.samplesize * data.channels;
- data.spa_format = sf_format_to_pw(format);
- data.fill = data.mode == mode_playback ?
- sf_fmt_playback_fill_fn(format) :
- sf_fmt_record_fill_fn(format);
-
- data.latency_unit = unit_none;
- s = data.latency;
- while (*s && isdigit(*s))
- s++;
- if (!*s)
- data.latency_unit = unit_samples;
- else if (!strcmp(s, "none"))
- data.latency_unit = unit_none;
- else if (!strcmp(s, "s") || !strcmp(s, "sec") || !strcmp(s, "secs"))
- data.latency_unit = unit_sec;
- else if (!strcmp(s, "ms") || !strcmp(s, "msec") || !strcmp(s, "msecs"))
- data.latency_unit = unit_msec;
- else if (!strcmp(s, "us") || !strcmp(s, "usec") || !strcmp(s, "usecs"))
- data.latency_unit = unit_usec;
- else if (!strcmp(s, "ns") || !strcmp(s, "nsec") || !strcmp(s, "nsecs"))
- data.latency_unit = unit_nsec;
- else {
- fprintf(stderr, "error: bad latency value %s (bad unit)\n", data.latency);
- goto error_bad_file;
- }
- data.latency_value = atoi(data.latency);
- if (!data.latency_value) {
- fprintf(stderr, "error: bad latency value %s (is zero)\n", data.latency);
- goto error_bad_file;
- }
-
- switch (data.latency_unit) {
- case unit_sec:
- nom = data.latency_value * data.rate;
- break;
- case unit_msec:
- nom = nearbyint((data.latency_value * data.rate) / 1000.0);
- break;
- case unit_usec:
- nom = nearbyint((data.latency_value * data.rate) / 1000000.0);
- break;
- case unit_nsec:
- nom = nearbyint((data.latency_value * data.rate) / 1000000000.0);
- break;
- case unit_samples:
- nom = data.latency_value;
- break;
- default:
- nom = 0;
- break;
- }
+ data.props = pw_properties_new(
+ PW_KEY_MEDIA_TYPE, data.media_type,
+ PW_KEY_MEDIA_CATEGORY, data.media_category,
+ PW_KEY_MEDIA_ROLE, data.media_role,
+ PW_KEY_APP_NAME, prog,
+ PW_KEY_MEDIA_NAME, data.filename,
+ PW_KEY_NODE_NAME, prog,
+ NULL);
- if (data.verbose)
- printf("rate=%u channels=%u fmt=%s samplesize=%u stride=%u latency=%u (%.3fs)\n",
- data.rate, data.channels,
- sf_fmt_to_str(format),
- data.samplesize,
- data.stride, nom, (double)nom/data.rate);
+ if (data.props == NULL) {
+ fprintf(stderr, "error: pw_properties_new() failed: %m\n");
+ goto error_no_props;
}
/* make a main loop. If you already have another main loop, you can add
@@ -1243,22 +1265,6 @@ int main(int argc, char *argv[])
goto error_no_context;
}
- props = pw_properties_new(
- PW_KEY_MEDIA_TYPE, data.media_type,
- PW_KEY_MEDIA_CATEGORY, data.media_category,
- PW_KEY_MEDIA_ROLE, data.media_role,
- PW_KEY_APP_NAME, prog,
- PW_KEY_MEDIA_NAME, data.filename,
- PW_KEY_NODE_NAME, prog,
- NULL);
-
- if (!props) {
- fprintf(stderr, "error: pw_properties_new() failed: %m\n");
- goto error_no_props;
- }
- if (nom)
- pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", nom, data.rate);
-
data.core = pw_context_connect(data.context,
pw_properties_new(
PW_KEY_REMOTE_NAME, data.remote_name,
@@ -1282,25 +1288,37 @@ int main(int argc, char *argv[])
if (!data.list_targets) {
struct spa_audio_info_raw info;
- data.stream = pw_stream_new(data.core, prog, props);
- if (!data.stream) {
- fprintf(stderr, "error: failed to create simple stream: %m\n");
- goto error_no_stream;
+ ret = setup_sndfile(&data);
+ switch (ret) {
+ case -EINVAL:
+ goto error_usage;
+ case -EIO:
+ goto error_bad_file;
+ default:
+ fprintf(stderr, "error: open failed: %s\n", spa_strerror(ret));
+ if (ret < 0)
+ goto error_usage;
}
- props = NULL;
- pw_stream_add_listener(data.stream, &data.stream_listener, &stream_events, &data);
-
info = SPA_AUDIO_INFO_RAW_INIT(
- .flags = data.channelmap.n_channels ? 0 : SPA_AUDIO_FLAG_UNPOSITIONED,
- .format = data.spa_format,
- .rate = data.rate,
- .channels = data.channels);
+ .flags = data.channelmap.n_channels ? 0 : SPA_AUDIO_FLAG_UNPOSITIONED,
+ .format = data.spa_format,
+ .rate = data.rate,
+ .channels = data.channels);
if (data.channelmap.n_channels)
memcpy(info.position, data.channelmap.channels, data.channels * sizeof(int));
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info);
+ data.stream = pw_stream_new(data.core, prog, data.props);
+ data.props = NULL;
+
+ if (data.stream == NULL) {
+ fprintf(stderr, "error: failed to create stream: %m\n");
+ goto error_no_stream;
+ }
+ pw_stream_add_listener(data.stream, &data.stream_listener, &stream_events, &data);
+
if (data.verbose)
printf("connecting %s stream; target_id=%"PRIu32"\n",
data.mode == mode_playback ? "playback" : "record",
@@ -1378,20 +1396,16 @@ error_no_stream:
error_no_registry:
pw_core_disconnect(data.core);
error_ctx_connect_failed:
- if (props)
- pw_properties_free(props);
-error_no_props:
pw_context_destroy(data.context);
-
error_no_context:
pw_main_loop_destroy(data.loop);
+error_no_props:
error_no_main_loop:
error_bad_file:
-
+ if (data.props)
+ pw_properties_free(data.props);
if (data.file)
sf_close(data.file);
-error_open_file:
-
return exit_code;
error_usage: