All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/4] sdp: Add initial support for MPS
@ 2015-02-14 13:02 Szymon Janc
  2015-02-14 13:02 ` [PATCH v2 2/4] sdp: Add support for MPMD in MPS Szymon Janc
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Szymon Janc @ 2015-02-14 13:02 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This allows to register Multi Profile Specification record with proper
MPSD bits set depending on currently registered services.

Service Name: Multi Profile
Service RecHandle: 0x10001
Service Class ID List:
  "" (0x113b)
Profile Descriptor List:
  "" (0x113a)
    Version: 0x0100
---
V2: use defines for feature bits

 src/main.c          |   1 +
 src/sdpd-database.c |   1 +
 src/sdpd-request.c  |   1 +
 src/sdpd-server.c   |   1 +
 src/sdpd-service.c  | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/sdpd.h          |   1 +
 6 files changed, 325 insertions(+), 1 deletion(-)

diff --git a/src/main.c b/src/main.c
index 061060d..b3140d0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -33,6 +33,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <sys/signalfd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
diff --git a/src/sdpd-database.c b/src/sdpd-database.c
index 6f5577b..e3b9e09 100644
--- a/src/sdpd-database.c
+++ b/src/sdpd-database.c
@@ -29,6 +29,7 @@
 #endif
 
 #include <stdlib.h>
+#include <stdbool.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
diff --git a/src/sdpd-request.c b/src/sdpd-request.c
index 3e58c22..081e7c8 100644
--- a/src/sdpd-request.c
+++ b/src/sdpd-request.c
@@ -31,6 +31,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <limits.h>
+#include <stdbool.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index 015551d..8ecda9b 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -31,6 +31,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <sys/stat.h>
 
 #include <bluetooth/bluetooth.h>
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index a90b299..abd48e7 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <sys/time.h>
+#include <stdbool.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
@@ -43,6 +44,163 @@
 #include "sdpd.h"
 #include "log.h"
 
+#define MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO		(1ULL << 0)
+#define MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO		(1ULL << 1)
+#define MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO		(1ULL << 2)
+#define MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO		(1ULL << 3)
+#define MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO		(1ULL << 4)
+#define MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO	(1ULL << 5)
+#define MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP		(1ULL << 6)
+#define MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP		(1ULL << 7)
+#define MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL	(1ULL << 8)
+#define MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL	(1ULL << 9)
+#define MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY	(1ULL << 10)
+#define MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY	(1ULL << 11)
+#define MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE	(1ULL << 12)
+#define MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE	(1ULL << 13)
+#define MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL		(1ULL << 14)
+#define MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL		(1ULL << 15)
+#define MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM	(1ULL << 16)
+#define MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM	(1ULL << 17)
+#define MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM	(1ULL << 18)
+#define MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM	(1ULL << 19)
+#define MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM	(1ULL << 20)
+#define MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM	(1ULL << 21)
+#define MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM	(1ULL << 22)
+#define MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM	(1ULL << 23)
+#define MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM	(1ULL << 24)
+#define MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM	(1ULL << 25)
+#define MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL		(1ULL << 26)
+#define MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL	(1ULL << 27)
+#define MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM	(1ULL << 28)
+#define MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM	(1ULL << 29)
+#define MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM	(1ULL << 30)
+#define MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM	(1ULL << 31)
+#define MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM	(1ULL << 32)
+#define MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM	(1ULL << 33)
+#define MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM	(1ULL << 34)
+#define MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM	(1ULL << 35)
+#define MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM	(1ULL << 36)
+#define MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM	(1ULL << 37)
+
+/* Note: in spec dependency bit position starts from 1 (bit 0 unused?) */
+#define MPS_DEPS_SNIFF_MODE_DURRING_STREAMING	(1ULL << 1)
+#define MPS_DEPS_GAVDP_REQUIREMENTS		(1ULL << 2)
+#define MPS_DEPS_DIS_CONNECTION_ORDER_BEHAVIOR	(1ULL << 3)
+
+/*
+ * default MPS features are all disabled, will be updated if relevant service
+ * is (un)registered
+ */
+#define MPS_MPSD_DEFAULT_FEATURES 0
+#define MPS_MPMD_DEFAULT_FEATURES 0
+
+/*
+ * Those defines bits for all features that depend on specific profile and role.
+ * If profile is not supported then all those bits should not be set in record
+ */
+#define MPS_MPSD_HFP_AG (MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO | \
+			MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO | \
+			MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO | \
+			MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP | \
+			MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL | \
+			MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY | \
+			MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL | \
+			MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
+			MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL | \
+			MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM)
+
+#define MPS_MPSD_HFP_HF (MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO | \
+			MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO | \
+			MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO | \
+			MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP | \
+			MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL | \
+			MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY | \
+			MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
+			MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL | \
+			MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL | \
+			MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM)
+
+#define MPS_MPSD_A2DP_SRC (MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO | \
+			MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO | \
+			MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO | \
+			MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP | \
+			MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL | \
+			MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY | \
+			MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
+			MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM | \
+			MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM | \
+			MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM | \
+			MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM | \
+			MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM)
+
+#define MPS_MPSD_A2DP_SNK (MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO | \
+			MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO | \
+			MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO | \
+			MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP | \
+			MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL | \
+			MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY | \
+			MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
+			MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM | \
+			MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM | \
+			MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM | \
+			MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM | \
+			MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM)
+
+#define MPS_MPSD_AVRCP_CT MPS_MPSD_A2DP_SNK
+
+#define MPS_MPSD_AVRCP_TG MPS_MPSD_A2DP_SRC
+
+#define MPS_MPSD_DUN_GW (MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL | \
+			MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM | \
+			MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM | \
+			MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM | \
+			MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM)
+
+#define MPS_MPSD_DUN_DT (MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL | \
+			MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM | \
+			MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM | \
+			MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM | \
+			MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM)
+
+#define MPS_MPSD_PAN_NAP (MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL | \
+			MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM | \
+			MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM | \
+			MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM)
+
+#define MPS_MPSD_PAN_PANU (MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL | \
+			MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM | \
+			MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM | \
+			MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM | \
+			MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM)
+
+#define MPS_MPSD_PBAP_SRC MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM
+
+#define MPS_MPSD_PBAP_CLI MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM
+
+#define MPS_MPSD_ALL (MPS_MPSD_HFP_AG | MPS_MPSD_HFP_HF | \
+			MPS_MPSD_A2DP_SRC | MPS_MPSD_A2DP_SNK | \
+			MPS_MPSD_AVRCP_CT | MPS_MPSD_AVRCP_TG | \
+			MPS_MPSD_DUN_GW | MPS_MPSD_DUN_DT | \
+			MPS_MPSD_PAN_NAP | MPS_MPSD_PAN_PANU | \
+			MPS_MPSD_PBAP_SRC | MPS_MPSD_PBAP_CLI)
+
+/* Assume all dependencies are supported */
+#define MPS_DEFAULT_DEPS (MPS_DEPS_SNIFF_MODE_DURRING_STREAMING | \
+			MPS_DEPS_GAVDP_REQUIREMENTS | \
+			MPS_DEPS_DIS_CONNECTION_ORDER_BEHAVIOR)
+
 static sdp_record_t *server = NULL;
 static uint32_t fixed_dbts = 0;
 
@@ -55,6 +213,9 @@ static sdp_version_t sdpVnumArray[1] = {
 };
 static const int sdpServerVnumEntries = 1;
 
+static uint32_t mps_handle = 0;
+static bool mps_mpmd = false;
+
 /*
  * A simple function which returns the time of day in
  * seconds. Used for updating the service db state
@@ -235,6 +396,161 @@ void register_device_id(uint16_t source, uint16_t vendor,
 	update_db_timestamp();
 }
 
+static bool class_supported(uint16_t class)
+{
+	sdp_list_t *list;
+	uuid_t uuid;
+
+	sdp_uuid16_create(&uuid, class);
+
+	for (list = sdp_get_record_list(); list; list = list->next) {
+		sdp_record_t *rec = list->data;
+
+		if (sdp_uuid_cmp(&rec->svclass, &uuid) == 0)
+			return true;
+	}
+
+	return false;
+}
+
+static uint64_t mps_mpsd_features(void)
+{
+	uint64_t feat = MPS_MPSD_ALL;
+
+	if (!class_supported(HANDSFREE_AGW_SVCLASS_ID))
+		feat &= ~MPS_MPSD_HFP_AG;
+
+	if (!class_supported(HANDSFREE_SVCLASS_ID))
+		feat &= ~MPS_MPSD_HFP_HF;
+
+	if (!class_supported(AUDIO_SOURCE_SVCLASS_ID))
+		feat &= ~MPS_MPSD_A2DP_SRC;
+
+	if (!class_supported(AUDIO_SINK_SVCLASS_ID))
+		feat &= ~MPS_MPSD_A2DP_SNK;
+
+	if (!class_supported(AV_REMOTE_CONTROLLER_SVCLASS_ID))
+		feat &= ~MPS_MPSD_AVRCP_CT;
+
+	if (!class_supported(AV_REMOTE_TARGET_SVCLASS_ID))
+		feat &= ~MPS_MPSD_AVRCP_TG;
+
+	if (!class_supported(DIALUP_NET_SVCLASS_ID))
+		feat &= ~MPS_MPSD_DUN_GW;
+
+	/* TODO */
+	feat &= ~MPS_MPSD_DUN_DT;
+
+	if (!class_supported(NAP_SVCLASS_ID))
+		feat &= ~MPS_MPSD_PAN_NAP;
+
+	if (!class_supported(PANU_SVCLASS_ID))
+		feat &= ~MPS_MPSD_PAN_PANU;
+
+	if (!class_supported(PBAP_PSE_SVCLASS_ID))
+		feat &= ~MPS_MPSD_PBAP_SRC;
+
+	if (!class_supported(PBAP_PCE_SVCLASS_ID))
+		feat &= ~MPS_MPSD_PBAP_CLI;
+
+	return feat;
+}
+
+static uint64_t mps_mpmd_features(void)
+{
+	/* TODO */
+
+	return 0;
+}
+
+static sdp_record_t *mps_record(int mpmd)
+{
+	sdp_data_t *mpsd_features, *mpmd_features, *dependencies;
+	sdp_list_t *svclass_id, *pfseq, *root;
+	uuid_t root_uuid, svclass_uuid;
+	sdp_profile_desc_t profile;
+	sdp_record_t *record;
+	uint64_t mpsd_feat = MPS_MPSD_DEFAULT_FEATURES;
+	uint64_t mpmd_feat = MPS_MPMD_DEFAULT_FEATURES;
+	uint16_t deps = MPS_DEFAULT_DEPS;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(NULL, &root_uuid);
+	sdp_set_browse_groups(record, root);
+	sdp_list_free(root, NULL);
+
+	sdp_uuid16_create(&svclass_uuid, MPS_SVCLASS_ID);
+	svclass_id = sdp_list_append(NULL, &svclass_uuid);
+	sdp_set_service_classes(record, svclass_id);
+	sdp_list_free(svclass_id, NULL);
+
+	sdp_uuid16_create(&profile.uuid, MPS_PROFILE_ID);
+	profile.version = 0x0100;
+	pfseq = sdp_list_append(NULL, &profile);
+	sdp_set_profile_descs(record, pfseq);
+	sdp_list_free(pfseq, NULL);
+
+	mpsd_features = sdp_data_alloc(SDP_UINT64, &mpsd_feat);
+	sdp_attr_add(record, SDP_ATTR_MPSD_SCENARIOS, mpsd_features);
+
+	if (mpmd) {
+		mpmd_features = sdp_data_alloc(SDP_UINT64, &mpmd_feat);
+		sdp_attr_add(record, SDP_ATTR_MPMD_SCENARIOS, mpmd_features);
+	}
+
+	dependencies = sdp_data_alloc(SDP_UINT16, &deps);
+	sdp_attr_add(record, SDP_ATTR_MPS_DEPENDENCIES, dependencies);
+
+	sdp_set_info_attr(record, "Multi Profile", 0, 0);
+
+	return record;
+}
+
+void register_mps(bool mpmd)
+{
+	sdp_record_t *record;
+
+	record = mps_record(mpmd);
+	if (!record)
+		return;
+
+	if (add_record_to_server(BDADDR_ANY, record) < 0) {
+		sdp_record_free(record);
+		return;
+	}
+
+	mps_handle = record->handle;
+	mps_mpmd = mpmd;
+}
+
+static void update_mps(void)
+{
+	sdp_record_t *rec;
+	sdp_data_t *data;
+	uint64_t mpsd_feat, mpmd_feat;
+
+	if (!mps_handle)
+		return;
+
+	rec = sdp_record_find(mps_handle);
+	if (!rec)
+		return;
+
+	mpsd_feat = mps_mpsd_features();
+	data = sdp_data_alloc(SDP_UINT64, &mpsd_feat);
+	sdp_attr_replace(rec, SDP_ATTR_MPSD_SCENARIOS, data);
+
+	if (mps_mpmd) {
+		mpmd_feat = mps_mpmd_features();
+		data = sdp_data_alloc(SDP_UINT64, &mpmd_feat);
+		sdp_attr_replace(rec, SDP_ATTR_MPMD_SCENARIOS, data);
+	}
+}
+
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
 {
 	sdp_data_t *data;
@@ -272,6 +588,7 @@ int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
 		DBG("Record pattern UUID %s", uuid);
 	}
 
+	update_mps();
 	update_db_timestamp();
 
 	return 0;
@@ -291,8 +608,10 @@ int remove_record_from_server(uint32_t handle)
 	if (!rec)
 		return -ENOENT;
 
-	if (sdp_record_remove(handle) == 0)
+	if (sdp_record_remove(handle) == 0) {
+		update_mps();
 		update_db_timestamp();
+	}
 
 	sdp_record_free(rec);
 
diff --git a/src/sdpd.h b/src/sdpd.h
index 6de0af7..4425c87 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -58,6 +58,7 @@ void register_public_browse_group(void);
 void register_server_service(void);
 void register_device_id(uint16_t source, uint16_t vendor,
 					uint16_t product, uint16_t version);
+void register_mps(bool mpmd);
 
 int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
-- 
1.9.3


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

* [PATCH v2 2/4] sdp: Add support for MPMD in MPS
  2015-02-14 13:02 [PATCH v2 1/4] sdp: Add initial support for MPS Szymon Janc
@ 2015-02-14 13:02 ` Szymon Janc
  2015-02-14 13:02 ` [PATCH v2 3/4] android: Use common MPS implementation Szymon Janc
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Szymon Janc @ 2015-02-14 13:02 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This enables MPMD field in MPS record.
---
 src/sdpd-service.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 92 insertions(+), 1 deletion(-)

diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index abd48e7..40aef62 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -83,6 +83,26 @@
 #define MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM	(1ULL << 36)
 #define MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM	(1ULL << 37)
 
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_ANSWER_CALL_DURING_AUDIO	(1ULL << 0)
+#define MPMD_A2DP_SRC_AVRCP_TG_ANSWER_CALL_DURING_AUDIO		(1ULL << 1)
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_OUTGOING_CALL_DURING_AUDIO (1ULL << 2)
+#define MPMD_A2DP_SRC_AVRCP_TG_OUTGOING_CALL_DURING_AUDIO	(1ULL << 3)
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_REJECT_CALL_DURING_AUDIO	(1ULL << 4)
+#define MPMD_A2DP_SRC_AVRCP_TG_REJECT_CALL_DURING_AUDIO		(1ULL << 5)
+#define MPMD_HFP_AG_CALL_TERMINATION_DURING_AVP			(1ULL << 6)
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_TERMINATION_DURING_AVP	(1ULL << 7)
+#define MPMD_A2DP_SRC_AVRCP_TG_TERMINATION_DURING_AVP		(1ULL << 8)
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_PLAY_DURING_CALL		(1ULL << 9)
+#define MPMD_A2DP_SRC_AVRCP_TG_PRESS_PLAY_DURING_CALL		(1ULL << 10)
+#define MPMD_AVRCP_CT_NO_A2DP_SNK_START_AUDIO_AFTER_PLAY	(1ULL << 11)
+#define MPMD_A2DP_SRC_AVRCP_TG_START_AUDIO_AFTER_PLAY		(1ULL << 12)
+#define MPMD_AVRCP_CT_NO_A2DP_SNK_SUSPEND_AUDIO_AFTER_PAUSE	(1ULL << 13)
+#define MPMD_A2DP_SRC_AVRCP_TG_SUSPEND_AUDIO_AFTER_PAUSE	(1ULL << 14)
+#define MPMD_A2DP_SRC_AVRCP_TG_START_AUDIO_DURING_DATA_COMM	(1ULL << 15)
+#define MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_AUDIO_DURING_DATA_COMM	(1ULL << 16)
+#define MPMD_A2DP_SRC_AVRCP_TG_START_DATA_DURING_AUDIO		(1ULL << 17)
+#define MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_START_DATA_DURING_AUDIO	(1ULL << 18)
+
 /* Note: in spec dependency bit position starts from 1 (bit 0 unused?) */
 #define MPS_DEPS_SNIFF_MODE_DURRING_STREAMING	(1ULL << 1)
 #define MPS_DEPS_GAVDP_REQUIREMENTS		(1ULL << 2)
@@ -196,6 +216,52 @@
 			MPS_MPSD_PAN_NAP | MPS_MPSD_PAN_PANU | \
 			MPS_MPSD_PBAP_SRC | MPS_MPSD_PBAP_CLI)
 
+#define MPS_MPMD_HFP_AG MPMD_HFP_AG_CALL_TERMINATION_DURING_AVP
+
+#define MPS_MPMD_HFP_HF ( \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_ANSWER_CALL_DURING_AUDIO | \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_OUTGOING_CALL_DURING_AUDIO | \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_REJECT_CALL_DURING_AUDIO | \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_TERMINATION_DURING_AVP | \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_PLAY_DURING_CALL)
+
+#define MPS_MPMD_A2DP_SRC (MPMD_A2DP_SRC_AVRCP_TG_ANSWER_CALL_DURING_AUDIO | \
+			MPMD_A2DP_SRC_AVRCP_TG_OUTGOING_CALL_DURING_AUDIO | \
+			MPMD_A2DP_SRC_AVRCP_TG_REJECT_CALL_DURING_AUDIO | \
+			MPMD_A2DP_SRC_AVRCP_TG_TERMINATION_DURING_AVP | \
+			MPMD_A2DP_SRC_AVRCP_TG_PRESS_PLAY_DURING_CALL | \
+			MPMD_A2DP_SRC_AVRCP_TG_START_AUDIO_AFTER_PLAY | \
+			MPMD_A2DP_SRC_AVRCP_TG_SUSPEND_AUDIO_AFTER_PAUSE | \
+			MPMD_A2DP_SRC_AVRCP_TG_START_AUDIO_DURING_DATA_COMM | \
+			MPMD_A2DP_SRC_AVRCP_TG_START_DATA_DURING_AUDIO)
+
+#define MPS_MPMD_A2DP_SNK ( \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_ANSWER_CALL_DURING_AUDIO | \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_OUTGOING_CALL_DURING_AUDIO | \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_REJECT_CALL_DURING_AUDIO | \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_TERMINATION_DURING_AVP | \
+		MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_PLAY_DURING_CALL | \
+		MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_AUDIO_DURING_DATA_COMM | \
+		MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_START_DATA_DURING_AUDIO)
+
+#define MPS_MPMD_AVRCP_CT MPS_MPMD_A2DP_SNK
+
+/* should be set only if CT is supported but SNK is not supported */
+#define MPS_MPMD_AVRCP_CT_ONLY ( \
+		MPMD_AVRCP_CT_NO_A2DP_SNK_START_AUDIO_AFTER_PLAY | \
+		MPMD_AVRCP_CT_NO_A2DP_SNK_SUSPEND_AUDIO_AFTER_PAUSE)
+
+#define MPS_MPMD_AVRCP_TG MPS_MPMD_A2DP_SRC
+
+#define MPS_MPMD_DUN_DT ( \
+		MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_AUDIO_DURING_DATA_COMM | \
+		MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_START_DATA_DURING_AUDIO)
+
+#define MPS_MPMD_ALL (MPS_MPMD_HFP_AG | MPS_MPMD_HFP_HF | MPS_MPMD_A2DP_SRC | \
+			MPS_MPMD_A2DP_SNK | MPS_MPMD_AVRCP_CT | \
+			MPS_MPMD_AVRCP_CT_ONLY | MPS_MPMD_AVRCP_TG | \
+			MPS_MPMD_DUN_DT)
+
 /* Assume all dependencies are supported */
 #define MPS_DEFAULT_DEPS (MPS_DEPS_SNIFF_MODE_DURRING_STREAMING | \
 			MPS_DEPS_GAVDP_REQUIREMENTS | \
@@ -458,9 +524,34 @@ static uint64_t mps_mpsd_features(void)
 
 static uint64_t mps_mpmd_features(void)
 {
+	uint64_t feat = MPS_MPMD_ALL;
+
+	if (!class_supported(HANDSFREE_AGW_SVCLASS_ID))
+		feat &= ~MPS_MPMD_HFP_AG;
+
+	if (!class_supported(HANDSFREE_SVCLASS_ID))
+		feat &= ~MPS_MPMD_HFP_HF;
+
+	if (!class_supported(AUDIO_SOURCE_SVCLASS_ID))
+		feat &= ~MPS_MPMD_A2DP_SRC;
+
+	if (!class_supported(AUDIO_SINK_SVCLASS_ID))
+		feat &= ~MPS_MPMD_A2DP_SNK;
+	else
+		feat &= ~MPS_MPMD_AVRCP_CT_ONLY;
+
+	if (!class_supported(AV_REMOTE_CONTROLLER_SVCLASS_ID)) {
+		feat &= ~MPS_MPMD_AVRCP_CT;
+		feat &= ~MPS_MPMD_AVRCP_CT_ONLY;
+	}
+
+	if (!class_supported(AV_REMOTE_TARGET_SVCLASS_ID))
+		feat &= ~MPS_MPMD_AVRCP_TG;
+
 	/* TODO */
+	feat &= ~MPS_MPMD_DUN_DT;
 
-	return 0;
+	return feat;
 }
 
 static sdp_record_t *mps_record(int mpmd)
-- 
1.9.3


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

* [PATCH v2 3/4] android: Use common MPS implementation
  2015-02-14 13:02 [PATCH v2 1/4] sdp: Add initial support for MPS Szymon Janc
  2015-02-14 13:02 ` [PATCH v2 2/4] sdp: Add support for MPMD in MPS Szymon Janc
