linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/4] Media Control Profile Client
@ 2022-10-06 14:33 Abhay Maheta
  2022-10-06 14:33 ` [PATCH BlueZ 1/4] lib/uuid: Add GMCS UUIDs Abhay Maheta
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Abhay Maheta @ 2022-10-06 14:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Abhay Maheta

This series of patches adds support for Media Control Profile for LE Audio.
These patches primarily foces on Media Control Client Role.

Abhay Maheta (4):
  lib/uuid: Add GMCS UUIDs
  shared/mcp: Add initial code for handling MCP
  profiles: Add initial code for mcp plugin
  monitor/att: Add decoding support for GMCS

 Makefile.am          |    1 +
 Makefile.plugins     |    5 +
 configure.ac         |    4 +
 lib/uuid.h           |   15 +
 monitor/att.c        |  511 +++++++++++++++
 profiles/audio/mcp.c |  429 +++++++++++++
 src/shared/mcp.c     | 1408 ++++++++++++++++++++++++++++++++++++++++++
 src/shared/mcp.h     |   60 ++
 src/shared/mcs.h     |   65 ++
 9 files changed, 2498 insertions(+)
 create mode 100644 profiles/audio/mcp.c
 create mode 100644 src/shared/mcp.c
 create mode 100644 src/shared/mcp.h
 create mode 100644 src/shared/mcs.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 1/4] lib/uuid: Add GMCS UUIDs
  2022-10-06 14:33 [PATCH BlueZ 0/4] Media Control Profile Client Abhay Maheta
@ 2022-10-06 14:33 ` Abhay Maheta
  2022-10-06 14:58   ` Media Control Profile Client bluez.test.bot
  2022-10-06 14:33 ` [PATCH BlueZ 2/4] shared/mcp: Add initial code for handling MCP Abhay Maheta
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Abhay Maheta @ 2022-10-06 14:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Abhay Maheta

