diff mbox series

[BlueZ,2/4] shared/mcp: Add initial code for handling MCP

Message ID 20221006143343.199055-3-abhay.maheshbhai.maheta@intel.com (mailing list archive)
State Superseded
Headers show
Series Media Control Profile Client | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/checkpatch fail [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.
tedd_an/gitlint success Gitlint PASS
tedd_an/incremental_build fail Make FAIL: 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

Commit Message

Abhay Maheta Oct. 6, 2022, 2:33 p.m. UTC
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 mbox series

Patch

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