From 94910b00a752fc5eae490b8fa3b24a66c197629f Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Fri, 29 Dec 2023 09:08:06 +0100 Subject: [PATCH] Optional hex input/output for bluealsa-cli open --- doc/bluealsa-cli.1.rst | 5 ++- test/test-utils-cli.c | 17 +++++----- utils/cli/cmd-open.c | 70 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 72 insertions(+), 20 deletions(-) diff --git a/doc/bluealsa-cli.1.rst b/doc/bluealsa-cli.1.rst index 53a2fe283..42120f31e 100644 --- a/doc/bluealsa-cli.1.rst +++ b/doc/bluealsa-cli.1.rst @@ -211,13 +211,16 @@ monitor [-p[PROPS] | --properties[=PROPS]] printed. If this argument is not given then changes to any of the above properties are printed. -open *PCM_PATH* +open [--hex] *PCM_PATH* Transfer raw audio frames to or from the given PCM. For sink PCMs the frames are read from standard input and written to the PCM. For source PCMs the frames are read from the PCM and written to standard output. The format, channels and sampling rate must match the properties of the PCM, as no format conversions are performed by this tool. + With the **--hex** option, the data is read or written as hexadecimal + strings. + COPYRIGHT ========= diff --git a/test/test-utils-cli.c b/test/test-utils-cli.c index 90256faae..b99ca64e0 100644 --- a/test/test-utils-cli.c +++ b/test/test-utils-cli.c @@ -410,11 +410,11 @@ CK_START_TEST(test_open) { NULL), -1); char * ba_cli_in_argv[32] = { - bluealsa_cli_path, "open", + bluealsa_cli_path, "open", "--hex", "/org/bluealsa/hci0/dev_23_45_67_89_AB_CD/hspag/source", NULL }; char * ba_cli_out_argv[32] = { - bluealsa_cli_path, "open", + bluealsa_cli_path, "open", "--hex", "/org/bluealsa/hci0/dev_23_45_67_89_AB_CD/hspag/sink", NULL }; @@ -427,18 +427,21 @@ CK_START_TEST(test_open) { sp_ba_cli_in.f_stdout, SPAWN_FLAG_NONE), -1); /* let it run for a while */ - sleep(1); + usleep(250000); spawn_terminate(&sp_ba_cli_in, 0); - spawn_terminate(&sp_ba_cli_out, 0); + spawn_terminate(&sp_ba_cli_out, 500); int wstatus = 0; - /* Make sure that both bluealsa-cli instances have been terminated by - * us (SIGTERM) and not by premature exit or any other reason. */ + /* Make sure that input bluealsa-cli instances have been terminated by + * us (SIGTERM) and not by premature exit or any other reason. On the other + * hand, the output bluealsa-cli instance should exit gracefully because + * of the end of input stream. */ spawn_close(&sp_ba_cli_in, &wstatus); ck_assert_int_eq(WTERMSIG(wstatus), SIGTERM); spawn_close(&sp_ba_cli_out, &wstatus); - ck_assert_int_eq(WTERMSIG(wstatus), SIGTERM); + ck_assert_int_eq(WIFEXITED(wstatus), 1); + ck_assert_int_eq(WEXITSTATUS(wstatus), 0); spawn_terminate(&sp_ba_mock, 0); spawn_close(&sp_ba_mock, NULL); diff --git a/utils/cli/cmd-open.c b/utils/cli/cmd-open.c index 6fdbcb9a6..d30ade9be 100644 --- a/utils/cli/cmd-open.c +++ b/utils/cli/cmd-open.c @@ -1,6 +1,6 @@ /* * BlueALSA - cmd-open.c - * Copyright (c) 2016-2022 Arkadiusz Bokowy + * Copyright (c) 2016-2023 Arkadiusz Bokowy * * This file is a part of bluez-alsa. * @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -19,11 +20,27 @@ #include "cli.h" #include "shared/dbus-client-pcm.h" +static void uint8_from_hex(uint8_t *value, const uint8_t *src) { + static const uint8_t map[256] = { + ['0'] = 0x0, ['1'] = 0x1, ['2'] = 0x2, ['3'] = 0x3, ['4'] = 0x4, + ['5'] = 0x5, ['6'] = 0x6, ['7'] = 0x7, ['8'] = 0x8, ['9'] = 0x9, + ['a'] = 0xa, ['b'] = 0xb, ['c'] = 0xc, ['d'] = 0xd, ['e'] = 0xe, ['f'] = 0xf, + ['A'] = 0xa, ['B'] = 0xb, ['C'] = 0xc, ['D'] = 0xd, ['E'] = 0xe, ['F'] = 0xf }; + *value = (map[src[0]] << 4) | map[src[1]]; +} + +static void uint8_to_hex(uint8_t *dest, uint8_t value) { + static const char map[] = "0123456789abcdef"; + dest[0] = map[value >> 4]; + dest[1] = map[value & 0x0f]; +} + static void usage(const char *command) { printf("Transfer raw PCM data via stdin or stdout.\n\n"); cli_print_usage("%s [OPTION]... PCM-PATH", command); printf("\nOptions:\n" " -h, --help\t\tShow this message and exit\n" + " -x, --hex\t\tTransfer data in hexadecimal format\n" "\nPositional arguments:\n" " PCM-PATH\tBlueALSA PCM D-Bus object path\n" ); @@ -32,18 +49,24 @@ static void usage(const char *command) { static int cmd_open_func(int argc, char *argv[]) { int opt; - const char *opts = "h"; + const char *opts = "hx"; const struct option longopts[] = { { "help", no_argument, NULL, 'h' }, + { "hex", no_argument, NULL, 'x' }, { 0 }, }; + bool hex = false; + opterr = 0; while ((opt = getopt_long(argc, argv, opts, longopts, NULL)) != -1) switch (opt) { case 'h' /* --help */ : usage(argv[0]); return EXIT_SUCCESS; + case 'x' /* --hex */ : + hex = true; + break; default: cmd_print_error("Invalid argument '%s'", argv[optind - 1]); return EXIT_FAILURE; @@ -64,7 +87,8 @@ static int cmd_open_func(int argc, char *argv[]) { return EXIT_FAILURE; } - int fd_pcm, fd_pcm_ctrl, input, output; + int fd_pcm, fd_pcm_ctrl; + int fd_input, fd_output; size_t len = strlen(path); DBusError err = DBUS_ERROR_INIT; @@ -74,21 +98,42 @@ static int cmd_open_func(int argc, char *argv[]) { } if (strcmp(path + len - strlen("source"), "source") == 0) { - input = fd_pcm; - output = STDOUT_FILENO; + fd_input = fd_pcm; + fd_output = STDOUT_FILENO; } else { - input = STDIN_FILENO; - output = fd_pcm; + fd_input = STDIN_FILENO; + fd_output = fd_pcm; } + uint8_t buffer[4096]; + uint8_t buffer_hex[sizeof(buffer) * 2]; ssize_t count; - char buffer[4096]; - while ((count = read(input, buffer, sizeof(buffer))) > 0) { + + while ((count = read(fd_input, buffer, sizeof(buffer))) > 0) { + + const uint8_t *pos = buffer; ssize_t written = 0; - const char *pos = buffer; + + if (hex) { + + if (fd_input == STDIN_FILENO) { + for (ssize_t i = 0; i < count; i += 2) + uint8_from_hex(&buffer[i / 2], &buffer[i]); + count /= 2; + } + + if (fd_output == STDOUT_FILENO) { + for (ssize_t i = 0; i < count; i++) + uint8_to_hex(&buffer_hex[i * 2], buffer[i]); + pos = buffer_hex; + count *= 2; + } + + } + while (written < count) { - ssize_t res = write(output, pos, count - written); + ssize_t res = write(fd_output, pos, count - written); if (res <= 0) { /* Cannot write any more, so just terminate */ goto finish; @@ -96,9 +141,10 @@ static int cmd_open_func(int argc, char *argv[]) { written += res; pos += res; } + } - if (output == fd_pcm) + if (fd_output == fd_pcm) ba_dbus_pcm_ctrl_send_drain(fd_pcm_ctrl, &err); finish: