Skip to content

Commit

Permalink
Optional hex input/output for bluealsa-cli open
Browse files Browse the repository at this point in the history
  • Loading branch information
arkq committed Dec 29, 2023
1 parent 4645def commit 94910b0
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 20 deletions.
5 changes: 4 additions & 1 deletion doc/bluealsa-cli.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
=========

Expand Down
17 changes: 10 additions & 7 deletions test/test-utils-cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

Expand All @@ -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);
Expand Down
70 changes: 58 additions & 12 deletions utils/cli/cmd-open.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/*
* BlueALSA - cmd-open.c
* Copyright (c) 2016-2022 Arkadiusz Bokowy
* Copyright (c) 2016-2023 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
* This project is licensed under the terms of the MIT license.
*
*/

#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -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"
);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -74,31 +98,53 @@ 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;
}
written += res;
pos += res;
}

}

if (output == fd_pcm)
if (fd_output == fd_pcm)
ba_dbus_pcm_ctrl_send_drain(fd_pcm_ctrl, &err);

finish:
Expand Down

0 comments on commit 94910b0

Please sign in to comment.