* [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration @ 2025-09-11 13:53 Per Waagø 2025-09-11 14:08 ` [BlueZ] " bluez.test.bot 2025-09-11 14:43 ` [PATCH BlueZ] " Luiz Augusto von Dentz 0 siblings, 2 replies; 8+ messages in thread From: Per Waagø @ 2025-09-11 13:53 UTC (permalink / raw) To: linux-bluetooth; +Cc: Per Waagø The A2DP specification defines error codes that shall be used if the codec capabilities contain improper settings. This change allows clients to trigger the sending of these specific error codes by returning the corresponding error messages from MediaEndpoint1.SetConfiguration. This update is fully backwards compatible: clients passing other error messages will continue to receive the default error code as before. On older BlueZ versions, these new errors will also result in the default error code, enabling clients to implement support for the new errors without breaking compatibility. This change enables passing A2DP/SNK/AVP/* and A2DP/SRC/AVP/* qualification tests. --- doc/org.bluez.MediaEndpoint.rst | 37 ++++++++++++++++ profiles/audio/a2dp.c | 78 ++++++++++++++++++++++++++++++--- profiles/audio/a2dp.h | 5 ++- profiles/audio/avdtp.c | 4 +- profiles/audio/media.c | 20 +++++---- src/error.h | 38 ++++++++++++++++ 6 files changed, 165 insertions(+), 17 deletions(-) diff --git a/doc/org.bluez.MediaEndpoint.rst b/doc/org.bluez.MediaEndpoint.rst index 474cc1160..2721d473e 100644 --- a/doc/org.bluez.MediaEndpoint.rst +++ b/doc/org.bluez.MediaEndpoint.rst @@ -54,6 +54,43 @@ be configured and the properties must contain the following properties: See **org.bluez.MediaTransport(5)** QoS property. + Possible errors: + :org.bluez.Error.A2DP.InvalidCodecType: + :org.bluez.Error.A2DP.NotSupportedCodecType: + :org.bluez.Error.A2DP.InvalidSamplingFrequency: + :org.bluez.Error.A2DP.NotSupportedSamplingFrequency: + :org.bluez.Error.A2DP.InvalidChannelMode: + :org.bluez.Error.A2DP.NotSupportedChannelMode: + :org.bluez.Error.A2DP.InvalidSubbands: + :org.bluez.Error.A2DP.NotSupportedSubbands: + :org.bluez.Error.A2DP.InvalidAllocationMethod: + :org.bluez.Error.A2DP.NotSupportedAllocationMethod: + :org.bluez.Error.A2DP.InvalidMinimumBitpoolValue: + :org.bluez.Error.A2DP.NotSupportedMinimumBitpoolValue: + :org.bluez.Error.A2DP.InvalidMaximumBitpoolValue: + :org.bluez.Error.A2DP.NotSupportedMaximumBitpoolValue: + :org.bluez.Error.A2DP.InvalidInvalidLayer: + :org.bluez.Error.A2DP.NotSupportedLayer: + :org.bluez.Error.A2DP.NotSupporterdCRC: + :org.bluez.Error.A2DP.NotSupporterdMPF: + :org.bluez.Error.A2DP.NotSupporterdVBR: + :org.bluez.Error.A2DP.InvalidBitRate: + :org.bluez.Error.A2DP.NotSupportedBitRate: + :org.bluez.Error.A2DP.InvalidObjectType: + :org.bluez.Error.A2DP.NotSupportedObjectType: + :org.bluez.Error.A2DP.InvalidChannels: + :org.bluez.Error.A2DP.NotSupportedChannels: + :org.bluez.Error.A2DP.InvalidVersion: + :org.bluez.Error.A2DP.NotSupportedVersion: + :org.bluez.Error.A2DP.NotSupportedMaximumSUL: + :org.bluez.Error.A2DP.InvalidBlockLength: + :org.bluez.Error.A2DP.InvalidCPType: + :org.bluez.Error.A2DP.InvalidCPFormat: + :org.bluez.Error.A2DP.InvalidCodecParameter: + :org.bluez.Error.A2DP.NotSupportedCodecParameter: + :org.bluez.Error.A2DP.InvalidDRC: + :org.bluez.Error.A2DP.NotSupportedDRC: + array{byte} SelectConfiguration(array{byte} capabilities) ````````````````````````````````````````````````````````` diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c index c0a53eae9..661843a89 100644 --- a/profiles/audio/a2dp.c +++ b/profiles/audio/a2dp.c @@ -157,6 +157,73 @@ static GSList *servers = NULL; static GSList *setups = NULL; static unsigned int cb_id = 0; +struct a2dp_error { + const char *error_name; + uint8_t error_code; +}; + +#define A2DP_ERROR_PREFIX ERROR_INTERFACE ".A2DP." + +static struct a2dp_error config_errors[] = { + {"InvalidCodecType", A2DP_INVALID_CODEC_TYPE}, + {"NotSupportedCodecType", A2DP_NOT_SUPPORTED_CODEC_TYPE}, + {"InvalidSamplingFrequency", A2DP_INVALID_SAMPLING_FREQUENCY}, + {"NotSupportedSamplingFrequency", + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY}, + {"InvalidChannelMode", A2DP_INVALID_CHANNEL_MODE}, + {"NotSupportedChannelMode", A2DP_NOT_SUPPORTED_CHANNEL_MODE}, + {"InvalidSubbands", A2DP_INVALID_SUBBANDS}, + {"NotSupportedSubbands", A2DP_NOT_SUPPORTED_SUBBANDS}, + {"InvalidAllocationMethod", A2DP_INVALID_ALLOCATION_METHOD}, + {"NotSupportedAllocationMethod", A2DP_NOT_SUPPORTED_ALLOCATION_METHOD}, + {"InvalidMinimumBitpoolValue", + A2DP_INVALID_MINIMUM_BITPOOL_VALUE}, + {"NotSupportedMinimumBitpoolValue", + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE}, + {"InvalidMaximumBitpoolValue", A2DP_INVALID_MAXIMUM_BITPOOL_VALUE}, + {"NotSupportedMaximumBitpoolValue", + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE}, + {"InvalidInvalidLayer", A2DP_INVALID_INVALID_LAYER}, + {"NotSupportedLayer", A2DP_NOT_SUPPORTED_LAYER}, + {"NotSupporterdCRC", A2DP_NOT_SUPPORTERD_CRC}, + {"NotSupporterdMPF", A2DP_NOT_SUPPORTERD_MPF}, + {"NotSupporterdVBR", A2DP_NOT_SUPPORTERD_VBR}, + {"InvalidBitRate", A2DP_INVALID_BIT_RATE}, + {"NotSupportedBitRate", A2DP_NOT_SUPPORTED_BIT_RATE}, + {"InvalidObjectType", A2DP_INVALID_OBJECT_TYPE}, + {"NotSupportedObjectType", A2DP_NOT_SUPPORTED_OBJECT_TYPE}, + {"InvalidChannels", A2DP_INVALID_CHANNELS}, + {"NotSupportedChannels", A2DP_NOT_SUPPORTED_CHANNELS}, + {"InvalidVersion", A2DP_INVALID_VERSION}, + {"NotSupportedVersion", A2DP_NOT_SUPPORTED_VERSION}, + {"NotSupportedMaximumSUL", A2DP_NOT_SUPPORTED_MAXIMUM_SUL}, + {"InvalidBlockLength", A2DP_INVALID_BLOCK_LENGTH}, + {"InvalidCPType", A2DP_INVALID_CP_TYPE}, + {"InvalidCPFormat", A2DP_INVALID_CP_FORMAT}, + {"InvalidCodecParameter", A2DP_INVALID_CODEC_PARAMETER}, + {"NotSupportedCodecParameter", A2DP_NOT_SUPPORTED_CODEC_PARAMETER}, + {"InvalidDRC", A2DP_INVALID_DRC}, + {"NotSupportedDRC", A2DP_NOT_SUPPORTED_DRC} +}; + +uint8_t a2dp_parse_config_error(const char *error_name) +{ + size_t prefix_length; + size_t i; + + prefix_length = strlen(A2DP_ERROR_PREFIX); + if (strncmp(A2DP_ERROR_PREFIX, error_name, prefix_length)) + return AVDTP_UNSUPPORTED_CONFIGURATION; + + error_name += prefix_length; + for (i = 0; i < ARRAY_SIZE(config_errors); i++) { + if (strcmp(config_errors[i].error_name, error_name) == 0) + return config_errors[i].error_code; + } + + return AVDTP_UNSUPPORTED_CONFIGURATION; +} + static struct a2dp_setup *setup_ref(struct a2dp_setup *setup) { setup->ref++; @@ -688,11 +755,10 @@ done: return FALSE; } -static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret) +static void endpoint_setconf_cb(struct a2dp_setup *setup, uint8_t error_code) { - if (ret == FALSE) - setup_error_init(setup, AVDTP_MEDIA_CODEC, - AVDTP_UNSUPPORTED_CONFIGURATION); + if (error_code != 0) + setup_error_init(setup, AVDTP_MEDIA_CODEC, error_code); auto_config(setup); setup_unref(setup); @@ -865,11 +931,11 @@ static gboolean endpoint_getcap_ind(struct avdtp *session, return TRUE; } -static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret) +static void endpoint_open_cb(struct a2dp_setup *setup, uint8_t error_code) { int err = error_to_errno(setup->err); - if (ret == FALSE) { + if (error_code != 0) { setup->stream = NULL; finalize_setup_errno(setup, -EPERM, finalize_config, NULL); goto done; diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h index c698bc983..afa02c12d 100644 --- a/profiles/audio/a2dp.h +++ b/profiles/audio/a2dp.h @@ -15,7 +15,8 @@ struct a2dp_setup; typedef void (*a2dp_endpoint_select_t) (struct a2dp_setup *setup, void *ret, int size); -typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, gboolean ret); +typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, + uint8_t error_code); struct a2dp_endpoint { const char *(*get_name) (struct a2dp_sep *sep, void *user_data); @@ -70,6 +71,8 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep, a2dp_config_cb_t cb, GSList *caps, void *user_data); +uint8_t a2dp_parse_config_error(const char *error_name); + unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep, a2dp_stream_cb_t cb, void *user_data); unsigned int a2dp_suspend(struct avdtp *session, struct a2dp_sep *sep, diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c index 30648251f..ed4e22b26 100644 --- a/profiles/audio/avdtp.c +++ b/profiles/audio/avdtp.c @@ -1494,8 +1494,8 @@ static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream, struct conf_rej rej; if (err != NULL) { - rej.error = AVDTP_UNSUPPORTED_CONFIGURATION; - rej.category = err->err.error_code; + rej.error = err->err.error_code; + rej.category = AVDTP_UNSUPPORTED_CONFIGURATION; avdtp_send(session, session->in_cmd.transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, &rej, sizeof(rej)); diff --git a/profiles/audio/media.c b/profiles/audio/media.c index 9b3042c18..332f643bb 100644 --- a/profiles/audio/media.c +++ b/profiles/audio/media.c @@ -333,7 +333,7 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) DBusMessage *reply; DBusMessageIter args, props; DBusError err; - gboolean value; + uint8_t error_code; void *ret = NULL; int size = -1; @@ -356,8 +356,12 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) if (dbus_message_is_method_call(request->msg, MEDIA_ENDPOINT_INTERFACE, - "SetConfiguration")) + "SetConfiguration")) { endpoint_remove_transport(endpoint, request->transport); + error_code = a2dp_parse_config_error(err.name); + ret = &error_code; + size = 1; + } dbus_error_free(&err); goto done; @@ -390,8 +394,8 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) } size = 1; - value = TRUE; - ret = &value; + error_code = 0; + ret = &error_code; done: dbus_message_unref(reply); @@ -634,9 +638,9 @@ static void config_cb(struct media_endpoint *endpoint, void *ret, int size, void *user_data) { struct a2dp_config_data *data = user_data; - gboolean *ret_value = ret; + uint8_t *ret_value = ret; - data->cb(data->setup, ret_value ? *ret_value : FALSE); + data->cb(data->setup, ret_value ? *ret_value : 1); } static int set_config(struct a2dp_sep *sep, uint8_t *configuration, @@ -1098,7 +1102,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, void *user_data) { struct pac_config_data *data = user_data; - gboolean *ret_value = ret; + uint8_t *error_code = ret; struct media_transport *transport; /* If transport was cleared, configuration was cancelled */ @@ -1106,7 +1110,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, if (!transport) return; - data->cb(data->stream, ret_value ? 0 : -EINVAL); + data->cb(data->stream, error_code == 0 ? 0 : -EINVAL); } static struct media_transport *pac_ucast_config(struct bt_bap_stream *stream, diff --git a/src/error.h b/src/error.h index 47602d39b..8157795c2 100644 --- a/src/error.h +++ b/src/error.h @@ -88,3 +88,41 @@ DBusMessage *btd_error_profile_unavailable(DBusMessage *msg); DBusMessage *btd_error_failed(DBusMessage *msg, const char *str); DBusMessage *btd_error_bredr_errno(DBusMessage *msg, int err); DBusMessage *btd_error_le_errno(DBusMessage *msg, int err); + +enum a2dp_error_codes : uint8_t { + A2DP_INVALID_CODEC_TYPE = 0xc1, + A2DP_NOT_SUPPORTED_CODEC_TYPE = 0xc2, + A2DP_INVALID_SAMPLING_FREQUENCY = 0xc3, + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xc4, + A2DP_INVALID_CHANNEL_MODE = 0xc5, + A2DP_NOT_SUPPORTED_CHANNEL_MODE = 0xc6, + A2DP_INVALID_SUBBANDS = 0xc7, + A2DP_NOT_SUPPORTED_SUBBANDS = 0xc8, + A2DP_INVALID_ALLOCATION_METHOD = 0xc9, + A2DP_NOT_SUPPORTED_ALLOCATION_METHOD = 0xca, + A2DP_INVALID_MINIMUM_BITPOOL_VALUE = 0xcb, + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xcc, + A2DP_INVALID_MAXIMUM_BITPOOL_VALUE = 0xcd, + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xce, + A2DP_INVALID_INVALID_LAYER = 0xcf, + A2DP_NOT_SUPPORTED_LAYER = 0xd0, + A2DP_NOT_SUPPORTERD_CRC = 0xd1, + A2DP_NOT_SUPPORTERD_MPF = 0xd2, + A2DP_NOT_SUPPORTERD_VBR = 0xd3, + A2DP_INVALID_BIT_RATE = 0xd4, + A2DP_NOT_SUPPORTED_BIT_RATE = 0xd5, + A2DP_INVALID_OBJECT_TYPE = 0xd6, + A2DP_NOT_SUPPORTED_OBJECT_TYPE = 0xd7, + A2DP_INVALID_CHANNELS = 0xd8, + A2DP_NOT_SUPPORTED_CHANNELS = 0xd9, + A2DP_INVALID_VERSION = 0xda, + A2DP_NOT_SUPPORTED_VERSION = 0xdb, + A2DP_NOT_SUPPORTED_MAXIMUM_SUL = 0xdc, + A2DP_INVALID_BLOCK_LENGTH = 0xdd, + A2DP_INVALID_CP_TYPE = 0xe0, + A2DP_INVALID_CP_FORMAT = 0xe1, + A2DP_INVALID_CODEC_PARAMETER = 0xe2, + A2DP_NOT_SUPPORTED_CODEC_PARAMETER = 0xe3, + A2DP_INVALID_DRC = 0xe4, + A2DP_NOT_SUPPORTED_DRC = 0xe5, +}; -- 2.43.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* RE: [BlueZ] audio: Add support for specific error codes for A2DP configuration 2025-09-11 13:53 [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration Per Waagø @ 2025-09-11 14:08 ` bluez.test.bot 2025-09-11 14:43 ` [PATCH BlueZ] " Luiz Augusto von Dentz 1 sibling, 0 replies; 8+ messages in thread From: bluez.test.bot @ 2025-09-11 14:08 UTC (permalink / raw) To: linux-bluetooth, pwaago [-- Attachment #1: Type: text/plain, Size: 27538 bytes --] This is automated email and please do not reply to this email! Dear submitter, Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series: PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1001368 ---Test result--- Test Summary: CheckPatch PENDING 0.30 seconds GitLint PENDING 0.40 seconds BuildEll PASS 19.86 seconds BluezMake FAIL 47.94 seconds MakeCheck FAIL 159.36 seconds MakeDistcheck FAIL 38.73 seconds CheckValgrind FAIL 41.27 seconds CheckSmatch FAIL 97.43 seconds bluezmakeextell FAIL 23.32 seconds IncrementalBuild PENDING 1.26 seconds ScanBuild FAIL 102.41 seconds Details ############################## Test: CheckPatch - PENDING Desc: Run checkpatch.pl script Output: ############################## Test: GitLint - PENDING Desc: Run gitlint Output: ############################## Test: BluezMake - FAIL Desc: Build BlueZ Output: In file included from tools/gatt-service.c:28: ./src/error.h:92:23: error: expected identifier or ‘(’ before ‘:’ token 92 | enum a2dp_error_codes : uint8_t { | ^ make[1]: *** [Makefile:6848: tools/gatt-service.o] Error 1 make[1]: *** Waiting for unfinished jobs.... tools/mgmt-tester.c: In function ‘main’: tools/mgmt-tester.c:12904:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without 12904 | int main(int argc, char *argv[]) | ^~~~ make: *** [Makefile:4039: all] Error 2 ############################## Test: MakeCheck - FAIL Desc: Run Bluez Make Check Output: In file included from tools/gatt-service.c:28: ./src/error.h:92:23: error: expected identifier or ‘(’ before ‘:’ token 92 | enum a2dp_error_codes : uint8_t { | ^ make[1]: *** [Makefile:6848: tools/gatt-service.o] Error 1 make: *** [Makefile:10469: check] Error 2 ############################## Test: MakeDistcheck - FAIL Desc: Run Bluez Make Distcheck Output: Package cups was not found in the pkg-config search path. Perhaps you should add the directory containing `cups.pc' to the PKG_CONFIG_PATH environment variable No package 'cups' found In file included from ../../tools/gatt-service.c:28: ../../src/error.h:92:23: error: expected identifier or ‘(’ before ‘:’ token 92 | enum a2dp_error_codes : uint8_t { | ^ make[2]: *** [Makefile:6848: tools/gatt-service.o] Error 1 make[2]: *** Waiting for unfinished jobs.... make[1]: *** [Makefile:4039: all] Error 2 make: *** [Makefile:10390: distcheck] Error 1 ############################## Test: CheckValgrind - FAIL Desc: Run Bluez Make Check with Valgrind Output: In file included from tools/gatt-service.c:28: ./src/error.h:92:23: error: expected identifier or ‘(’ before ‘:’ token 92 | enum a2dp_error_codes : uint8_t { | ^ make[1]: *** [Makefile:6848: tools/gatt-service.o] Error 1 make[1]: *** Waiting for unfinished jobs.... tools/mgmt-tester.c: In function ‘main’: tools/mgmt-tester.c:12904:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without 12904 | int main(int argc, char *argv[]) | ^~~~ make: *** [Makefile:10469: check] Error 2 ############################## Test: CheckSmatch - FAIL Desc: Run smatch tool with source Output: src/shared/crypto.c:271:21: warning: Variable length array is used. src/shared/crypto.c:272:23: warning: Variable length array is used. src/shared/gatt-helpers.c:768:31: warning: Variable length array is used. src/shared/gatt-helpers.c:830:31: warning: Variable length array is used. src/shared/gatt-helpers.c:1323:31: warning: Variable length array is used. src/shared/gatt-helpers.c:1354:23: warning: Variable length array is used. src/shared/gatt-server.c:278:25: warning: Variable length array is used. src/shared/gatt-server.c:618:25: warning: Variable length array is used. src/shared/gatt-server.c:716:25: warning: Variable length array is used. src/shared/bap.c:317:25: warning: array of flexible structures src/shared/bap.c: note: in included file: ./src/shared/ascs.h:88:25: warning: array of flexible structures src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h): /usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function' /usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction' /usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction' /usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction' src/shared/crypto.c:271:21: warning: Variable length array is used. src/shared/crypto.c:272:23: warning: Variable length array is used. src/shared/gatt-helpers.c:768:31: warning: Variable length array is used. src/shared/gatt-helpers.c:830:31: warning: Variable length array is used. src/shared/gatt-helpers.c:1323:31: warning: Variable length array is used. src/shared/gatt-helpers.c:1354:23: warning: Variable length array is used. src/shared/gatt-server.c:278:25: warning: Variable length array is used. src/shared/gatt-server.c:618:25: warning: Variable length array is used. src/shared/gatt-server.c:716:25: warning: Variable length array is used. src/shared/bap.c:317:25: warning: array of flexible structures src/shared/bap.c: note: in included file: ./src/shared/ascs.h:88:25: warning: array of flexible structures src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h): /usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function' /usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction' /usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction' /usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction' tools/mesh-cfgtest.c:1453:17: warning: unknown escape sequence: '\%' tools/sco-tester.c: note: in included file: ./lib/bluetooth/bluetooth.h:232:15: warning: array of flexible structures ./lib/bluetooth/bluetooth.h:237:31: warning: array of flexible structures tools/bneptest.c:634:39: warning: unknown escape sequence: '\%' tools/seq2bseq.c:57:26: warning: Variable length array is used. tools/gatt-service.c: note: in included file: ./src/error.h:92:23: warning: missing identifier in declaration ./src/error.h:92:23: error: Expected ; at the end of type declaration ./src/error.h:92:23: error: got : In file included from tools/gatt-service.c:28: ./src/error.h:92:23: error: expected identifier or ‘(’ before ‘:’ token 92 | enum a2dp_error_codes : uint8_t { | ^ make[1]: *** [Makefile:6848: tools/gatt-service.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:4039: all] Error 2 ############################## Test: bluezmakeextell - FAIL Desc: Build Bluez with External ELL Output: In file included from tools/gatt-service.c:28: ./src/error.h:92:23: error: expected identifier or ‘(’ before ‘:’ token 92 | enum a2dp_error_codes : uint8_t { | ^ make[1]: *** [Makefile:6848: tools/gatt-service.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:4039: all] Error 2 ############################## Test: IncrementalBuild - PENDING Desc: Incremental build with the patches in the series Output: ############################## Test: ScanBuild - FAIL Desc: Run Scan Build Output: src/shared/gatt-client.c:451:21: warning: Use of memory after it is freed gatt_db_unregister(op->client->db, op->db_id); ^~~~~~~~~~ src/shared/gatt-client.c:696:2: warning: Use of memory after it is freed discovery_op_complete(op, false, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:996:2: warning: Use of memory after it is freed discovery_op_complete(op, success, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1102:2: warning: Use of memory after it is freed discovery_op_complete(op, success, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1296:2: warning: Use of memory after it is freed discovery_op_complete(op, success, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1361:2: warning: Use of memory after it is freed discovery_op_complete(op, success, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1636:6: warning: Use of memory after it is freed if (read_db_hash(op)) { ^~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1641:2: warning: Use of memory after it is freed discover_all(op); ^~~~~~~~~~~~~~~~ src/shared/gatt-client.c:2147:6: warning: Use of memory after it is freed if (read_db_hash(op)) { ^~~~~~~~~~~~~~~~ src/shared/gatt-client.c:2155:8: warning: Use of memory after it is freed discovery_op_ref(op), ^~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:3180:2: warning: Use of memory after it is freed complete_write_long_op(req, success, 0, false); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:3202:2: warning: Use of memory after it is freed request_unref(req); ^~~~~~~~~~~~~~~~~~ 12 warnings generated. src/shared/bap.c:1534:8: warning: Use of memory after it is freed bap = bt_bap_ref_safe(bap); ^~~~~~~~~~~~~~~~~~~~ src/shared/bap.c:2316:20: warning: Use of memory after it is freed return queue_find(stream->bap->streams, NULL, stream); ^~~~~~~~~~~~~~~~~~~~ 2 warnings generated. src/shared/gatt-client.c:451:21: warning: Use of memory after it is freed gatt_db_unregister(op->client->db, op->db_id); ^~~~~~~~~~ src/shared/gatt-client.c:696:2: warning: Use of memory after it is freed discovery_op_complete(op, false, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:996:2: warning: Use of memory after it is freed discovery_op_complete(op, success, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1102:2: warning: Use of memory after it is freed discovery_op_complete(op, success, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1296:2: warning: Use of memory after it is freed discovery_op_complete(op, success, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1361:2: warning: Use of memory after it is freed discovery_op_complete(op, success, att_ecode); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1636:6: warning: Use of memory after it is freed if (read_db_hash(op)) { ^~~~~~~~~~~~~~~~ src/shared/gatt-client.c:1641:2: warning: Use of memory after it is freed discover_all(op); ^~~~~~~~~~~~~~~~ src/shared/gatt-client.c:2147:6: warning: Use of memory after it is freed if (read_db_hash(op)) { ^~~~~~~~~~~~~~~~ src/shared/gatt-client.c:2155:8: warning: Use of memory after it is freed discovery_op_ref(op), ^~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:3180:2: warning: Use of memory after it is freed complete_write_long_op(req, success, 0, false); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/shared/gatt-client.c:3202:2: warning: Use of memory after it is freed request_unref(req); ^~~~~~~~~~~~~~~~~~ 12 warnings generated. tools/hciattach.c:817:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' if ((n = read_hci_event(fd, resp, 10)) < 0) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/hciattach.c:865:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' if ((n = read_hci_event(fd, resp, 4)) < 0) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/hciattach.c:887:8: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' if ((n = read_hci_event(fd, resp, 10)) < 0) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/hciattach.c:909:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' if ((n = read_hci_event(fd, resp, 4)) < 0) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/hciattach.c:930:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' if ((n = read_hci_event(fd, resp, 4)) < 0) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/hciattach.c:974:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' if ((n = read_hci_event(fd, resp, 6)) < 0) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 warnings generated. src/shared/bap.c:1534:8: warning: Use of memory after it is freed bap = bt_bap_ref_safe(bap); ^~~~~~~~~~~~~~~~~~~~ src/shared/bap.c:2316:20: warning: Use of memory after it is freed return queue_find(stream->bap->streams, NULL, stream); ^~~~~~~~~~~~~~~~~~~~ 2 warnings generated. src/oui.c:50:2: warning: Value stored to 'hwdb' is never read hwdb = udev_hwdb_unref(hwdb); ^ ~~~~~~~~~~~~~~~~~~~~~ src/oui.c:53:2: warning: Value stored to 'udev' is never read udev = udev_unref(udev); ^ ~~~~~~~~~~~~~~~~ 2 warnings generated. tools/rfcomm.c:234:3: warning: Value stored to 'i' is never read i = execvp(cmdargv[0], cmdargv); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/rfcomm.c:234:7: warning: Null pointer passed to 1st parameter expecting 'nonnull' i = execvp(cmdargv[0], cmdargv); ^~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/rfcomm.c:354:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd' if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/rfcomm.c:497:14: warning: Assigned value is garbage or undefined req.channel = raddr.rc_channel; ^ ~~~~~~~~~~~~~~~~ tools/rfcomm.c:515:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd' if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 warnings generated. tools/hcidump.c:180:9: warning: Potential leak of memory pointed to by 'dp' if (fds[i].fd == sock) ^~~ tools/hcidump.c:248:17: warning: Assigned value is garbage or undefined dh->ts_sec = htobl(frm.ts.tv_sec); ^ ~~~~~~~~~~~~~~~~~~~~ tools/hcidump.c:326:9: warning: 1st function call argument is an uninitialized value if (be32toh(dp.flags) & 0x02) { ^~~~~~~~~~~~~~~~~ /usr/include/endian.h:46:22: note: expanded from macro 'be32toh' # define be32toh(x) __bswap_32 (x) ^~~~~~~~~~~~~~ tools/hcidump.c:341:20: warning: 1st function call argument is an uninitialized value frm.data_len = be32toh(dp.len); ^~~~~~~~~~~~~~~ /usr/include/endian.h:46:22: note: expanded from macro 'be32toh' # define be32toh(x) __bswap_32 (x) ^~~~~~~~~~~~~~ tools/hcidump.c:346:14: warning: 1st function call argument is an uninitialized value opcode = be32toh(dp.flags) & 0xffff; ^~~~~~~~~~~~~~~~~ /usr/include/endian.h:46:22: note: expanded from macro 'be32toh' # define be32toh(x) __bswap_32 (x) ^~~~~~~~~~~~~~ tools/hcidump.c:384:17: warning: Assigned value is garbage or undefined frm.data_len = btohs(dh.len); ^ ~~~~~~~~~~~~~ tools/hcidump.c:394:11: warning: Assigned value is garbage or undefined frm.len = frm.data_len; ^ ~~~~~~~~~~~~ tools/hcidump.c:398:9: warning: 1st function call argument is an uninitialized value ts = be64toh(ph.ts); ^~~~~~~~~~~~~~ /usr/include/endian.h:51:22: note: expanded from macro 'be64toh' # define be64toh(x) __bswap_64 (x) ^~~~~~~~~~~~~~ tools/hcidump.c:403:13: warning: 1st function call argument is an uninitialized value frm.in = be32toh(dp.flags) & 0x01; ^~~~~~~~~~~~~~~~~ /usr/include/endian.h:46:22: note: expanded from macro 'be32toh' # define be32toh(x) __bswap_32 (x) ^~~~~~~~~~~~~~ tools/hcidump.c:408:11: warning: Assigned value is garbage or undefined frm.in = dh.in; ^ ~~~~~ tools/hcidump.c:437:7: warning: Null pointer passed to 1st parameter expecting 'nonnull' fd = open(file, open_flags, 0644); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 warnings generated. tools/ciptool.c:351:7: warning: 5th function call argument is an uninitialized value sk = do_connect(ctl, dev_id, &src, &dst, psm, (1 << CMTP_LOOPBACK)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 warning generated. src/sdp-xml.c:126:10: warning: Assigned value is garbage or undefined buf[1] = data[i + 1]; ^ ~~~~~~~~~~~ src/sdp-xml.c:306:11: warning: Assigned value is garbage or undefined buf[1] = data[i + 1]; ^ ~~~~~~~~~~~ src/sdp-xml.c:344:11: warning: Assigned value is garbage or undefined buf[1] = data[i + 1]; ^ ~~~~~~~~~~~ 3 warnings generated. tools/sdptool.c:941:26: warning: Result of 'malloc' is converted to a pointer of type 'uint32_t', which is incompatible with sizeof operand type 'int' uint32_t *value_int = malloc(sizeof(int)); ~~~~~~~~~~ ^~~~~~ ~~~~~~~~~~~ tools/sdptool.c:980:4: warning: 1st function call argument is an uninitialized value free(allocArray[i]); ^~~~~~~~~~~~~~~~~~~ tools/sdptool.c:3777:2: warning: Potential leak of memory pointed to by 'si.name' return add_service(0, &si); ^~~~~~~~~~~~~~~~~~~~~~~~~~ tools/sdptool.c:4112:4: warning: Potential leak of memory pointed to by 'context.svc' return -1; ^~~~~~~~~ 4 warnings generated. tools/avtest.c:243:5: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:253:5: warning: Value stored to 'len' is never read len = write(sk, buf, 4); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:262:5: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:276:5: warning: Value stored to 'len' is never read len = write(sk, buf, ^ ~~~~~~~~~~~~~~ tools/avtest.c:283:5: warning: Value stored to 'len' is never read len = write(sk, buf, ^ ~~~~~~~~~~~~~~ tools/avtest.c:290:5: warning: Value stored to 'len' is never read len = write(sk, buf, ^ ~~~~~~~~~~~~~~ tools/avtest.c:297:5: warning: Value stored to 'len' is never read len = write(sk, buf, ^ ~~~~~~~~~~~~~~ tools/avtest.c:309:5: warning: Value stored to 'len' is never read len = write(sk, buf, 4); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:313:5: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:322:5: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:326:5: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:335:5: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:342:5: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:364:5: warning: Value stored to 'len' is never read len = write(sk, buf, 4); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:368:5: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:377:5: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:381:5: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:394:5: warning: Value stored to 'len' is never read len = write(sk, buf, 4); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:398:5: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:405:4: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:415:4: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:580:3: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:588:3: warning: Value stored to 'len' is never read len = write(sk, buf, invalid ? 2 : 3); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/avtest.c:602:3: warning: Value stored to 'len' is never read len = write(sk, buf, 4 + media_transport_size); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/avtest.c:615:3: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:625:3: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:637:3: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:652:3: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:664:3: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:673:3: warning: Value stored to 'len' is never read len = write(sk, buf, 3); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:680:3: warning: Value stored to 'len' is never read len = write(sk, buf, 2); ^ ~~~~~~~~~~~~~~~~~ tools/avtest.c:716:2: warning: Value stored to 'len' is never read len = write(sk, buf, AVCTP_HEADER_LENGTH + sizeof(play_pressed)); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 warnings generated. tools/btproxy.c:836:15: warning: Null pointer passed to 1st parameter expecting 'nonnull' tcp_port = atoi(optarg); ^~~~~~~~~~~~ tools/btproxy.c:839:8: warning: Null pointer passed to 1st parameter expecting 'nonnull' if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3)) ^~~~~~~~~~~~~~ 2 warnings generated. tools/create-image.c:76:3: warning: Value stored to 'fd' is never read fd = -1; ^ ~~ tools/create-image.c:84:3: warning: Value stored to 'fd' is never read fd = -1; ^ ~~ tools/create-image.c:92:3: warning: Value stored to 'fd' is never read fd = -1; ^ ~~ tools/create-image.c:105:2: warning: Value stored to 'fd' is never read fd = -1; ^ ~~ 4 warnings generated. tools/iso-tester.c:1906:7: warning: Potential leak of memory pointed to by 'addr' err = bind(sk, (struct sockaddr *) addr, sizeof(*addr) + ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ tools/iso-tester.c:1914:7: warning: Potential leak of memory pointed to by 'addr' err = bind(sk, (struct sockaddr *) addr, sizeof(*addr)); ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 warnings generated. tools/check-selftest.c:42:3: warning: Value stored to 'ptr' is never read ptr = fgets(result, sizeof(result), fp); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 warning generated. In file included from tools/gatt-service.c:28: ./src/error.h:92:23: error: expected identifier or ‘(’ before ‘:’ token 92 | enum a2dp_error_codes : uint8_t { | ^ make[1]: *** [Makefile:6848: tools/gatt-service.o] Error 1 make[1]: *** Waiting for unfinished jobs.... tools/btgatt-client.c:1824:2: warning: Value stored to 'argv' is never read argv += optind; ^ ~~~~~~ 1 warning generated. tools/btgatt-server.c:1212:2: warning: Value stored to 'argv' is never read argv -= optind; ^ ~~~~~~ 1 warning generated. make: *** [Makefile:4039: all] Error 2 --- Regards, Linux Bluetooth ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration 2025-09-11 13:53 [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration Per Waagø 2025-09-11 14:08 ` [BlueZ] " bluez.test.bot @ 2025-09-11 14:43 ` Luiz Augusto von Dentz 2025-09-11 15:12 ` Per Waago (pwaago) 2025-09-11 16:25 ` Pauli Virtanen 1 sibling, 2 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2025-09-11 14:43 UTC (permalink / raw) To: Per Waagø, Pauli Virtanen; +Cc: linux-bluetooth Hi Per, On Thu, Sep 11, 2025 at 9:56 AM Per Waagø <pwaago@cisco.com> wrote: > > The A2DP specification defines error codes that shall be used if > the codec capabilities contain improper settings. This change allows > clients to trigger the sending of these specific error codes by > returning the corresponding error messages from > MediaEndpoint1.SetConfiguration. > > This update is fully backwards compatible: clients passing other error > messages will continue to receive the default error code as before. On > older BlueZ versions, these new errors will also result in the default > error code, enabling clients to implement support for the new errors > without breaking compatibility. While I can see the value for debugging I doubt we could do any handling of these errors, so the result would be the same regardless of what error is sent back it is not recoverable. @Pauli Virtanen Perhaps you can give some feedback regarding these codes, would pipewire be interested in generating specific error codes? Some of them seems to be SBC specific like bitpool. > This change enables passing A2DP/SNK/AVP/* and A2DP/SRC/AVP/* > qualification tests. > --- > doc/org.bluez.MediaEndpoint.rst | 37 ++++++++++++++++ > profiles/audio/a2dp.c | 78 ++++++++++++++++++++++++++++++--- > profiles/audio/a2dp.h | 5 ++- > profiles/audio/avdtp.c | 4 +- > profiles/audio/media.c | 20 +++++---- > src/error.h | 38 ++++++++++++++++ > 6 files changed, 165 insertions(+), 17 deletions(-) > > diff --git a/doc/org.bluez.MediaEndpoint.rst b/doc/org.bluez.MediaEndpoint.rst > index 474cc1160..2721d473e 100644 > --- a/doc/org.bluez.MediaEndpoint.rst > +++ b/doc/org.bluez.MediaEndpoint.rst > @@ -54,6 +54,43 @@ be configured and the properties must contain the following properties: > > See **org.bluez.MediaTransport(5)** QoS property. > > + Possible errors: > + :org.bluez.Error.A2DP.InvalidCodecType: > + :org.bluez.Error.A2DP.NotSupportedCodecType: > + :org.bluez.Error.A2DP.InvalidSamplingFrequency: > + :org.bluez.Error.A2DP.NotSupportedSamplingFrequency: > + :org.bluez.Error.A2DP.InvalidChannelMode: > + :org.bluez.Error.A2DP.NotSupportedChannelMode: > + :org.bluez.Error.A2DP.InvalidSubbands: > + :org.bluez.Error.A2DP.NotSupportedSubbands: > + :org.bluez.Error.A2DP.InvalidAllocationMethod: > + :org.bluez.Error.A2DP.NotSupportedAllocationMethod: > + :org.bluez.Error.A2DP.InvalidMinimumBitpoolValue: > + :org.bluez.Error.A2DP.NotSupportedMinimumBitpoolValue: > + :org.bluez.Error.A2DP.InvalidMaximumBitpoolValue: > + :org.bluez.Error.A2DP.NotSupportedMaximumBitpoolValue: > + :org.bluez.Error.A2DP.InvalidInvalidLayer: > + :org.bluez.Error.A2DP.NotSupportedLayer: > + :org.bluez.Error.A2DP.NotSupporterdCRC: > + :org.bluez.Error.A2DP.NotSupporterdMPF: > + :org.bluez.Error.A2DP.NotSupporterdVBR: > + :org.bluez.Error.A2DP.InvalidBitRate: > + :org.bluez.Error.A2DP.NotSupportedBitRate: > + :org.bluez.Error.A2DP.InvalidObjectType: > + :org.bluez.Error.A2DP.NotSupportedObjectType: > + :org.bluez.Error.A2DP.InvalidChannels: > + :org.bluez.Error.A2DP.NotSupportedChannels: > + :org.bluez.Error.A2DP.InvalidVersion: > + :org.bluez.Error.A2DP.NotSupportedVersion: > + :org.bluez.Error.A2DP.NotSupportedMaximumSUL: > + :org.bluez.Error.A2DP.InvalidBlockLength: > + :org.bluez.Error.A2DP.InvalidCPType: > + :org.bluez.Error.A2DP.InvalidCPFormat: > + :org.bluez.Error.A2DP.InvalidCodecParameter: > + :org.bluez.Error.A2DP.NotSupportedCodecParameter: > + :org.bluez.Error.A2DP.InvalidDRC: > + :org.bluez.Error.A2DP.NotSupportedDRC: Introducing a error domain for A2DP is probably a good idea, but this only applies to endpoints that are A2DP specific, so this need to be adjusted to e.g.: possible for A2DP or something like that, also I don't know how the client would be able to tell it can return these errors? Or the expectation is that the client can start sending them immediately since the old behavior will convert them to AVDTP_UNSUPPORTED_CONFIGURATION anyway? While at it split the commit to have the documentation changes as a separate change. > array{byte} SelectConfiguration(array{byte} capabilities) > ````````````````````````````````````````````````````````` > > diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c > index c0a53eae9..661843a89 100644 > --- a/profiles/audio/a2dp.c > +++ b/profiles/audio/a2dp.c > @@ -157,6 +157,73 @@ static GSList *servers = NULL; > static GSList *setups = NULL; > static unsigned int cb_id = 0; > > +struct a2dp_error { > + const char *error_name; > + uint8_t error_code; > +}; > + > +#define A2DP_ERROR_PREFIX ERROR_INTERFACE ".A2DP." > + > +static struct a2dp_error config_errors[] = { > + {"InvalidCodecType", A2DP_INVALID_CODEC_TYPE}, > + {"NotSupportedCodecType", A2DP_NOT_SUPPORTED_CODEC_TYPE}, > + {"InvalidSamplingFrequency", A2DP_INVALID_SAMPLING_FREQUENCY}, > + {"NotSupportedSamplingFrequency", > + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY}, > + {"InvalidChannelMode", A2DP_INVALID_CHANNEL_MODE}, > + {"NotSupportedChannelMode", A2DP_NOT_SUPPORTED_CHANNEL_MODE}, > + {"InvalidSubbands", A2DP_INVALID_SUBBANDS}, > + {"NotSupportedSubbands", A2DP_NOT_SUPPORTED_SUBBANDS}, > + {"InvalidAllocationMethod", A2DP_INVALID_ALLOCATION_METHOD}, > + {"NotSupportedAllocationMethod", A2DP_NOT_SUPPORTED_ALLOCATION_METHOD}, > + {"InvalidMinimumBitpoolValue", > + A2DP_INVALID_MINIMUM_BITPOOL_VALUE}, > + {"NotSupportedMinimumBitpoolValue", > + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE}, > + {"InvalidMaximumBitpoolValue", A2DP_INVALID_MAXIMUM_BITPOOL_VALUE}, > + {"NotSupportedMaximumBitpoolValue", > + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE}, > + {"InvalidInvalidLayer", A2DP_INVALID_INVALID_LAYER}, > + {"NotSupportedLayer", A2DP_NOT_SUPPORTED_LAYER}, > + {"NotSupporterdCRC", A2DP_NOT_SUPPORTERD_CRC}, > + {"NotSupporterdMPF", A2DP_NOT_SUPPORTERD_MPF}, > + {"NotSupporterdVBR", A2DP_NOT_SUPPORTERD_VBR}, > + {"InvalidBitRate", A2DP_INVALID_BIT_RATE}, > + {"NotSupportedBitRate", A2DP_NOT_SUPPORTED_BIT_RATE}, > + {"InvalidObjectType", A2DP_INVALID_OBJECT_TYPE}, > + {"NotSupportedObjectType", A2DP_NOT_SUPPORTED_OBJECT_TYPE}, > + {"InvalidChannels", A2DP_INVALID_CHANNELS}, > + {"NotSupportedChannels", A2DP_NOT_SUPPORTED_CHANNELS}, > + {"InvalidVersion", A2DP_INVALID_VERSION}, > + {"NotSupportedVersion", A2DP_NOT_SUPPORTED_VERSION}, > + {"NotSupportedMaximumSUL", A2DP_NOT_SUPPORTED_MAXIMUM_SUL}, > + {"InvalidBlockLength", A2DP_INVALID_BLOCK_LENGTH}, > + {"InvalidCPType", A2DP_INVALID_CP_TYPE}, > + {"InvalidCPFormat", A2DP_INVALID_CP_FORMAT}, > + {"InvalidCodecParameter", A2DP_INVALID_CODEC_PARAMETER}, > + {"NotSupportedCodecParameter", A2DP_NOT_SUPPORTED_CODEC_PARAMETER}, > + {"InvalidDRC", A2DP_INVALID_DRC}, > + {"NotSupportedDRC", A2DP_NOT_SUPPORTED_DRC} > +}; > + > +uint8_t a2dp_parse_config_error(const char *error_name) > +{ > + size_t prefix_length; > + size_t i; > + > + prefix_length = strlen(A2DP_ERROR_PREFIX); > + if (strncmp(A2DP_ERROR_PREFIX, error_name, prefix_length)) > + return AVDTP_UNSUPPORTED_CONFIGURATION; > + > + error_name += prefix_length; > + for (i = 0; i < ARRAY_SIZE(config_errors); i++) { > + if (strcmp(config_errors[i].error_name, error_name) == 0) > + return config_errors[i].error_code; > + } > + > + return AVDTP_UNSUPPORTED_CONFIGURATION; > +} > + > static struct a2dp_setup *setup_ref(struct a2dp_setup *setup) > { > setup->ref++; > @@ -688,11 +755,10 @@ done: > return FALSE; > } > > -static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret) > +static void endpoint_setconf_cb(struct a2dp_setup *setup, uint8_t error_code) > { > - if (ret == FALSE) > - setup_error_init(setup, AVDTP_MEDIA_CODEC, > - AVDTP_UNSUPPORTED_CONFIGURATION); > + if (error_code != 0) > + setup_error_init(setup, AVDTP_MEDIA_CODEC, error_code); > > auto_config(setup); > setup_unref(setup); > @@ -865,11 +931,11 @@ static gboolean endpoint_getcap_ind(struct avdtp *session, > return TRUE; > } > > -static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret) > +static void endpoint_open_cb(struct a2dp_setup *setup, uint8_t error_code) > { > int err = error_to_errno(setup->err); > > - if (ret == FALSE) { > + if (error_code != 0) { > setup->stream = NULL; > finalize_setup_errno(setup, -EPERM, finalize_config, NULL); > goto done; > diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h > index c698bc983..afa02c12d 100644 > --- a/profiles/audio/a2dp.h > +++ b/profiles/audio/a2dp.h > @@ -15,7 +15,8 @@ struct a2dp_setup; > > typedef void (*a2dp_endpoint_select_t) (struct a2dp_setup *setup, void *ret, > int size); > -typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, gboolean ret); > +typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, > + uint8_t error_code); > > struct a2dp_endpoint { > const char *(*get_name) (struct a2dp_sep *sep, void *user_data); > @@ -70,6 +71,8 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, > unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep, > a2dp_config_cb_t cb, GSList *caps, > void *user_data); > +uint8_t a2dp_parse_config_error(const char *error_name); > + > unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep, > a2dp_stream_cb_t cb, void *user_data); > unsigned int a2dp_suspend(struct avdtp *session, struct a2dp_sep *sep, > diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c > index 30648251f..ed4e22b26 100644 > --- a/profiles/audio/avdtp.c > +++ b/profiles/audio/avdtp.c > @@ -1494,8 +1494,8 @@ static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream, > struct conf_rej rej; > > if (err != NULL) { > - rej.error = AVDTP_UNSUPPORTED_CONFIGURATION; > - rej.category = err->err.error_code; > + rej.error = err->err.error_code; > + rej.category = AVDTP_UNSUPPORTED_CONFIGURATION; > avdtp_send(session, session->in_cmd.transaction, > AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, > &rej, sizeof(rej)); > diff --git a/profiles/audio/media.c b/profiles/audio/media.c > index 9b3042c18..332f643bb 100644 > --- a/profiles/audio/media.c > +++ b/profiles/audio/media.c > @@ -333,7 +333,7 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > DBusMessage *reply; > DBusMessageIter args, props; > DBusError err; > - gboolean value; > + uint8_t error_code; > void *ret = NULL; > int size = -1; > > @@ -356,8 +356,12 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > if (dbus_message_is_method_call(request->msg, > MEDIA_ENDPOINT_INTERFACE, > - "SetConfiguration")) > + "SetConfiguration")) { > endpoint_remove_transport(endpoint, request->transport); > + error_code = a2dp_parse_config_error(err.name); > + ret = &error_code; > + size = 1; > + } > > dbus_error_free(&err); > goto done; > @@ -390,8 +394,8 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > } > > size = 1; > - value = TRUE; > - ret = &value; > + error_code = 0; > + ret = &error_code; > > done: > dbus_message_unref(reply); > @@ -634,9 +638,9 @@ static void config_cb(struct media_endpoint *endpoint, void *ret, int size, > void *user_data) > { > struct a2dp_config_data *data = user_data; > - gboolean *ret_value = ret; > + uint8_t *ret_value = ret; > > - data->cb(data->setup, ret_value ? *ret_value : FALSE); > + data->cb(data->setup, ret_value ? *ret_value : 1); > } > > static int set_config(struct a2dp_sep *sep, uint8_t *configuration, > @@ -1098,7 +1102,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, > void *user_data) > { > struct pac_config_data *data = user_data; > - gboolean *ret_value = ret; > + uint8_t *error_code = ret; > struct media_transport *transport; > > /* If transport was cleared, configuration was cancelled */ > @@ -1106,7 +1110,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, > if (!transport) > return; > > - data->cb(data->stream, ret_value ? 0 : -EINVAL); > + data->cb(data->stream, error_code == 0 ? 0 : -EINVAL); > } > > static struct media_transport *pac_ucast_config(struct bt_bap_stream *stream, > diff --git a/src/error.h b/src/error.h > index 47602d39b..8157795c2 100644 > --- a/src/error.h > +++ b/src/error.h > @@ -88,3 +88,41 @@ DBusMessage *btd_error_profile_unavailable(DBusMessage *msg); > DBusMessage *btd_error_failed(DBusMessage *msg, const char *str); > DBusMessage *btd_error_bredr_errno(DBusMessage *msg, int err); > DBusMessage *btd_error_le_errno(DBusMessage *msg, int err); > + > +enum a2dp_error_codes : uint8_t { > + A2DP_INVALID_CODEC_TYPE = 0xc1, > + A2DP_NOT_SUPPORTED_CODEC_TYPE = 0xc2, > + A2DP_INVALID_SAMPLING_FREQUENCY = 0xc3, > + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xc4, > + A2DP_INVALID_CHANNEL_MODE = 0xc5, > + A2DP_NOT_SUPPORTED_CHANNEL_MODE = 0xc6, > + A2DP_INVALID_SUBBANDS = 0xc7, > + A2DP_NOT_SUPPORTED_SUBBANDS = 0xc8, > + A2DP_INVALID_ALLOCATION_METHOD = 0xc9, > + A2DP_NOT_SUPPORTED_ALLOCATION_METHOD = 0xca, > + A2DP_INVALID_MINIMUM_BITPOOL_VALUE = 0xcb, > + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xcc, > + A2DP_INVALID_MAXIMUM_BITPOOL_VALUE = 0xcd, > + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xce, > + A2DP_INVALID_INVALID_LAYER = 0xcf, > + A2DP_NOT_SUPPORTED_LAYER = 0xd0, > + A2DP_NOT_SUPPORTERD_CRC = 0xd1, > + A2DP_NOT_SUPPORTERD_MPF = 0xd2, > + A2DP_NOT_SUPPORTERD_VBR = 0xd3, > + A2DP_INVALID_BIT_RATE = 0xd4, > + A2DP_NOT_SUPPORTED_BIT_RATE = 0xd5, > + A2DP_INVALID_OBJECT_TYPE = 0xd6, > + A2DP_NOT_SUPPORTED_OBJECT_TYPE = 0xd7, > + A2DP_INVALID_CHANNELS = 0xd8, > + A2DP_NOT_SUPPORTED_CHANNELS = 0xd9, > + A2DP_INVALID_VERSION = 0xda, > + A2DP_NOT_SUPPORTED_VERSION = 0xdb, > + A2DP_NOT_SUPPORTED_MAXIMUM_SUL = 0xdc, > + A2DP_INVALID_BLOCK_LENGTH = 0xdd, > + A2DP_INVALID_CP_TYPE = 0xe0, > + A2DP_INVALID_CP_FORMAT = 0xe1, > + A2DP_INVALID_CODEC_PARAMETER = 0xe2, > + A2DP_NOT_SUPPORTED_CODEC_PARAMETER = 0xe3, > + A2DP_INVALID_DRC = 0xe4, > + A2DP_NOT_SUPPORTED_DRC = 0xe5, > +}; Hmm, I guess there should be part of a2dp.h since this error header is about D-Bus not A2DP codes. > -- > 2.43.0 > > -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration 2025-09-11 14:43 ` [PATCH BlueZ] " Luiz Augusto von Dentz @ 2025-09-11 15:12 ` Per Waago (pwaago) 2025-09-11 15:52 ` Luiz Augusto von Dentz 2025-09-11 16:25 ` Pauli Virtanen 1 sibling, 1 reply; 8+ messages in thread From: Per Waago (pwaago) @ 2025-09-11 15:12 UTC (permalink / raw) To: Luiz Augusto von Dentz, Pauli Virtanen; +Cc: linux-bluetooth@vger.kernel.org Hi Luiz, thanks for reviewing. > From: Luiz Augusto von Dentz <luiz.dentz@gmail.com> > Sent: Thursday, September 11, 2025 16:43 > To: Per Waago (pwaago); Pauli Virtanen > Cc: linux-bluetooth@vger.kernel.org > Subject: Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration > > Hi Per, > > On Thu, Sep 11, 2025 at 9:56 AM Per Waagø <pwaago@cisco.com> wrote: > > > > The A2DP specification defines error codes that shall be used if > > the codec capabilities contain improper settings. This change allows > > clients to trigger the sending of these specific error codes by > > returning the corresponding error messages from > > MediaEndpoint1.SetConfiguration. > > > > This update is fully backwards compatible: clients passing other error > > messages will continue to receive the default error code as before. On > > older BlueZ versions, these new errors will also result in the default > > error code, enabling clients to implement support for the new errors > > without breaking compatibility. > > While I can see the value for debugging I doubt we could do any > handling of these errors, so the result would be the same regardless > of what error is sent back it is not recoverable. > The main motivation for adding them is to be able to pass the mandatory qualification tests, which now checks the errors codes returned from SetConfiguration in detail. I don't think they are very useful otherwise. The errors are specified in table 5.5 in the A2DP spec: https://www.bluetooth.com/specifications/specs/html/?src=a2dp_v1-4-1_1752513648/A2DP_v1.4.1/out/en/index-en.html#UUID-0ba19ee9-7277-1068-d2dc-b9e638cca568_Table_5.5 I included all of them for completeness. In that table, it is also stated which codecs they apply to. Some are SBC-specific, some apply to all codecs or other codecs. > @Pauli Virtanen Perhaps you can give some feedback regarding these > codes, would pipewire be interested in generating specific error > codes? Some of them seems to be SBC specific like bitpool. > > > This change enables passing A2DP/SNK/AVP/* and A2DP/SRC/AVP/* > > qualification tests. > > --- > > doc/org.bluez.MediaEndpoint.rst | 37 ++++++++++++++++ > > profiles/audio/a2dp.c | 78 ++++++++++++++++++++++++++++++--- > > profiles/audio/a2dp.h | 5 ++- > > profiles/audio/avdtp.c | 4 +- > > profiles/audio/media.c | 20 +++++---- > > src/error.h | 38 ++++++++++++++++ > > 6 files changed, 165 insertions(+), 17 deletions(-) > > > > diff --git a/doc/org.bluez.MediaEndpoint.rst b/doc/org.bluez.MediaEndpoint.rst > > index 474cc1160..2721d473e 100644 > > --- a/doc/org.bluez.MediaEndpoint.rst > > +++ b/doc/org.bluez.MediaEndpoint.rst > > @@ -54,6 +54,43 @@ be configured and the properties must contain the following properties: > > > > See **org.bluez.MediaTransport(5)** QoS property. > > > > + Possible errors: > > + :org.bluez.Error.A2DP.InvalidCodecType: > > + :org.bluez.Error.A2DP.NotSupportedCodecType: > > + :org.bluez.Error.A2DP.InvalidSamplingFrequency: > > + :org.bluez.Error.A2DP.NotSupportedSamplingFrequency: > > + :org.bluez.Error.A2DP.InvalidChannelMode: > > + :org.bluez.Error.A2DP.NotSupportedChannelMode: > > + :org.bluez.Error.A2DP.InvalidSubbands: > > + :org.bluez.Error.A2DP.NotSupportedSubbands: > > + :org.bluez.Error.A2DP.InvalidAllocationMethod: > > + :org.bluez.Error.A2DP.NotSupportedAllocationMethod: > > + :org.bluez.Error.A2DP.InvalidMinimumBitpoolValue: > > + :org.bluez.Error.A2DP.NotSupportedMinimumBitpoolValue: > > + :org.bluez.Error.A2DP.InvalidMaximumBitpoolValue: > > + :org.bluez.Error.A2DP.NotSupportedMaximumBitpoolValue: > > + :org.bluez.Error.A2DP.InvalidInvalidLayer: > > + :org.bluez.Error.A2DP.NotSupportedLayer: > > + :org.bluez.Error.A2DP.NotSupporterdCRC: > > + :org.bluez.Error.A2DP.NotSupporterdMPF: > > + :org.bluez.Error.A2DP.NotSupporterdVBR: > > + :org.bluez.Error.A2DP.InvalidBitRate: > > + :org.bluez.Error.A2DP.NotSupportedBitRate: > > + :org.bluez.Error.A2DP.InvalidObjectType: > > + :org.bluez.Error.A2DP.NotSupportedObjectType: > > + :org.bluez.Error.A2DP.InvalidChannels: > > + :org.bluez.Error.A2DP.NotSupportedChannels: > > + :org.bluez.Error.A2DP.InvalidVersion: > > + :org.bluez.Error.A2DP.NotSupportedVersion: > > + :org.bluez.Error.A2DP.NotSupportedMaximumSUL: > > + :org.bluez.Error.A2DP.InvalidBlockLength: > > + :org.bluez.Error.A2DP.InvalidCPType: > > + :org.bluez.Error.A2DP.InvalidCPFormat: > > + :org.bluez.Error.A2DP.InvalidCodecParameter: > > + :org.bluez.Error.A2DP.NotSupportedCodecParameter: > > + :org.bluez.Error.A2DP.InvalidDRC: > > + :org.bluez.Error.A2DP.NotSupportedDRC: > > Introducing a error domain for A2DP is probably a good idea, but this > only applies to endpoints that are A2DP specific, so this need to be > adjusted to e.g.: possible for A2DP or something like that, also I > don't know how the client would be able to tell it can return these > errors? Or the expectation is that the client can start sending them > immediately since the old behavior will convert them to > AVDTP_UNSUPPORTED_CONFIGURATION anyway? > That was what I thought. The clients can just start sending these, and they will be converted to the correct error code if bluez supports it or to AVDTP_UNSUPPORTED_CONFIGURATION otherwise. > While at it split the commit to have the documentation changes as a > separate change. Will adjust text and split into a separate commit. > > > array{byte} SelectConfiguration(array{byte} capabilities) > > ````````````````````````````````````````````````````````` > > > > diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c > > index c0a53eae9..661843a89 100644 > > --- a/profiles/audio/a2dp.c > > +++ b/profiles/audio/a2dp.c > > @@ -157,6 +157,73 @@ static GSList *servers = NULL; > > static GSList *setups = NULL; > > static unsigned int cb_id = 0; > > > > +struct a2dp_error { > > + const char *error_name; > > + uint8_t error_code; > > +}; > > + > > +#define A2DP_ERROR_PREFIX ERROR_INTERFACE ".A2DP." > > + > > +static struct a2dp_error config_errors[] = { > > + {"InvalidCodecType", A2DP_INVALID_CODEC_TYPE}, > > + {"NotSupportedCodecType", A2DP_NOT_SUPPORTED_CODEC_TYPE}, > > + {"InvalidSamplingFrequency", A2DP_INVALID_SAMPLING_FREQUENCY}, > > + {"NotSupportedSamplingFrequency", > > + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY}, > > + {"InvalidChannelMode", A2DP_INVALID_CHANNEL_MODE}, > > + {"NotSupportedChannelMode", A2DP_NOT_SUPPORTED_CHANNEL_MODE}, > > + {"InvalidSubbands", A2DP_INVALID_SUBBANDS}, > > + {"NotSupportedSubbands", A2DP_NOT_SUPPORTED_SUBBANDS}, > > + {"InvalidAllocationMethod", A2DP_INVALID_ALLOCATION_METHOD}, > > + {"NotSupportedAllocationMethod", A2DP_NOT_SUPPORTED_ALLOCATION_METHOD}, > > + {"InvalidMinimumBitpoolValue", > > + A2DP_INVALID_MINIMUM_BITPOOL_VALUE}, > > + {"NotSupportedMinimumBitpoolValue", > > + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE}, > > + {"InvalidMaximumBitpoolValue", A2DP_INVALID_MAXIMUM_BITPOOL_VALUE}, > > + {"NotSupportedMaximumBitpoolValue", > > + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE}, > > + {"InvalidInvalidLayer", A2DP_INVALID_INVALID_LAYER}, > > + {"NotSupportedLayer", A2DP_NOT_SUPPORTED_LAYER}, > > + {"NotSupporterdCRC", A2DP_NOT_SUPPORTERD_CRC}, > > + {"NotSupporterdMPF", A2DP_NOT_SUPPORTERD_MPF}, > > + {"NotSupporterdVBR", A2DP_NOT_SUPPORTERD_VBR}, > > + {"InvalidBitRate", A2DP_INVALID_BIT_RATE}, > > + {"NotSupportedBitRate", A2DP_NOT_SUPPORTED_BIT_RATE}, > > + {"InvalidObjectType", A2DP_INVALID_OBJECT_TYPE}, > > + {"NotSupportedObjectType", A2DP_NOT_SUPPORTED_OBJECT_TYPE}, > > + {"InvalidChannels", A2DP_INVALID_CHANNELS}, > > + {"NotSupportedChannels", A2DP_NOT_SUPPORTED_CHANNELS}, > > + {"InvalidVersion", A2DP_INVALID_VERSION}, > > + {"NotSupportedVersion", A2DP_NOT_SUPPORTED_VERSION}, > > + {"NotSupportedMaximumSUL", A2DP_NOT_SUPPORTED_MAXIMUM_SUL}, > > + {"InvalidBlockLength", A2DP_INVALID_BLOCK_LENGTH}, > > + {"InvalidCPType", A2DP_INVALID_CP_TYPE}, > > + {"InvalidCPFormat", A2DP_INVALID_CP_FORMAT}, > > + {"InvalidCodecParameter", A2DP_INVALID_CODEC_PARAMETER}, > > + {"NotSupportedCodecParameter", A2DP_NOT_SUPPORTED_CODEC_PARAMETER}, > > + {"InvalidDRC", A2DP_INVALID_DRC}, > > + {"NotSupportedDRC", A2DP_NOT_SUPPORTED_DRC} > > +}; > > + > > +uint8_t a2dp_parse_config_error(const char *error_name) > > +{ > > + size_t prefix_length; > > + size_t i; > > + > > + prefix_length = strlen(A2DP_ERROR_PREFIX); > > + if (strncmp(A2DP_ERROR_PREFIX, error_name, prefix_length)) > > + return AVDTP_UNSUPPORTED_CONFIGURATION; > > + > > + error_name += prefix_length; > > + for (i = 0; i < ARRAY_SIZE(config_errors); i++) { > > + if (strcmp(config_errors[i].error_name, error_name) == 0) > > + return config_errors[i].error_code; > > + } > > + > > + return AVDTP_UNSUPPORTED_CONFIGURATION; > > +} > > + > > static struct a2dp_setup *setup_ref(struct a2dp_setup *setup) > > { > > setup->ref++; > > @@ -688,11 +755,10 @@ done: > > return FALSE; > > } > > > > -static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret) > > +static void endpoint_setconf_cb(struct a2dp_setup *setup, uint8_t error_code) > > { > > - if (ret == FALSE) > > - setup_error_init(setup, AVDTP_MEDIA_CODEC, > > - AVDTP_UNSUPPORTED_CONFIGURATION); > > + if (error_code != 0) > > + setup_error_init(setup, AVDTP_MEDIA_CODEC, error_code); > > > > auto_config(setup); > > setup_unref(setup); > > @@ -865,11 +931,11 @@ static gboolean endpoint_getcap_ind(struct avdtp *session, > > return TRUE; > > } > > > > -static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret) > > +static void endpoint_open_cb(struct a2dp_setup *setup, uint8_t error_code) > > { > > int err = error_to_errno(setup->err); > > > > - if (ret == FALSE) { > > + if (error_code != 0) { > > setup->stream = NULL; > > finalize_setup_errno(setup, -EPERM, finalize_config, NULL); > > goto done; > > diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h > > index c698bc983..afa02c12d 100644 > > --- a/profiles/audio/a2dp.h > > +++ b/profiles/audio/a2dp.h > > @@ -15,7 +15,8 @@ struct a2dp_setup; > > > > typedef void (*a2dp_endpoint_select_t) (struct a2dp_setup *setup, void *ret, > > int size); > > -typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, gboolean ret); > > +typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, > > + uint8_t error_code); > > > > struct a2dp_endpoint { > > const char *(*get_name) (struct a2dp_sep *sep, void *user_data); > > @@ -70,6 +71,8 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, > > unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep, > > a2dp_config_cb_t cb, GSList *caps, > > void *user_data); > > +uint8_t a2dp_parse_config_error(const char *error_name); > > + > > unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep, > > a2dp_stream_cb_t cb, void *user_data); > > unsigned int a2dp_suspend(struct avdtp *session, struct a2dp_sep *sep, > > diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c > > index 30648251f..ed4e22b26 100644 > > --- a/profiles/audio/avdtp.c > > +++ b/profiles/audio/avdtp.c > > @@ -1494,8 +1494,8 @@ static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream, > > struct conf_rej rej; > > > > if (err != NULL) { > > - rej.error = AVDTP_UNSUPPORTED_CONFIGURATION; > > - rej.category = err->err.error_code; > > + rej.error = err->err.error_code; > > + rej.category = AVDTP_UNSUPPORTED_CONFIGURATION; > > avdtp_send(session, session->in_cmd.transaction, > > AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, > > &rej, sizeof(rej)); > > diff --git a/profiles/audio/media.c b/profiles/audio/media.c > > index 9b3042c18..332f643bb 100644 > > --- a/profiles/audio/media.c > > +++ b/profiles/audio/media.c > > @@ -333,7 +333,7 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > DBusMessage *reply; > > DBusMessageIter args, props; > > DBusError err; > > - gboolean value; > > + uint8_t error_code; > > void *ret = NULL; > > int size = -1; > > > > @@ -356,8 +356,12 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > > > if (dbus_message_is_method_call(request->msg, > > MEDIA_ENDPOINT_INTERFACE, > > - "SetConfiguration")) > > + "SetConfiguration")) { > > endpoint_remove_transport(endpoint, request->transport); > > + error_code = a2dp_parse_config_error(err.name); > > + ret = &error_code; > > + size = 1; > > + } > > > > dbus_error_free(&err); > > goto done; > > @@ -390,8 +394,8 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > } > > > > size = 1; > > - value = TRUE; > > - ret = &value; > > + error_code = 0; > > + ret = &error_code; > > > > done: > > dbus_message_unref(reply); > > @@ -634,9 +638,9 @@ static void config_cb(struct media_endpoint *endpoint, void *ret, int size, > > void *user_data) > > { > > struct a2dp_config_data *data = user_data; > > - gboolean *ret_value = ret; > > + uint8_t *ret_value = ret; > > > > - data->cb(data->setup, ret_value ? *ret_value : FALSE); > > + data->cb(data->setup, ret_value ? *ret_value : 1); > > } > > > > static int set_config(struct a2dp_sep *sep, uint8_t *configuration, > > @@ -1098,7 +1102,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, > > void *user_data) > > { > > struct pac_config_data *data = user_data; > > - gboolean *ret_value = ret; > > + uint8_t *error_code = ret; > > struct media_transport *transport; > > > > /* If transport was cleared, configuration was cancelled */ > > @@ -1106,7 +1110,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, > > if (!transport) > > return; > > > > - data->cb(data->stream, ret_value ? 0 : -EINVAL); > > + data->cb(data->stream, error_code == 0 ? 0 : -EINVAL); > > } > > > > static struct media_transport *pac_ucast_config(struct bt_bap_stream *stream, > > diff --git a/src/error.h b/src/error.h > > index 47602d39b..8157795c2 100644 > > --- a/src/error.h > > +++ b/src/error.h > > @@ -88,3 +88,41 @@ DBusMessage *btd_error_profile_unavailable(DBusMessage *msg); > > DBusMessage *btd_error_failed(DBusMessage *msg, const char *str); > > DBusMessage *btd_error_bredr_errno(DBusMessage *msg, int err); > > DBusMessage *btd_error_le_errno(DBusMessage *msg, int err); > > + > > +enum a2dp_error_codes : uint8_t { > > + A2DP_INVALID_CODEC_TYPE = 0xc1, > > + A2DP_NOT_SUPPORTED_CODEC_TYPE = 0xc2, > > + A2DP_INVALID_SAMPLING_FREQUENCY = 0xc3, > > + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xc4, > > + A2DP_INVALID_CHANNEL_MODE = 0xc5, > > + A2DP_NOT_SUPPORTED_CHANNEL_MODE = 0xc6, > > + A2DP_INVALID_SUBBANDS = 0xc7, > > + A2DP_NOT_SUPPORTED_SUBBANDS = 0xc8, > > + A2DP_INVALID_ALLOCATION_METHOD = 0xc9, > > + A2DP_NOT_SUPPORTED_ALLOCATION_METHOD = 0xca, > > + A2DP_INVALID_MINIMUM_BITPOOL_VALUE = 0xcb, > > + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xcc, > > + A2DP_INVALID_MAXIMUM_BITPOOL_VALUE = 0xcd, > > + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xce, > > + A2DP_INVALID_INVALID_LAYER = 0xcf, > > + A2DP_NOT_SUPPORTED_LAYER = 0xd0, > > + A2DP_NOT_SUPPORTERD_CRC = 0xd1, > > + A2DP_NOT_SUPPORTERD_MPF = 0xd2, > > + A2DP_NOT_SUPPORTERD_VBR = 0xd3, > > + A2DP_INVALID_BIT_RATE = 0xd4, > > + A2DP_NOT_SUPPORTED_BIT_RATE = 0xd5, > > + A2DP_INVALID_OBJECT_TYPE = 0xd6, > > + A2DP_NOT_SUPPORTED_OBJECT_TYPE = 0xd7, > > + A2DP_INVALID_CHANNELS = 0xd8, > > + A2DP_NOT_SUPPORTED_CHANNELS = 0xd9, > > + A2DP_INVALID_VERSION = 0xda, > > + A2DP_NOT_SUPPORTED_VERSION = 0xdb, > > + A2DP_NOT_SUPPORTED_MAXIMUM_SUL = 0xdc, > > + A2DP_INVALID_BLOCK_LENGTH = 0xdd, > > + A2DP_INVALID_CP_TYPE = 0xe0, > > + A2DP_INVALID_CP_FORMAT = 0xe1, > > + A2DP_INVALID_CODEC_PARAMETER = 0xe2, > > + A2DP_NOT_SUPPORTED_CODEC_PARAMETER = 0xe3, > > + A2DP_INVALID_DRC = 0xe4, > > + A2DP_NOT_SUPPORTED_DRC = 0xe5, > > +}; > > Hmm, I guess there should be part of a2dp.h since this error header is > about D-Bus not A2DP codes. > Ok, will move them to a2dp.h ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration 2025-09-11 15:12 ` Per Waago (pwaago) @ 2025-09-11 15:52 ` Luiz Augusto von Dentz 2025-09-11 19:56 ` Per Waago (pwaago) 0 siblings, 1 reply; 8+ messages in thread From: Luiz Augusto von Dentz @ 2025-09-11 15:52 UTC (permalink / raw) To: Per Waago (pwaago); +Cc: Pauli Virtanen, linux-bluetooth@vger.kernel.org Hi Per, On Thu, Sep 11, 2025 at 11:12 AM Per Waago (pwaago) <pwaago@cisco.com> wrote: > > Hi Luiz, thanks for reviewing. > > > From: Luiz Augusto von Dentz <luiz.dentz@gmail.com> > > Sent: Thursday, September 11, 2025 16:43 > > To: Per Waago (pwaago); Pauli Virtanen > > Cc: linux-bluetooth@vger.kernel.org > > Subject: Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration > > > > Hi Per, > > > > On Thu, Sep 11, 2025 at 9:56 AM Per Waagø <pwaago@cisco.com> wrote: > > > > > > The A2DP specification defines error codes that shall be used if > > > the codec capabilities contain improper settings. This change allows > > > clients to trigger the sending of these specific error codes by > > > returning the corresponding error messages from > > > MediaEndpoint1.SetConfiguration. > > > > > > This update is fully backwards compatible: clients passing other error > > > messages will continue to receive the default error code as before. On > > > older BlueZ versions, these new errors will also result in the default > > > error code, enabling clients to implement support for the new errors > > > without breaking compatibility. > > > > While I can see the value for debugging I doubt we could do any > > handling of these errors, so the result would be the same regardless > > of what error is sent back it is not recoverable. > > > > The main motivation for adding them is to be able to pass the > mandatory qualification tests, which now checks the errors codes > returned from SetConfiguration in detail. I don't think they are very > useful otherwise. > > The errors are specified in table 5.5 in the A2DP spec: > https://www.bluetooth.com/specifications/specs/html/?src=a2dp_v1-4-1_1752513648/A2DP_v1.4.1/out/en/index-en.html#UUID-0ba19ee9-7277-1068-d2dc-b9e638cca568_Table_5.5 > > I included all of them for completeness. In that table, it is also stated > which codecs they apply to. Some are SBC-specific, some apply to all codecs or > other codecs. Ok this is very annoying if PTS suddenly adds a new test case that checks error codes that otherwise are only useful for debugging. I'd say that it probably needs a configuration entry to skip these tests, btw this seems to be introduced in 1.4.1: https://www.bluetooth.com/specifications/specs/html/?src=a2dp_v1-4-1_1752513648/A2DP_v1.4.1/out/en/index-en.html#UUID-05a1c924-2070-eb38-c2cc-a9ffa178bdb9 BlueZ SDP record is still 1.4 (a2dp_ver = 0x0104), it seems 1.4.1 is an errata only change but that introduces new error codes which is really intrusive to say the least. > > @Pauli Virtanen Perhaps you can give some feedback regarding these > > codes, would pipewire be interested in generating specific error > > codes? Some of them seems to be SBC specific like bitpool. > > > > > This change enables passing A2DP/SNK/AVP/* and A2DP/SRC/AVP/* > > > qualification tests. > > > --- > > > doc/org.bluez.MediaEndpoint.rst | 37 ++++++++++++++++ > > > profiles/audio/a2dp.c | 78 ++++++++++++++++++++++++++++++--- > > > profiles/audio/a2dp.h | 5 ++- > > > profiles/audio/avdtp.c | 4 +- > > > profiles/audio/media.c | 20 +++++---- > > > src/error.h | 38 ++++++++++++++++ > > > 6 files changed, 165 insertions(+), 17 deletions(-) > > > > > > diff --git a/doc/org.bluez.MediaEndpoint.rst b/doc/org.bluez.MediaEndpoint.rst > > > index 474cc1160..2721d473e 100644 > > > --- a/doc/org.bluez.MediaEndpoint.rst > > > +++ b/doc/org.bluez.MediaEndpoint.rst > > > @@ -54,6 +54,43 @@ be configured and the properties must contain the following properties: > > > > > > See **org.bluez.MediaTransport(5)** QoS property. > > > > > > + Possible errors: > > > + :org.bluez.Error.A2DP.InvalidCodecType: > > > + :org.bluez.Error.A2DP.NotSupportedCodecType: > > > + :org.bluez.Error.A2DP.InvalidSamplingFrequency: > > > + :org.bluez.Error.A2DP.NotSupportedSamplingFrequency: > > > + :org.bluez.Error.A2DP.InvalidChannelMode: > > > + :org.bluez.Error.A2DP.NotSupportedChannelMode: > > > + :org.bluez.Error.A2DP.InvalidSubbands: > > > + :org.bluez.Error.A2DP.NotSupportedSubbands: > > > + :org.bluez.Error.A2DP.InvalidAllocationMethod: > > > + :org.bluez.Error.A2DP.NotSupportedAllocationMethod: > > > + :org.bluez.Error.A2DP.InvalidMinimumBitpoolValue: > > > + :org.bluez.Error.A2DP.NotSupportedMinimumBitpoolValue: > > > + :org.bluez.Error.A2DP.InvalidMaximumBitpoolValue: > > > + :org.bluez.Error.A2DP.NotSupportedMaximumBitpoolValue: > > > + :org.bluez.Error.A2DP.InvalidInvalidLayer: > > > + :org.bluez.Error.A2DP.NotSupportedLayer: > > > + :org.bluez.Error.A2DP.NotSupporterdCRC: > > > + :org.bluez.Error.A2DP.NotSupporterdMPF: > > > + :org.bluez.Error.A2DP.NotSupporterdVBR: > > > + :org.bluez.Error.A2DP.InvalidBitRate: > > > + :org.bluez.Error.A2DP.NotSupportedBitRate: > > > + :org.bluez.Error.A2DP.InvalidObjectType: > > > + :org.bluez.Error.A2DP.NotSupportedObjectType: > > > + :org.bluez.Error.A2DP.InvalidChannels: > > > + :org.bluez.Error.A2DP.NotSupportedChannels: > > > + :org.bluez.Error.A2DP.InvalidVersion: > > > + :org.bluez.Error.A2DP.NotSupportedVersion: > > > + :org.bluez.Error.A2DP.NotSupportedMaximumSUL: > > > + :org.bluez.Error.A2DP.InvalidBlockLength: > > > + :org.bluez.Error.A2DP.InvalidCPType: > > > + :org.bluez.Error.A2DP.InvalidCPFormat: > > > + :org.bluez.Error.A2DP.InvalidCodecParameter: > > > + :org.bluez.Error.A2DP.NotSupportedCodecParameter: > > > + :org.bluez.Error.A2DP.InvalidDRC: > > > + :org.bluez.Error.A2DP.NotSupportedDRC: > > > > Introducing a error domain for A2DP is probably a good idea, but this > > only applies to endpoints that are A2DP specific, so this need to be > > adjusted to e.g.: possible for A2DP or something like that, also I > > don't know how the client would be able to tell it can return these > > errors? Or the expectation is that the client can start sending them > > immediately since the old behavior will convert them to > > AVDTP_UNSUPPORTED_CONFIGURATION anyway? > > > > That was what I thought. The clients can just start sending these, and > they will be converted to the correct error code if bluez supports it > or to AVDTP_UNSUPPORTED_CONFIGURATION otherwise. > > > While at it split the commit to have the documentation changes as a > > separate change. > > Will adjust text and split into a separate commit. > > > > > > array{byte} SelectConfiguration(array{byte} capabilities) > > > ````````````````````````````````````````````````````````` > > > > > > diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c > > > index c0a53eae9..661843a89 100644 > > > --- a/profiles/audio/a2dp.c > > > +++ b/profiles/audio/a2dp.c > > > @@ -157,6 +157,73 @@ static GSList *servers = NULL; > > > static GSList *setups = NULL; > > > static unsigned int cb_id = 0; > > > > > > +struct a2dp_error { > > > + const char *error_name; > > > + uint8_t error_code; > > > +}; > > > + > > > +#define A2DP_ERROR_PREFIX ERROR_INTERFACE ".A2DP." > > > + > > > +static struct a2dp_error config_errors[] = { > > > + {"InvalidCodecType", A2DP_INVALID_CODEC_TYPE}, > > > + {"NotSupportedCodecType", A2DP_NOT_SUPPORTED_CODEC_TYPE}, > > > + {"InvalidSamplingFrequency", A2DP_INVALID_SAMPLING_FREQUENCY}, > > > + {"NotSupportedSamplingFrequency", > > > + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY}, > > > + {"InvalidChannelMode", A2DP_INVALID_CHANNEL_MODE}, > > > + {"NotSupportedChannelMode", A2DP_NOT_SUPPORTED_CHANNEL_MODE}, > > > + {"InvalidSubbands", A2DP_INVALID_SUBBANDS}, > > > + {"NotSupportedSubbands", A2DP_NOT_SUPPORTED_SUBBANDS}, > > > + {"InvalidAllocationMethod", A2DP_INVALID_ALLOCATION_METHOD}, > > > + {"NotSupportedAllocationMethod", A2DP_NOT_SUPPORTED_ALLOCATION_METHOD}, > > > + {"InvalidMinimumBitpoolValue", > > > + A2DP_INVALID_MINIMUM_BITPOOL_VALUE}, > > > + {"NotSupportedMinimumBitpoolValue", > > > + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE}, > > > + {"InvalidMaximumBitpoolValue", A2DP_INVALID_MAXIMUM_BITPOOL_VALUE}, > > > + {"NotSupportedMaximumBitpoolValue", > > > + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE}, > > > + {"InvalidInvalidLayer", A2DP_INVALID_INVALID_LAYER}, > > > + {"NotSupportedLayer", A2DP_NOT_SUPPORTED_LAYER}, > > > + {"NotSupporterdCRC", A2DP_NOT_SUPPORTERD_CRC}, > > > + {"NotSupporterdMPF", A2DP_NOT_SUPPORTERD_MPF}, > > > + {"NotSupporterdVBR", A2DP_NOT_SUPPORTERD_VBR}, > > > + {"InvalidBitRate", A2DP_INVALID_BIT_RATE}, > > > + {"NotSupportedBitRate", A2DP_NOT_SUPPORTED_BIT_RATE}, > > > + {"InvalidObjectType", A2DP_INVALID_OBJECT_TYPE}, > > > + {"NotSupportedObjectType", A2DP_NOT_SUPPORTED_OBJECT_TYPE}, > > > + {"InvalidChannels", A2DP_INVALID_CHANNELS}, > > > + {"NotSupportedChannels", A2DP_NOT_SUPPORTED_CHANNELS}, > > > + {"InvalidVersion", A2DP_INVALID_VERSION}, > > > + {"NotSupportedVersion", A2DP_NOT_SUPPORTED_VERSION}, > > > + {"NotSupportedMaximumSUL", A2DP_NOT_SUPPORTED_MAXIMUM_SUL}, > > > + {"InvalidBlockLength", A2DP_INVALID_BLOCK_LENGTH}, > > > + {"InvalidCPType", A2DP_INVALID_CP_TYPE}, > > > + {"InvalidCPFormat", A2DP_INVALID_CP_FORMAT}, > > > + {"InvalidCodecParameter", A2DP_INVALID_CODEC_PARAMETER}, > > > + {"NotSupportedCodecParameter", A2DP_NOT_SUPPORTED_CODEC_PARAMETER}, > > > + {"InvalidDRC", A2DP_INVALID_DRC}, > > > + {"NotSupportedDRC", A2DP_NOT_SUPPORTED_DRC} > > > +}; > > > + > > > +uint8_t a2dp_parse_config_error(const char *error_name) > > > +{ > > > + size_t prefix_length; > > > + size_t i; > > > + > > > + prefix_length = strlen(A2DP_ERROR_PREFIX); > > > + if (strncmp(A2DP_ERROR_PREFIX, error_name, prefix_length)) > > > + return AVDTP_UNSUPPORTED_CONFIGURATION; > > > + > > > + error_name += prefix_length; > > > + for (i = 0; i < ARRAY_SIZE(config_errors); i++) { > > > + if (strcmp(config_errors[i].error_name, error_name) == 0) > > > + return config_errors[i].error_code; > > > + } > > > + > > > + return AVDTP_UNSUPPORTED_CONFIGURATION; > > > +} > > > + > > > static struct a2dp_setup *setup_ref(struct a2dp_setup *setup) > > > { > > > setup->ref++; > > > @@ -688,11 +755,10 @@ done: > > > return FALSE; > > > } > > > > > > -static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret) > > > +static void endpoint_setconf_cb(struct a2dp_setup *setup, uint8_t error_code) > > > { > > > - if (ret == FALSE) > > > - setup_error_init(setup, AVDTP_MEDIA_CODEC, > > > - AVDTP_UNSUPPORTED_CONFIGURATION); > > > + if (error_code != 0) > > > + setup_error_init(setup, AVDTP_MEDIA_CODEC, error_code); > > > > > > auto_config(setup); > > > setup_unref(setup); > > > @@ -865,11 +931,11 @@ static gboolean endpoint_getcap_ind(struct avdtp *session, > > > return TRUE; > > > } > > > > > > -static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret) > > > +static void endpoint_open_cb(struct a2dp_setup *setup, uint8_t error_code) > > > { > > > int err = error_to_errno(setup->err); > > > > > > - if (ret == FALSE) { > > > + if (error_code != 0) { > > > setup->stream = NULL; > > > finalize_setup_errno(setup, -EPERM, finalize_config, NULL); > > > goto done; > > > diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h > > > index c698bc983..afa02c12d 100644 > > > --- a/profiles/audio/a2dp.h > > > +++ b/profiles/audio/a2dp.h > > > @@ -15,7 +15,8 @@ struct a2dp_setup; > > > > > > typedef void (*a2dp_endpoint_select_t) (struct a2dp_setup *setup, void *ret, > > > int size); > > > -typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, gboolean ret); > > > +typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, > > > + uint8_t error_code); > > > > > > struct a2dp_endpoint { > > > const char *(*get_name) (struct a2dp_sep *sep, void *user_data); > > > @@ -70,6 +71,8 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, > > > unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep, > > > a2dp_config_cb_t cb, GSList *caps, > > > void *user_data); > > > +uint8_t a2dp_parse_config_error(const char *error_name); > > > + > > > unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep, > > > a2dp_stream_cb_t cb, void *user_data); > > > unsigned int a2dp_suspend(struct avdtp *session, struct a2dp_sep *sep, > > > diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c > > > index 30648251f..ed4e22b26 100644 > > > --- a/profiles/audio/avdtp.c > > > +++ b/profiles/audio/avdtp.c > > > @@ -1494,8 +1494,8 @@ static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream, > > > struct conf_rej rej; > > > > > > if (err != NULL) { > > > - rej.error = AVDTP_UNSUPPORTED_CONFIGURATION; > > > - rej.category = err->err.error_code; > > > + rej.error = err->err.error_code; > > > + rej.category = AVDTP_UNSUPPORTED_CONFIGURATION; > > > avdtp_send(session, session->in_cmd.transaction, > > > AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, > > > &rej, sizeof(rej)); > > > diff --git a/profiles/audio/media.c b/profiles/audio/media.c > > > index 9b3042c18..332f643bb 100644 > > > --- a/profiles/audio/media.c > > > +++ b/profiles/audio/media.c > > > @@ -333,7 +333,7 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > > DBusMessage *reply; > > > DBusMessageIter args, props; > > > DBusError err; > > > - gboolean value; > > > + uint8_t error_code; > > > void *ret = NULL; > > > int size = -1; > > > > > > @@ -356,8 +356,12 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > > > > > if (dbus_message_is_method_call(request->msg, > > > MEDIA_ENDPOINT_INTERFACE, > > > - "SetConfiguration")) > > > + "SetConfiguration")) { > > > endpoint_remove_transport(endpoint, request->transport); > > > + error_code = a2dp_parse_config_error(err.name); > > > + ret = &error_code; > > > + size = 1; > > > + } > > > > > > dbus_error_free(&err); > > > goto done; > > > @@ -390,8 +394,8 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > > } > > > > > > size = 1; > > > - value = TRUE; > > > - ret = &value; > > > + error_code = 0; > > > + ret = &error_code; > > > > > > done: > > > dbus_message_unref(reply); > > > @@ -634,9 +638,9 @@ static void config_cb(struct media_endpoint *endpoint, void *ret, int size, > > > void *user_data) > > > { > > > struct a2dp_config_data *data = user_data; > > > - gboolean *ret_value = ret; > > > + uint8_t *ret_value = ret; > > > > > > - data->cb(data->setup, ret_value ? *ret_value : FALSE); > > > + data->cb(data->setup, ret_value ? *ret_value : 1); > > > } > > > > > > static int set_config(struct a2dp_sep *sep, uint8_t *configuration, > > > @@ -1098,7 +1102,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, > > > void *user_data) > > > { > > > struct pac_config_data *data = user_data; > > > - gboolean *ret_value = ret; > > > + uint8_t *error_code = ret; > > > struct media_transport *transport; > > > > > > /* If transport was cleared, configuration was cancelled */ > > > @@ -1106,7 +1110,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, > > > if (!transport) > > > return; > > > > > > - data->cb(data->stream, ret_value ? 0 : -EINVAL); > > > + data->cb(data->stream, error_code == 0 ? 0 : -EINVAL); > > > } > > > > > > static struct media_transport *pac_ucast_config(struct bt_bap_stream *stream, > > > diff --git a/src/error.h b/src/error.h > > > index 47602d39b..8157795c2 100644 > > > --- a/src/error.h > > > +++ b/src/error.h > > > @@ -88,3 +88,41 @@ DBusMessage *btd_error_profile_unavailable(DBusMessage *msg); > > > DBusMessage *btd_error_failed(DBusMessage *msg, const char *str); > > > DBusMessage *btd_error_bredr_errno(DBusMessage *msg, int err); > > > DBusMessage *btd_error_le_errno(DBusMessage *msg, int err); > > > + > > > +enum a2dp_error_codes : uint8_t { > > > + A2DP_INVALID_CODEC_TYPE = 0xc1, > > > + A2DP_NOT_SUPPORTED_CODEC_TYPE = 0xc2, > > > + A2DP_INVALID_SAMPLING_FREQUENCY = 0xc3, > > > + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xc4, > > > + A2DP_INVALID_CHANNEL_MODE = 0xc5, > > > + A2DP_NOT_SUPPORTED_CHANNEL_MODE = 0xc6, > > > + A2DP_INVALID_SUBBANDS = 0xc7, > > > + A2DP_NOT_SUPPORTED_SUBBANDS = 0xc8, > > > + A2DP_INVALID_ALLOCATION_METHOD = 0xc9, > > > + A2DP_NOT_SUPPORTED_ALLOCATION_METHOD = 0xca, > > > + A2DP_INVALID_MINIMUM_BITPOOL_VALUE = 0xcb, > > > + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xcc, > > > + A2DP_INVALID_MAXIMUM_BITPOOL_VALUE = 0xcd, > > > + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xce, > > > + A2DP_INVALID_INVALID_LAYER = 0xcf, > > > + A2DP_NOT_SUPPORTED_LAYER = 0xd0, > > > + A2DP_NOT_SUPPORTERD_CRC = 0xd1, > > > + A2DP_NOT_SUPPORTERD_MPF = 0xd2, > > > + A2DP_NOT_SUPPORTERD_VBR = 0xd3, > > > + A2DP_INVALID_BIT_RATE = 0xd4, > > > + A2DP_NOT_SUPPORTED_BIT_RATE = 0xd5, > > > + A2DP_INVALID_OBJECT_TYPE = 0xd6, > > > + A2DP_NOT_SUPPORTED_OBJECT_TYPE = 0xd7, > > > + A2DP_INVALID_CHANNELS = 0xd8, > > > + A2DP_NOT_SUPPORTED_CHANNELS = 0xd9, > > > + A2DP_INVALID_VERSION = 0xda, > > > + A2DP_NOT_SUPPORTED_VERSION = 0xdb, > > > + A2DP_NOT_SUPPORTED_MAXIMUM_SUL = 0xdc, > > > + A2DP_INVALID_BLOCK_LENGTH = 0xdd, > > > + A2DP_INVALID_CP_TYPE = 0xe0, > > > + A2DP_INVALID_CP_FORMAT = 0xe1, > > > + A2DP_INVALID_CODEC_PARAMETER = 0xe2, > > > + A2DP_NOT_SUPPORTED_CODEC_PARAMETER = 0xe3, > > > + A2DP_INVALID_DRC = 0xe4, > > > + A2DP_NOT_SUPPORTED_DRC = 0xe5, > > > +}; > > > > Hmm, I guess there should be part of a2dp.h since this error header is > > about D-Bus not A2DP codes. > > > > Ok, will move them to a2dp.h > -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration 2025-09-11 15:52 ` Luiz Augusto von Dentz @ 2025-09-11 19:56 ` Per Waago (pwaago) 2025-09-11 20:32 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 8+ messages in thread From: Per Waago (pwaago) @ 2025-09-11 19:56 UTC (permalink / raw) To: Luiz Augusto von Dentz; +Cc: Pauli Virtanen, linux-bluetooth@vger.kernel.org > ________________________________________ > From: Luiz Augusto von Dentz <luiz.dentz@gmail.com> > Sent: Thursday, September 11, 2025 17:52 > To: Per Waago (pwaago) > Cc: Pauli Virtanen; linux-bluetooth@vger.kernel.org > Subject: Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration > > Hi Per, > > On Thu, Sep 11, 2025 at 11:12 AM Per Waago (pwaago) <pwaago@cisco.com> wrote: > > > > Hi Luiz, thanks for reviewing. > > > > > From: Luiz Augusto von Dentz <luiz.dentz@gmail.com> > > > Sent: Thursday, September 11, 2025 16:43 > > > To: Per Waago (pwaago); Pauli Virtanen > > > Cc: linux-bluetooth@vger.kernel.org > > > Subject: Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP > configuration > > > > > > Hi Per, > > > > > > On Thu, Sep 11, 2025 at 9:56 AM Per Waagø <pwaago@cisco.com> wrote: > > > > > > > > The A2DP specification defines error codes that shall be used if > > > > the codec capabilities contain improper settings. This change allows > > > > clients to trigger the sending of these specific error codes by > > > > returning the corresponding error messages from > > > > MediaEndpoint1.SetConfiguration. > > > > > > > > This update is fully backwards compatible: clients passing other error > > > > messages will continue to receive the default error code as before. On > > > > older BlueZ versions, these new errors will also result in the default > > > > error code, enabling clients to implement support for the new errors > > > > without breaking compatibility. > > > > > > While I can see the value for debugging I doubt we could do any > > > handling of these errors, so the result would be the same regardless > > > of what error is sent back it is not recoverable. > > > > > > > The main motivation for adding them is to be able to pass the > > mandatory qualification tests, which now checks the errors codes > > returned from SetConfiguration in detail. I don't think they are very > > useful otherwise. > > > > The errors are specified in table 5.5 in the A2DP spec: > > > https://www.bluetooth.com/specifications/specs/html/?src=a2dp_v1-4-1_1752513648/A2DP_v1.4.1/o> ut/en/index-en.html#UUID-0ba19ee9-7277-1068-d2dc-b9e638cca568_Table_5.5 > > > > I included all of them for completeness. In that table, it is also stated > > which codecs they apply to. Some are SBC-specific, some apply to all codecs or > > other codecs. > > Ok this is very annoying if PTS suddenly adds a new test case that > checks error codes that otherwise are only useful for debugging. I'd > say that it probably needs a configuration entry to skip these tests, > btw this seems to be introduced in 1.4.1: > > https://www.bluetooth.com/specifications/specs/html/?src=a2dp_v1-4-1_1752513648/A2DP_v1.4.1/o> ut/en/index-en.html#UUID-05a1c924-2070-eb38-c2cc-a9ffa178bdb9 > > BlueZ SDP record is still 1.4 (a2dp_ver = 0x0104), it seems 1.4.1 is > an errata only change but that introduces new error codes which is > really intrusive to say the least.really intrusive to say the least. I have tried to read the specs in some more detail now. It seems the error codes themselves have been there all the time. The errata that was incorporated in 1.4.1 actually eases the requirements a bit, so the spec now says that these error codes shall be returned if error codes from GAVDP or AVDTP aren't used. So the way I interpret it, returning AVDTP_UNSUPPORTED_CONFIGURAION could be ok according to 1.4.1. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration 2025-09-11 19:56 ` Per Waago (pwaago) @ 2025-09-11 20:32 ` Luiz Augusto von Dentz 0 siblings, 0 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2025-09-11 20:32 UTC (permalink / raw) To: Per Waago (pwaago); +Cc: Pauli Virtanen, linux-bluetooth@vger.kernel.org Hi Per, On Thu, Sep 11, 2025 at 3:56 PM Per Waago (pwaago) <pwaago@cisco.com> wrote: > > > > > > ________________________________________ > > From: Luiz Augusto von Dentz <luiz.dentz@gmail.com> > > Sent: Thursday, September 11, 2025 17:52 > > To: Per Waago (pwaago) > > Cc: Pauli Virtanen; linux-bluetooth@vger.kernel.org > > Subject: Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration > > > > Hi Per, > > > > On Thu, Sep 11, 2025 at 11:12 AM Per Waago (pwaago) <pwaago@cisco.com> wrote: > > > > > > Hi Luiz, thanks for reviewing. > > > > > > > From: Luiz Augusto von Dentz <luiz.dentz@gmail.com> > > > > Sent: Thursday, September 11, 2025 16:43 > > > > To: Per Waago (pwaago); Pauli Virtanen > > > > Cc: linux-bluetooth@vger.kernel.org > > > > Subject: Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP > configuration > > > > > > > > Hi Per, > > > > > > > > On Thu, Sep 11, 2025 at 9:56 AM Per Waagø <pwaago@cisco.com> wrote: > > > > > > > > > > The A2DP specification defines error codes that shall be used if > > > > > the codec capabilities contain improper settings. This change allows > > > > > clients to trigger the sending of these specific error codes by > > > > > returning the corresponding error messages from > > > > > MediaEndpoint1.SetConfiguration. > > > > > > > > > > This update is fully backwards compatible: clients passing other error > > > > > messages will continue to receive the default error code as before. On > > > > > older BlueZ versions, these new errors will also result in the default > > > > > error code, enabling clients to implement support for the new errors > > > > > without breaking compatibility. > > > > > > > > While I can see the value for debugging I doubt we could do any > > > > handling of these errors, so the result would be the same regardless > > > > of what error is sent back it is not recoverable. > > > > > > > > > > The main motivation for adding them is to be able to pass the > > > mandatory qualification tests, which now checks the errors codes > > > returned from SetConfiguration in detail. I don't think they are very > > > useful otherwise. > > > > > > The errors are specified in table 5.5 in the A2DP spec: > > > > https://www.bluetooth.com/specifications/specs/html/?src=a2dp_v1-4-1_1752513648/A2DP_v1.4.1/o> ut/en/index-en.html#UUID-0ba19ee9-7277-1068-d2dc-b9e638cca568_Table_5.5 > > > > > > I included all of them for completeness. In that table, it is also stated > > > which codecs they apply to. Some are SBC-specific, some apply to all codecs or > > > other codecs. > > > > Ok this is very annoying if PTS suddenly adds a new test case that > > checks error codes that otherwise are only useful for debugging. I'd > > say that it probably needs a configuration entry to skip these tests, > > btw this seems to be introduced in 1.4.1: > > > > https://www.bluetooth.com/specifications/specs/html/?src=a2dp_v1-4-1_1752513648/A2DP_v1.4.1/o> ut/en/index-en.html#UUID-05a1c924-2070-eb38-c2cc-a9ffa178bdb9 > > > > BlueZ SDP record is still 1.4 (a2dp_ver = 0x0104), it seems 1.4.1 is > > an errata only change but that introduces new error codes which is > > really intrusive to say the least.really intrusive to say the least. > > I have tried to read the specs in some more detail now. It seems the error > codes themselves have been there all the time. The errata that was incorporated > in 1.4.1 actually eases the requirements a bit, so the spec now says > that these error codes shall be returned if error codes from GAVDP or AVDTP > aren't used. So the way I interpret it, returning AVDTP_UNSUPPORTED_CONFIGURAION > could be ok according to 1.4.1. Indeed it says 'are not rejected with error codes specified by GAVDTP or AVDTP: 'If the Codec Specific Information Elements include improper settings and are not rejected with the error codes specified by GAVDP [3] or AVDTP [4], then an applicable error code from the list in Table 5.5 shall be returned.' So why it was failing if we returned AVDTP_UNSUPPORTED_CONFIGURATION, that should still be valid according to the above AVDTP error codes are still valid. -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration 2025-09-11 14:43 ` [PATCH BlueZ] " Luiz Augusto von Dentz 2025-09-11 15:12 ` Per Waago (pwaago) @ 2025-09-11 16:25 ` Pauli Virtanen 1 sibling, 0 replies; 8+ messages in thread From: Pauli Virtanen @ 2025-09-11 16:25 UTC (permalink / raw) To: Luiz Augusto von Dentz, Per Waagø; +Cc: linux-bluetooth to, 2025-09-11 kello 10:43 -0400, Luiz Augusto von Dentz kirjoitti: > Hi Per, > > On Thu, Sep 11, 2025 at 9:56 AM Per Waagø <pwaago@cisco.com> wrote: > > > > The A2DP specification defines error codes that shall be used if > > the codec capabilities contain improper settings. This change allows > > clients to trigger the sending of these specific error codes by > > returning the corresponding error messages from > > MediaEndpoint1.SetConfiguration. > > > > This update is fully backwards compatible: clients passing other error > > messages will continue to receive the default error code as before. On > > older BlueZ versions, these new errors will also result in the default > > error code, enabling clients to implement support for the new errors > > without breaking compatibility. > > While I can see the value for debugging I doubt we could do any > handling of these errors, so the result would be the same regardless > of what error is sent back it is not recoverable. > > @Pauli Virtanen Perhaps you can give some feedback regarding these > codes, would pipewire be interested in generating specific error > codes? Some of them seems to be SBC specific like bitpool. Pipewire can start generating specific error codes if required by specification / PTS, but I think there's probably not much real use for these codes otherwise since it should be clear from capability bitmasks what the cause for error is. > > This change enables passing A2DP/SNK/AVP/* and A2DP/SRC/AVP/* > > qualification tests. > > --- > > doc/org.bluez.MediaEndpoint.rst | 37 ++++++++++++++++ > > profiles/audio/a2dp.c | 78 ++++++++++++++++++++++++++++++--- > > profiles/audio/a2dp.h | 5 ++- > > profiles/audio/avdtp.c | 4 +- > > profiles/audio/media.c | 20 +++++---- > > src/error.h | 38 ++++++++++++++++ > > 6 files changed, 165 insertions(+), 17 deletions(-) > > > > diff --git a/doc/org.bluez.MediaEndpoint.rst b/doc/org.bluez.MediaEndpoint.rst > > index 474cc1160..2721d473e 100644 > > --- a/doc/org.bluez.MediaEndpoint.rst > > +++ b/doc/org.bluez.MediaEndpoint.rst > > @@ -54,6 +54,43 @@ be configured and the properties must contain the following properties: > > > > See **org.bluez.MediaTransport(5)** QoS property. > > > > + Possible errors: > > + :org.bluez.Error.A2DP.InvalidCodecType: > > + :org.bluez.Error.A2DP.NotSupportedCodecType: > > + :org.bluez.Error.A2DP.InvalidSamplingFrequency: > > + :org.bluez.Error.A2DP.NotSupportedSamplingFrequency: > > + :org.bluez.Error.A2DP.InvalidChannelMode: > > + :org.bluez.Error.A2DP.NotSupportedChannelMode: > > + :org.bluez.Error.A2DP.InvalidSubbands: > > + :org.bluez.Error.A2DP.NotSupportedSubbands: > > + :org.bluez.Error.A2DP.InvalidAllocationMethod: > > + :org.bluez.Error.A2DP.NotSupportedAllocationMethod: > > + :org.bluez.Error.A2DP.InvalidMinimumBitpoolValue: > > + :org.bluez.Error.A2DP.NotSupportedMinimumBitpoolValue: > > + :org.bluez.Error.A2DP.InvalidMaximumBitpoolValue: > > + :org.bluez.Error.A2DP.NotSupportedMaximumBitpoolValue: > > + :org.bluez.Error.A2DP.InvalidInvalidLayer: > > + :org.bluez.Error.A2DP.NotSupportedLayer: > > + :org.bluez.Error.A2DP.NotSupporterdCRC: > > + :org.bluez.Error.A2DP.NotSupporterdMPF: > > + :org.bluez.Error.A2DP.NotSupporterdVBR: > > + :org.bluez.Error.A2DP.InvalidBitRate: > > + :org.bluez.Error.A2DP.NotSupportedBitRate: > > + :org.bluez.Error.A2DP.InvalidObjectType: > > + :org.bluez.Error.A2DP.NotSupportedObjectType: > > + :org.bluez.Error.A2DP.InvalidChannels: > > + :org.bluez.Error.A2DP.NotSupportedChannels: > > + :org.bluez.Error.A2DP.InvalidVersion: > > + :org.bluez.Error.A2DP.NotSupportedVersion: > > + :org.bluez.Error.A2DP.NotSupportedMaximumSUL: > > + :org.bluez.Error.A2DP.InvalidBlockLength: > > + :org.bluez.Error.A2DP.InvalidCPType: > > + :org.bluez.Error.A2DP.InvalidCPFormat: > > + :org.bluez.Error.A2DP.InvalidCodecParameter: > > + :org.bluez.Error.A2DP.NotSupportedCodecParameter: > > + :org.bluez.Error.A2DP.InvalidDRC: > > + :org.bluez.Error.A2DP.NotSupportedDRC: > > Introducing a error domain for A2DP is probably a good idea, but this > only applies to endpoints that are A2DP specific, so this need to be > adjusted to e.g.: possible for A2DP or something like that, also I > don't know how the client would be able to tell it can return these > errors? Or the expectation is that the client can start sending them > immediately since the old behavior will convert them to > AVDTP_UNSUPPORTED_CONFIGURATION anyway? > > While at it split the commit to have the documentation changes as a > separate change. > > > array{byte} SelectConfiguration(array{byte} capabilities) > > ````````````````````````````````````````````````````````` > > > > diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c > > index c0a53eae9..661843a89 100644 > > --- a/profiles/audio/a2dp.c > > +++ b/profiles/audio/a2dp.c > > @@ -157,6 +157,73 @@ static GSList *servers = NULL; > > static GSList *setups = NULL; > > static unsigned int cb_id = 0; > > > > +struct a2dp_error { > > + const char *error_name; > > + uint8_t error_code; > > +}; > > + > > +#define A2DP_ERROR_PREFIX ERROR_INTERFACE ".A2DP." > > + > > +static struct a2dp_error config_errors[] = { > > + {"InvalidCodecType", A2DP_INVALID_CODEC_TYPE}, > > + {"NotSupportedCodecType", A2DP_NOT_SUPPORTED_CODEC_TYPE}, > > + {"InvalidSamplingFrequency", A2DP_INVALID_SAMPLING_FREQUENCY}, > > + {"NotSupportedSamplingFrequency", > > + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY}, > > + {"InvalidChannelMode", A2DP_INVALID_CHANNEL_MODE}, > > + {"NotSupportedChannelMode", A2DP_NOT_SUPPORTED_CHANNEL_MODE}, > > + {"InvalidSubbands", A2DP_INVALID_SUBBANDS}, > > + {"NotSupportedSubbands", A2DP_NOT_SUPPORTED_SUBBANDS}, > > + {"InvalidAllocationMethod", A2DP_INVALID_ALLOCATION_METHOD}, > > + {"NotSupportedAllocationMethod", A2DP_NOT_SUPPORTED_ALLOCATION_METHOD}, > > + {"InvalidMinimumBitpoolValue", > > + A2DP_INVALID_MINIMUM_BITPOOL_VALUE}, > > + {"NotSupportedMinimumBitpoolValue", > > + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE}, > > + {"InvalidMaximumBitpoolValue", A2DP_INVALID_MAXIMUM_BITPOOL_VALUE}, > > + {"NotSupportedMaximumBitpoolValue", > > + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE}, > > + {"InvalidInvalidLayer", A2DP_INVALID_INVALID_LAYER}, > > + {"NotSupportedLayer", A2DP_NOT_SUPPORTED_LAYER}, > > + {"NotSupporterdCRC", A2DP_NOT_SUPPORTERD_CRC}, > > + {"NotSupporterdMPF", A2DP_NOT_SUPPORTERD_MPF}, > > + {"NotSupporterdVBR", A2DP_NOT_SUPPORTERD_VBR}, > > + {"InvalidBitRate", A2DP_INVALID_BIT_RATE}, > > + {"NotSupportedBitRate", A2DP_NOT_SUPPORTED_BIT_RATE}, > > + {"InvalidObjectType", A2DP_INVALID_OBJECT_TYPE}, > > + {"NotSupportedObjectType", A2DP_NOT_SUPPORTED_OBJECT_TYPE}, > > + {"InvalidChannels", A2DP_INVALID_CHANNELS}, > > + {"NotSupportedChannels", A2DP_NOT_SUPPORTED_CHANNELS}, > > + {"InvalidVersion", A2DP_INVALID_VERSION}, > > + {"NotSupportedVersion", A2DP_NOT_SUPPORTED_VERSION}, > > + {"NotSupportedMaximumSUL", A2DP_NOT_SUPPORTED_MAXIMUM_SUL}, > > + {"InvalidBlockLength", A2DP_INVALID_BLOCK_LENGTH}, > > + {"InvalidCPType", A2DP_INVALID_CP_TYPE}, > > + {"InvalidCPFormat", A2DP_INVALID_CP_FORMAT}, > > + {"InvalidCodecParameter", A2DP_INVALID_CODEC_PARAMETER}, > > + {"NotSupportedCodecParameter", A2DP_NOT_SUPPORTED_CODEC_PARAMETER}, > > + {"InvalidDRC", A2DP_INVALID_DRC}, > > + {"NotSupportedDRC", A2DP_NOT_SUPPORTED_DRC} > > +}; > > + > > +uint8_t a2dp_parse_config_error(const char *error_name) > > +{ > > + size_t prefix_length; > > + size_t i; > > + > > + prefix_length = strlen(A2DP_ERROR_PREFIX); > > + if (strncmp(A2DP_ERROR_PREFIX, error_name, prefix_length)) > > + return AVDTP_UNSUPPORTED_CONFIGURATION; > > + > > + error_name += prefix_length; > > + for (i = 0; i < ARRAY_SIZE(config_errors); i++) { > > + if (strcmp(config_errors[i].error_name, error_name) == 0) > > + return config_errors[i].error_code; > > + } > > + > > + return AVDTP_UNSUPPORTED_CONFIGURATION; > > +} > > + > > static struct a2dp_setup *setup_ref(struct a2dp_setup *setup) > > { > > setup->ref++; > > @@ -688,11 +755,10 @@ done: > > return FALSE; > > } > > > > -static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret) > > +static void endpoint_setconf_cb(struct a2dp_setup *setup, uint8_t error_code) > > { > > - if (ret == FALSE) > > - setup_error_init(setup, AVDTP_MEDIA_CODEC, > > - AVDTP_UNSUPPORTED_CONFIGURATION); > > + if (error_code != 0) > > + setup_error_init(setup, AVDTP_MEDIA_CODEC, error_code); > > > > auto_config(setup); > > setup_unref(setup); > > @@ -865,11 +931,11 @@ static gboolean endpoint_getcap_ind(struct avdtp *session, > > return TRUE; > > } > > > > -static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret) > > +static void endpoint_open_cb(struct a2dp_setup *setup, uint8_t error_code) > > { > > int err = error_to_errno(setup->err); > > > > - if (ret == FALSE) { > > + if (error_code != 0) { > > setup->stream = NULL; > > finalize_setup_errno(setup, -EPERM, finalize_config, NULL); > > goto done; > > diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h > > index c698bc983..afa02c12d 100644 > > --- a/profiles/audio/a2dp.h > > +++ b/profiles/audio/a2dp.h > > @@ -15,7 +15,8 @@ struct a2dp_setup; > > > > typedef void (*a2dp_endpoint_select_t) (struct a2dp_setup *setup, void *ret, > > int size); > > -typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, gboolean ret); > > +typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, > > + uint8_t error_code); > > > > struct a2dp_endpoint { > > const char *(*get_name) (struct a2dp_sep *sep, void *user_data); > > @@ -70,6 +71,8 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, > > unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep, > > a2dp_config_cb_t cb, GSList *caps, > > void *user_data); > > +uint8_t a2dp_parse_config_error(const char *error_name); > > + > > unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep, > > a2dp_stream_cb_t cb, void *user_data); > > unsigned int a2dp_suspend(struct avdtp *session, struct a2dp_sep *sep, > > diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c > > index 30648251f..ed4e22b26 100644 > > --- a/profiles/audio/avdtp.c > > +++ b/profiles/audio/avdtp.c > > @@ -1494,8 +1494,8 @@ static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream, > > struct conf_rej rej; > > > > if (err != NULL) { > > - rej.error = AVDTP_UNSUPPORTED_CONFIGURATION; > > - rej.category = err->err.error_code; > > + rej.error = err->err.error_code; > > + rej.category = AVDTP_UNSUPPORTED_CONFIGURATION; > > avdtp_send(session, session->in_cmd.transaction, > > AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, > > &rej, sizeof(rej)); > > diff --git a/profiles/audio/media.c b/profiles/audio/media.c > > index 9b3042c18..332f643bb 100644 > > --- a/profiles/audio/media.c > > +++ b/profiles/audio/media.c > > @@ -333,7 +333,7 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > DBusMessage *reply; > > DBusMessageIter args, props; > > DBusError err; > > - gboolean value; > > + uint8_t error_code; > > void *ret = NULL; > > int size = -1; > > > > @@ -356,8 +356,12 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > > > if (dbus_message_is_method_call(request->msg, > > MEDIA_ENDPOINT_INTERFACE, > > - "SetConfiguration")) > > + "SetConfiguration")) { > > endpoint_remove_transport(endpoint, request->transport); > > + error_code = a2dp_parse_config_error(err.name); > > + ret = &error_code; > > + size = 1; > > + } > > > > dbus_error_free(&err); > > goto done; > > @@ -390,8 +394,8 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data) > > } > > > > size = 1; > > - value = TRUE; > > - ret = &value; > > + error_code = 0; > > + ret = &error_code; > > > > done: > > dbus_message_unref(reply); > > @@ -634,9 +638,9 @@ static void config_cb(struct media_endpoint *endpoint, void *ret, int size, > > void *user_data) > > { > > struct a2dp_config_data *data = user_data; > > - gboolean *ret_value = ret; > > + uint8_t *ret_value = ret; > > > > - data->cb(data->setup, ret_value ? *ret_value : FALSE); > > + data->cb(data->setup, ret_value ? *ret_value : 1); > > } > > > > static int set_config(struct a2dp_sep *sep, uint8_t *configuration, > > @@ -1098,7 +1102,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, > > void *user_data) > > { > > struct pac_config_data *data = user_data; > > - gboolean *ret_value = ret; > > + uint8_t *error_code = ret; > > struct media_transport *transport; > > > > /* If transport was cleared, configuration was cancelled */ > > @@ -1106,7 +1110,7 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, > > if (!transport) > > return; > > > > - data->cb(data->stream, ret_value ? 0 : -EINVAL); > > + data->cb(data->stream, error_code == 0 ? 0 : -EINVAL); > > } > > > > static struct media_transport *pac_ucast_config(struct bt_bap_stream *stream, > > diff --git a/src/error.h b/src/error.h > > index 47602d39b..8157795c2 100644 > > --- a/src/error.h > > +++ b/src/error.h > > @@ -88,3 +88,41 @@ DBusMessage *btd_error_profile_unavailable(DBusMessage *msg); > > DBusMessage *btd_error_failed(DBusMessage *msg, const char *str); > > DBusMessage *btd_error_bredr_errno(DBusMessage *msg, int err); > > DBusMessage *btd_error_le_errno(DBusMessage *msg, int err); > > + > > +enum a2dp_error_codes : uint8_t { > > + A2DP_INVALID_CODEC_TYPE = 0xc1, > > + A2DP_NOT_SUPPORTED_CODEC_TYPE = 0xc2, > > + A2DP_INVALID_SAMPLING_FREQUENCY = 0xc3, > > + A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xc4, > > + A2DP_INVALID_CHANNEL_MODE = 0xc5, > > + A2DP_NOT_SUPPORTED_CHANNEL_MODE = 0xc6, > > + A2DP_INVALID_SUBBANDS = 0xc7, > > + A2DP_NOT_SUPPORTED_SUBBANDS = 0xc8, > > + A2DP_INVALID_ALLOCATION_METHOD = 0xc9, > > + A2DP_NOT_SUPPORTED_ALLOCATION_METHOD = 0xca, > > + A2DP_INVALID_MINIMUM_BITPOOL_VALUE = 0xcb, > > + A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xcc, > > + A2DP_INVALID_MAXIMUM_BITPOOL_VALUE = 0xcd, > > + A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xce, > > + A2DP_INVALID_INVALID_LAYER = 0xcf, > > + A2DP_NOT_SUPPORTED_LAYER = 0xd0, > > + A2DP_NOT_SUPPORTERD_CRC = 0xd1, > > + A2DP_NOT_SUPPORTERD_MPF = 0xd2, > > + A2DP_NOT_SUPPORTERD_VBR = 0xd3, > > + A2DP_INVALID_BIT_RATE = 0xd4, > > + A2DP_NOT_SUPPORTED_BIT_RATE = 0xd5, > > + A2DP_INVALID_OBJECT_TYPE = 0xd6, > > + A2DP_NOT_SUPPORTED_OBJECT_TYPE = 0xd7, > > + A2DP_INVALID_CHANNELS = 0xd8, > > + A2DP_NOT_SUPPORTED_CHANNELS = 0xd9, > > + A2DP_INVALID_VERSION = 0xda, > > + A2DP_NOT_SUPPORTED_VERSION = 0xdb, > > + A2DP_NOT_SUPPORTED_MAXIMUM_SUL = 0xdc, > > + A2DP_INVALID_BLOCK_LENGTH = 0xdd, > > + A2DP_INVALID_CP_TYPE = 0xe0, > > + A2DP_INVALID_CP_FORMAT = 0xe1, > > + A2DP_INVALID_CODEC_PARAMETER = 0xe2, > > + A2DP_NOT_SUPPORTED_CODEC_PARAMETER = 0xe3, > > + A2DP_INVALID_DRC = 0xe4, > > + A2DP_NOT_SUPPORTED_DRC = 0xe5, > > +}; > > Hmm, I guess there should be part of a2dp.h since this error header is > about D-Bus not A2DP codes. > > > -- > > 2.43.0 > > > > > -- Pauli Virtanen ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-09-11 20:32 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-09-11 13:53 [PATCH BlueZ] audio: Add support for specific error codes for A2DP configuration Per Waagø 2025-09-11 14:08 ` [BlueZ] " bluez.test.bot 2025-09-11 14:43 ` [PATCH BlueZ] " Luiz Augusto von Dentz 2025-09-11 15:12 ` Per Waago (pwaago) 2025-09-11 15:52 ` Luiz Augusto von Dentz 2025-09-11 19:56 ` Per Waago (pwaago) 2025-09-11 20:32 ` Luiz Augusto von Dentz 2025-09-11 16:25 ` Pauli Virtanen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox