File: cmd-codec.c

package info (click to toggle)
bluez-alsa 4.3.1-3.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,156 kB
  • sloc: ansic: 32,301; makefile: 865; sh: 431; xml: 243; python: 236; pascal: 205
file content (150 lines) | stat: -rw-r--r-- 4,042 bytes parent folder | download | duplicates (2)
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,
};