This adds GMCS UUIDs which will be used by Media Control Profile.
---
 lib/uuid.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index f667a74b9..d5e5665e4 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -171,6 +171,21 @@ extern "C" {
 #define VOL_CP_CHRC_UUID				0x2B7E
 #define VOL_FLAG_CHRC_UUID				0x2B7F
 
+#define GMCS_UUID                               0x1849
+#define MEDIA_PLAYER_NAME_CHRC_UUID             0x2b93
+#define MEDIA_TRACK_CHNGD_CHRC_UUID             0x2b96
+#define MEDIA_TRACK_TITLE_CHRC_UUID             0x2b97
+#define MEDIA_TRACK_DURATION_CHRC_UUID          0x2b98
+#define MEDIA_TRACK_POSTION_CHRC_UUID           0x2b99
+#define MEDIA_PLAYBACK_SPEED_CHRC_UUID          0x2b9a
+#define MEDIA_SEEKING_SPEED_CHRC_UUID           0x2b9b
+#define MEDIA_PLAYING_ORDER_CHRC_UUID           0x2ba1
+#define MEDIA_PLAY_ORDER_SUPPRTD_CHRC_UUID      0x2ba2
+#define MEDIA_STATE_CHRC_UUID                   0x2ba3
+#define MEDIA_CP_CHRC_UUID                      0x2ba4
+#define MEDIA_CP_OP_SUPPORTED_CHRC_UUID         0x2ba5
+#define MEDIA_CONTENT_CONTROL_ID_CHRC_UUID      0x2bba
+
 typedef struct {
 	enum {
 		BT_UUID_UNSPEC = 0,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 2/4] shared/mcp: Add initial code for handling MCP
  2022-10-06 14:33 [PATCH BlueZ 0/4] Media Control Profile Client Abhay Maheta
  2022-10-06 14:33 ` [PATCH BlueZ 1/4] lib/uuid: Add GMCS UUIDs Abhay Maheta
@ 2022-10-06 14:33 ` Abhay Maheta
  2022-10-06 14:33 ` [PATCH BlueZ 3/4] profiles: Add initial code for mcp plugin Abhay Maheta
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Abhay Maheta @ 2022-10-06 14:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Abhay Maheta

This adds initial code for Media Control Profile for Client Role.
---
 Makefile.am      |    1 +
 src/shared/mcp.c | 1408 ++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/mcp.h |   60 ++
 src/shared/mcs.h |   65 +++
 4 files changed, 1534 insertions(+)
 create mode 100644 src/shared/mcp.c
 create mode 100644 src/shared/mcp.h
 create mode 100644 src/shared/mcs.h

diff --git a/Makefile.am b/Makefile.am
index 27715c73d..23f6c1b98 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -231,6 +231,7 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
 			src/shared/gap.h src/shared/gap.c \
 			src/shared/log.h src/shared/log.c \
 			src/shared/bap.h src/shared/bap.c src/shared/ascs.h \
+			src shared/mcs.h src/shared/mcp.h src/shared/mcp.c \
 			src/shared/vcp.c src/shared/vcp.h \
 			src/shared/lc3.h src/shared/tty.h
 
diff --git a/src/shared/mcp.c b/src/shared/mcp.c
new file mode 100644
index 000000000..20f18d2c0
--- /dev/null
+++ b/src/shared/mcp.c
@@ -0,0 +1,1408 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define _GNU_SOURCE
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+#include "lib/hci.h"
+
+#include "src/shared/queue.h"
+#include "src/shared/util.h"
+#include "src/shared/timeout.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/mcp.h"
+#include "src/shared/mcs.h"
+
+#define DBG(_mcp, fmt, arg...) \
+	mcp_debug(_mcp, "%s:%s() " fmt, __FILE__, __func__, ## arg)
+
+struct bt_mcp_db {
+	struct gatt_db *db;
+	struct bt_mcs *mcs;
+};
+
+struct bt_mcp_pending {
+	unsigned int id;
+	struct bt_mcp *mcp;
+	bt_gatt_client_read_callback_t func;
+	void *user_data;
+};
+
+struct event_callback {
+	const struct bt_mcp_event_callback *cbs;
+	void *user_data;
+};
+
+struct bt_mcp_session_info {
+	uint8_t content_control_id;
+	uint32_t cp_op_supported;
+};
+
+struct bt_mcp {
+	int ref_count;
+	struct bt_gatt_client *client;
+	struct bt_mcp_db *ldb;
+	struct bt_mcp_db *rdb;
+	unsigned int mp_name_id;
+	unsigned int track_changed_id;
+	unsigned int track_title_id;
+	unsigned int track_duration_id;
+	unsigned int track_position_id;
+	unsigned int media_state_id;
+	unsigned int media_cp_id;
+	unsigned int media_cp_op_supported_id;
+
+    struct bt_mcp_session_info session;
+	struct event_callback *cb;
+
+	struct queue *pending;
+
+    bt_mcp_debug_func_t debug_func;
+    bt_mcp_destroy_func_t debug_destroy;
+    void *debug_data;
+	void *user_data;
+};
+
+struct bt_mcs {
+	struct bt_mcp_db *mdb;
+	struct gatt_db_attribute *service;
+	struct gatt_db_attribute *mp_name;
+	struct gatt_db_attribute *track_changed;
+	struct gatt_db_attribute *track_changed_ccc;
+	struct gatt_db_attribute *track_title;
+	struct gatt_db_attribute *track_duration;
+	struct gatt_db_attribute *track_position;
+	struct gatt_db_attribute *playback_speed;
+	struct gatt_db_attribute *seeking_speed;
+	struct gatt_db_attribute *play_order;
+	struct gatt_db_attribute *play_order_supported;
+	struct gatt_db_attribute *media_state;
+	struct gatt_db_attribute *media_state_ccc;
+	struct gatt_db_attribute *media_cp;
+	struct gatt_db_attribute *media_cp_ccc;
+	struct gatt_db_attribute *media_cp_op_supportd;
+	struct gatt_db_attribute *content_control_id;
+	struct gatt_db_attribute *content_control_id_ccc;
+};
+
+static struct queue *mcp_db;
+
+static void mcp_debug(struct bt_mcp *mcp, const char *format, ...)
+{
+	va_list ap;
+
+	if (!mcp || !format || !mcp->debug_func)
+		return;
+
+	va_start(ap, format);
+	util_debug_va(mcp->debug_func, mcp->debug_data, format, ap);
+	va_end(ap);
+}
+
+static bool mcp_db_match(const void *data, const void *match_data)
+{
+	const struct bt_mcp_db *mdb = data;
+	const struct gatt_db *db = match_data;
+
+	return (mdb->db == db);
+}
+
+static void mcp_db_free(void *data)
+{
+	struct bt_mcp_db *bdb = data;
+
+	if (!bdb)
+		return;
+
+	gatt_db_unref(bdb->db);
+
+	free(bdb->mcs);
+	free(bdb);
+}
+
+static void mcp_free(void *data)
+{
+	struct bt_mcp *mcp = data;
+
+	DBG(mcp, "");
+
+	bt_mcp_detach(mcp);
+
+	mcp_db_free(mcp->rdb);
+
+	queue_destroy(mcp->pending, NULL);
+
+	free(mcp);
+}
+
+struct bt_mcp *bt_mcp_ref(struct bt_mcp *mcp)
+{
+	if (!mcp)
+		return NULL;
+
+	__sync_fetch_and_add(&mcp->ref_count, 1);
+
+	return mcp;
+}
+
+void bt_mcp_unref(struct bt_mcp *mcp)
+{
+	if (!mcp)
+		return;
+
+	if (__sync_sub_and_fetch(&mcp->ref_count, 1))
+		return;
+
+	mcp_free(mcp);
+}
+
+bool bt_mcp_set_user_data(struct bt_mcp *mcp, void *user_data)
+{
+	if (!mcp)
+		return false;
+
+	mcp->user_data = user_data;
+
+	return true;
+}
+
+void *bt_mcp_get_user_data(struct bt_mcp *mcp)
+{
+	if (!mcp)
+		return NULL;
+
+	return mcp->user_data;
+}
+
+bool bt_mcp_set_debug(struct bt_mcp *mcp, bt_mcp_debug_func_t func,
+			void *user_data, bt_mcp_destroy_func_t destroy)
+{
+	if (!mcp)
+		return false;
+
+	if (mcp->debug_destroy)
+		mcp->debug_destroy(mcp->debug_data);
+
+	mcp->debug_func = func;
+	mcp->debug_destroy = destroy;
+	mcp->debug_data = user_data;
+
+	return true;
+}
+
+static void mcs_mp_name_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	char mp_name[] = "";
+	struct iovec iov;
+
+	iov.iov_base = mp_name;
+	iov.iov_len = sizeof(mp_name);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_track_title_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	char track_title[] = "";
+	struct iovec iov;
+
+	iov.iov_base = track_title;
+	iov.iov_len = 0;
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_track_duration_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	int32_t track_duration = 0xFFFFFFFF;
+	struct iovec iov;
+
+	iov.iov_base = &track_duration;
+	iov.iov_len = sizeof(track_duration);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_track_position_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	int32_t track_position = 0xFFFFFFFF;
+	struct iovec iov;
+
+	iov.iov_base = &track_position;
+	iov.iov_len = sizeof(track_position);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_track_position_write(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				const uint8_t *value, size_t len,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	gatt_db_attribute_write_result(attrib, id,
+			BT_ATT_ERROR_INSUFFICIENT_RESOURCES);
+}
+
+static void mcs_playback_speed_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	int8_t playback_speed = 0x00;
+	struct iovec iov;
+
+	iov.iov_base = &playback_speed;
+	iov.iov_len = sizeof(playback_speed);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_playback_speed_write(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				const uint8_t *value, size_t len,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	gatt_db_attribute_write_result(attrib, id,
+				BT_ATT_ERROR_INSUFFICIENT_RESOURCES);
+}
+
+static void mcs_seeking_speed_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	int8_t seeking_speed = 0x00;
+	struct iovec iov;
+
+	iov.iov_base = &seeking_speed;
+	iov.iov_len = sizeof(seeking_speed);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_playing_order_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	uint8_t playing_order = 0x01;
+	struct iovec iov;
+
+	iov.iov_base = &playing_order;
+	iov.iov_len = sizeof(playing_order);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_playing_order_write(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				const uint8_t *value, size_t len,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	gatt_db_attribute_write_result(attrib, id,
+				BT_ATT_ERROR_INSUFFICIENT_RESOURCES);
+}
+
+static void mcs_playing_order_supported_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	uint16_t playing_order_supported = 0x01;
+	struct iovec iov;
+
+	iov.iov_base = &playing_order_supported;
+	iov.iov_len = sizeof(playing_order_supported);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_media_state_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	uint8_t media_state = 0x00;
+	struct iovec iov;
+
+	iov.iov_base = &media_state;
+	iov.iov_len = sizeof(media_state);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_media_cp_write(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				const uint8_t *value, size_t len,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	gatt_db_attribute_write_result(attrib, id,
+				BT_ATT_ERROR_INSUFFICIENT_RESOURCES);
+}
+
+static void mcs_media_cp_op_supported_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	uint32_t cp_op_supported = 0x00000000;
+	struct iovec iov;
+
+	iov.iov_base = &cp_op_supported;
+	iov.iov_len = sizeof(cp_op_supported);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void mcs_media_content_control_id_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	uint8_t content_control_id = 0x00;
+	struct iovec iov;
+
+	iov.iov_base = &content_control_id;
+	iov.iov_len = sizeof(content_control_id);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static struct bt_mcs *mcs_new(struct gatt_db *db)
+{
+	struct bt_mcs *mcs;
+	bt_uuid_t uuid;
+
+	if (!db)
+		return NULL;
+
+	mcs = new0(struct bt_mcs, 1);
+
+	/* Populate DB with MCS attributes */
+	bt_uuid16_create(&uuid, GMCS_UUID);
+	mcs->service = gatt_db_add_service(db, &uuid, true, 31);
+
+	bt_uuid16_create(&uuid, MEDIA_PLAYER_NAME_CHRC_UUID);
+	mcs->mp_name = gatt_db_service_add_characteristic(mcs->service, &uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					mcs_mp_name_read, NULL,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_TRACK_CHNGD_CHRC_UUID);
+	mcs->track_changed = gatt_db_service_add_characteristic(mcs->service,
+                    &uuid,
+					BT_ATT_PERM_NONE,
+					BT_GATT_CHRC_PROP_NOTIFY,
+					NULL, NULL,
+					mcs);
+
+	mcs->track_changed_ccc = gatt_db_service_add_ccc(mcs->service,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+
+	bt_uuid16_create(&uuid, MEDIA_TRACK_TITLE_CHRC_UUID);
+	mcs->track_title = gatt_db_service_add_characteristic(mcs->service, &uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					mcs_track_title_read, NULL,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_TRACK_DURATION_CHRC_UUID);
+	mcs->track_duration = gatt_db_service_add_characteristic(mcs->service,
+					&uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					mcs_track_duration_read, NULL,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_TRACK_POSTION_CHRC_UUID);
+	mcs->track_position = gatt_db_service_add_characteristic(mcs->service,
+					&uuid,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE |
+					BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP,
+					mcs_track_position_read, mcs_track_position_write,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_PLAYBACK_SPEED_CHRC_UUID);
+	mcs->playback_speed = gatt_db_service_add_characteristic(mcs->service,
+					&uuid,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE |
+					BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP,
+					mcs_playback_speed_read, mcs_playback_speed_write,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_SEEKING_SPEED_CHRC_UUID);
+	mcs->seeking_speed = gatt_db_service_add_characteristic(mcs->service,
+                    &uuid,
+                    BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					mcs_seeking_speed_read, NULL,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_PLAYING_ORDER_CHRC_UUID);
+	mcs->play_order = gatt_db_service_add_characteristic(mcs->service, &uuid,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE |
+					BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP,
+					mcs_playing_order_read, mcs_playing_order_write,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_PLAY_ORDER_SUPPRTD_CHRC_UUID);
+	mcs->play_order_supported = gatt_db_service_add_characteristic(mcs->service,
+					&uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					mcs_playing_order_supported_read, NULL,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_STATE_CHRC_UUID);
+	mcs->media_state = gatt_db_service_add_characteristic(mcs->service, &uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_NOTIFY,
+					mcs_media_state_read, NULL,
+					mcs);
+
+	mcs->media_state_ccc = gatt_db_service_add_ccc(mcs->service,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+
+	bt_uuid16_create(&uuid, MEDIA_CP_CHRC_UUID);
+	mcs->media_cp = gatt_db_service_add_characteristic(mcs->service, &uuid,
+					BT_ATT_PERM_WRITE,
+					BT_GATT_CHRC_PROP_WRITE | BT_GATT_CHRC_PROP_NOTIFY |
+					BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP,
+					NULL, mcs_media_cp_write,
+					mcs);
+
+	mcs->media_cp_ccc = gatt_db_service_add_ccc(mcs->service,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+
+	bt_uuid16_create(&uuid, MEDIA_CP_OP_SUPPORTED_CHRC_UUID);
+	mcs->media_cp_op_supportd = gatt_db_service_add_characteristic(mcs->service,
+					&uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					mcs_media_cp_op_supported_read, NULL,
+					mcs);
+
+	bt_uuid16_create(&uuid, MEDIA_CONTENT_CONTROL_ID_CHRC_UUID);
+	mcs->content_control_id = gatt_db_service_add_characteristic(mcs->service,
+					&uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_NOTIFY,
+					mcs_media_content_control_id_read, NULL,
+					mcs);
+
+	mcs->content_control_id_ccc = gatt_db_service_add_ccc(mcs->service,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+
+	gatt_db_service_set_active(mcs->service, false);
+
+	return mcs;
+}
+
+static struct bt_mcs *mcp_get_mcs(struct bt_mcp *mcp)
+{
+	if (!mcp)
+		return NULL;
+
+	if (mcp->rdb->mcs)
+		return mcp->rdb->mcs;
+
+	mcp->rdb->mcs = new0(struct bt_mcs, 1);
+	mcp->rdb->mcs->mdb = mcp->rdb;
+
+	return mcp->rdb->mcs;
+}
+
+static unsigned int mcp_send(struct bt_mcp *mcp, uint8_t operation)
+{
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+	int ret;
+	uint16_t handle;
+
+	DBG(mcp, "mcs %p", mcs);
+
+	if (!mcp->client)
+		return -1;
+
+	if (!gatt_db_attribute_get_char_data(mcs->media_cp, NULL, &handle,
+					NULL, NULL, NULL))
+		return -1;
+
+	ret = bt_gatt_client_write_without_response(mcp->client, handle, false,
+					&operation, sizeof(uint8_t));
+	if (!ret)
+		return -1;
+
+	return 0;
+}
+
+unsigned int bt_mcp_play(struct bt_mcp *mcp)
+{
+	if (!(mcp->session.cp_op_supported & BT_MCS_CMD_PLAY_SUPPORTED))
+		return -ENOTSUP;
+
+	DBG(mcp, "mcp %p", mcp);
+
+	return mcp_send(mcp, BT_MCS_CMD_PLAY);
+}
+
+unsigned int bt_mcp_pause(struct bt_mcp *mcp)
+{
+	if (!(mcp->session.cp_op_supported & BT_MCS_CMD_PAUSE_SUPPORTED))
+		return -ENOTSUP;
+
+	DBG(mcp, "mcp %p", mcp);
+
+	return mcp_send(mcp, BT_MCS_CMD_PAUSE);
+}
+
+unsigned int bt_mcp_stop(struct bt_mcp *mcp)
+{
+	if (!(mcp->session.cp_op_supported & BT_MCS_CMD_STOP_SUPPORTED))
+		return -ENOTSUP;
+
+	DBG(mcp, "mcp %p", mcp);
+
+	return mcp_send(mcp, BT_MCS_CMD_STOP);
+}
+
+static void mcp_mp_set_player_name(struct bt_mcp *mcp, const uint8_t *value,
+					uint16_t length)
+{
+	struct event_callback *cb = mcp->cb;
+
+	if (cb && cb->cbs && cb->cbs->player_name)
+		cb->cbs->player_name(mcp, value, length);
+}
+
+static void mcp_mp_set_track_title(struct bt_mcp *mcp, const uint8_t *value,
+					uint16_t length)
+{
+	struct event_callback *cb = mcp->cb;
+
+	if (cb && cb->cbs && cb->cbs->track_title)
+		cb->cbs->track_title(mcp, value, length);
+}
+
+static void mcp_mp_set_title_duration(struct bt_mcp *mcp, int32_t duration)
+{
+	struct event_callback *cb = mcp->cb;
+
+	DBG(mcp, "Track Duration 0x%08x", duration);
+
+	if (cb && cb->cbs && cb->cbs->track_duration)
+		cb->cbs->track_duration(mcp, duration);
+}
+
+static void mcp_mp_set_title_position(struct bt_mcp *mcp, int32_t position)
+{
+	struct event_callback *cb = mcp->cb;
+
+	DBG(mcp, "Track Position 0x%08x", position);
+
+	if (cb && cb->cbs && cb->cbs->track_position)
+		cb->cbs->track_position(mcp, position);
+}
+
+static void mcp_mp_set_media_state(struct bt_mcp *mcp, uint8_t state)
+{
+	struct event_callback *cb = mcp->cb;
+
+	DBG(mcp, "Media State 0x%02x", state);
+
+	if (cb && cb->cbs && cb->cbs->media_state)
+		cb->cbs->media_state(mcp, state);
+}
+
+static void read_media_player_name(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	if (!success) {
+		DBG(mcp, "Unable to read media player name: error 0x%02x", att_ecode);
+		return;
+	}
+
+	if (!length)
+		return;
+
+	mcp_mp_set_player_name(mcp, value, length);
+}
+
+static void read_track_title(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+	struct event_callback *cb = mcp->cb;
+
+	if (!success) {
+		DBG(mcp, "Unable to read track title: error 0x%02x", att_ecode);
+		return;
+	}
+
+	if (!length)
+		return;
+
+	mcp_mp_set_track_title(mcp, value, length);
+}
+
+static void read_track_duration(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+	int32_t duration;
+
+	if (!success) {
+		DBG(mcp, "Unable to read track duration: error 0x%02x", att_ecode);
+		return;
+	}
+
+	if (length != sizeof(duration)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}
+
+	memcpy(&duration, value, length);
+	mcp_mp_set_title_duration(mcp, duration);
+}
+
+static void read_track_position(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+	int32_t position;
+
+	if (!success) {
+		DBG(mcp, "Unable to read track position: error 0x%02x", att_ecode);
+		return;
+	}
+
+	if (length != sizeof(position)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}
+
+	memcpy(&position, value, length);
+	mcp_mp_set_title_position(mcp, position);
+}
+
+static void read_media_state(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	if (!success) {
+		DBG(mcp, "Unable to read media state: error 0x%02x", att_ecode);
+		return;
+	}
+
+	if (length != sizeof(uint8_t)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}
+
+	mcp_mp_set_media_state(mcp, *value);
+}
+
+static void read_media_cp_op_supported(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	if (!success) {
+		DBG(mcp, "Unable to read media CP opcodes supported: error 0x%02x",
+				att_ecode);
+		return;
+	}
+
+	if (length != sizeof(uint32_t)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}
+
+	memcpy(&mcp->session.cp_op_supported, value, sizeof(uint32_t));
+	DBG(mcp, "Media Control Point Opcodes Supported 0x%08x",
+			mcp->session.cp_op_supported);
+}
+
+static void read_content_control_id(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	if (!success) {
+		DBG(mcp, "Unable to read content control id: error 0x%02x", att_ecode);
+		return;
+	}
+
+	if (length != sizeof(uint8_t)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}
+
+	DBG(mcp, "Content Control ID 0x%02x", *value);
+}
+
+static void mcp_pending_destroy(void *data)
+{
+	struct bt_mcp_pending *pending = data;
+	struct bt_mcp *mcp = pending->mcp;
+
+	queue_remove_if(mcp->pending, NULL, pending);
+}
+
+static void mcp_pending_complete(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_mcp_pending *pending = user_data;
+
+	if (pending->func)
+		pending->func(success, att_ecode, value, length,
+						pending->user_data);
+}
+
+static void mcp_read_value(struct bt_mcp *mcp, uint16_t value_handle,
+				bt_gatt_client_read_callback_t func,
+				void *user_data)
+{
+	struct bt_mcp_pending *pending;
+
+	pending = new0(struct bt_mcp_pending, 1);
+	pending->mcp = mcp;
+	pending->func = func;
+	pending->user_data = user_data;
+
+	pending->id = bt_gatt_client_read_value(mcp->client, value_handle,
+						mcp_pending_complete, pending,
+						mcp_pending_destroy);
+	if (!pending->id) {
+		DBG(mcp, "Unable to send Read request");
+		free(pending);
+		return;
+	}
+
+	queue_push_tail(mcp->pending, pending);
+}
+
+static void mcp_mp_name_register(uint16_t att_ecode, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	if (att_ecode)
+		DBG(mcp, "Media Player Name notification failed: 0x%04x", att_ecode);
+}
+
+static void mcp_mp_name_notify(uint16_t value_handle, const uint8_t *value,
+					uint16_t length, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	if (!length)
+		return;
+
+	mcp_mp_set_player_name(mcp, value, length);
+}
+
+static void mcp_track_changed_register(uint16_t att_ecode, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	if (att_ecode)
+		DBG(mcp, "Media Track Changed notification failed: 0x%04x", att_ecode);
+}
+
+static void mcp_track_changed_notify(uint16_t value_handle,
+                    const uint8_t *value, uint16_t length, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+	struct event_callback *cb = mcp->cb;
+
+	DBG(mcp, "Track Changed");
+
+	if (cb && cb->cbs && cb->cbs->track_changed)
+		cb->cbs->track_changed(mcp);
+}
+
+static void mcp_track_title_register(uint16_t att_ecode, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	if (att_ecode)
+		DBG(mcp, "Media Track Title notification failed: 0x%04x", att_ecode);
+}
+
+static void mcp_track_title_notify(uint16_t value_handle, const uint8_t *value,
+					uint16_t length, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	mcp_mp_set_track_title(mcp, value, length);
+}
+
+static void mcp_track_duration_register(uint16_t att_ecode, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	if (att_ecode)
+		DBG(mcp, "Media Track Duration notification failed: 0x%04x", att_ecode);
+}
+
+static void mcp_track_duration_notify(uint16_t value_handle,
+        const uint8_t *value, uint16_t length, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+	int32_t duration;
+
+	memcpy(&duration, value, sizeof(int32_t));
+	mcp_mp_set_title_duration(mcp, duration);
+}
+
+static void mcp_track_position_register(uint16_t att_ecode, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	if (att_ecode)
+		DBG(mcp, "Media Track Position notification failed: 0x%04x", att_ecode);
+}
+
+static void mcp_track_position_notify(uint16_t value_handle,
+        const uint8_t *value, uint16_t length, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+	int32_t position;
+
+	memcpy(&position, value, sizeof(int32_t));
+	mcp_mp_set_title_position(mcp, position);
+}
+
+static void mcp_media_state_register(uint16_t att_ecode, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	if (att_ecode)
+		DBG(mcp, "Media Media State notification failed: 0x%04x", att_ecode);
+}
+
+static void mcp_media_state_notify(uint16_t value_handle, const uint8_t *value,
+					uint16_t length, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	mcp_mp_set_media_state(mcp, *value);
+}
+
+static void mcp_media_cp_register(uint16_t att_ecode, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	if (att_ecode)
+		DBG(mcp, "Media Media CP notification failed: 0x%04x", att_ecode);
+}
+
+static void mcp_media_cp_notify(uint16_t value_handle, const uint8_t *value,
+					uint16_t length, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	DBG(mcp, "Media CP Notification");
+}
+
+static void mcp_media_cp_op_supported_register(uint16_t att_ecode,
+                    void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	if (att_ecode)
+		DBG(mcp, "Media Media CP OP Supported notification failed: 0x%04x",
+			att_ecode);
+}
+
+static void mcp_media_cp_op_supported_notify(uint16_t value_handle,
+					const uint8_t *value, uint16_t length, void *user_data)
+{
+    struct bt_mcp *mcp = user_data;
+
+	memcpy(&mcp->session.cp_op_supported, value, sizeof(uint32_t));
+	DBG(mcp, "Media CP Opcodes Supported Notification 0x%08x",
+			mcp->session.cp_op_supported);
+}
+
+void bt_mcp_mp_name_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->mp_name, NULL, &value_handle,
+						NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Media Player handle 0x%04x", value_handle);
+
+	mcp_read_value(mcp, value_handle, read_media_player_name, mcp);
+
+	mcp->mp_name_id = bt_gatt_client_register_notify(mcp->client,
+					value_handle, mcp_mp_name_register, mcp_mp_name_notify,
+					mcp, NULL);
+}
+
+void bt_mcp_track_changed_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->track_changed, NULL,
+				&value_handle, NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Track Changed handle 0x%04x", value_handle);
+
+	mcp->track_changed_id = bt_gatt_client_register_notify(mcp->client,
+						value_handle, mcp_track_changed_register,
+						mcp_track_changed_notify, mcp, NULL);
+}
+
+void bt_mcp_track_title_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->track_title, NULL,
+				&value_handle, NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Track Title handle 0x%04x", value_handle);
+
+	mcp_read_value(mcp, value_handle, read_track_title, mcp);
+
+	mcp->track_title_id = bt_gatt_client_register_notify(mcp->client,
+					value_handle, mcp_track_title_register,
+					mcp_track_title_notify, mcp, NULL);
+}
+
+void bt_mcp_track_duration_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->track_duration, NULL,
+				&value_handle, NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Track Duration handle 0x%04x", value_handle);
+
+	mcp_read_value(mcp, value_handle, read_track_duration, mcp);
+
+	mcp->track_duration_id = bt_gatt_client_register_notify(mcp->client,
+					value_handle, mcp_track_duration_register,
+					mcp_track_duration_notify, mcp, NULL);
+}
+
+void bt_mcp_track_position_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->track_position, NULL,
+				&value_handle, NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Track Position handle 0x%04x", value_handle);
+
+	mcp_read_value(mcp, value_handle, read_track_position, mcp);
+
+	mcp->track_position_id = bt_gatt_client_register_notify(mcp->client,
+					value_handle, mcp_track_position_register,
+					mcp_track_position_notify, mcp, NULL);
+}
+
+void bt_mcp_media_state_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->media_state, NULL,
+				&value_handle, NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Media State handle 0x%04x", value_handle);
+
+	mcp_read_value(mcp, value_handle, read_media_state, mcp);
+
+	mcp->media_state_id = bt_gatt_client_register_notify(mcp->client,
+					value_handle, mcp_media_state_register,
+					mcp_media_state_notify, mcp, NULL);
+}
+
+void bt_mcp_media_cp_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->media_cp, NULL,
+				&value_handle, NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Media Control Point handle 0x%04x", value_handle);
+
+	mcp->media_cp_id = bt_gatt_client_register_notify(mcp->client,
+						value_handle, mcp_media_cp_register,
+						mcp_media_cp_notify, mcp, NULL);
+}
+
+void bt_mcp_media_cp_op_supported_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->media_cp_op_supportd, NULL,
+				&value_handle, NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Media Control Point Opcodes Supported handle 0x%04x",
+                value_handle);
+
+	mcp_read_value(mcp, value_handle, read_media_cp_op_supported, mcp);
+
+	mcp->media_cp_op_supported_id = bt_gatt_client_register_notify(
+				mcp->client, value_handle, mcp_media_cp_op_supported_register,
+				mcp_media_cp_op_supported_notify, mcp, NULL);
+}
+
+void bt_mcp_content_control_id_supported_attach(struct bt_mcp *mcp)
+{
+	uint16_t value_handle;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	if (!gatt_db_attribute_get_char_data(mcs->content_control_id, NULL,
+				&value_handle, NULL, NULL, NULL))
+		return;
+
+	DBG(mcp, "Media Content Control id Supported handle 0x%04x", value_handle);
+	mcp_read_value(mcp, value_handle, read_content_control_id, mcp);
+}
+
+static void foreach_mcs_char(struct gatt_db_attribute *attr, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+	uint16_t value_handle;
+	bt_uuid_t uuid, uuid_mp_name, uuid_track_changed, uuid_track_title,
+				uuid_track_duration, uuid_track_position, uuid_media_state,
+				uuid_media_cp, uuid_media_cp_op_supported,
+				uuid_content_control_id;
+	struct bt_mcs *mcs;
+
+	if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle,
+						NULL, NULL, &uuid))
+		return;
+
+	bt_uuid16_create(&uuid_mp_name, MEDIA_PLAYER_NAME_CHRC_UUID);
+	bt_uuid16_create(&uuid_track_changed, MEDIA_TRACK_CHNGD_CHRC_UUID);
+	bt_uuid16_create(&uuid_track_title, MEDIA_TRACK_TITLE_CHRC_UUID);
+	bt_uuid16_create(&uuid_track_duration, MEDIA_TRACK_DURATION_CHRC_UUID);
+	bt_uuid16_create(&uuid_track_position, MEDIA_TRACK_POSTION_CHRC_UUID);
+	bt_uuid16_create(&uuid_media_state, MEDIA_STATE_CHRC_UUID);
+	bt_uuid16_create(&uuid_media_cp, MEDIA_CP_CHRC_UUID);
+	bt_uuid16_create(&uuid_media_cp_op_supported,
+						MEDIA_CP_OP_SUPPORTED_CHRC_UUID);
+	bt_uuid16_create(&uuid_content_control_id,
+						MEDIA_CONTENT_CONTROL_ID_CHRC_UUID);
+
+	if (!bt_uuid_cmp(&uuid, &uuid_mp_name)) {
+		DBG(mcp, "Media Player Name found: handle 0x%04x", value_handle);
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->mp_name)
+			return;
+
+		mcs->mp_name = attr;
+		bt_mcp_mp_name_attach(mcp);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_track_changed)) {
+		DBG(mcp, "Track Changed found: handle 0x%04x", value_handle);
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->track_changed)
+			return;
+
+		mcs->track_changed = attr;
+		bt_mcp_track_changed_attach(mcp);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_track_title)) {
+		DBG(mcp, "Track Title found: handle 0x%04x", value_handle);
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->track_title)
+			return;
+
+		mcs->track_title = attr;
+		bt_mcp_track_title_attach(mcp);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_track_duration)) {
+		DBG(mcp, "Track Duration found: handle 0x%04x", value_handle);
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->track_duration)
+			return;
+
+		mcs->track_duration = attr;
+		bt_mcp_track_duration_attach(mcp);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_track_position)) {
+		DBG(mcp, "Track Position found: handle 0x%04x", value_handle);
+
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->track_position)
+			return;
+
+		mcs->track_position = attr;
+		bt_mcp_track_position_attach(mcp);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_media_state)) {
+		DBG(mcp, "Media State found: handle 0x%04x", value_handle);
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->media_state)
+			return;
+
+		mcs->media_state = attr;
+		bt_mcp_media_state_attach(mcp);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_media_cp)) {
+		DBG(mcp, "Media Control Point found: handle 0x%04x", value_handle);
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->media_cp)
+			return;
+
+		mcs->media_cp = attr;
+		bt_mcp_media_cp_attach(mcp);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_media_cp_op_supported)) {
+		DBG(mcp, "Media Control Point Opecodes Supported found: handle 0x%04x",
+				value_handle);
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->media_cp_op_supportd)
+			return;
+
+		mcs->media_cp_op_supportd = attr;
+		bt_mcp_media_cp_op_supported_attach(mcp);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_content_control_id)) {
+		DBG(mcp, "Content Control ID found: handle 0x%04x", value_handle);
+
+		mcs = mcp_get_mcs(mcp);
+		if (!mcs || mcs->content_control_id)
+			return;
+
+		mcs->content_control_id = attr;
+		bt_mcp_content_control_id_supported_attach(mcp);
+	}
+}
+
+void bt_mcp_set_event_callbacks(struct bt_mcp *mcp,
+				const struct bt_mcp_event_callback *cbs,
+				void *user_data)
+{
+	struct event_callback *cb;
+
+	if (mcp->cb)
+		free(mcp->cb);
+
+	cb = new0(struct event_callback, 1);
+	cb->cbs = cbs;
+	cb->user_data = user_data;
+
+	mcp->cb = cb;
+}
+
+static void foreach_mcs_service(struct gatt_db_attribute *attr,
+						void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+	struct bt_mcs *mcs = mcp_get_mcs(mcp);
+
+	DBG(mcp, "");
+
+	mcs->service = attr;
+
+	gatt_db_service_foreach_char(attr, foreach_mcs_char, mcp);
+}
+
+static struct bt_mcp_db *mcp_db_new(struct gatt_db *db)
+{
+	struct bt_mcp_db *mdb;
+
+	if (!db)
+		return NULL;
+
+	mdb = new0(struct bt_mcp_db, 1);
+	mdb->db = gatt_db_ref(db);
+
+	if (!mcp_db)
+		mcp_db = queue_new();
+
+	queue_push_tail(mcp_db, mdb);
+
+	mdb->mcs = mcs_new(db);
+	return mdb;
+}
+
+static struct bt_mcp_db *mcp_get_db(struct gatt_db *db)
+{
+	struct bt_mcp_db *mdb;
+
+	mdb = queue_find(mcp_db, mcp_db_match, db);
+	if (mdb)
+		return mdb;
+
+	return mcp_db_new(db);
+}
+
+struct bt_mcp *bt_mcp_new(struct gatt_db *ldb, struct gatt_db *rdb)
+{
+	struct bt_mcp *mcp;
+	struct bt_mcp_db *mdb;
+
+	if (!ldb)
+		return NULL;
+
+	mdb = mcp_get_db(ldb);
+	if (!mdb)
+		return NULL;
+
+	mcp = new0(struct bt_mcp, 1);
+	mcp->ldb = mdb;
+	mcp->pending = queue_new();
+
+	if (!rdb)
+		goto done;
+
+	mdb = new0(struct bt_mcp_db, 1);
+	mdb->db = gatt_db_ref(rdb);
+
+	mcp->rdb = mdb;
+
+done:
+	bt_mcp_ref(mcp);
+
+	return mcp;
+}
+
+void bt_mcp_register(struct gatt_db *db)
+{
+	mcp_db_new(db);
+}
+
+bool bt_mcp_attach(struct bt_mcp *mcp, struct bt_gatt_client *client)
+{
+	bt_uuid_t uuid;
+
+	DBG(mcp, "mcp %p", mcp);
+
+	mcp->client = bt_gatt_client_clone(client);
+	if (!mcp->client)
+		return false;
+
+	if (mcp->rdb->mcs) {
+		uint16_t value_handle;
+
+		bt_mcp_mp_name_attach(mcp);
+		bt_mcp_track_changed_attach(mcp);
+		bt_mcp_track_title_attach(mcp);
+		bt_mcp_track_duration_attach(mcp);
+		bt_mcp_track_position_attach(mcp);
+		bt_mcp_media_state_attach(mcp);
+		bt_mcp_media_cp_attach(mcp);
+		bt_mcp_media_cp_op_supported_attach(mcp);
+		bt_mcp_content_control_id_supported_attach(mcp);
+
+		return true;
+	}
+
+	bt_uuid16_create(&uuid, GMCS_UUID);
+	gatt_db_foreach_service(mcp->rdb->db, &uuid, foreach_mcs_service, mcp);
+
+	return true;
+}
+
+void bt_mcp_detach(struct bt_mcp *mcp)
+{
+	DBG(mcp, "%p", mcp);
+
+	bt_gatt_client_unref(mcp->client);
+	mcp->client = NULL;
+}
diff --git a/src/shared/mcp.h b/src/shared/mcp.h
new file mode 100644
index 000000000..0a85631cf
--- /dev/null
+++ b/src/shared/mcp.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ */
+
+#include <stdbool.h>
+#include <inttypes.h>
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+struct bt_mcp;
+struct bt_mcp_db;
+struct bt_mcp_session_info;
+
+typedef void (*bt_mcp_debug_func_t)(const char *str, void *user_data);
+typedef void (*bt_mcp_destroy_func_t)(void *user_data);
+
+struct bt_mcp_event_callback {
+	void (*player_name)(struct bt_mcp *mcp,  const uint8_t *value,
+					uint16_t length);
+	void (*track_changed)(struct bt_mcp *mcp);
+	void (*track_title)(struct bt_mcp *mcp, const uint8_t *value,
+					uint16_t length);
+	void (*track_duration)(struct bt_mcp *mcp, int32_t duration);
+	void (*track_position)(struct bt_mcp *mcp, int32_t position);
+	void (*playback_speed)(struct bt_mcp *mcp, int8_t speed);
+	void (*seeking_speed)(struct bt_mcp *mcp, int8_t speed);
+	void (*play_order)(struct bt_mcp *mcp, uint8_t order);
+	void (*play_order_supported)(struct bt_mcp *mcp, uint16_t order_supported);
+	void (*media_state)(struct bt_mcp *mcp, uint8_t state);
+	void (*content_control_id)(struct bt_mcp *mcp, uint8_t cc_id);
+};
+
+void bt_mcp_set_event_callbacks(struct bt_mcp *mcp,
+				const struct bt_mcp_event_callback *cbs,
+				void *user_data);
+
+bool bt_mcp_set_debug(struct bt_mcp *mcp, bt_mcp_debug_func_t cb,
+			void *user_data, bt_mcp_destroy_func_t destroy);
+
+void bt_mcp_register(struct gatt_db *db);
+bool bt_mcp_attach(struct bt_mcp *mcp, struct bt_gatt_client *client);
+void bt_mcp_detach(struct bt_mcp *mcp);
+
+struct bt_mcp *bt_mcp_new(struct gatt_db *ldb, struct gatt_db *rdb);
+struct bt_mcp *bt_mcp_ref(struct bt_mcp *mcp);
+void bt_mcp_unref(struct bt_mcp *mcp);
+
+bool bt_mcp_set_user_data(struct bt_mcp *mcp, void *user_data);
+void *bt_mcp_get_user_data(struct bt_mcp *mcp);
+
+unsigned int bt_mcp_play(struct bt_mcp *mcp);
+unsigned int bt_mcp_pause(struct bt_mcp *mcp);
+unsigned int bt_mcp_stop(struct bt_mcp *mcp);
diff --git a/src/shared/mcs.h b/src/shared/mcs.h
new file mode 100644
index 000000000..51c24d89c
--- /dev/null
+++ b/src/shared/mcs.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ */
+
+/* MCP Media State */
+#define BT_MCS_STATUS_INACTIVE	0x00
+#define BT_MCS_STATUS_PLAYING	0x01
+#define BT_MCS_STATUS_PAUSED	0x02
+#define BT_MCS_STATUS_SEEKING	0x03
+
+/* MCP Control Point Opcodes */
+#define BT_MCS_CMD_PLAY			    0x01
+#define BT_MCS_CMD_PAUSE		    0x02
+#define BT_MCS_CMD_FAST_REWIND	    0x03
+#define BT_MCS_CMD_FAST_FORWARD	    0x04
+#define BT_MCS_CMD_STOP			    0x05
+
+#define BT_MCS_CMD_MOVE_RELATIVE    0x10
+
+#define BT_MCS_CMD_PREV_SEGMENT     0x20
+#define BT_MCS_CMD_NEXT_SEGMENT     0x21
+#define BT_MCS_CMD_FIRST_SEGMENT    0x22
+#define BT_MCS_CMD_LAST_SEGMENT     0x23
+#define BT_MCS_CMD_GOTO_SEGMENT     0x24
+
+#define BT_MCS_CMD_PREV_TRACK       0x30
+#define BT_MCS_CMD_NEXT_TRACK       0x31
+#define BT_MCS_CMD_FIRST_TRACK      0x32
+#define BT_MCS_CMD_LAST_TRACK       0x33
+#define BT_MCS_CMD_GOTO_TRACK       0x34
+
+#define BT_MCS_CMD_PREV_GROUP       0x40
+#define BT_MCS_CMD_NEXT_GROUP       0x41
+#define BT_MCS_CMD_FIRST_GROUP      0x42
+#define BT_MCS_CMD_LAST_GROUP       0x43
+#define BT_MCS_CMD_GOTO_GROUP       0x44
+
+
+/* MCP Control Point Opcodes Supported */
+#define BT_MCS_CMD_PLAY_SUPPORTED		    0x00000001
+#define BT_MCS_CMD_PAUSE_SUPPORTED		    0x00000002
+#define BT_MCS_CMD_FAST_REWIND_SUPPORTED    0x00000004
+#define BT_MCS_CMD_FAST_FORWARD_SUPPORTED   0x00000008
+#define BT_MCS_CMD_STOP_SUPPORTED		    0x00000010
+#define BT_MCS_CMD_MOVE_RELATIVE_SUPPORTED  0x00000020
+#define BT_MCS_CMD_PREV_SEGMENT_SUPPORTED   0x00000040
+#define BT_MCS_CMD_NEXT_SEGMENT_SUPPORTED   0x00000080
+#define BT_MCS_CMD_FIRST_SEGMENT_SUPPORTED  0x00000100
+#define BT_MCS_CMD_LAST_SEGMENT_SUPPORTED   0x00000200
+#define BT_MCS_CMD_GOTO_SEGMENT_SUPPORTED   0x00000400
+#define BT_MCS_CMD_PREV_TRACK_SUPPORTED     0x00000800
+#define BT_MCS_CMD_NEXT_TRACK_SUPPORTED     0x00001000
+#define BT_MCS_CMD_FIRST_TRACK_SUPPORTED    0x00002000
+#define BT_MCS_CMD_LAST_TRACK_SUPPORTED     0x00004000
+#define BT_MCS_CMD_GOTO_TRACK_SUPPORTED     0x00008000
+#define BT_MCS_CMD_PREV_GROUP_SUPPORTED     0x00010000
+#define BT_MCS_CMD_NEXT_GROUP_SUPPORTED     0x00020000
+#define BT_MCS_CMD_FIRST_GROUP_SUPPORTED    0x00040000
+#define BT_MCS_CMD_LAST_GROUP_SUPPORTED     0x00080000
+#define BT_MCS_CMD_GOTO_GROUP_SUPPORTED     0x00100000
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 3/4] profiles: Add initial code for mcp plugin
  2022-10-06 14:33 [PATCH BlueZ 0/4] Media Control Profile Client Abhay Maheta
  2022-10-06 14:33 ` [PATCH BlueZ 1/4] lib/uuid: Add GMCS UUIDs Abhay Maheta
  2022-10-06 14:33 ` [PATCH BlueZ 2/4] shared/mcp: Add initial code for handling MCP Abhay Maheta
@ 2022-10-06 14:33 ` Abhay Maheta
  2022-10-06 14:33 ` [PATCH BlueZ 4/4] monitor/att: Add decoding support for GMCS Abhay Maheta
  2022-10-06 20:40 ` [PATCH BlueZ 0/4] Media Control Profile Client Luiz Augusto von Dentz
  4 siblings, 0 replies; 7+ messages in thread
From: Abhay Maheta @ 2022-10-06 14:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Abhay Maheta

This adds initial code for mcp plugin which handles Media Control Profile
and Generic Media Control Service for Client Role.
---
 Makefile.plugins     |   5 +
 configure.ac         |   4 +
 profiles/audio/mcp.c | 429 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 438 insertions(+)
 create mode 100644 profiles/audio/mcp.c

diff --git a/Makefile.plugins b/Makefile.plugins
index a3654980f..20cac384e 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -122,6 +122,11 @@ builtin_modules += bap
 builtin_sources += profiles/audio/bap.c
 endif
 
+if MCP
+builtin_modules += mcp
+builtin_sources += profiles/audio/mcp.c
+endif
+
 if VCP
 builtin_modules += vcp
 builtin_sources += profiles/audio/vcp.c
diff --git a/configure.ac b/configure.ac
index 79645e691..363a222a7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,6 +199,10 @@ AC_ARG_ENABLE(bap, AS_HELP_STRING([--disable-bap],
 		[disable BAP profile]), [enable_bap=${enableval}])
 AM_CONDITIONAL(BAP, test "${enable_bap}" != "no")
 
+AC_ARG_ENABLE(mcp, AS_HELP_STRING([--disable-mcp],
+        [disable MCP profile]), [enable_mcp=${enableval}])
+AM_CONDITIONAL(MCP, test "${enable_mcp}" != "no")
+
 AC_ARG_ENABLE(vcp, AS_HELP_STRING([--disable-vcp],
 		[disable VCP profile]), [enable_vcp=${enableval}])
 AM_CONDITIONAL(VCP, test "${enable_vcp}" != "no")
diff --git a/profiles/audio/mcp.c b/profiles/audio/mcp.c
new file mode 100644
index 000000000..0a8d83198
--- /dev/null
+++ b/profiles/audio/mcp.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "gdbus/gdbus.h"
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "src/dbus-common.h"
+#include "src/shared/util.h"
+#include "src/shared/att.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/mcp.h"
+#include "src/shared/mcs.h"
+
+#include "btio/btio.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/gatt-database.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+#include "src/log.h"
+#include "src/error.h"
+#include "player.h"
+
+#define GMCS_UUID_STR "00001849-0000-1000-8000-00805f9b34fb"
+
+struct mcp_data {
+	struct btd_device *device;
+	struct btd_service *service;
+	struct bt_mcp *mcp;
+	unsigned int state_id;
+
+	struct media_player *mp;
+};
+
+static void mcp_debug(const char *str, void *user_data)
+{
+	DBG_IDX(0xffff, "%s", str);
+}
+
+static char *name2utf8(const uint8_t *name, uint16_t len)
+{
+	char utf8_name[HCI_MAX_NAME_LENGTH + 2];
+	int i;
+
+	if (g_utf8_validate((const char *) name, len, NULL))
+		return g_strndup((char *) name, len);
+
+	len = MIN(len, sizeof(utf8_name) - 1);
+
+	memset(utf8_name, 0, sizeof(utf8_name));
+	strncpy(utf8_name, (char *) name, len);
+
+	/* Assume ASCII, and replace all non-ASCII with spaces */
+	for (i = 0; utf8_name[i] != '\0'; i++) {
+		if (!isascii(utf8_name[i]))
+			utf8_name[i] = ' ';
+	}
+
+	/* Remove leading and trailing whitespace characters */
+	g_strstrip(utf8_name);
+
+	return g_strdup(utf8_name);
+}
+
+static const char *mcp_status_val_to_string(uint8_t status)
+{
+	switch (status) {
+	case BT_MCS_STATUS_PLAYING:
+		return "playing";
+	case BT_MCS_STATUS_PAUSED:
+		return "paused";
+	case BT_MCS_STATUS_INACTIVE:
+		return "stopped";
+	case BT_MCS_STATUS_SEEKING:
+		/* TODO: find a way for fwd/rvs seeking, probably by storing
+		 * control point operation sent before
+		 */
+		return "forward-seek";
+	default:
+		return "error";
+	}
+}
+
+static struct mcp_data *mcp_data_new(struct btd_device *device)
+{
+	struct mcp_data *data;
+
+	data = new0(struct mcp_data, 1);
+	data->device = device;
+
+	return data;
+}
+
+static void cb_player_name(struct bt_mcp *mcp,  const uint8_t *value,
+					uint16_t length)
+{
+	char *name;
+	struct media_player *mp = bt_mcp_get_user_data(mcp);
+
+	name = name2utf8(value, length);
+	DBG("Media Player Name %s", (const char *)name);
+
+	media_player_set_name(mp, name);
+
+	g_free(name);
+}
+
+void cb_track_changed(struct bt_mcp *mcp)
+{
+	DBG("Track Changed");
+	/* Since track changed has happened
+	 * track title notification is expected
+	 */
+}
+
+void cb_track_title(struct bt_mcp *mcp, const uint8_t *value,
+					uint16_t length)
+{
+	char *name;
+	uint16_t len;
+	struct media_player *mp = bt_mcp_get_user_data(mcp);
+
+	name = name2utf8(value, length);
+	len = strlen(name);
+
+	DBG("Track Title %s", (const char *)name);
+
+	media_player_set_metadata(mp, NULL, "Title", name, len);
+	media_player_metadata_changed(mp);
+
+	g_free(name);
+}
+
+void cb_track_duration(struct bt_mcp *mcp, int32_t duration)
+{
+	struct media_player *mp = bt_mcp_get_user_data(mcp);
+	unsigned char buf[10];
+
+	/* MCP defines duration is int32 but api takes it as uint32 */
+	sprintf(buf, "%d", duration);
+	media_player_set_metadata(mp, NULL, "Duration", buf, sizeof(buf));
+	media_player_metadata_changed(mp);
+}
+
+void cb_track_position(struct bt_mcp *mcp, int32_t duration)
+{
+	struct media_player *mp = bt_mcp_get_user_data(mcp);
+
+	/* MCP defines duration is int32 but api takes it as uint32 */
+	media_player_set_position(mp, duration);
+}
+
+void cb_media_state(struct bt_mcp *mcp, uint8_t status)
+{
+	struct media_player *mp = bt_mcp_get_user_data(mcp);
+
+	media_player_set_status(mp, mcp_status_val_to_string(status));
+}
+
+static const struct bt_mcp_event_callback cbs = {
+	.player_name			= &cb_player_name,
+	.track_changed			= &cb_track_changed,
+	.track_title			= &cb_track_title,
+	.track_duration			= &cb_track_duration,
+	.track_position			= &cb_track_position,
+	.playback_speed			= NULL,
+	.seeking_speed			= NULL,
+	.play_order				= NULL,
+	.play_order_supported	= NULL,
+	.media_state			= &cb_media_state,
+	.content_control_id		= NULL,
+};
+
+static int ct_play(struct media_player *mp, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	return bt_mcp_play(mcp);
+}
+
+static int ct_pause(struct media_player *mp, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	return bt_mcp_pause(mcp);
+}
+
+static int ct_stop(struct media_player *mp, void *user_data)
+{
+	struct bt_mcp *mcp = user_data;
+
+	return bt_mcp_stop(mcp);
+}
+
+static const struct media_player_callback ct_cbs = {
+	.set_setting	= NULL,
+	.play		= &ct_play,
+	.pause		= &ct_pause,
+	.stop		= &ct_stop,
+	.next		= NULL,
+	.previous	= NULL,
+	.fast_forward	= NULL,
+	.rewind		= NULL,
+	.press		= NULL,
+	.hold		= NULL,
+	.release	= NULL,
+	.list_items	= NULL,
+	.change_folder	= NULL,
+	.search		= NULL,
+	.play_item	= NULL,
+	.add_to_nowplaying = NULL,
+	.total_items = NULL,
+};
+
+static int mcp_probe(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct btd_adapter *adapter = device_get_adapter(device);
+	struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+	struct mcp_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	/* Ignore, if we were probed for this device already */
+	if (data) {
+		error("Profile probed twice for the same device!");
+		return -EINVAL;
+	}
+
+	data = mcp_data_new(device);
+	data->service = service;
+
+	data->mcp = bt_mcp_new(btd_gatt_database_get_db(database),
+					btd_device_get_gatt_db(device));
+
+    bt_mcp_set_debug(data->mcp, mcp_debug, NULL, NULL);
+	btd_service_set_user_data(service, data);
+
+	return 0;
+}
+
+static void mcp_data_free(struct mcp_data *data)
+{
+	DBG("");
+
+	if (data->service) {
+		btd_service_set_user_data(data->service, NULL);
+		bt_mcp_set_user_data(data->mcp, NULL);
+	}
+
+    if (data->mp) {
+        media_player_destroy(data->mp);
+        data->mp = NULL;
+    }
+
+	bt_mcp_unref(data->mcp);
+	free(data);
+}
+
+static void mcp_data_remove(struct mcp_data *data)
+{
+	DBG("data %p", data);
+
+	mcp_data_free(data);
+}
+
+static void mcp_remove(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct mcp_data *data;
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	data = btd_service_get_user_data(service);
+	if (!data) {
+		error("MCP service not handled by profile");
+		return;
+	}
+
+	mcp_data_remove(data);
+}
+
+static int mcp_accept(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct bt_gatt_client *client = btd_device_get_gatt_client(device);
+	struct mcp_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	bt_mcp_attach(data->mcp, client);
+
+	data->mp = media_player_controller_create(device_get_path(device), 0);
+	if (data->mp == NULL) {
+		DBG("Unable to create Media Player");
+		return -EINVAL;
+	}
+
+	media_player_set_callbacks(data->mp, &ct_cbs, data->mcp);
+
+	bt_mcp_set_user_data(data->mcp, data->mp);
+	bt_mcp_set_event_callbacks(data->mcp, &cbs, data->mp);
+	btd_service_connecting_complete(service, 0);
+
+	return 0;
+}
+
+static int mcp_connect(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	return 0;
+}
+
+static int mcp_disconnect(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct mcp_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+    if (data->mp) {
+        media_player_destroy(data->mp);
+        data->mp = NULL;
+    }
+
+	bt_mcp_detach(data->mcp);
+
+	btd_service_disconnecting_complete(service, 0);
+
+	return 0;
+}
+
+static int media_control_server_probe(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+	bt_mcp_register(btd_gatt_database_get_db(database));
+	return 0;
+}
+
+static void media_control_server_remove(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+
+}
+
+static struct btd_profile mcp_profile = {
+	.name			= "mcp",
+	.priority		= BTD_PROFILE_PRIORITY_MEDIUM,
+	.remote_uuid	= GMCS_UUID_STR,
+	.device_probe	= mcp_probe,
+	.device_remove	= mcp_remove,
+	.accept			= mcp_accept,
+	.connect		= mcp_connect,
+	.disconnect		= mcp_disconnect,
+
+	.adapter_probe	= media_control_server_probe,
+	.adapter_remove = media_control_server_remove,
+};
+
+static int mcp_init(void)
+{
+	DBG("");
+
+	if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) {
+        warn("D-Bus experimental not enabled");
+        return -ENOTSUP;
+	}
+
+    btd_profile_register(&mcp_profile);
+	return 0;
+}
+
+static void mcp_exit(void)
+{
+	DBG("");
+
+	if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
+		btd_profile_unregister(&mcp_profile);
+	}
+}
+
+BLUETOOTH_PLUGIN_DEFINE(mcp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+							mcp_init, mcp_exit)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 4/4] monitor/att: Add decoding support for GMCS
  2022-10-06 14:33 [PATCH BlueZ 0/4] Media Control Profile Client Abhay Maheta
                   ` (2 preceding siblings ...)
  2022-10-06 14:33 ` [PATCH BlueZ 3/4] profiles: Add initial code for mcp plugin Abhay Maheta
