summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Ranostay <matt.ranostay@konsulko.com>2018-11-12 00:55:01 -0800
committerMatt Ranostay <matt.ranostay@konsulko.com>2018-11-21 15:41:13 -0800
commit246361069bf6bf973847b5365c17d91bdee07aa6 (patch)
tree4bd05e12b230f481989cd9a034ae00b69ef0cad7
parenta3f73d2a1846b7a1c656674a9d5f96d5d914a545 (diff)
binding: mediaplayer: add avrcp support
Proxy avrcp metadata from bluetooth binding to mediaplayer service subscribers. Also allow transparent access to local and avrcp controls. Bug-AGL: SPEC-1630 Change-Id: I75cfd71ee62976a9312474b81469b8eb13a06015 Signed-off-by: Matt Ranostay <matt.ranostay@konsulko.com>
-rw-r--r--binding/afm-common.c19
-rw-r--r--binding/afm-common.h3
-rw-r--r--binding/afm-mediaplayer-binding.c134
-rw-r--r--conf.d/wgt/config-4a.xml.in1
-rw-r--r--conf.d/wgt/config.xml.in4
5 files changed, 132 insertions, 29 deletions
diff --git a/binding/afm-common.c b/binding/afm-common.c
index ec68b8d..93e6f54 100644
--- a/binding/afm-common.c
+++ b/binding/afm-common.c
@@ -19,7 +19,7 @@
#include "afm-common.h"
-const char *control_commands[] = {
+const char *gstreamer_control_commands[] = {
"play",
"pause",
"previous",
@@ -33,6 +33,21 @@ const char *control_commands[] = {
"stop",
};
+/* NULLs signal this functional isn't available */
+const char *avrcp_control_commands[] = {
+ "Play",
+ "Pause",
+ "Previous",
+ "Next",
+ NULL,
+ "FastForward",
+ "Rewind",
+ NULL,
+ NULL,
+ NULL,
+ "Stop",
+};
+
int get_command_index(const char *name)
{
int i;
@@ -41,7 +56,7 @@ int get_command_index(const char *name)
return -EINVAL;
for (i = 0; i < NUM_CMDS; i++) {
- if (!strcasecmp(control_commands[i], name))
+ if (!strcasecmp(gstreamer_control_commands[i], name))
return i;
}
diff --git a/binding/afm-common.h b/binding/afm-common.h
index 34258da..0439aa9 100644
--- a/binding/afm-common.h
+++ b/binding/afm-common.h
@@ -53,7 +53,8 @@ enum {
NUM_CMDS
};
-const char *control_commands[NUM_CMDS];
+const char *avrcp_control_commands[NUM_CMDS];
+const char *gstreamer_control_commands[NUM_CMDS];
int get_command_index(const char *name);
GList *find_media_index(GList *list, long int index);
void g_free_playlist_item(void *ptr);
diff --git a/binding/afm-mediaplayer-binding.c b/binding/afm-mediaplayer-binding.c
index d8efe37..6e85fa1 100644
--- a/binding/afm-mediaplayer-binding.c
+++ b/binding/afm-mediaplayer-binding.c
@@ -48,6 +48,9 @@ typedef struct _CustomData {
long int volume;
gint64 position;
gint64 duration;
+
+ /* avrcp */
+ gboolean avrcp_connected;
} CustomData;
CustomData data = {
@@ -328,34 +331,47 @@ static int seek_track(int cmd)
return 0;
}
-/* @value can be one of the following values:
- * play - go to playing transition
- * pause - go to pause transition
- * previous - skip to previous track
- * next - skip to the next track
- * seek - go to position (in milliseconds)
- *
- * fast-forward - skip forward in milliseconds
- * rewind - skip backward in milliseconds
- *
- * pick-track - select track via index number
- * volume - set volume between 0 - 100%
- * loop - set looping of playlist (true or false)
- */
+static void avrcp_controls(afb_req_t request)
+{
+ const char *value = afb_req_value(request, "value");
+ const char *action = NULL;
+ afb_api_t api = afb_req_get_api(request);
+ int cmd = get_command_index(value), ret;
+ json_object *response, *jresp = NULL;
-static void controls(afb_req_t request)
+ if (cmd < 0) {
+ afb_req_fail(request, "failed", "unknown command");
+ return;
+ }
+
+ action = avrcp_control_commands[cmd];
+ if (!action) {
+ afb_req_fail(request, "failed", "command not supported");
+ return;
+ }
+
+ jresp = json_object_new_object();
+ json_object_object_add(jresp, "action", json_object_new_string(action));
+
+ ret = afb_api_call_sync(api, "Bluetooth-Manager",
+ "avrcp_controls", jresp, &response, NULL, NULL);
+ json_object_put(response);
+
+ if (ret < 0) {
+ afb_req_fail(request, "failed", "cannot request avrcp_control");
+ return;
+ }
+
+ afb_req_success(request, NULL, NULL);
+}
+
+static void gstreamer_controls(afb_req_t request)
{
const char *value = afb_req_value(request, "value");
const char *position = afb_req_value(request, "position");
int cmd = get_command_index(value);
json_object *jresp = NULL;
- if (!value) {
- afb_req_fail(request, "failed", "no value was passed");
- return;
- }
-
- pthread_mutex_lock(&mutex);
errno = 0;
switch (cmd) {
@@ -368,7 +384,6 @@ static void controls(afb_req_t request)
if (current_track && current_track->data)
set_media_uri(current_track->data);
else {
- pthread_mutex_unlock(&mutex);
afb_req_fail(request, "failed", "No playlist");
return;
}
@@ -407,7 +422,6 @@ static void controls(afb_req_t request)
if (idx == 0 && errno) {
afb_req_fail(request, "failed", "invalid index");
- pthread_mutex_unlock(&mutex);
return;
}
@@ -419,7 +433,6 @@ static void controls(afb_req_t request)
current_track = list;
} else {
afb_req_fail(request, "failed", "couldn't find index");
- pthread_mutex_unlock(&mutex);
return;
}
@@ -431,7 +444,6 @@ static void controls(afb_req_t request)
if (volume == 0 && errno) {
afb_req_fail(request, "failed", "invalid volume");
- pthread_mutex_unlock(&mutex);
return;
}
@@ -458,11 +470,41 @@ static void controls(afb_req_t request)
break;
default:
afb_req_fail(request, "failed", "unknown command");
- pthread_mutex_unlock(&mutex);
return;
}
afb_req_success(request, jresp, NULL);
+}
+
+/* @value can be one of the following values:
+ * play - go to playing transition
+ * pause - go to pause transition
+ * previous - skip to previous track
+ * next - skip to the next track
+ * seek - go to position (in milliseconds)
+ *
+ * fast-forward - skip forward in milliseconds
+ * rewind - skip backward in milliseconds
+ *
+ * pick-track - select track via index number
+ * volume - set volume between 0 - 100%
+ * loop - set looping of playlist (true or false)
+ */
+
+static void controls(afb_req_t request)
+{
+ const char *value = afb_req_value(request, "value");
+
+ if (!value) {
+ afb_req_fail(request, "failed", "no value was passed");
+ return;
+ }
+
+ pthread_mutex_lock(&mutex);
+ if (data.avrcp_connected)
+ avrcp_controls(request);
+ else
+ gstreamer_controls(request);
pthread_mutex_unlock(&mutex);
}
@@ -587,11 +629,31 @@ static void metadata(afb_req_t request)
afb_req_success(request, jresp, "Metadata results");
}
+static int bluetooth_subscribe(afb_api_t api)
+{
+ json_object *response, *query;
+ int ret;
+
+ query = json_object_new_object();
+ json_object_object_add(query, "value", json_object_new_string("media"));
+
+ ret = afb_api_call_sync(api, "Bluetooth-Manager", "subscribe", query, &response, NULL, NULL);
+ json_object_put(response);
+
+ if (ret < 0) {
+ AFB_ERROR("Cannot subscribe to Bluetooth media event");
+ return ret;
+ }
+
+ return 0;
+}
+
static void subscribe(afb_req_t request)
{
const char *value = afb_req_value(request, "value");
if (!strcasecmp(value, "metadata")) {
+ afb_api_t api = afb_req_get_api(request);
json_object *jresp = NULL;
afb_req_subscribe(request, metadata_event);
@@ -603,6 +665,8 @@ static void subscribe(afb_req_t request)
afb_event_push(metadata_event, jresp);
+ bluetooth_subscribe(api);
+
return;
} else if (!strcasecmp(value, "playlist")) {
json_object *jresp = json_object_new_object();
@@ -860,6 +924,24 @@ static void onevent(afb_api_t api, const char *event, struct json_object *object
if (current_track == NULL)
current_track = g_list_first(playlist);
+ } else if (!g_ascii_strcasecmp(event, "Bluetooth-Manager/media")) {
+ json_object *val;
+
+ pthread_mutex_lock(&mutex);
+
+ if (json_object_object_get_ex(object, "connected", &val)) {
+ gboolean state = json_object_get_boolean(val);
+ data.avrcp_connected = state;
+
+ if (state)
+ gst_element_set_state(data.playbin, GST_STATE_PAUSED);
+ }
+
+ pthread_mutex_unlock(&mutex);
+
+ afb_event_push(metadata_event, object);
+
+ return;
} else {
AFB_ERROR("Invalid event: %s", event);
return;
diff --git a/conf.d/wgt/config-4a.xml.in b/conf.d/wgt/config-4a.xml.in
index a6ab311..175e1d3 100644
--- a/conf.d/wgt/config-4a.xml.in
+++ b/conf.d/wgt/config-4a.xml.in
@@ -19,6 +19,7 @@
<feature name="urn:AGL:widget:required-api">
<param name="mediascanner" value="ws" />
+ <param name="Bluetooth-Manager" value="ws" />
<param name="ahl-4a" value="ws" />
<param name="@WIDGET_ENTRY_POINT@" value="local" />
</feature>
diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in
index 00711b6..3e8447a 100644
--- a/conf.d/wgt/config.xml.in
+++ b/conf.d/wgt/config.xml.in
@@ -18,6 +18,10 @@
<feature name="urn:AGL:widget:required-api">
<param name="mediascanner" value="ws" />
+ <param name="Bluetooth-Manager" value="ws" />
+ </feature>
+
+ <feature name="urn:AGL:widget:required-binding">
<param name="@WIDGET_ENTRY_POINT@" value="local" />
</feature>
</widget>