Add AVRCP control volume up / down method
[platform/core/connectivity/bluetooth-frwk.git] / bt-oal / bluez_hal / src / bt-hal-avrcp-ctrl-dbus-handler.c
1 /*
2  *
3  * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
4  *
5  * Contact: Nilesh Trimbake <t.shripati@samsung.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *              http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <string.h>
25
26 #include <glib.h>
27 #include <gio/gio.h>
28 #include <dlog.h>
29 #include <vconf.h>
30
31 #include "bt-hal-avrcp-ctrl-dbus-handler.h"
32 #include "bt-hal-dbus-common-utils.h"
33 #include "bt-hal-internal.h"
34
35 static bt_player_settinngs_t repeat_status[] = {
36         { REPEAT_MODE_OFF, "off" },
37         { REPEAT_SINGLE_TRACK, "singletrack" },
38         { REPEAT_ALL_TRACK, "alltracks" },
39         { REPEAT_GROUP, "group" },
40         { REPEAT_INVALID, "" }
41 };
42
43 static bt_player_settinngs_t equalizer_status[] = {
44         { EQUALIZER_OFF, "off" },
45         { EQUALIZER_ON, "on" },
46         { EQUALIZER_INVALID, "" },
47 };
48
49 static bt_player_settinngs_t scan_status[] = {
50         { SCAN_MODE_OFF, "off" },
51         { SCAN_ALL_TRACK, "alltracks" },
52         { SCAN_GROUP, "group" },
53         { SCAN_INVALID, "" },
54 };
55
56 static bt_player_settinngs_t shuffle_settings[] = {
57         { SHUFFLE_MODE_OFF, "off" },
58         { SHUFFLE_ALL_TRACK, "alltracks" },
59         { SHUFFLE_GROUP, "group" },
60         { SHUFFLE_INVALID, "" }
61 };
62
63 static handle_stack_msg event_cb = NULL;
64
65 /* To send stack event to hal-avrcp-ctrl handler */
66 void _bt_hal_register_avrcp_ctrl_dbus_handler_cb(handle_stack_msg cb)
67 {
68         event_cb = cb;
69 }
70
71 /* To send stack event to hal-avrcp-ctrl handler */
72 void _bt_hal_unregister_avrcp_ctrl_dbus_handler_cb()
73 {
74         event_cb = NULL;
75 }
76
77 static void __bt_avrcp_target_connect_cb(GDBusProxy *proxy, GAsyncResult *res,
78                 gpointer user_data)
79 {
80         struct hal_ev_avrcp_ctrl_conn_state ev;
81         char *address = user_data;
82         int result = BT_STATUS_SUCCESS;
83         GVariant *reply = NULL;
84         GError *g_error = NULL;
85
86         DBG("+");
87
88         reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
89         g_object_unref(proxy);
90         if (reply == NULL) {
91                 ERR("AVRCP Target Connect Dbus Call Error");
92                 if (g_error) {
93                         ERR("Error: %s\n", g_error->message);
94                         g_clear_error(&g_error);
95                 }
96                 result = BT_STATUS_FAIL;
97         }
98         g_variant_unref(reply);
99
100         DBG("Address: %s", address);
101         /*
102          * If result is success, Remote device connected event will be triggered
103          * automatically from stack, so return from here.
104          */
105         if (result == BT_STATUS_SUCCESS)
106                 goto done;
107
108         /* Prepare to send AVRCP Target connection state event */
109         memset(&ev, 0, sizeof(ev));
110         _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
111         ev.state = HAL_AVRCP_CTRL_STATE_DISCONNECTED;
112         if (!event_cb)
113                 ERR("AVRCP CTRL DBUS handler callback not registered");
114         else
115                 event_cb(HAL_EV_AVRCP_CTRL_CONN_STATE, (void *)&ev, sizeof(ev));
116
117 done:
118         g_free(address);
119 }
120
121 bt_status_t _bt_hal_dbus_handler_avrcp_ctrl_connect(bt_bdaddr_t *bd_addr)
122 {
123         char *address;
124         int ret;
125         GDBusConnection *conn;
126
127         if (!bd_addr) {
128                 ERR("bd_addr is NULL, return");
129                 return BT_STATUS_PARM_INVALID;
130         }
131
132         conn = _bt_hal_get_system_gconn();
133         if (!conn) {
134                 ERR("_bt_hal_get_system_gconn returned NULL, return");
135                 return BT_STATUS_FAIL;
136         }
137
138         address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
139         if (!address) {
140                 ERR("Memory allocation failed");
141                 return BT_STATUS_NOMEM;
142         }
143         _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
144
145         ret = _bt_hal_connect_profile(address, AVRCP_TARGET_UUID,
146                         __bt_avrcp_target_connect_cb, address);
147
148         if (ret != BT_HAL_ERROR_NONE) {
149                 ERR("_bt_hal_connect_profile(AVRCP Target) Error");
150                 g_free(address);
151                 return BT_STATUS_FAIL;
152         }
153
154         return BT_STATUS_SUCCESS;
155 }
156
157 static void __bt_avrcp_target_disconnect_cb(GDBusProxy *proxy, GAsyncResult *res,
158                 gpointer user_data)
159 {
160         struct hal_ev_avrcp_ctrl_conn_state ev;
161         char *address = user_data;
162         int result = BT_STATUS_SUCCESS;
163         GError *g_error = NULL;
164         GVariant *reply = NULL;
165
166         DBG("+");
167
168         reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
169         g_object_unref(proxy);
170         if (reply == NULL) {
171                 ERR("AVRCP Target Disconnect Dbus Call Error");
172                 if (g_error) {
173                         ERR("Error: %s\n", g_error->message);
174                         g_clear_error(&g_error);
175                 }
176                 result = BT_STATUS_FAIL;
177         }
178         g_variant_unref(reply);
179
180         if (result != BT_STATUS_FAIL) {
181                 DBG("AVRCP Target Disconnect successful for Device: %s", address);
182                 g_free(address);
183                 return;
184         } else {
185                 DBG("AVRCP Target Disconnect un-successful for Device: %s", address);
186         }
187
188         /*
189          * Prepare to send AVRCP Target connection state event indicating
190          * disconnection failed.
191          */
192         memset(&ev, 0, sizeof(ev));
193         _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
194         ev.state = HAL_AVRCP_CTRL_STATE_CONNECTED;
195         if (!event_cb)
196                 ERR("AVRCP Target DBUS handler callback not registered");
197         else
198                 event_cb(HAL_EV_AVRCP_CTRL_CONN_STATE, (void *)&ev, sizeof(ev));
199         g_free(address);
200         DBG("-");
201 }
202
203 bt_status_t _bt_hal_dbus_handler_avrcp_ctrl_disconnect(bt_bdaddr_t *bd_addr)
204 {
205         char *address;
206         int ret;
207         GDBusConnection *conn;
208
209         if (!bd_addr) {
210                 ERR("bd_addr is NULL, return");
211                 return BT_STATUS_PARM_INVALID;
212         }
213
214         conn = _bt_hal_get_system_gconn();
215         if (!conn) {
216                 ERR("_bt_hal_get_system_gconn returned NULL, return");
217                 return BT_STATUS_FAIL;
218         }
219
220         address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
221         if (!address) {
222                 ERR("Memory allocation failed");
223                 return BT_STATUS_NOMEM;
224         }
225         _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
226
227         ret = _bt_hal_disconnect_profile(address, AVRCP_TARGET_UUID,
228                         __bt_avrcp_target_disconnect_cb, address);
229
230         if (ret != BT_HAL_ERROR_NONE) {
231                 ERR("_bt_hal_connect_profile(AVRCP Target) Error");
232                 g_free(address);
233                 return BT_STATUS_FAIL;
234         }
235
236         return BT_STATUS_SUCCESS;
237 }
238
239 static int __bt_media_send_control_msg(bt_bdaddr_t *bd_addr, const char *name)
240 {
241         GVariant *reply = NULL;
242         GError *err = NULL;
243         GDBusProxy *proxy = NULL;
244
245         if (name == NULL) {
246                 ERR("Command is NULL");
247                 return BT_STATUS_FAIL;
248         }
249         DBG("Command [%s]", name);
250         proxy = _bt_hal_get_avrcp_ctrl_proxy(bd_addr);
251         if (proxy == NULL) {
252                 ERR("Unable to allocate new proxy \n");
253                 if (err) {
254                         ERR("%s", err->message);
255                         g_clear_error(&err);
256                 }
257                 return BT_STATUS_FAIL;
258         }
259         reply = g_dbus_proxy_call_sync(proxy, name, NULL,
260                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
261
262         if (!reply) {
263                 ERR("Error returned in method call");
264                 if (err) {
265                         ERR("%s", err->message);
266                         g_clear_error(&err);
267                 }
268                 return BT_STATUS_FAIL;
269         }
270         g_variant_unref(reply);
271         DBG("-");
272         return BT_STATUS_SUCCESS;
273 }
274
275 bt_status_t _bt_hal_dbus_handler_avrcp_ctrl_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state)
276 {       int ret;
277         DBG("+");
278
279         switch (key_code) {
280                 case PLAY: {
281                         ret = __bt_media_send_control_msg(bd_addr, "Play");
282                         break;
283                 }
284                 case PAUSE: {
285                         ret = __bt_media_send_control_msg(bd_addr, "Pause");
286                         break;
287                 }
288                 case STOP: {
289                         ret = __bt_media_send_control_msg(bd_addr, "Stop");
290                         break;
291                 }
292                 case NEXT: {
293                         ret = __bt_media_send_control_msg(bd_addr, "Next");
294                         break;
295                 }
296                 case PREVIOUS: {
297                         ret = __bt_media_send_control_msg(bd_addr, "Previous");
298                         break;
299                 }
300                 case PRESS_FAST_FORWARD: {
301                         ret = __bt_media_send_control_msg(bd_addr, "PressFastForward");
302                         break;
303                 }
304                 case RELEASE_FAST_FORWARD: {
305                         ret = __bt_media_send_control_msg(bd_addr, "ReleaseFastForward");
306                         break;
307                 }
308                 case PRESS_REWIND: {
309                         ret = __bt_media_send_control_msg(bd_addr, "PressRewind");
310                         break;
311                 }
312                 case RELEASE_REWIND: {
313                         ret = __bt_media_send_control_msg(bd_addr, "ReleaseRewind");
314                         break;
315                 }
316                 case VOLUME_UP: {
317                         ret = __bt_media_send_control_msg(bd_addr, "VolumeUp");
318                         break;
319                 }
320                 case VOLUME_DOWN: {
321                         ret = __bt_media_send_control_msg(bd_addr, "VolumeDown");
322                         break;
323                 }
324                 default: {
325                         DBG("Invalid Type\n");
326                         return BT_STATUS_FAIL;
327                 }
328         }
329         DBG("-");
330         return ret;
331 }
332 static const char *__bt_media_type_to_str(int type)
333 {
334         switch (type) {
335         case BTRC_PLAYER_ATTR_EQUALIZER:
336                 return "Equalizer";
337         case BTRC_PLAYER_ATTR_REPEAT:
338                 return "Repeat";
339         case BTRC_PLAYER_ATTR_SHUFFLE:
340                 return "Shuffle";
341         case BTRC_PLAYER_ATTR_SCAN:
342                 return "Scan";
343         default:
344                 return NULL;
345         }
346
347         return NULL;
348 }
349
350 #if 0
351 static const char *__bt_transport_type_to_str(int type)
352 {
353         switch (type) {
354         case BTRC_TRANSPORT_ATTR_DELAY:
355                 return "Delay";
356         case BTRC_TRANSPORT_ATTR_VOLUME:
357                 return "Volume";
358         default:
359                 return NULL;
360         }
361
362         return NULL;
363 }
364 #endif
365
366 bt_status_t _bt_hal_dbus_handler_avrcp_ctrl_set_property(bt_bdaddr_t *bd_addr, uint8_t type, uint8_t value)
367 {
368         GVariant *reply, *param = NULL;
369         GError *err = NULL;
370         GDBusProxy *proxy = NULL;
371
372         DBG("+");
373         switch (type) {
374         case BTRC_PLAYER_ATTR_EQUALIZER:
375                 param = g_variant_new("s", equalizer_status[value].property);
376                 INFO("equalizer_status %s", equalizer_status[value].property);
377                 break;
378         case BTRC_PLAYER_ATTR_REPEAT:
379                 param = g_variant_new("s", repeat_status[value].property);
380                 INFO("repeat_status %s", repeat_status[value].property);
381                 break;
382         case BTRC_PLAYER_ATTR_SHUFFLE:
383                 param = g_variant_new("s", shuffle_settings[value].property);
384                 INFO("shuffle_settings %s", shuffle_settings[value].property);
385                 break;
386         case BTRC_PLAYER_ATTR_SCAN:
387                 param = g_variant_new("s", scan_status[value].property);
388                 INFO("scan_status %s", scan_status[value].property);
389                 break;
390         default:
391                 ERR("Invalid property type: %d", type);
392                 return BT_STATUS_FAIL;
393         }
394
395         proxy = _bt_hal_get_avrcp_ctrl_properties_proxy(bd_addr);
396         if (proxy == NULL) {
397                 ERR("Unable to allocate new proxy \n");
398                 if (err) {
399                         ERR("%s", err->message);
400                         g_clear_error(&err);
401                 }
402                 return BT_STATUS_FAIL;
403         }
404
405         reply = g_dbus_proxy_call_sync(proxy,
406                         "Set", g_variant_new("(ssv)",
407                                 BT_HAL_PLAYER_CONTROL_INTERFACE,
408                                 __bt_media_type_to_str(type), param),
409                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
410         g_object_unref(proxy);
411         if (!reply) {
412                 ERR("Can't get managed objects");
413                 if (err) {
414                         ERR("SetProperty Fail: %s", err->message);
415                         g_clear_error(&err);
416                         return BT_STATUS_FAIL;
417                 }
418         }
419
420         g_variant_unref(reply);
421         DBG("-");
422         return BT_STATUS_SUCCESS;
423 }
424
425 bt_status_t _bt_hal_dbus_handler_avrcp_transport_set_property(bt_bdaddr_t *bd_addr, int type, unsigned int value)
426 {
427         GVariant *reply, *param = NULL;
428         GError *err = NULL;
429         GDBusProxy *proxy = NULL;
430         uint16_t property_level = (uint16_t)value;
431
432         DBG("+");
433         switch (type) {
434         case BTRC_TRANSPORT_ATTR_DELAY:
435                 param = g_variant_new("q", property_level);
436                 INFO("delay level %d", property_level);
437                 break;
438         case BTRC_TRANSPORT_ATTR_VOLUME:
439                 param = g_variant_new("q", property_level);
440                 INFO("volume level %d", property_level);
441                 break;
442         default:
443                 ERR("Invalid property type: %d", type);
444                 return BT_STATUS_FAIL;
445         }
446
447         proxy = _bt_hal_get_avrcp_transport_properties_proxy(bd_addr);
448         if (proxy == NULL) {
449                 ERR("Unable to allocate new proxy \n");
450                 if (err) {
451                         ERR("%s", err->message);
452                         g_clear_error(&err);
453                 }
454                 return BT_STATUS_FAIL;
455         }
456
457         reply = g_dbus_proxy_call_sync(proxy,
458                         "Set", g_variant_new("(ssv)",
459                                 BT_HAL_MEDIATRANSPORT_INTERFACE,
460                                 __bt_media_type_to_str(type), param),
461                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
462         g_object_unref(proxy);
463         if (!reply) {
464                 ERR("Can't get managed objects");
465                 if (err) {
466                         ERR("SetProperty Fail: %s", err->message);
467                         g_clear_error(&err);
468                         return BT_STATUS_FAIL;
469                 }
470         }
471
472         g_variant_unref(reply);
473         DBG("-");
474         return BT_STATUS_SUCCESS;
475 }