@ 2022-10-06 14:33 ` Abhay Maheta
  2022-10-06 20:40 ` [PATCH BlueZ 0/4] Media Control Profile Client Luiz Augusto von Dentz
  4 siblings, 0 replies; 7+ messages in thread
From: Abhay Maheta @ 2022-10-06 14:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Abhay Maheta

This adds decoding support for GMCS attributes.

< ACL Data TX: Handle 3585 flags 0x00 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x0056 Type: Media Control Point Opcodes Supported (0x2ba5)
> ACL Data RX: Handle 3585 flags 0x02 dlen 9
      ATT: Read Response (0x0b) len 4
        Value: 33180000
        Handle: 0x0056 Type: Media Control Point Opcodes Supported (0x2ba5)
              Supported Opcodes: 0x00001833
                Play (0x00000001)
                Pause (0x00000002)
                Stop (0x00000010)
                Move Relative (0x00000020)
                Previous Track (0x00000800)
                Next Track (0x00001000)
---
 monitor/att.c | 511 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 511 insertions(+)

diff --git a/monitor/att.c b/monitor/att.c
index f5fc32cb0..1bb9f58f6 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -14,6 +14,7 @@
 #endif
 
 #define _GNU_SOURCE
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -22,6 +23,8 @@
 #include <errno.h>
 #include <linux/limits.h>
 
