1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
/*
* BlueALSA - cmd-codec.c
* Copyright (c) 2016-2024 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
* This project is licensed under the terms of the MIT license.
*
*/
#include <stdbool.h>
#include <errno.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus.h>
#include "cli.h"
#include "shared/dbus-client-pcm.h"
#include "shared/hex.h"
static void usage(const char *command) {
printf("Get or set the Bluetooth codec used by the given PCM.\n\n");
cli_print_usage("%s [OPTION]... PCM-PATH [CODEC[:CONFIG]]", command);
printf("\nOptions:\n"
" -h, --help\t\tShow this message and exit\n"
" -c, --channels=NUM\tSelect configuration with NUM channels\n"
" -s, --sampling=NUM\tSelect configuration with NUM sampling frequency\n"
" -f, --force\t\tForce codec configuration (skip conformance check)\n"
"\nPositional arguments:\n"
" PCM-PATH\tBlueALSA PCM D-Bus object path\n"
" CODEC\t\tCodec identifier for setting new codec\n"
" CONFIG\tOptional configuration for new codec\n"
"\nNote:\n"
" This command requires BlueZ version >= 5.52 for SEP support.\n"
);
}
static int cmd_codec_func(int argc, char *argv[]) {
int opt;
const char *opts = "hqvc:s:f";
const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, 'v' },
{ "channels", required_argument, NULL, 'c' },
{ "sampling", required_argument, NULL, 's' },
{ "force", no_argument, NULL, 'f' },
{ 0 },
};
unsigned int channels = 0;
unsigned int sampling = 0;
bool force = false;
opterr = 0;
while ((opt = getopt_long(argc, argv, opts, longopts, NULL)) != -1) {
if (cli_parse_common_options(opt))
continue;
switch (opt) {
case 'h' /* --help */ :
usage(argv[0]);
return EXIT_SUCCESS;
case 'c' /* --channels */ :
channels = atoi(optarg);
break;
case 's' /* --sampling */ :
sampling = atoi(optarg);
break;
case 'f' /* --force */ :
force = true;
break;
default:
cmd_print_error("Invalid argument '%s'", argv[optind - 1]);
return EXIT_FAILURE;
}
}
if (argc - optind < 1) {
cmd_print_error("Missing BlueALSA PCM path argument");
return EXIT_FAILURE;
}
if (argc - optind > 2) {
cmd_print_error("Invalid number of arguments");
return EXIT_FAILURE;
}
DBusError err = DBUS_ERROR_INIT;
const char *path = argv[optind];
struct ba_pcm pcm;
if (!cli_get_ba_pcm(path, &pcm, &err)) {
cmd_print_error("Couldn't get BlueALSA PCM: %s", err.message);
return EXIT_FAILURE;
}
if (argc - optind == 1) {
cli_print_pcm_available_codecs(&pcm, NULL);
cli_print_pcm_selected_codec(&pcm);
return EXIT_SUCCESS;
}
char *codec = argv[optind + 1];
uint8_t codec_config[64] = { 0 };
ssize_t codec_config_len = 0;
unsigned int flags = BA_PCM_SELECT_CODEC_FLAG_NONE;
int result = EXIT_FAILURE;
char *codec_config_hex;
/* split the given string into name and configuration components */
if ((codec_config_hex = strchr(codec, ':')) != NULL) {
*codec_config_hex++ = '\0';
size_t codec_config_hex_len;
if ((codec_config_hex_len = strlen(codec_config_hex)) > sizeof(codec_config) * 2) {
dbus_set_error(&err, DBUS_ERROR_FAILED, "Invalid codec configuration: %s", codec_config_hex);
goto fail;
}
if ((codec_config_len = hex2bin(codec_config_hex, codec_config, codec_config_hex_len)) == -1) {
dbus_set_error(&err, DBUS_ERROR_FAILED, "%s", strerror(errno));
goto fail;
}
}
if (force)
flags |= BA_PCM_SELECT_CODEC_FLAG_NON_CONFORMANT;
if (!ba_dbus_pcm_select_codec(&config.dbus, path, ba_dbus_pcm_codec_get_canonical_name(codec),
codec_config, codec_config_len, channels, sampling, flags, &err))
goto fail;
result = EXIT_SUCCESS;
fail:
if (dbus_error_is_set(&err))
cmd_print_error("Couldn't select BlueALSA PCM Codec: %s", err.message);
return result;
}
const struct cli_command cmd_codec = {
"codec",
"Get or set PCM Bluetooth codec",
cmd_codec_func,
};
|