@ 2015-02-14 13:02 ` Szymon Janc
  2015-02-14 13:02 ` [PATCH v2 4/4] core: Add support for Multi Profile Specification Szymon Janc
  2015-02-17 17:31 ` [PATCH v2 1/4] sdp: Add initial support for MPS Szymon Janc
  3 siblings, 0 replies; 10+ messages in thread
From: Szymon Janc @ 2015-02-14 13:02 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This allow for dynamic MPS configuration ie fixing MPS on tablets.
---
 android/bluetooth.c | 109 +++++-----------------------------------------------
 1 file changed, 9 insertions(+), 100 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index fdf7b91..b99dab1 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -54,40 +54,6 @@
 #include "utils.h"
 #include "bluetooth.h"
 
-/*
- * bits in bitmask as defined in table 6.3 of Multi Profile Specification
- * HFP AG + A2DP SRC + AVRCP TG + PAN (NAP/PANU) + PBAP PSE
- */
-#define MPS_DEFAULT_MPSD ((1ULL << 0) | (1ULL << 2) | (1ULL << 4) | \
-				(1ULL << 6) | (1ULL << 8) | (1ULL << 10) | \
-				(1ULL << 12) | (1ULL << 26) | (1ULL << 28) | \
-				(1ULL << 30) | (1ULL << 32) | (1ULL << 34) | \
-				(1ULL << 36))
-
-/*
- * bits in bitmask as defined in table 6.4 of Multi Profile Specification
- * HFP AG + A2DP SRC + AVRCP TG + PAN (NAP/PANU) + PBAP PSE
- */
-#define MPS_DEFAULT_MPMD ((1ULL << 1) | (1ULL << 3) | (1ULL << 5) | \
-				(1ULL << 6) | (1ULL << 8) | (1ULL << 10) | \
-				(1ULL << 12) | (1ULL << 15) | (1ULL << 17))
-
-/*
- * bits in bitmask as defined in table 6.5 of Multi Profile Specification
- * Note that in this table spec starts bit positions from 1 (bit 0 unused?)
- */
-#define MPS_DEFAULT_DEPS ((1 << 1) | (1 << 2) | (1 << 3))
-
-/* MPSD bit dependent on HFP AG support */
-#define MPS_MPSD_HFP_AG_DEP ((1ULL << 0) | (1ULL << 2) | (1ULL << 4) | \
-				(1ULL << 6) | (1ULL << 8) | (1ULL << 10) | \
-				(1ULL << 12) | (1ULL << 14) | (1ULL << 16) | \
-				(1ULL << 18) | (1ULL << 26) | (1ULL << 28) | \
-				(1ULL << 30))
-
-/* MPMD bit dependent on HFP AG support */
-#define MPS_MPMD_HFP_AG_DEP (1ULL << 6)
-
 #define DUT_MODE_FILE "/sys/kernel/debug/bluetooth/hci%u/dut_mode"
 
 #define SETTINGS_FILE ANDROID_STORAGEDIR"/settings"
@@ -3310,75 +3276,18 @@ static void set_adapter_class(void)
 	error("Failed to set class of device");
 }
 
-static sdp_record_t *mps_record(void)
+static void enable_mps(void)
 {
-	sdp_data_t *mpsd_features, *mpmd_features, *dependencies;
-	sdp_list_t *svclass_id, *pfseq, *root;
-	uuid_t root_uuid, svclass_uuid;
-	sdp_profile_desc_t profile;
-	sdp_record_t *record;
-	uint64_t mpsd_feat, mpmd_feat;
-	uint16_t deps;
-
-	record = sdp_record_alloc();
-	if (!record)
-		return NULL;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(record, root);
-
-	sdp_uuid16_create(&svclass_uuid, MPS_SVCLASS_ID);
-	svclass_id = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, MPS_PROFILE_ID);
-	profile.version = 0x0100;
-	pfseq = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(record, pfseq);
+	uuid_t uuid, *uuid128;
 
-	mpsd_feat = MPS_DEFAULT_MPSD;
-	mpmd_feat = MPS_DEFAULT_MPMD;
-
-	/* TODO should be configurable based on HFP AG support */
-	if (false) {
-		mpsd_feat &= MPS_MPSD_HFP_AG_DEP;
-		mpmd_feat &= MPS_MPMD_HFP_AG_DEP;
-	}
-
-	mpsd_features = sdp_data_alloc(SDP_UINT64, &mpsd_feat);
-	sdp_attr_add(record, SDP_ATTR_MPSD_SCENARIOS, mpsd_features);
-
-	mpmd_features = sdp_data_alloc(SDP_UINT64, &mpmd_feat);
-	sdp_attr_add(record, SDP_ATTR_MPMD_SCENARIOS, mpmd_features);
-
-	deps = MPS_DEFAULT_DEPS;
-	dependencies = sdp_data_alloc(SDP_UINT16, &deps);
-	sdp_attr_add(record, SDP_ATTR_MPS_DEPENDENCIES, dependencies);
-
-	sdp_set_info_attr(record, "Multi Profile", 0, 0);
-
-	sdp_list_free(pfseq, NULL);
-	sdp_list_free(root, NULL);
-	sdp_list_free(svclass_id, NULL);
-
-	return record;
-}
-
-static void add_mps_record(void)
-{
-	sdp_record_t *rec;
-
-	rec = mps_record();
-	if (!rec) {
-		error("Failed to allocate MPS record");
+	sdp_uuid16_create(&uuid, MPS_PROFILE_ID);
+	uuid128 = sdp_uuid_to_uuid128(&uuid);
+	if (!uuid128)
 		return;
-	}
 
-	if (bt_adapter_add_record(rec, 0) < 0) {
-		error("Failed to register MPS record");
-		sdp_record_free(rec);
-	}
+	register_mps(true);
+	adapter.uuids = g_slist_prepend(adapter.uuids, uuid128);
+	add_uuid(0, uuid128);
 }
 
 static void clear_auto_connect_list_complete(uint8_t status,
@@ -3467,7 +3376,7 @@ static void read_info_complete(uint8_t status, uint16_t length,
 
 	set_io_capability();
 	set_device_id();
-	add_mps_record();
+	enable_mps();
 
 	missing_settings = adapter.current_settings ^
 						adapter.supported_settings;
-- 
1.9.3


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

* [PATCH v2 4/4] core: Add support for Multi Profile Specification
  2015-02-14 13:02 [PATCH v2 1/4] sdp: Add initial support for MPS Szymon Janc
  2015-02-14 13:02 ` [PATCH v2 2/4] sdp: Add support for MPMD in MPS Szymon Janc
  2015-02-14 13:02 ` [PATCH v2 3/4] android: Use common MPS implementation Szymon Janc
@ 2015-02-14 13:02 ` Szymon Janc
  2015-02-14 14:43   ` Johan Hedberg
  2015-02-14 15:34   ` [PATCH v3 " Szymon Janc
  2015-02-17 17:31 ` [PATCH v2 1/4] sdp: Add initial support for MPS Szymon Janc
  3 siblings, 2 replies; 10+ messages in thread
From: Szymon Janc @ 2015-02-14 13:02 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This adds new main.conf configure option named MultiProfile. It allows
to enable MPSD and MPMD scenarios for MPS. By default MPS is disabled.
---
 src/main.c    | 22 ++++++++++++++++++++++
 src/main.conf |  5 +++++
 2 files changed, 27 insertions(+)

diff --git a/src/main.c b/src/main.c
index b3140d0..0acab65 100644
--- a/src/main.c
+++ b/src/main.c
@@ -69,6 +69,9 @@
 struct main_opts main_opts;
 static GKeyFile *main_conf;
 
+static bool mps_mpsd = false;
+static bool mps_mpmd = false;
+
 static const char * const supported_options[] = {
 	"Name",
 	"Class",
@@ -307,6 +310,22 @@ static void parse_config(GKeyFile *config)
 		main_opts.mode = get_mode(str);
 		g_free(str);
 	}
+
+	str = g_key_file_get_string(config, "General", "MultiProfile", &err);
+	if (err) {
+		g_clear_error(&err);
+	} else {
+		DBG("MultiProfile=%s", str);
+
+		if (strcmp(str, "mpsd")) {
+			mps_mpsd = true;
+		} else if (strcmp(str, "mpmd")) {
+			mps_mpsd = true;
+			mps_mpmd = true;
+		}
+
+		g_free(str);
+	}
 }
 
 static void init_defaults(void)
@@ -599,6 +618,9 @@ int main(int argc, char *argv[])
 		register_device_id(main_opts.did_source, main_opts.did_vendor,
 				main_opts.did_product, main_opts.did_version);
 
+	if (mps_mpsd)
+		register_mps(mps_mpmd);
+
 	/* Loading plugins has to be done after D-Bus has been setup since
 	 * the plugins might wanna expose some paths on the bus. However the
 	 * best order of how to init various subsystems of the Bluetooth
diff --git a/src/main.conf b/src/main.conf
index d4d6ab0..a8f37f0 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -52,6 +52,11 @@
 # Possible values: "dual", "bredr", "le"
 #ControllerMode = dual
 
+# Enables Multi Profile Specification support. This allows to specify if
+# system supports only MPSD or both MPSD/MPMD scenarios.
+# Possible values: "mpsd", "mpmd"
+#MultiProfile = mpsd
+
 #[Policy]
 #
 # The ReconnectUUIDs defines the set of remote services that should try
-- 
1.9.3


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

* Re: [PATCH v2 4/4] core: Add support for Multi Profile Specification
  2015-02-14 13:02 ` [PATCH v2 4/4] core: Add support for Multi Profile Specification Szymon Janc
@ 2015-02-14 14:43   ` Johan Hedberg
  2015-02-14 14:51     ` Szymon Janc
  2015-02-14 15:34   ` [PATCH v3 " Szymon Janc
  1 sibling, 1 reply; 10+ messages in thread
From: Johan Hedberg @ 2015-02-14 14:43 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth

Hi Szymon,

On Sat, Feb 14, 2015, Szymon Janc wrote:
> +	str = g_key_file_get_string(config, "General", "MultiProfile", &err);
> +	if (err) {
> +		g_clear_error(&err);
> +	} else {
> +		DBG("MultiProfile=%s", str);
> +
> +		if (strcmp(str, "mpsd")) {
> +			mps_mpsd = true;
> +		} else if (strcmp(str, "mpmd")) {
> +			mps_mpsd = true;
> +			mps_mpmd = true;
> +		}

Shouldn't these be '!strcmp'?

Johan

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

* Re: [PATCH v2 4/4] core: Add support for Multi Profile Specification
  2015-02-14 14:43   ` Johan Hedberg
@ 2015-02-14 14:51     ` Szymon Janc
  0 siblings, 0 replies; 10+ messages in thread
From: Szymon Janc @ 2015-02-14 14:51 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth

Hi Johan,

On Saturday 14 of February 2015 16:43:50 Johan Hedberg wrote:
> Hi Szymon,
> 
> On Sat, Feb 14, 2015, Szymon Janc wrote:
> > +	str = g_key_file_get_string(config, "General", "MultiProfile", &err);
> > +	if (err) {
> > +		g_clear_error(&err);
> > +	} else {
> > +		DBG("MultiProfile=%s", str);
> > +
> > +		if (strcmp(str, "mpsd")) {
> > +			mps_mpsd = true;
> > +		} else if (strcmp(str, "mpmd")) {
> > +			mps_mpsd = true;
> > +			mps_mpmd = true;
> > +		}
> 
> Shouldn't these be '!strcmp'?
> 
> Johan

They should. I'll send V3 of this patch shortly.

-- 
BR
Szymon Janc

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

* [PATCH v3 4/4] core: Add support for Multi Profile Specification
  2015-02-14 13:02 ` [PATCH v2 4/4] core: Add support for Multi Profile Specification Szymon Janc
  2015-02-14 14:43   ` Johan Hedberg
@ 2015-02-14 15:34   ` Szymon Janc
  2015-02-14 19:59     ` Marcel Holtmann
  2015-02-15 15:43     ` [PATCH v4 " Szymon Janc
  1 sibling, 2 replies; 10+ messages in thread
From: Szymon Janc @ 2015-02-14 15:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This adds new main.conf configure option named MultiProfile. It allows
to enable MPSD and MPMD scenarios for MPS. By default MPS is disabled.
---
V3: - fixed string checks when parsing option
    - added MultiProfile to list of known options

 src/main.c    | 23 +++++++++++++++++++++++
 src/main.conf |  5 +++++
 2 files changed, 28 insertions(+)

diff --git a/src/main.c b/src/main.c
index b3140d0..0af3ed9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -69,6 +69,9 @@
 struct main_opts main_opts;
 static GKeyFile *main_conf;
 
+static bool mps_mpsd = false;
+static bool mps_mpmd = false;
+
 static const char * const supported_options[] = {
 	"Name",
 	"Class",
@@ -81,6 +84,7 @@ static const char * const supported_options[] = {
 	"NameResolving",
 	"DebugKeys",
 	"ControllerMode",
+	"MultiProfile",
 };
 
 GKeyFile *btd_get_main_conf(void)
@@ -307,6 +311,22 @@ static void parse_config(GKeyFile *config)
 		main_opts.mode = get_mode(str);
 		g_free(str);
 	}
+
+	str = g_key_file_get_string(config, "General", "MultiProfile", &err);
+	if (err) {
+		g_clear_error(&err);
+	} else {
+		DBG("MultiProfile=%s", str);
+
+		if (!strcmp(str, "mpsd")) {
+			mps_mpsd = true;
+		} else if (!strcmp(str, "mpmd")) {
+			mps_mpsd = true;
+			mps_mpmd = true;
+		}
+
+		g_free(str);
+	}
 }
 
 static void init_defaults(void)
@@ -599,6 +619,9 @@ int main(int argc, char *argv[])
 		register_device_id(main_opts.did_source, main_opts.did_vendor,
 				main_opts.did_product, main_opts.did_version);
 
+	if (mps_mpsd)
+		register_mps(mps_mpmd);
+
 	/* Loading plugins has to be done after D-Bus has been setup since
 	 * the plugins might wanna expose some paths on the bus. However the
 	 * best order of how to init various subsystems of the Bluetooth
diff --git a/src/main.conf b/src/main.conf
index d4d6ab0..a8f37f0 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -52,6 +52,11 @@
 # Possible values: "dual", "bredr", "le"
 #ControllerMode = dual
 
+# Enables Multi Profile Specification support. This allows to specify if
+# system supports only MPSD or both MPSD/MPMD scenarios.
+# Possible values: "mpsd", "mpmd"
+#MultiProfile = mpsd
+
 #[Policy]
 #
 # The ReconnectUUIDs defines the set of remote services that should try
-- 
1.9.3


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

* Re: [PATCH v3 4/4] core: Add support for Multi Profile Specification
  2015-02-14 15:34   ` [PATCH v3 " Szymon Janc
@ 2015-02-14 19:59     ` Marcel Holtmann
  2015-02-15 15:43     ` [PATCH v4 " Szymon Janc
  1 sibling, 0 replies; 10+ messages in thread
From: Marcel Holtmann @ 2015-02-14 19:59 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth

Hi Szymon,

> This adds new main.conf configure option named MultiProfile. It allows
> to enable MPSD and MPMD scenarios for MPS. By default MPS is disabled.
> ---
> V3: - fixed string checks when parsing option
>    - added MultiProfile to list of known options
> 
> src/main.c    | 23 +++++++++++++++++++++++
> src/main.conf |  5 +++++
> 2 files changed, 28 insertions(+)
> 
> diff --git a/src/main.c b/src/main.c
> index b3140d0..0af3ed9 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -69,6 +69,9 @@
> struct main_opts main_opts;
> static GKeyFile *main_conf;
> 
> +static bool mps_mpsd = false;
> +static bool mps_mpmd = false;
> +
> static const char * const supported_options[] = {
> 	"Name",
> 	"Class",
> @@ -81,6 +84,7 @@ static const char * const supported_options[] = {
> 	"NameResolving",
> 	"DebugKeys",
> 	"ControllerMode",
> +	"MultiProfile",
> };
> 
> GKeyFile *btd_get_main_conf(void)
> @@ -307,6 +311,22 @@ static void parse_config(GKeyFile *config)
> 		main_opts.mode = get_mode(str);
> 		g_free(str);
> 	}
> +
> +	str = g_key_file_get_string(config, "General", "MultiProfile", &err);
> +	if (err) {
> +		g_clear_error(&err);
> +	} else {
> +		DBG("MultiProfile=%s", str);
> +
> +		if (!strcmp(str, "mpsd")) {
> +			mps_mpsd = true;
> +		} else if (!strcmp(str, "mpmd")) {
> +			mps_mpsd = true;
> +			mps_mpmd = true;
> +		}
> +
> +		g_free(str);
> +	}
> }
> 
> static void init_defaults(void)
> @@ -599,6 +619,9 @@ int main(int argc, char *argv[])
> 		register_device_id(main_opts.did_source, main_opts.did_vendor,
> 				main_opts.did_product, main_opts.did_version);
> 
> +	if (mps_mpsd)
> +		register_mps(mps_mpmd);
> +
> 	/* Loading plugins has to be done after D-Bus has been setup since
> 	 * the plugins might wanna expose some paths on the bus. However the
> 	 * best order of how to init various subsystems of the Bluetooth
> diff --git a/src/main.conf b/src/main.conf
> index d4d6ab0..a8f37f0 100644
> --- a/src/main.conf
> +++ b/src/main.conf
> @@ -52,6 +52,11 @@
> # Possible values: "dual", "bredr", "le"
> #ControllerMode = dual
> 
> +# Enables Multi Profile Specification support. This allows to specify if
> +# system supports only MPSD or both MPSD/MPMD scenarios.
> +# Possible values: "mpsd", "mpmd"
> +#MultiProfile = mpsd
> +

actually the commented out entry should be the default\x10. So you need off, mpsd and mpmd here. However since these stand for single device and multiple device, then why not actually name it in plain English.

So "off", "single" and "multiple" with "off" being the default. And then have the text refer to Multiple Profile Single Device (MPSD) and Multiple Profile Multiple Devices (MPMD). So that specification readers know what each option maps to.

Regards

Marcel


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

* [PATCH v4 4/4] core: Add support for Multi Profile Specification
  2015-02-14 15:34   ` [PATCH v3 " Szymon Janc
  2015-02-14 19:59     ` Marcel Holtmann
@ 2015-02-15 15:43     ` Szymon Janc
  1 sibling, 0 replies; 10+ messages in thread
From: Szymon Janc @ 2015-02-15 15:43 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This adds new main.conf configure option named MultiProfile. It allows
to enable MPSD and MPMD scenarios for MPS. By default MPS is disabled.
---
 src/main.c    | 23 +++++++++++++++++++++++
 src/main.conf |  7 +++++++
 2 files changed, 30 insertions(+)

diff --git a/src/main.c b/src/main.c
index b3140d0..54cbeb0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -69,6 +69,9 @@
 struct main_opts main_opts;
 static GKeyFile *main_conf;
 
+static bool mps_mpsd = false;
+static bool mps_mpmd = false;
+
 static const char * const supported_options[] = {
 	"Name",
 	"Class",
@@ -81,6 +84,7 @@ static const char * const supported_options[] = {
 	"NameResolving",
 	"DebugKeys",
 	"ControllerMode",
+	"MultiProfile",
 };
 
 GKeyFile *btd_get_main_conf(void)
@@ -307,6 +311,22 @@ static void parse_config(GKeyFile *config)
 		main_opts.mode = get_mode(str);
 		g_free(str);
 	}
+
+	str = g_key_file_get_string(config, "General", "MultiProfile", &err);
+	if (err) {
+		g_clear_error(&err);
+	} else {
+		DBG("MultiProfile=%s", str);
+
+		if (!strcmp(str, "single")) {
+			mps_mpsd = true;
+		} else if (!strcmp(str, "multiple")) {
+			mps_mpsd = true;
+			mps_mpmd = true;
+		}
+
+		g_free(str);
+	}
 }
 
 static void init_defaults(void)
@@ -599,6 +619,9 @@ int main(int argc, char *argv[])
 		register_device_id(main_opts.did_source, main_opts.did_vendor,
 				main_opts.did_product, main_opts.did_version);
 
+	if (mps_mpsd)
+		register_mps(mps_mpmd);
+
 	/* Loading plugins has to be done after D-Bus has been setup since
 	 * the plugins might wanna expose some paths on the bus. However the
 	 * best order of how to init various subsystems of the Bluetooth
diff --git a/src/main.conf b/src/main.conf
index d4d6ab0..9be90af 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -52,6 +52,13 @@
 # Possible values: "dual", "bredr", "le"
 #ControllerMode = dual
 
+# Enables Multi Profile Specification support. This allows to specify if
+# system supports only Multiple Profiles Single Device (MPSD) configuration
+# or both Multiple Profiles Single Device (MPSD) and Multiple Profiles Multiple
+# Devices (MPMD) configurations.
+# Possible values: "off", "single", "multiple"
+#MultiProfile = off
+
 #[Policy]
 #
 # The ReconnectUUIDs defines the set of remote services that should try
-- 
1.9.3


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

* Re: [PATCH v2 1/4] sdp: Add initial support for MPS
  2015-02-14 13:02 [PATCH v2 1/4] sdp: Add initial support for MPS Szymon Janc
                   ` (2 preceding siblings ...)
  2015-02-14 13:02 ` [PATCH v2 4/4] core: Add support for Multi Profile Specification Szymon Janc
@ 2015-02-17 17:31 ` Szymon Janc
  3 siblings, 0 replies; 10+ messages in thread
From: Szymon Janc @ 2015-02-17 17:31 UTC (permalink / raw)
  To: linux-bluetooth

On Saturday 14 of February 2015 14:02:23 Szymon Janc wrote:
> This allows to register Multi Profile Specification record with proper
> MPSD bits set depending on currently registered services.
> 
> Service Name: Multi Profile
> Service RecHandle: 0x10001
> Service Class ID List:
>   "" (0x113b)
> Profile Descriptor List:
>   "" (0x113a)
>     Version: 0x0100
> ---
> V2: use defines for feature bits
> 
>  src/main.c          |   1 +
>  src/sdpd-database.c |   1 +
>  src/sdpd-request.c  |   1 +
>  src/sdpd-server.c   |   1 +
>  src/sdpd-service.c  | 321
> +++++++++++++++++++++++++++++++++++++++++++++++++++- src/sdpd.h          | 
>  1 +
>  6 files changed, 325 insertions(+), 1 deletion(-)
> 
> diff --git a/src/main.c b/src/main.c
> index 061060d..b3140d0 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -33,6 +33,7 @@
>  #include <stdlib.h>
>  #include <string.h>
>  #include <signal.h>
> +#include <stdbool.h>
>  #include <sys/signalfd.h>
>  #include <sys/types.h>
>  #include <sys/stat.h>
> diff --git a/src/sdpd-database.c b/src/sdpd-database.c
> index 6f5577b..e3b9e09 100644
> --- a/src/sdpd-database.c
> +++ b/src/sdpd-database.c
> @@ -29,6 +29,7 @@
>  #endif
> 
>  #include <stdlib.h>
> +#include <stdbool.h>
> 
>  #include <bluetooth/bluetooth.h>
>  #include <bluetooth/sdp.h>
> diff --git a/src/sdpd-request.c b/src/sdpd-request.c
> index 3e58c22..081e7c8 100644
> --- a/src/sdpd-request.c
> +++ b/src/sdpd-request.c
> @@ -31,6 +31,7 @@
>  #include <errno.h>
>  #include <stdlib.h>
>  #include <limits.h>
> +#include <stdbool.h>
> 
>  #include <bluetooth/bluetooth.h>
>  #include <bluetooth/l2cap.h>
> diff --git a/src/sdpd-server.c b/src/sdpd-server.c
> index 015551d..8ecda9b 100644
> --- a/src/sdpd-server.c
> +++ b/src/sdpd-server.c
> @@ -31,6 +31,7 @@
>  #include <errno.h>
>  #include <unistd.h>
>  #include <stdlib.h>
> +#include <stdbool.h>
>  #include <sys/stat.h>
> 
>  #include <bluetooth/bluetooth.h>
> diff --git a/src/sdpd-service.c b/src/sdpd-service.c
> index a90b299..abd48e7 100644
> --- a/src/sdpd-service.c
> +++ b/src/sdpd-service.c
> @@ -32,6 +32,7 @@
>  #include <stdlib.h>
>  #include <assert.h>
>  #include <sys/time.h>
> +#include <stdbool.h>
> 
>  #include <bluetooth/bluetooth.h>
>  #include <bluetooth/sdp.h>
> @@ -43,6 +44,163 @@
>  #include "sdpd.h"
>  #include "log.h"
> 
> +#define MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO		(1ULL << 0)
> +#define MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO		(1ULL << 1)
> +#define MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO		(1ULL << 2)
> +#define MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO		(1ULL << 3)
> +#define MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO		(1ULL << 4)
> +#define MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO	(1ULL << 5)
> +#define MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP		(1ULL << 6)
> +#define MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP		(1ULL << 7)
> +#define MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL	(1ULL << 8)
> +#define MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL	(1ULL << 9)
> +#define MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY	(1ULL << 10)
> +#define MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY	(1ULL << 11)
> +#define MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE	(1ULL << 12)
> +#define MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE	(1ULL << 13)
> +#define MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL		(1ULL << 14)
> +#define MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL		(1ULL << 15)
> +#define MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM	(1ULL << 16)
> +#define MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM	(1ULL << 17)
> +#define MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM	(1ULL << 18)
> +#define MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM	(1ULL << 19)
> +#define MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM	(1ULL << 20)
> +#define MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM	(1ULL << 21)
> +#define MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM	(1ULL << 22)
> +#define MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM	(1ULL << 23)
> +#define MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM	(1ULL << 24)
> +#define MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM	(1ULL << 25)
> +#define MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL		(1ULL << 26)
> +#define MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL	(1ULL << 27)
> +#define MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM	(1ULL << 28)
> +#define MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM	(1ULL << 29)
> +#define MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM	(1ULL << 30)
> +#define MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM	(1ULL << 31)
> +#define MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM	(1ULL << 32)
> +#define MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM	(1ULL << 33)
> +#define MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM	(1ULL << 34)
> +#define MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM	(1ULL << 35)
> +#define MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM	(1ULL << 36)
> +#define MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM	(1ULL << 37)
> +
> +/* Note: in spec dependency bit position starts from 1 (bit 0 unused?) */
> +#define MPS_DEPS_SNIFF_MODE_DURRING_STREAMING	(1ULL << 1)
> +#define MPS_DEPS_GAVDP_REQUIREMENTS		(1ULL << 2)
> +#define MPS_DEPS_DIS_CONNECTION_ORDER_BEHAVIOR	(1ULL << 3)
> +
> +/*
> + * default MPS features are all disabled, will be updated if relevant
> service + * is (un)registered
> + */
> +#define MPS_MPSD_DEFAULT_FEATURES 0
> +#define MPS_MPMD_DEFAULT_FEATURES 0
> +
> +/*
> + * Those defines bits for all features that depend on specific profile and
> role. + * If profile is not supported then all those bits should not be set
> in record + */
> +#define MPS_MPSD_HFP_AG (MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO | \
> +			MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO | \
> +			MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO | \
> +			MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP | \
> +			MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL | \
> +			MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY | \
> +			MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL | \
> +			MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
> +			MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL | \
> +			MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM)
> +
> +#define MPS_MPSD_HFP_HF (MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO | \
> +			MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO | \
> +			MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO | \
> +			MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP | \
> +			MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL | \
> +			MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY | \
> +			MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
> +			MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL | \
> +			MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL | \
> +			MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM)
> +
> +#define MPS_MPSD_A2DP_SRC (MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO |
> \ +			MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO | \
> +			MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO | \
> +			MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP | \
> +			MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL | \
> +			MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY | \
> +			MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
> +			MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM | \
> +			MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM | \
> +			MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM | \
> +			MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM | \
> +			MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM)
> +
> +#define MPS_MPSD_A2DP_SNK (MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO |
> \ +			MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO | \
> +			MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO | \
> +			MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP | \
> +			MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL | \
> +			MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY | \
> +			MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
> +			MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM | \
> +			MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM | \
> +			MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM | \
> +			MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM | \
> +			MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM)
> +
> +#define MPS_MPSD_AVRCP_CT MPS_MPSD_A2DP_SNK
> +
> +#define MPS_MPSD_AVRCP_TG MPS_MPSD_A2DP_SRC
> +
> +#define MPS_MPSD_DUN_GW (MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL | \
> +			MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM | \
> +			MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM | \
> +			MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM | \
> +			MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM)
> +
> +#define MPS_MPSD_DUN_DT (MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL | \
> +			MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM | \
> +			MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM | \
> +			MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM | \
> +			MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM)
> +
> +#define MPS_MPSD_PAN_NAP (MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL |
> \ +			MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM | \
> +			MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM | \
> +			MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM)
> +
> +#define MPS_MPSD_PAN_PANU (MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL
> | \ +			MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM | \
> +			MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM | \
> +			MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM | \
> +			MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM)
> +
> +#define MPS_MPSD_PBAP_SRC MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM
> +
> +#define MPS_MPSD_PBAP_CLI MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM
> +
> +#define MPS_MPSD_ALL (MPS_MPSD_HFP_AG | MPS_MPSD_HFP_HF | \
> +			MPS_MPSD_A2DP_SRC | MPS_MPSD_A2DP_SNK | \
> +			MPS_MPSD_AVRCP_CT | MPS_MPSD_AVRCP_TG | \
> +			MPS_MPSD_DUN_GW | MPS_MPSD_DUN_DT | \
> +			MPS_MPSD_PAN_NAP | MPS_MPSD_PAN_PANU | \
> +			MPS_MPSD_PBAP_SRC | MPS_MPSD_PBAP_CLI)
> +
> +/* Assume all dependencies are supported */
> +#define MPS_DEFAULT_DEPS (MPS_DEPS_SNIFF_MODE_DURRING_STREAMING | \
> +			MPS_DEPS_GAVDP_REQUIREMENTS | \
> +			MPS_DEPS_DIS_CONNECTION_ORDER_BEHAVIOR)
> +
>  static sdp_record_t *server = NULL;
>  static uint32_t fixed_dbts = 0;
> 
> @@ -55,6 +213,9 @@ static sdp_version_t sdpVnumArray[1] = {
>  };
>  static const int sdpServerVnumEntries = 1;
> 
> +static uint32_t mps_handle = 0;
> +static bool mps_mpmd = false;
> +
>  /*
>   * A simple function which returns the time of day in
>   * seconds. Used for updating the service db state
> @@ -235,6 +396,161 @@ void register_device_id(uint16_t source, uint16_t
> vendor, update_db_timestamp();
>  }
> 
> +static bool class_supported(uint16_t class)
> +{
> +	sdp_list_t *list;
> +	uuid_t uuid;
> +
> +	sdp_uuid16_create(&uuid, class);
> +
> +	for (list = sdp_get_record_list(); list; list = list->next) {
> +		sdp_record_t *rec = list->data;
> +
> +		if (sdp_uuid_cmp(&rec->svclass, &uuid) == 0)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static uint64_t mps_mpsd_features(void)
> +{
> +	uint64_t feat = MPS_MPSD_ALL;
> +
> +	if (!class_supported(HANDSFREE_AGW_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_HFP_AG;
> +
> +	if (!class_supported(HANDSFREE_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_HFP_HF;
> +
> +	if (!class_supported(AUDIO_SOURCE_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_A2DP_SRC;
> +
> +	if (!class_supported(AUDIO_SINK_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_A2DP_SNK;
> +
> +	if (!class_supported(AV_REMOTE_CONTROLLER_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_AVRCP_CT;
> +
> +	if (!class_supported(AV_REMOTE_TARGET_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_AVRCP_TG;
> +
> +	if (!class_supported(DIALUP_NET_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_DUN_GW;
> +
> +	/* TODO */
> +	feat &= ~MPS_MPSD_DUN_DT;
> +
> +	if (!class_supported(NAP_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_PAN_NAP;
> +
> +	if (!class_supported(PANU_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_PAN_PANU;
> +
> +	if (!class_supported(PBAP_PSE_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_PBAP_SRC;
> +
> +	if (!class_supported(PBAP_PCE_SVCLASS_ID))
> +		feat &= ~MPS_MPSD_PBAP_CLI;
> +
> +	return feat;
> +}
> +
> +static uint64_t mps_mpmd_features(void)
> +{
> +	/* TODO */
> +
> +	return 0;
> +}
> +
> +static sdp_record_t *mps_record(int mpmd)
> +{
> +	sdp_data_t *mpsd_features, *mpmd_features, *dependencies;
> +	sdp_list_t *svclass_id, *pfseq, *root;
> +	uuid_t root_uuid, svclass_uuid;
> +	sdp_profile_desc_t profile;
> +	sdp_record_t *record;
> +	uint64_t mpsd_feat = MPS_MPSD_DEFAULT_FEATURES;
> +	uint64_t mpmd_feat = MPS_MPMD_DEFAULT_FEATURES;
> +	uint16_t deps = MPS_DEFAULT_DEPS;
> +
> +	record = sdp_record_alloc();
> +	if (!record)
> +		return NULL;
> +
> +	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
> +	root = sdp_list_append(NULL, &root_uuid);
> +	sdp_set_browse_groups(record, root);
> +	sdp_list_free(root, NULL);
> +
> +	sdp_uuid16_create(&svclass_uuid, MPS_SVCLASS_ID);
> +	svclass_id = sdp_list_append(NULL, &svclass_uuid);
> +	sdp_set_service_classes(record, svclass_id);
> +	sdp_list_free(svclass_id, NULL);
> +
> +	sdp_uuid16_create(&profile.uuid, MPS_PROFILE_ID);
> +	profile.version = 0x0100;
> +	pfseq = sdp_list_append(NULL, &profile);
> +	sdp_set_profile_descs(record, pfseq);
> +	sdp_list_free(pfseq, NULL);
> +
> +	mpsd_features = sdp_data_alloc(SDP_UINT64, &mpsd_feat);
> +	sdp_attr_add(record, SDP_ATTR_MPSD_SCENARIOS, mpsd_features);
> +
> +	if (mpmd) {
> +		mpmd_features = sdp_data_alloc(SDP_UINT64, &mpmd_feat);
> +		sdp_attr_add(record, SDP_ATTR_MPMD_SCENARIOS, mpmd_features);
> +	}
> +
> +	dependencies = sdp_data_alloc(SDP_UINT16, &deps);
> +	sdp_attr_add(record, SDP_ATTR_MPS_DEPENDENCIES, dependencies);
> +
> +	sdp_set_info_attr(record, "Multi Profile", 0, 0);
> +
> +	return record;
> +}
> +
> +void register_mps(bool mpmd)
> +{
> +	sdp_record_t *record;
> +
> +	record = mps_record(mpmd);
> +	if (!record)
> +		return;
> +
> +	if (add_record_to_server(BDADDR_ANY, record) < 0) {
> +		sdp_record_free(record);
> +		return;
> +	}
> +
> +	mps_handle = record->handle;
> +	mps_mpmd = mpmd;
> +}
> +
> +static void update_mps(void)
> +{
> +	sdp_record_t *rec;
> +	sdp_data_t *data;
> +	uint64_t mpsd_feat, mpmd_feat;
> +
> +	if (!mps_handle)
> +		return;
> +
> +	rec = sdp_record_find(mps_handle);
> +	if (!rec)
> +		return;
> +
> +	mpsd_feat = mps_mpsd_features();
> +	data = sdp_data_alloc(SDP_UINT64, &mpsd_feat);
> +	sdp_attr_replace(rec, SDP_ATTR_MPSD_SCENARIOS, data);
> +
> +	if (mps_mpmd) {
> +		mpmd_feat = mps_mpmd_features();
> +		data = sdp_data_alloc(SDP_UINT64, &mpmd_feat);
> +		sdp_attr_replace(rec, SDP_ATTR_MPMD_SCENARIOS, data);
> +	}
> +}
> +
>  int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
>  {
>  	sdp_data_t *data;
> @@ -272,6 +588,7 @@ int add_record_to_server(const bdaddr_t *src,
> sdp_record_t *rec) DBG("Record pattern UUID %s", uuid);
>  	}
> 
> +	update_mps();
>  	update_db_timestamp();
> 
>  	return 0;
> @@ -291,8 +608,10 @@ int remove_record_from_server(uint32_t handle)
>  	if (!rec)
>  		return -ENOENT;
> 
> -	if (sdp_record_remove(handle) == 0)
> +	if (sdp_record_remove(handle) == 0) {
> +		update_mps();
>  		update_db_timestamp();
> +	}
> 
>  	sdp_record_free(rec);
> 
> diff --git a/src/sdpd.h b/src/sdpd.h
> index 6de0af7..4425c87 100644
> --- a/src/sdpd.h
> +++ b/src/sdpd.h
> @@ -58,6 +58,7 @@ void register_public_browse_group(void);
>  void register_server_service(void);
>  void register_device_id(uint16_t source, uint16_t vendor,
>  					uint16_t product, uint16_t version);
> +void register_mps(bool mpmd);
> 
>  int record_sort(const void *r1, const void *r2);
>  void sdp_svcdb_reset(void);

Applied.

-- 
BR
Szymon Janc

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

end of thread, other threads:[~2015-02-17 17:31 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-14 13:02 [PATCH v2 1/4] sdp: Add initial support for MPS Szymon Janc
2015-02-14 13:02 ` [PATCH v2 2/4] sdp: Add support for MPMD in MPS Szymon Janc
2015-02-14 13:02 ` [PATCH v2 3/4] android: Use common MPS implementation Szymon Janc
2015-02-14 13:02 ` [PATCH v2 4/4] core: Add support for Multi Profile Specification Szymon Janc
2015-02-14 14:43   ` Johan Hedberg
2015-02-14 14:51     ` Szymon Janc
2015-02-14 15:34   ` [PATCH v3 " Szymon Janc
2015-02-14 19:59     ` Marcel Holtmann
2015-02-15 15:43     ` [PATCH v4 " Szymon Janc
2015-02-17 17:31 ` [PATCH v2 1/4] sdp: Add initial support for MPS Szymon Janc

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.