+#include <glib.h>
+
 #include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "lib/hci.h"
@@ -1746,6 +1749,497 @@ static void vol_flag_notify(const struct l2cap_frame *frame)
 	print_vcs_flag(frame);
 }
 
+static char *name2utf8(const uint8_t *name, uint16_t len)
+{
+    char utf8_name[HCI_MAX_NAME_LENGTH + 2];
+    int i;
+
+    if (g_utf8_validate((const char *) name, len, NULL))
+        return g_strndup((char *) name, len);
+
+    len = MIN(len, sizeof(utf8_name) - 1);
+
+    memset(utf8_name, 0, sizeof(utf8_name));
+    strncpy(utf8_name, (char *) name, len);
+
+    /* Assume ASCII, and replace all non-ASCII with spaces */
+    for (i = 0; utf8_name[i] != '\0'; i++) {
+        if (!isascii(utf8_name[i]))
+            utf8_name[i] = ' ';
+    }
+
+    /* Remove leading and trailing whitespace characters */
+    g_strstrip(utf8_name);
+
+    return g_strdup(utf8_name);
+}
+
+static void print_mp_name(const struct l2cap_frame *frame)
+{
+	char *name;
+
+	name = name2utf8((uint8_t *)frame->data, frame->size);
+
+	print_field("  Media Player Name: %s", name);
+}
+
+static void mp_name_read(const struct l2cap_frame *frame)
+{
+	print_mp_name(frame);
+}
+
+static void mp_name_notify(const struct l2cap_frame *frame)
+{
+	print_mp_name(frame);
+}
+
+static void print_track_changed(const struct l2cap_frame *frame)
+{
+	print_field("  Track Changed");
+}
+
+static void track_changed_notify(const struct l2cap_frame *frame)
+{
+	print_track_changed(frame);
+}
+
+static void print_track_title(const struct l2cap_frame *frame)
+{
+	char *name;
+
+	name = name2utf8((uint8_t *)frame->data, frame->size);
+
+	print_field("  Track Title: %s", name);
+}
+
+static void track_title_read(const struct l2cap_frame *frame)
+{
+	print_track_title(frame);
+}
+
+static void track_title_notify(const struct l2cap_frame *frame)
+{
+	print_track_title(frame);
+}
+
+static void print_track_duration(const struct l2cap_frame *frame)
+{
+	int32_t duration;
+
+	if (!l2cap_frame_get_le32((void *)frame, (uint32_t *)&duration)) {
+		print_text(COLOR_ERROR, "  Track Duration: invalid size");
+		goto done;
+	}
+
+	print_field("  Track Duration: %u", duration);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void track_duration_read(const struct l2cap_frame *frame)
+{
+	print_track_duration(frame);
+}
+
+static void track_duration_notify(const struct l2cap_frame *frame)
+{
+	print_track_duration(frame);
+}
+
+static void print_track_position(const struct l2cap_frame *frame)
+{
+	int32_t position;
+
+	if (!l2cap_frame_get_le32((void *)frame, (uint32_t *)&position)) {
+		print_text(COLOR_ERROR, "  Track Position: invalid size");
+		goto done;
+	}
+
+	print_field("  Track Position: %u", position);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void track_position_read(const struct l2cap_frame *frame)
+{
+	print_track_position(frame);
+}
+
+static void track_position_write(const struct l2cap_frame *frame)
+{
+	print_track_position(frame);
+}
+
+static void track_position_notify(const struct l2cap_frame *frame)
+{
+	print_track_position(frame);
+}
+
+static void print_playback_speed(const struct l2cap_frame *frame)
+{
+	int8_t playback_speed;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&playback_speed)) {
+		print_text(COLOR_ERROR, "  Playback Speed: invalid size");
+		goto done;
+	}
+
+	print_field("  Playback Speed: %u", playback_speed);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void playback_speed_read(const struct l2cap_frame *frame)
+{
+	print_playback_speed(frame);
+}
+
+static void playback_speed_write(const struct l2cap_frame *frame)
+{
+	print_playback_speed(frame);
+}
+
+static void playback_speed_notify(const struct l2cap_frame *frame)
+{
+	print_playback_speed(frame);
+}
+
+static void print_seeking_speed(const struct l2cap_frame *frame)
+{
+	int8_t seeking_speed;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&seeking_speed)) {
+		print_text(COLOR_ERROR, "  Seeking Speed: invalid size");
+		goto done;
+	}
+
+	print_field("  Seeking Speed: %u", seeking_speed);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void seeking_speed_read(const struct l2cap_frame *frame)
+{
+	print_seeking_speed(frame);
+}
+
+static void seeking_speed_notify(const struct l2cap_frame *frame)
+{
+	print_seeking_speed(frame);
+}
+
+const char *play_order_str(uint8_t order)
+{
+	switch (order) {
+	case 0x01:
+		return "Single once";
+	case 0x02:
+		return "Single repeat";
+	case 0x03:
+		return "In order once";
+	case 0x04:
+		return "In order repeat";
+	case 0x05:
+		return "Oldest once";
+	case 0x06:
+		return "Oldest repeat";
+	case 0x07:
+		return "Newest once";
+	case 0x08:
+		return "Newest repeat";
+	case 0x09:
+		return "Shuffle once";
+	case 0x0A:
+		return "Shuffle repeat";
+	default:
+		return "RFU";
+	}
+}
+
+static void print_playing_order(const struct l2cap_frame *frame)
+{
+	int8_t playing_order;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&playing_order)) {
+		print_text(COLOR_ERROR, "  Playing Order: invalid size");
+		goto done;
+	}
+
+	print_field("  Playing Order: %s", play_order_str(playing_order));
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void playing_order_read(const struct l2cap_frame *frame)
+{
+	print_playing_order(frame);
+}
+
+static void playing_order_write(const struct l2cap_frame *frame)
+{
+	print_playing_order(frame);
+}
+
+static void playing_order_notify(const struct l2cap_frame *frame)
+{
+	print_playing_order(frame);
+}
+
+static const struct bitfield_data playing_orders_table[] = {
+	{  0, "Single once (0x0001)"	    },
+	{  1, "Single repeat (0x0002)"		},
+	{  2, "In order once (0x0004)"		},
+	{  3, "In Order Repeat (0x0008)"	},
+	{  4, "Oldest once (0x0010)"		},
+	{  5, "Oldest repeat (0x0020)"		},
+	{  6, "Newest once (0x0040)"		},
+	{  7, "Newest repeat (0x0080)"	    },
+	{  8, "Shuffle once (0x0100)"		},
+	{  9, "Shuffle repeat (0x0200)"		},
+	{  10, "RFU (0x0400)"			    },
+	{  11, "RFU (0x0800)"		        },
+	{  12, "RFU (0x1000)"				},
+	{  13, "RFU (0x2000)"				},
+	{  14, "RFU (0x4000)"				},
+	{  15, "RFU (0x8000)"				},
+	{ }
+};
+
+static void print_playing_orders_supported(const struct l2cap_frame *frame)
+{
+	uint16_t supported_orders;
+	uint16_t mask;
+
+	if (!l2cap_frame_get_le16((void *)frame, &supported_orders)) {
+		print_text(COLOR_ERROR, "    Supported Playing Orders: invalid size");
+		goto done;
+	}
+
+	print_field("      Supported Playing Orders: 0x%4.4x", supported_orders);
+
+	mask = print_bitfield(8, supported_orders, playing_orders_table);
+	if (mask)
+		print_text(COLOR_WHITE_BG, "    Unknown fields (0x%4.4x)",
+								mask);
+
+done:
+	if (frame->size)
+		print_hex_field("    Data", frame->data, frame->size);
+}
+
+static void playing_orders_supported_read(const struct l2cap_frame *frame)
+{
+	print_playing_orders_supported(frame);
+}
+
+const char *media_state_str(uint8_t state)
+{
+	switch (state) {
+	case 0x00:
+		return "Inactive";
+	case 0x01:
+		return "Playing";
+	case 0x02:
+		return "Paused";
+	case 0x03:
+		return "Seeking";
+	default:
+		return "RFU";
+	}
+}
+
+static void print_media_state(const struct l2cap_frame *frame)
+{
+	int8_t state;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&state)) {
+		print_text(COLOR_ERROR, "  Media State: invalid size");
+		goto done;
+	}
+
+	print_field("  Media State: %s", media_state_str(state));
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void media_state_read(const struct l2cap_frame *frame)
+{
+	print_media_state(frame);
+}
+
+static void media_state_notify(const struct l2cap_frame *frame)
+{
+	print_media_state(frame);
+}
+
+struct media_cp_opcode {
+	uint8_t opcode;
+	const char *opcode_str;
+} media_cp_opcode_table[] = {
+	{0x01, "Play"},
+	{0x02 ,	"Pause"},
+	{0x03 ,	"Fast Rewind"},
+	{0x04 ,	"Fast Forward"},
+	{0x05 ,	"Stop"},
+	{0x10 ,	"Move Relative"},
+	{0x20 ,	"Previous Segment"},
+	{0x21 ,	"Next Segment"},
+	{0x22 ,	"First Segment"},
+	{0x23 ,	"Last Segment"},
+	{0x24 ,	"Goto Segment"},
+	{0x30 ,	"Previous Track"},
+	{0x31 ,	"Next Track"},
+	{0x32 ,	"First Track"},
+	{0x33 ,	"Last Track"},
+	{0x34 ,	"Goto Track"},
+	{0x40 ,	"Previous Group"},
+	{0x41 ,	"Next Group"},
+	{0x42 ,	"First Group"},
+	{0x43 ,	"Last Group"},
+	{0x44 ,	"Goto Group"},
+};
+
+const char *cp_opcode_str(uint8_t opcode)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(media_cp_opcode_table); i++) {
+		const char *str = media_cp_opcode_table[i].opcode_str;
+
+		if (opcode == media_cp_opcode_table[i].opcode)
+			return str;
+	}
+
+	return "RFU";
+}
+
+static void print_media_cp(const struct l2cap_frame *frame)
+{
+	int8_t opcode;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&opcode)) {
+		print_text(COLOR_ERROR, "  Media Control Point: invalid size");
+		goto done;
+	}
+
+	print_field("  Media Control Point: %s", cp_opcode_str(opcode));
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void media_cp_write(const struct l2cap_frame *frame)
+{
+	print_media_cp(frame);
+}
+
+static void media_cp_notify(const struct l2cap_frame *frame)
+{
+	print_media_cp(frame);
+}
+
+static const struct bitfield_data supported_opcodes_table[] = {
+    {0	, "Play (0x00000001)"				},
+    {1	, "Pause (0x00000002)"				},
+    {2	, "Fast Rewind	(0x00000004)"		},
+    {3	, "Fast Forward (0x00000008)"		},
+    {4	, "Stop (0x00000010)"				},
+    {5	, "Move Relative (0x00000020)"		},
+    {6	, "Previous Segment (0x00000040)"	},
+    {7	, "Next Segment (0x00000080)"		},
+    {8	, "First Segment (0x00000100)"		},
+    {9	, "Last Segment (0x00000200)"		},
+    {10	, "Goto Segment (0x00000400)"		},
+    {11	, "Previous Track (0x00000800)"     },
+    {12	, "Next Track (0x00001000)"		    },
+    {13	, "First Track (0x00002000)"		},
+    {14	, "Last Track (0x00004000)"		    },
+    {15	, "Goto Track (0x00008000)"		    },
+    {16	, "Previous Group (0x00010000)"	    },
+    {17	, "Next Group (0x00020000)"		    },
+    {18	, "First Group (0x00040000)"		},
+    {19	, "Last Group (0x00080000)"		    },
+    {20 , "Goto Group (0x00100000)"		    },
+    {21	, "RFU (0x00200000)"				},
+    {22	, "RFU (0x00400000)"				},
+    {23	, "RFU (0x00800000)"				},
+    {24	, "RFU (0x01000000)"				},
+    {25	, "RFU (0x02000000)"				},
+    {26	, "RFU (0x04000000)"				},
+    {27	, "RFU (0x08000000)"				},
+    {28	, "RFU (0x10000000)"				},
+    {29	, "RFU (0x20000000)"				},
+    {30	, "RFU (0x40000000)"				},
+    {31	, "RFU (0x80000000)"				},
+    { }
+};
+
+static void print_media_cp_op_supported(const struct l2cap_frame *frame)
+{
+	uint32_t supported_opcodes;
+	uint32_t mask;
+
+	if (!l2cap_frame_get_le32((void *)frame, &supported_opcodes)) {
+		print_text(COLOR_ERROR, "    value: invalid size");
+		goto done;
+	}
+
+	print_field("      Supported Opcodes: 0x%8.8x", supported_opcodes);
+
+	mask = print_bitfield(8, supported_opcodes, supported_opcodes_table);
+	if (mask)
+		print_text(COLOR_WHITE_BG, "    Unknown fields (0x%4.4x)",
+								mask);
+
+done:
+	if (frame->size)
+		print_hex_field("    Data", frame->data, frame->size);
+}
+
+static void media_cp_op_supported_read(const struct l2cap_frame *frame)
+{
+	print_media_cp_op_supported(frame);
+}
+
+static void media_cp_op_supported_notify(const struct l2cap_frame *frame)
+{
+	print_media_cp_op_supported(frame);
+}
+
+static void print_content_control_id(const struct l2cap_frame *frame)
+{
+	int8_t ccid;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&ccid)) {
+		print_text(COLOR_ERROR, "  Content Control ID: invalid size");
+		goto done;
+	}
+
+	print_field("  Content Control ID: 0x%2.2x", ccid);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void content_control_id_read(const struct l2cap_frame *frame)
+{
+	print_content_control_id(frame);
+}
+
 #define GATT_HANDLER(_uuid, _read, _write, _notify) \
 { \
 	.uuid = { \
@@ -1776,6 +2270,23 @@ struct gatt_handler {
 	GATT_HANDLER(0x2b7d, vol_state_read, NULL, vol_state_notify),
 	GATT_HANDLER(0x2b7e, NULL, vol_cp_write, NULL),
 	GATT_HANDLER(0x2b7f, vol_flag_read, NULL, vol_flag_notify),
+	GATT_HANDLER(0x2b93, mp_name_read, NULL, mp_name_notify),
+	GATT_HANDLER(0x2b96, NULL, NULL, track_changed_notify),
+	GATT_HANDLER(0x2b97, track_title_read, NULL, track_title_notify),
+	GATT_HANDLER(0x2b98, track_duration_read, NULL, track_duration_notify),
+	GATT_HANDLER(0x2b99, track_position_read, track_position_write,
+					track_position_notify),
+	GATT_HANDLER(0x2b9a, playback_speed_read, playback_speed_write,
+					playback_speed_notify),
+	GATT_HANDLER(0x2b9b, seeking_speed_read, NULL, seeking_speed_notify),
+	GATT_HANDLER(0x2ba1, playing_order_read, playing_order_write,
+					playing_order_notify),
+	GATT_HANDLER(0x2ba2, playing_orders_supported_read, NULL, NULL),
+	GATT_HANDLER(0x2ba3, media_state_read, NULL, media_state_notify),
+	GATT_HANDLER(0x2ba4, NULL, media_cp_write, media_cp_notify),
+	GATT_HANDLER(0x2ba5, media_cp_op_supported_read, NULL,
+					media_cp_op_supported_notify),
+	GATT_HANDLER(0x2bba, content_control_id_read, NULL, NULL),
 };
 
 static struct gatt_handler *get_handler(struct gatt_db_attribute *attr)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* RE: Media Control Profile Client
  2022-10-06 14:33 ` [PATCH BlueZ 1/4] lib/uuid: Add GMCS UUIDs Abhay Maheta
@ 2022-10-06 14:58   ` bluez.test.bot
  0 siblings, 0 replies; 7+ messages in thread
From: bluez.test.bot @ 2022-10-06 14:58 UTC (permalink / raw)
  To: linux-bluetooth, abhay.maheshbhai.maheta

[-- Attachment #1: Type: text/plain, Size: 53979 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=683505

---Test result---

Test Summary:
CheckPatch                    FAIL      5.09 seconds
GitLint                       PASS      1.96 seconds
Prep - Setup ELL              PASS      31.81 seconds
Build - Prep                  PASS      0.67 seconds
Build - Configure             PASS      10.15 seconds
Build - Make                  FAIL      12.78 seconds
Make Check                    FAIL      33.53 seconds
Make Check w/Valgrind         FAIL      19.54 seconds
Make Distcheck                FAIL      13.15 seconds
Build w/ext ELL - Configure   PASS      10.24 seconds
Build w/ext ELL - Make        FAIL      4.95 seconds
Incremental Build w/ patches  FAIL      136.59 seconds
Scan Build                    FAIL      636.05 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script with rule in .checkpatch.conf
Output:
[BlueZ,2/4] shared/mcp: Add initial code for handling MCP
ERROR:FSF_MAILING_ADDRESS: Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.
#113: FILE: src/shared/mcp.c:19:
+ *  License along with this library; if not, write to the Free Software$

ERROR:FSF_MAILING_ADDRESS: Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.
#114: FILE: src/shared/mcp.c:20:
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#179: FILE: src/shared/mcp.c:85:
+    struct bt_mcp_session_info session;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#184: FILE: src/shared/mcp.c:90:
+    bt_mcp_debug_func_t debug_func;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#185: FILE: src/shared/mcp.c:91:
+    bt_mcp_destroy_func_t debug_destroy;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#186: FILE: src/shared/mcp.c:92:
+    void *debug_data;$

ERROR:CODE_INDENT: code indent should use tabs where possible
#545: FILE: src/shared/mcp.c:451:
+                    &uuid,$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#545: FILE: src/shared/mcp.c:451:
+                    &uuid,$

WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#555: FILE: src/shared/mcp.c:461:
+	mcs->track_title = gatt_db_service_add_characteristic(mcs->service, &uuid,

WARNING:LONG_LINE: line length of 90 exceeds 80 columns
#573: FILE: src/shared/mcp.c:479:
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE |

WARNING:LONG_LINE: line length of 90 exceeds 80 columns
#575: FILE: src/shared/mcp.c:481:
+					mcs_track_position_read, mcs_track_position_write,

WARNING:LONG_LINE: line length of 90 exceeds 80 columns
#582: FILE: src/shared/mcp.c:488:
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE |

WARNING:LONG_LINE: line length of 90 exceeds 80 columns
#584: FILE: src/shared/mcp.c:490:
+					mcs_playback_speed_read, mcs_playback_speed_write,

ERROR:CODE_INDENT: code indent should use tabs where possible
#589: FILE: src/shared/mcp.c:495:
+                    &uuid,$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#589: FILE: src/shared/mcp.c:495:
+                    &uuid,$

ERROR:CODE_INDENT: code indent should use tabs where possible
#590: FILE: src/shared/mcp.c:496:
+                    BT_ATT_PERM_READ,$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#590: FILE: src/shared/mcp.c:496:
+                    BT_ATT_PERM_READ,$

WARNING:LONG_LINE: line length of 81 exceeds 80 columns
#596: FILE: src/shared/mcp.c:502:
+	mcs->play_order = gatt_db_service_add_characteristic(mcs->service, &uuid,

WARNING:LONG_LINE: line length of 90 exceeds 80 columns
#598: FILE: src/shared/mcp.c:504:
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE |

WARNING:LONG_LINE: line length of 88 exceeds 80 columns
#600: FILE: src/shared/mcp.c:506:
+					mcs_playing_order_read, mcs_playing_order_write,

WARNING:LONG_LINE: line length of 84 exceeds 80 columns
#604: FILE: src/shared/mcp.c:510:
+	mcs->play_order_supported = gatt_db_service_add_characteristic(mcs->service,

WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#612: FILE: src/shared/mcp.c:518:
+	mcs->media_state = gatt_db_service_add_characteristic(mcs->service, &uuid,

WARNING:LONG_LINE: line length of 90 exceeds 80 columns
#614: FILE: src/shared/mcp.c:520:
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_NOTIFY,

WARNING:LONG_LINE: line length of 92 exceeds 80 columns
#624: FILE: src/shared/mcp.c:530:
+					BT_GATT_CHRC_PROP_WRITE | BT_GATT_CHRC_PROP_NOTIFY |

WARNING:LONG_LINE: line length of 84 exceeds 80 columns
#633: FILE: src/shared/mcp.c:539:
+	mcs->media_cp_op_supportd = gatt_db_service_add_characteristic(mcs->service,

WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#641: FILE: src/shared/mcp.c:547:
+	mcs->content_control_id = gatt_db_service_add_characteristic(mcs->service,

WARNING:LONG_LINE: line length of 90 exceeds 80 columns
#644: FILE: src/shared/mcp.c:550:
+					BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_NOTIFY,

WARNING:LONG_LINE: line length of 86 exceeds 80 columns
#778: FILE: src/shared/mcp.c:684:
+		DBG(mcp, "Unable to read media player name: error 0x%02x", att_ecode);

WARNING:LONG_LINE: line length of 83 exceeds 80 columns
#814: FILE: src/shared/mcp.c:720:
+		DBG(mcp, "Unable to read track duration: error 0x%02x", att_ecode);

WARNING:BRACES: braces {} are not necessary for single statement blocks
#818: FILE: src/shared/mcp.c:724:
+	if (length != sizeof(duration)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}

WARNING:LONG_LINE: line length of 83 exceeds 80 columns
#834: FILE: src/shared/mcp.c:740:
+		DBG(mcp, "Unable to read track position: error 0x%02x", att_ecode);

WARNING:BRACES: braces {} are not necessary for single statement blocks
#838: FILE: src/shared/mcp.c:744:
+	if (length != sizeof(position)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}

WARNING:BRACES: braces {} are not necessary for single statement blocks
#857: FILE: src/shared/mcp.c:763:
+	if (length != sizeof(uint8_t)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}

WARNING:LONG_LINE_STRING: line length of 83 exceeds 80 columns
#871: FILE: src/shared/mcp.c:777:
+		DBG(mcp, "Unable to read media CP opcodes supported: error 0x%02x",

WARNING:BRACES: braces {} are not necessary for single statement blocks
#876: FILE: src/shared/mcp.c:782:
+	if (length != sizeof(uint32_t)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}

WARNING:LONG_LINE: line length of 87 exceeds 80 columns
#892: FILE: src/shared/mcp.c:798:
+		DBG(mcp, "Unable to read content control id: error 0x%02x", att_ecode);

WARNING:BRACES: braces {} are not necessary for single statement blocks
#896: FILE: src/shared/mcp.c:802:
+	if (length != sizeof(uint8_t)) {
+		DBG(mcp, "Wrong length received Length : %u", length);
+	}

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#947: FILE: src/shared/mcp.c:853:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE: line length of 85 exceeds 80 columns
#950: FILE: src/shared/mcp.c:856:
+		DBG(mcp, "Media Player Name notification failed: 0x%04x", att_ecode);

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#966: FILE: src/shared/mcp.c:872:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE: line length of 87 exceeds 80 columns
#969: FILE: src/shared/mcp.c:875:
+		DBG(mcp, "Media Track Changed notification failed: 0x%04x", att_ecode);

ERROR:CODE_INDENT: code indent should use tabs where possible
#973: FILE: src/shared/mcp.c:879:
+                    const uint8_t *value, uint16_t length, void *user_data)$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#973: FILE: src/shared/mcp.c:879:
+                    const uint8_t *value, uint16_t length, void *user_data)$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#986: FILE: src/shared/mcp.c:892:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE: line length of 85 exceeds 80 columns
#989: FILE: src/shared/mcp.c:895:
+		DBG(mcp, "Media Track Title notification failed: 0x%04x", att_ecode);

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1002: FILE: src/shared/mcp.c:908:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE: line length of 88 exceeds 80 columns
#1005: FILE: src/shared/mcp.c:911:
+		DBG(mcp, "Media Track Duration notification failed: 0x%04x", att_ecode);

ERROR:CODE_INDENT: code indent should use tabs where possible
#1009: FILE: src/shared/mcp.c:915:
+        const uint8_t *value, uint16_t length, void *user_data)$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1009: FILE: src/shared/mcp.c:915:
+        const uint8_t *value, uint16_t length, void *user_data)$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1020: FILE: src/shared/mcp.c:926:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE: line length of 88 exceeds 80 columns
#1023: FILE: src/shared/mcp.c:929:
+		DBG(mcp, "Media Track Position notification failed: 0x%04x", att_ecode);

ERROR:CODE_INDENT: code indent should use tabs where possible
#1027: FILE: src/shared/mcp.c:933:
+        const uint8_t *value, uint16_t length, void *user_data)$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1027: FILE: src/shared/mcp.c:933:
+        const uint8_t *value, uint16_t length, void *user_data)$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1038: FILE: src/shared/mcp.c:944:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE: line length of 85 exceeds 80 columns
#1041: FILE: src/shared/mcp.c:947:
+		DBG(mcp, "Media Media State notification failed: 0x%04x", att_ecode);

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1054: FILE: src/shared/mcp.c:960:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#1057: FILE: src/shared/mcp.c:963:
+		DBG(mcp, "Media Media CP notification failed: 0x%04x", att_ecode);

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1063: FILE: src/shared/mcp.c:969:
+    struct bt_mcp *mcp = user_data;$

ERROR:CODE_INDENT: code indent should use tabs where possible
#1069: FILE: src/shared/mcp.c:975:
+                    void *user_data)$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1069: FILE: src/shared/mcp.c:975:
+                    void *user_data)$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1071: FILE: src/shared/mcp.c:977:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE_STRING: line length of 83 exceeds 80 columns
#1074: FILE: src/shared/mcp.c:980:
+		DBG(mcp, "Media Media CP OP Supported notification failed: 0x%04x",

WARNING:LONG_LINE: line length of 95 exceeds 80 columns
#1079: FILE: src/shared/mcp.c:985:
+					const uint8_t *value, uint16_t length, void *user_data)

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1081: FILE: src/shared/mcp.c:987:
+    struct bt_mcp *mcp = user_data;$

WARNING:LONG_LINE: line length of 95 exceeds 80 columns
#1102: FILE: src/shared/mcp.c:1008:
+					value_handle, mcp_mp_name_register, mcp_mp_name_notify,

WARNING:LONG_LINE: line length of 89 exceeds 80 columns
#1118: FILE: src/shared/mcp.c:1024:
+						value_handle, mcp_track_changed_register,

WARNING:LONG_LINE: line length of 85 exceeds 80 columns
#1119: FILE: src/shared/mcp.c:1025:
+						mcp_track_changed_notify, mcp, NULL);

WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#1154: FILE: src/shared/mcp.c:1060:
+					value_handle, mcp_track_duration_register,

WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#1172: FILE: src/shared/mcp.c:1078:
+					value_handle, mcp_track_position_register,

WARNING:LONG_LINE: line length of 84 exceeds 80 columns
#1206: FILE: src/shared/mcp.c:1112:
+						value_handle, mcp_media_cp_register,

ERROR:CODE_INDENT: code indent should use tabs where possible
#1220: FILE: src/shared/mcp.c:1126:
+                value_handle);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#1220: FILE: src/shared/mcp.c:1126:
+                value_handle);$

WARNING:LONG_LINE: line length of 94 exceeds 80 columns
#1225: FILE: src/shared/mcp.c:1131:
+				mcp->client, value_handle, mcp_media_cp_op_supported_register,

WARNING:LONG_LINE: line length of 83 exceeds 80 columns
#1238: FILE: src/shared/mcp.c:1144:
+	DBG(mcp, "Media Content Control id Supported handle 0x%04x", value_handle);

WARNING:LONG_LINE: line length of 91 exceeds 80 columns
#1247: FILE: src/shared/mcp.c:1153:
+				uuid_track_duration, uuid_track_position, uuid_media_state,

WARNING:LONG_LINE: line length of 81 exceeds 80 columns
#1264: FILE: src/shared/mcp.c:1170:
+						MEDIA_CP_OP_SUPPORTED_CHRC_UUID);

WARNING:LONG_LINE: line length of 84 exceeds 80 columns
#1266: FILE: src/shared/mcp.c:1172:
+						MEDIA_CONTENT_CONTROL_ID_CHRC_UUID);

WARNING:LONG_LINE: line length of 81 exceeds 80 columns
#1269: FILE: src/shared/mcp.c:1175:
+		DBG(mcp, "Media Player Name found: handle 0x%04x", value_handle);

WARNING:LONG_LINE: line length of 83 exceeds 80 columns
#1336: FILE: src/shared/mcp.c:1242:
+		DBG(mcp, "Media Control Point found: handle 0x%04x", value_handle);

WARNING:LONG_LINE_STRING: line length of 87 exceeds 80 columns
#1347: FILE: src/shared/mcp.c:1253:
+		DBG(mcp, "Media Control Point Opecodes Supported found: handle 0x%04x",

WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#1359: FILE: src/shared/mcp.c:1265:
+		DBG(mcp, "Content Control ID found: handle 0x%04x", value_handle);

WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
#1522: FILE: src/shared/mcp.h:14:
+#define __packed __attribute__((packed))

WARNING:LONG_LINE: line length of 83 exceeds 80 columns
#1543: FILE: src/shared/mcp.h:35:
+	void (*play_order_supported)(struct bt_mcp *mcp, uint16_t order_supported);

/github/workspace/src/13000447.patch total: 10 errors, 73 warnings, 1540 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

NOTE: Whitespace errors detected.
      You may wish to use scripts/cleanpatch or scripts/cleanfile

/github/workspace/src/13000447.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.

[BlueZ,3/4] profiles: Add initial code for mcp plugin
WARNING:LEADING_SPACE: please, no spaces at the start of a line
#381: FILE: profiles/audio/mcp.c:270:
+    bt_mcp_set_debug(data->mcp, mcp_debug, NULL, NULL);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#396: FILE: profiles/audio/mcp.c:285:
+    if (data->mp) {$

ERROR:CODE_INDENT: code indent should use tabs where possible
#397: FILE: profiles/audio/mcp.c:286:
+        media_player_destroy(data->mp);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#397: FILE: profiles/audio/mcp.c:286:
+        media_player_destroy(data->mp);$

ERROR:CODE_INDENT: code indent should use tabs where possible
#398: FILE: profiles/audio/mcp.c:287:
+        data->mp = NULL;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#398: FILE: profiles/audio/mcp.c:287:
+        data->mp = NULL;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#399: FILE: profiles/audio/mcp.c:288:
+    }$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#477: FILE: profiles/audio/mcp.c:366:
+    if (data->mp) {$

ERROR:CODE_INDENT: code indent should use tabs where possible
#478: FILE: profiles/audio/mcp.c:367:
+        media_player_destroy(data->mp);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#478: FILE: profiles/audio/mcp.c:367:
+        media_player_destroy(data->mp);$

ERROR:CODE_INDENT: code indent should use tabs where possible
#479: FILE: profiles/audio/mcp.c:368:
+        data->mp = NULL;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#479: FILE: profiles/audio/mcp.c:368:
+        data->mp = NULL;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#480: FILE: profiles/audio/mcp.c:369:
+    }$

WARNING:LINE_SPACING: Missing a blank line after declarations
#493: FILE: profiles/audio/mcp.c:382:
+	struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+	bt_mcp_register(btd_gatt_database_get_db(database));

WARNING:SUSPECT_CODE_INDENT: suspect code indent for conditional statements (8, 8)
#521: FILE: profiles/audio/mcp.c:410:
+	if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) {
+        warn("D-Bus experimental not enabled");

ERROR:CODE_INDENT: code indent should use tabs where possible
#522: FILE: profiles/audio/mcp.c:411:
+        warn("D-Bus experimental not enabled");$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#522: FILE: profiles/audio/mcp.c:411:
+        warn("D-Bus experimental not enabled");$

ERROR:CODE_INDENT: code indent should use tabs where possible
#523: FILE: profiles/audio/mcp.c:412:
+        return -ENOTSUP;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#523: FILE: profiles/audio/mcp.c:412:
+        return -ENOTSUP;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#526: FILE: profiles/audio/mcp.c:415:
+    btd_profile_register(&mcp_profile);$

WARNING:BRACES: braces {} are not necessary for single statement blocks
#534: FILE: profiles/audio/mcp.c:423:
+	if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
+		btd_profile_unregister(&mcp_profile);
+	}

/github/workspace/src/13000445.patch total: 6 errors, 15 warnings, 450 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

NOTE: Whitespace errors detected.
      You may wish to use scripts/cleanpatch or scripts/cleanfile

/github/workspace/src/13000445.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.

[BlueZ,4/4] monitor/att: Add decoding support for GMCS
WARNING:LEADING_SPACE: please, no spaces at the start of a line
#113: FILE: monitor/att.c:1754:
+    char utf8_name[HCI_MAX_NAME_LENGTH + 2];$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#114: FILE: monitor/att.c:1755:
+    int i;$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#116: FILE: monitor/att.c:1757:
+    if (g_utf8_validate((const char *) name, len, NULL))$

ERROR:CODE_INDENT: code indent should use tabs where possible
#117: FILE: monitor/att.c:1758:
+        return g_strndup((char *) name, len);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#117: FILE: monitor/att.c:1758:
+        return g_strndup((char *) name, len);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#119: FILE: monitor/att.c:1760:
+    len = MIN(len, sizeof(utf8_name) - 1);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#121: FILE: monitor/att.c:1762:
+    memset(utf8_name, 0, sizeof(utf8_name));$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#122: FILE: monitor/att.c:1763:
+    strncpy(utf8_name, (char *) name, len);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#125: FILE: monitor/att.c:1766:
+    for (i = 0; utf8_name[i] != '\0'; i++) {$

ERROR:CODE_INDENT: code indent should use tabs where possible
#126: FILE: monitor/att.c:1767:
+        if (!isascii(utf8_name[i]))$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#126: FILE: monitor/att.c:1767:
+        if (!isascii(utf8_name[i]))$

WARNING:SUSPECT_CODE_INDENT: suspect code indent for conditional statements (8, 12)
#126: FILE: monitor/att.c:1767:
+        if (!isascii(utf8_name[i]))
+            utf8_name[i] = ' ';

ERROR:CODE_INDENT: code indent should use tabs where possible
#127: FILE: monitor/att.c:1768:
+            utf8_name[i] = ' ';$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#127: FILE: monitor/att.c:1768:
+            utf8_name[i] = ' ';$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#128: FILE: monitor/att.c:1769:
+    }$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#131: FILE: monitor/att.c:1772:
+    g_strstrip(utf8_name);$

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#133: FILE: monitor/att.c:1774:
+    return g_strdup(utf8_name);$

WARNING:LONG_LINE_STRING: line length of 86 exceeds 80 columns
#383: FILE: monitor/att.c:2024:
+		print_text(COLOR_ERROR, "    Supported Playing Orders: invalid size");

WARNING:LONG_LINE: line length of 81 exceeds 80 columns
#387: FILE: monitor/att.c:2028:
+	print_field("      Supported Playing Orders: 0x%4.4x", supported_orders);

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#451: FILE: monitor/att.c:2092:
+	{0x02 ,	"Pause"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#452: FILE: monitor/att.c:2093:
+	{0x03 ,	"Fast Rewind"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#453: FILE: monitor/att.c:2094:
+	{0x04 ,	"Fast Forward"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#454: FILE: monitor/att.c:2095:
+	{0x05 ,	"Stop"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#455: FILE: monitor/att.c:2096:
+	{0x10 ,	"Move Relative"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#456: FILE: monitor/att.c:2097:
+	{0x20 ,	"Previous Segment"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#457: FILE: monitor/att.c:2098:
+	{0x21 ,	"Next Segment"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#458: FILE: monitor/att.c:2099:
+	{0x22 ,	"First Segment"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#459: FILE: monitor/att.c:2100:
+	{0x23 ,	"Last Segment"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#460: FILE: monitor/att.c:2101:
+	{0x24 ,	"Goto Segment"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#461: FILE: monitor/att.c:2102:
+	{0x30 ,	"Previous Track"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#462: FILE: monitor/att.c:2103:
+	{0x31 ,	"Next Track"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#463: FILE: monitor/att.c:2104:
+	{0x32 ,	"First Track"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#464: FILE: monitor/att.c:2105:
+	{0x33 ,	"Last Track"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#465: FILE: monitor/att.c:2106:
+	{0x34 ,	"Goto Track"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#466: FILE: monitor/att.c:2107:
+	{0x40 ,	"Previous Group"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#467: FILE: monitor/att.c:2108:
+	{0x41 ,	"Next Group"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#468: FILE: monitor/att.c:2109:
+	{0x42 ,	"First Group"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#469: FILE: monitor/att.c:2110:
+	{0x43 ,	"Last Group"},
 	      ^

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#470: FILE: monitor/att.c:2111:
+	{0x44 ,	"Goto Group"},
 	      ^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#514: FILE: monitor/att.c:2155:
+    {0^I, "Play (0x00000001)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#514: FILE: monitor/att.c:2155:
+    {0	, "Play (0x00000001)"				},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#515: FILE: monitor/att.c:2156:
+    {1^I, "Pause (0x00000002)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#515: FILE: monitor/att.c:2156:
+    {1	, "Pause (0x00000002)"				},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#516: FILE: monitor/att.c:2157:
+    {2^I, "Fast Rewind^I(0x00000004)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#516: FILE: monitor/att.c:2157:
+    {2	, "Fast Rewind	(0x00000004)"		},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#517: FILE: monitor/att.c:2158:
+    {3^I, "Fast Forward (0x00000008)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#517: FILE: monitor/att.c:2158:
+    {3	, "Fast Forward (0x00000008)"		},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#518: FILE: monitor/att.c:2159:
+    {4^I, "Stop (0x00000010)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#518: FILE: monitor/att.c:2159:
+    {4	, "Stop (0x00000010)"				},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#519: FILE: monitor/att.c:2160:
+    {5^I, "Move Relative (0x00000020)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#519: FILE: monitor/att.c:2160:
+    {5	, "Move Relative (0x00000020)"		},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#520: FILE: monitor/att.c:2161:
+    {6^I, "Previous Segment (0x00000040)"^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#520: FILE: monitor/att.c:2161:
+    {6	, "Previous Segment (0x00000040)"	},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#521: FILE: monitor/att.c:2162:
+    {7^I, "Next Segment (0x00000080)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#521: FILE: monitor/att.c:2162:
+    {7	, "Next Segment (0x00000080)"		},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#522: FILE: monitor/att.c:2163:
+    {8^I, "First Segment (0x00000100)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#522: FILE: monitor/att.c:2163:
+    {8	, "First Segment (0x00000100)"		},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#523: FILE: monitor/att.c:2164:
+    {9^I, "Last Segment (0x00000200)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#523: FILE: monitor/att.c:2164:
+    {9	, "Last Segment (0x00000200)"		},
       	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#524: FILE: monitor/att.c:2165:
+    {10^I, "Goto Segment (0x00000400)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#524: FILE: monitor/att.c:2165:
+    {10	, "Goto Segment (0x00000400)"		},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#525: FILE: monitor/att.c:2166:
+    {11^I, "Previous Track (0x00000800)"     },$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#525: FILE: monitor/att.c:2166:
+    {11	, "Previous Track (0x00000800)"     },
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#526: FILE: monitor/att.c:2167:
+    {12^I, "Next Track (0x00001000)"^I^I    },$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#526: FILE: monitor/att.c:2167:
+    {12	, "Next Track (0x00001000)"		    },
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#527: FILE: monitor/att.c:2168:
+    {13^I, "First Track (0x00002000)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#527: FILE: monitor/att.c:2168:
+    {13	, "First Track (0x00002000)"		},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#528: FILE: monitor/att.c:2169:
+    {14^I, "Last Track (0x00004000)"^I^I    },$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#528: FILE: monitor/att.c:2169:
+    {14	, "Last Track (0x00004000)"		    },
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#529: FILE: monitor/att.c:2170:
+    {15^I, "Goto Track (0x00008000)"^I^I    },$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#529: FILE: monitor/att.c:2170:
+    {15	, "Goto Track (0x00008000)"		    },
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#530: FILE: monitor/att.c:2171:
+    {16^I, "Previous Group (0x00010000)"^I    },$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#530: FILE: monitor/att.c:2171:
+    {16	, "Previous Group (0x00010000)"	    },
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#531: FILE: monitor/att.c:2172:
+    {17^I, "Next Group (0x00020000)"^I^I    },$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#531: FILE: monitor/att.c:2172:
+    {17	, "Next Group (0x00020000)"		    },
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#532: FILE: monitor/att.c:2173:
+    {18^I, "First Group (0x00040000)"^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#532: FILE: monitor/att.c:2173:
+    {18	, "First Group (0x00040000)"		},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#533: FILE: monitor/att.c:2174:
+    {19^I, "Last Group (0x00080000)"^I^I    },$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#533: FILE: monitor/att.c:2174:
+    {19	, "Last Group (0x00080000)"		    },
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#534: FILE: monitor/att.c:2175:
+    {20 , "Goto Group (0x00100000)"^I^I    },$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#534: FILE: monitor/att.c:2175:
+    {20 , "Goto Group (0x00100000)"		    },
         ^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#535: FILE: monitor/att.c:2176:
+    {21^I, "RFU (0x00200000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#535: FILE: monitor/att.c:2176:
+    {21	, "RFU (0x00200000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#536: FILE: monitor/att.c:2177:
+    {22^I, "RFU (0x00400000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#536: FILE: monitor/att.c:2177:
+    {22	, "RFU (0x00400000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#537: FILE: monitor/att.c:2178:
+    {23^I, "RFU (0x00800000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#537: FILE: monitor/att.c:2178:
+    {23	, "RFU (0x00800000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#538: FILE: monitor/att.c:2179:
+    {24^I, "RFU (0x01000000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#538: FILE: monitor/att.c:2179:
+    {24	, "RFU (0x01000000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#539: FILE: monitor/att.c:2180:
+    {25^I, "RFU (0x02000000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#539: FILE: monitor/att.c:2180:
+    {25	, "RFU (0x02000000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#540: FILE: monitor/att.c:2181:
+    {26^I, "RFU (0x04000000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#540: FILE: monitor/att.c:2181:
+    {26	, "RFU (0x04000000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#541: FILE: monitor/att.c:2182:
+    {27^I, "RFU (0x08000000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#541: FILE: monitor/att.c:2182:
+    {27	, "RFU (0x08000000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#542: FILE: monitor/att.c:2183:
+    {28^I, "RFU (0x10000000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#542: FILE: monitor/att.c:2183:
+    {28	, "RFU (0x10000000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#543: FILE: monitor/att.c:2184:
+    {29^I, "RFU (0x20000000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#543: FILE: monitor/att.c:2184:
+    {29	, "RFU (0x20000000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#544: FILE: monitor/att.c:2185:
+    {30^I, "RFU (0x40000000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#544: FILE: monitor/att.c:2185:
+    {30	, "RFU (0x40000000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#545: FILE: monitor/att.c:2186:
+    {31^I, "RFU (0x80000000)"^I^I^I^I},$

ERROR:SPACING: space prohibited before that ',' (ctx:WxW)
#545: FILE: monitor/att.c:2186:
+    {31	, "RFU (0x80000000)"				},
        	^

WARNING:LEADING_SPACE: please, no spaces at the start of a line
#546: FILE: monitor/att.c:2187:
+    { }$

/github/workspace/src/13000446.patch total: 55 errors, 49 warnings, 535 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

NOTE: Whitespace errors detected.
      You may wish to use scripts/cleanpatch or scripts/cleanfile

/github/workspace/src/13000446.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: Build - Make - FAIL
Desc: Build the BlueZ source tree
Output:
src/shared/mcp.c: In function ‘read_track_title’:
src/shared/mcp.c:699:25: error: unused variable ‘cb’ [-Werror=unused-variable]
  699 |  struct event_callback *cb = mcp->cb;
      |                         ^~
src/shared/mcp.c: At top level:
src/shared/mcp.c:994:6: error: no previous declaration for ‘bt_mcp_mp_name_attach’ [-Werror=missing-declarations]
  994 | void bt_mcp_mp_name_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1012:6: error: no previous declaration for ‘bt_mcp_track_changed_attach’ [-Werror=missing-declarations]
 1012 | void bt_mcp_track_changed_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1028:6: error: no previous declaration for ‘bt_mcp_track_title_attach’ [-Werror=missing-declarations]
 1028 | void bt_mcp_track_title_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1046:6: error: no previous declaration for ‘bt_mcp_track_duration_attach’ [-Werror=missing-declarations]
 1046 | void bt_mcp_track_duration_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1064:6: error: no previous declaration for ‘bt_mcp_track_position_attach’ [-Werror=missing-declarations]
 1064 | void bt_mcp_track_position_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1082:6: error: no previous declaration for ‘bt_mcp_media_state_attach’ [-Werror=missing-declarations]
 1082 | void bt_mcp_media_state_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1100:6: error: no previous declaration for ‘bt_mcp_media_cp_attach’ [-Werror=missing-declarations]
 1100 | void bt_mcp_media_cp_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1116:6: error: no previous declaration for ‘bt_mcp_media_cp_op_supported_attach’ [-Werror=missing-declarations]
 1116 | void bt_mcp_media_cp_op_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1135:6: error: no previous declaration for ‘bt_mcp_content_control_id_supported_attach’ [-Werror=missing-declarations]
 1135 | void bt_mcp_content_control_id_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c: In function ‘bt_mcp_attach’:
src/shared/mcp.c:1381:12: error: unused variable ‘value_handle’ [-Werror=unused-variable]
 1381 |   uint16_t value_handle;
      |            ^~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8235: src/shared/libshared_mainloop_la-mcp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4465: all] Error 2


##############################
Test: Make Check - FAIL
Desc: Run 'make check'
Output:
src/shared/mcp.c: In function ‘read_track_title’:
src/shared/mcp.c:699:25: error: unused variable ‘cb’ [-Werror=unused-variable]
  699 |  struct event_callback *cb = mcp->cb;
      |                         ^~
src/shared/mcp.c: At top level:
src/shared/mcp.c:994:6: error: no previous declaration for ‘bt_mcp_mp_name_attach’ [-Werror=missing-declarations]
  994 | void bt_mcp_mp_name_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1012:6: error: no previous declaration for ‘bt_mcp_track_changed_attach’ [-Werror=missing-declarations]
 1012 | void bt_mcp_track_changed_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1028:6: error: no previous declaration for ‘bt_mcp_track_title_attach’ [-Werror=missing-declarations]
 1028 | void bt_mcp_track_title_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1046:6: error: no previous declaration for ‘bt_mcp_track_duration_attach’ [-Werror=missing-declarations]
 1046 | void bt_mcp_track_duration_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1064:6: error: no previous declaration for ‘bt_mcp_track_position_attach’ [-Werror=missing-declarations]
 1064 | void bt_mcp_track_position_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1082:6: error: no previous declaration for ‘bt_mcp_media_state_attach’ [-Werror=missing-declarations]
 1082 | void bt_mcp_media_state_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1100:6: error: no previous declaration for ‘bt_mcp_media_cp_attach’ [-Werror=missing-declarations]
 1100 | void bt_mcp_media_cp_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1116:6: error: no previous declaration for ‘bt_mcp_media_cp_op_supported_attach’ [-Werror=missing-declarations]
 1116 | void bt_mcp_media_cp_op_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1135:6: error: no previous declaration for ‘bt_mcp_content_control_id_supported_attach’ [-Werror=missing-declarations]
 1135 | void bt_mcp_content_control_id_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c: In function ‘bt_mcp_attach’:
src/shared/mcp.c:1381:12: error: unused variable ‘value_handle’ [-Werror=unused-variable]
 1381 |   uint16_t value_handle;
      |            ^~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8032: src/shared/libshared_glib_la-mcp.lo] Error 1
make: *** [Makefile:11650: check] Error 2


##############################
Test: Make Check w/Valgrind - FAIL
Desc: Run 'make check' with Valgrind
Output:
src/shared/mcp.c: In function ‘read_track_title’:
src/shared/mcp.c:699:25: error: unused variable ‘cb’ [-Werror=unused-variable]
  699 |  struct event_callback *cb = mcp->cb;
      |                         ^~
src/shared/mcp.c: At top level:
src/shared/mcp.c:994:6: error: no previous declaration for ‘bt_mcp_mp_name_attach’ [-Werror=missing-declarations]
  994 | void bt_mcp_mp_name_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1012:6: error: no previous declaration for ‘bt_mcp_track_changed_attach’ [-Werror=missing-declarations]
 1012 | void bt_mcp_track_changed_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1028:6: error: no previous declaration for ‘bt_mcp_track_title_attach’ [-Werror=missing-declarations]
 1028 | void bt_mcp_track_title_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1046:6: error: no previous declaration for ‘bt_mcp_track_duration_attach’ [-Werror=missing-declarations]
 1046 | void bt_mcp_track_duration_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1064:6: error: no previous declaration for ‘bt_mcp_track_position_attach’ [-Werror=missing-declarations]
 1064 | void bt_mcp_track_position_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1082:6: error: no previous declaration for ‘bt_mcp_media_state_attach’ [-Werror=missing-declarations]
 1082 | void bt_mcp_media_state_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1100:6: error: no previous declaration for ‘bt_mcp_media_cp_attach’ [-Werror=missing-declarations]
 1100 | void bt_mcp_media_cp_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1116:6: error: no previous declaration for ‘bt_mcp_media_cp_op_supported_attach’ [-Werror=missing-declarations]
 1116 | void bt_mcp_media_cp_op_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1135:6: error: no previous declaration for ‘bt_mcp_content_control_id_supported_attach’ [-Werror=missing-declarations]
 1135 | void bt_mcp_content_control_id_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c: In function ‘bt_mcp_attach’:
src/shared/mcp.c:1381:12: error: unused variable ‘value_handle’ [-Werror=unused-variable]
 1381 |   uint16_t value_handle;
      |            ^~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8235: src/shared/libshared_mainloop_la-mcp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4465: all] Error 2


##############################
Test: Make Distcheck - FAIL
Desc: Run distcheck to check the distribution
Output:
make[2]: *** No rule to make target 'shared/mcs.h', needed by 'distdir-am'.  Stop.
make[1]: *** [Makefile:11483: distdir] Error 2
make: *** [Makefile:11559: dist] Error 2


##############################
Test: Build w/ext ELL - Make - FAIL
Desc: Build BlueZ source with '--enable-external-ell' configuration
Output:
src/shared/mcp.c: In function ‘read_track_title’:
src/shared/mcp.c:699:25: error: unused variable ‘cb’ [-Werror=unused-variable]
  699 |  struct event_callback *cb = mcp->cb;
      |                         ^~
src/shared/mcp.c: At top level:
src/shared/mcp.c:994:6: error: no previous declaration for ‘bt_mcp_mp_name_attach’ [-Werror=missing-declarations]
  994 | void bt_mcp_mp_name_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1012:6: error: no previous declaration for ‘bt_mcp_track_changed_attach’ [-Werror=missing-declarations]
 1012 | void bt_mcp_track_changed_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1028:6: error: no previous declaration for ‘bt_mcp_track_title_attach’ [-Werror=missing-declarations]
 1028 | void bt_mcp_track_title_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1046:6: error: no previous declaration for ‘bt_mcp_track_duration_attach’ [-Werror=missing-declarations]
 1046 | void bt_mcp_track_duration_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1064:6: error: no previous declaration for ‘bt_mcp_track_position_attach’ [-Werror=missing-declarations]
 1064 | void bt_mcp_track_position_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1082:6: error: no previous declaration for ‘bt_mcp_media_state_attach’ [-Werror=missing-declarations]
 1082 | void bt_mcp_media_state_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1100:6: error: no previous declaration for ‘bt_mcp_media_cp_attach’ [-Werror=missing-declarations]
 1100 | void bt_mcp_media_cp_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1116:6: error: no previous declaration for ‘bt_mcp_media_cp_op_supported_attach’ [-Werror=missing-declarations]
 1116 | void bt_mcp_media_cp_op_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1135:6: error: no previous declaration for ‘bt_mcp_content_control_id_supported_attach’ [-Werror=missing-declarations]
 1135 | void bt_mcp_content_control_id_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c: In function ‘bt_mcp_attach’:
src/shared/mcp.c:1381:12: error: unused variable ‘value_handle’ [-Werror=unused-variable]
 1381 |   uint16_t value_handle;
      |            ^~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8235: src/shared/libshared_mainloop_la-mcp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4465: all] Error 2


##############################
Test: Incremental Build w/ patches - FAIL
Desc: Incremental build per patch in the series
Output:
src/shared/mcp.c: In function ‘read_track_title’:
src/shared/mcp.c:699:25: error: unused variable ‘cb’ [-Werror=unused-variable]
  699 |  struct event_callback *cb = mcp->cb;
      |                         ^~
src/shared/mcp.c: At top level:
src/shared/mcp.c:994:6: error: no previous declaration for ‘bt_mcp_mp_name_attach’ [-Werror=missing-declarations]
  994 | void bt_mcp_mp_name_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1012:6: error: no previous declaration for ‘bt_mcp_track_changed_attach’ [-Werror=missing-declarations]
 1012 | void bt_mcp_track_changed_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1028:6: error: no previous declaration for ‘bt_mcp_track_title_attach’ [-Werror=missing-declarations]
 1028 | void bt_mcp_track_title_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1046:6: error: no previous declaration for ‘bt_mcp_track_duration_attach’ [-Werror=missing-declarations]
 1046 | void bt_mcp_track_duration_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1064:6: error: no previous declaration for ‘bt_mcp_track_position_attach’ [-Werror=missing-declarations]
 1064 | void bt_mcp_track_position_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1082:6: error: no previous declaration for ‘bt_mcp_media_state_attach’ [-Werror=missing-declarations]
 1082 | void bt_mcp_media_state_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1100:6: error: no previous declaration for ‘bt_mcp_media_cp_attach’ [-Werror=missing-declarations]
 1100 | void bt_mcp_media_cp_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1116:6: error: no previous declaration for ‘bt_mcp_media_cp_op_supported_attach’ [-Werror=missing-declarations]
 1116 | void bt_mcp_media_cp_op_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1135:6: error: no previous declaration for ‘bt_mcp_content_control_id_supported_attach’ [-Werror=missing-declarations]
 1135 | void bt_mcp_content_control_id_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c: In function ‘bt_mcp_attach’:
src/shared/mcp.c:1381:12: error: unused variable ‘value_handle’ [-Werror=unused-variable]
 1381 |   uint16_t value_handle;
      |            ^~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8226: src/shared/libshared_mainloop_la-mcp.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4460: all] Error 2


##############################
Test: Scan Build - FAIL
Desc: Run Scan Build with patches
Output:
client/player.c:1756:25: warning: Dereference of null pointer
        iov_append(&cfg->caps, preset->data.iov_base, preset->data.iov_len);
                               ^~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/shared/ad.c:369:19: warning: Use of zero-allocated memory
                                buf[(*pos)++] = ad_type;
                                              ^
1 warning generated.
src/shared/gatt-client.c:387:21: warning: Use of memory after it is freed
        gatt_db_unregister(op->client->db, op->db_id);
                           ^~~~~~~~~~
src/shared/gatt-client.c:600:2: warning: Use of memory after it is freed
        discovery_op_complete(op, false, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:900:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1009:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1185:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1250:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1521:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1526:2: warning: Use of memory after it is freed
        discover_all(op);
        ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2028:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2036:8: warning: Use of memory after it is freed
                                                        discovery_op_ref(op),
                                                        ^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3119:2: warning: Use of memory after it is freed
        complete_write_long_op(req, success, 0, false);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3141:2: warning: Use of memory after it is freed
        request_unref(req);
        ^~~~~~~~~~~~~~~~~~
12 warnings generated.
src/shared/mcp.c: In function ‘read_track_title’:
src/shared/mcp.c:699:25: error: unused variable ‘cb’ [-Werror=unused-variable]
  699 |  struct event_callback *cb = mcp->cb;
      |                         ^~
src/shared/mcp.c: At top level:
src/shared/mcp.c:994:6: error: no previous declaration for ‘bt_mcp_mp_name_attach’ [-Werror=missing-declarations]
  994 | void bt_mcp_mp_name_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1012:6: error: no previous declaration for ‘bt_mcp_track_changed_attach’ [-Werror=missing-declarations]
 1012 | void bt_mcp_track_changed_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1028:6: error: no previous declaration for ‘bt_mcp_track_title_attach’ [-Werror=missing-declarations]
 1028 | void bt_mcp_track_title_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1046:6: error: no previous declaration for ‘bt_mcp_track_duration_attach’ [-Werror=missing-declarations]
 1046 | void bt_mcp_track_duration_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1064:6: error: no previous declaration for ‘bt_mcp_track_position_attach’ [-Werror=missing-declarations]
 1064 | void bt_mcp_track_position_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1082:6: error: no previous declaration for ‘bt_mcp_media_state_attach’ [-Werror=missing-declarations]
 1082 | void bt_mcp_media_state_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1100:6: error: no previous declaration for ‘bt_mcp_media_cp_attach’ [-Werror=missing-declarations]
 1100 | void bt_mcp_media_cp_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1116:6: error: no previous declaration for ‘bt_mcp_media_cp_op_supported_attach’ [-Werror=missing-declarations]
 1116 | void bt_mcp_media_cp_op_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c:1135:6: error: no previous declaration for ‘bt_mcp_content_control_id_supported_attach’ [-Werror=missing-declarations]
 1135 | void bt_mcp_content_control_id_supported_attach(struct bt_mcp *mcp)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/mcp.c: In function ‘bt_mcp_attach’:
src/shared/mcp.c:1381:12: error: unused variable ‘value_handle’ [-Werror=unused-variable]
 1381 |   uint16_t value_handle;
      |            ^~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8032: src/shared/libshared_glib_la-mcp.lo] Error 1
make: *** [Makefile:4465: all] Error 2




---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH BlueZ 0/4] Media Control Profile Client
  2022-10-06 14:33 [PATCH BlueZ 0/4] Media Control Profile Client Abhay Maheta
                   ` (3 preceding siblings ...)
  2022-10-06 14:33 ` [PATCH BlueZ 4/4] monitor/att: Add decoding support for GMCS Abhay Maheta
@ 2022-10-06 20:40 ` Luiz Augusto von Dentz
  4 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2022-10-06 20:40 UTC (permalink / raw)
  To: Abhay Maheta; +Cc: linux-bluetooth

Hi Abhay,

On Thu, Oct 6, 2022 at 7:39 AM Abhay Maheta
<abhay.maheshbhai.maheta@intel.com> wrote:
>
> This series of patches adds support for Media Control Profile for LE Audio.
> These patches primarily foces on Media Control Client Role.
>
> Abhay Maheta (4):
>   lib/uuid: Add GMCS UUIDs
>   shared/mcp: Add initial code for handling MCP
>   profiles: Add initial code for mcp plugin
>   monitor/att: Add decoding support for GMCS
>
>  Makefile.am          |    1 +
>  Makefile.plugins     |    5 +
>  configure.ac         |    4 +
>  lib/uuid.h           |   15 +
>  monitor/att.c        |  511 +++++++++++++++
>  profiles/audio/mcp.c |  429 +++++++++++++
>  src/shared/mcp.c     | 1408 ++++++++++++++++++++++++++++++++++++++++++
>  src/shared/mcp.h     |   60 ++
>  src/shared/mcs.h     |   65 ++
>  9 files changed, 2498 insertions(+)
>  create mode 100644 profiles/audio/mcp.c
>  create mode 100644 src/shared/mcp.c
>  create mode 100644 src/shared/mcp.h
>  create mode 100644 src/shared/mcs.h
>
> --
> 2.25.1

Please fix the code style, there are quite a few problems with that,
it would also be great to give some information on how the plugin
works for instance does it work with bluetoothctl player menu?

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-10-06 20:41 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-06 14:33 [PATCH BlueZ 0/4] Media Control Profile Client Abhay Maheta
2022-10-06 14:33 ` [PATCH BlueZ 1/4] lib/uuid: Add GMCS UUIDs Abhay Maheta
2022-10-06 14:58   ` Media Control Profile Client bluez.test.bot
2022-10-06 14:33 ` [PATCH BlueZ 2/4] shared/mcp: Add initial code for handling MCP Abhay Maheta
2022-10-06 14:33 ` [PATCH BlueZ 3/4] profiles: Add initial code for mcp plugin Abhay Maheta
2022-10-06 14:33 ` [PATCH BlueZ 4/4] monitor/att: Add decoding support for GMCS Abhay Maheta
2022-10-06 20:40 ` [PATCH BlueZ 0/4] Media Control Profile Client Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).