tizen 2.3.1 release
[framework/connectivity/bluez.git] / profiles / audio / media.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2006-2007  Nokia Corporation
6  *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
7  *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
8  *
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <errno.h>
31 #include <inttypes.h>
32
33 #include <glib.h>
34
35 #include "lib/bluetooth.h"
36 #include "lib/sdp.h"
37 #include "lib/uuid.h"
38
39 #include "gdbus/gdbus.h"
40
41 #include "src/plugin.h"
42 #include "src/adapter.h"
43 #include "src/device.h"
44 #include "src/dbus-common.h"
45 #include "src/profile.h"
46
47 #ifdef __TIZEN_PATCH__
48 #include "src/service.h"
49 #endif
50
51 #include "src/uuid-helper.h"
52 #include "src/log.h"
53 #include "src/error.h"
54 #include "src/shared/queue.h"
55
56 #include "avdtp.h"
57 #include "media.h"
58 #include "transport.h"
59 #include "a2dp.h"
60 #include "avrcp.h"
61 #ifdef __TIZEN_PATCH__
62 #include "sink.h"
63 #endif
64
65
66 #define MEDIA_INTERFACE "org.bluez.Media1"
67 #define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
68 #define MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
69
70 #define REQUEST_TIMEOUT (3 * 1000)              /* 3 seconds */
71
72 #ifdef __TIZEN_PATCH__
73 #define SINK_SUSPEND_TIMEOUT 4          /* 4 seconds */
74
75 unsigned int suspend_timer_id = 0;
76 #endif
77
78 struct media_adapter {
79         struct btd_adapter      *btd_adapter;
80         GSList                  *endpoints;     /* Endpoints list */
81         GSList                  *players;       /* Players list */
82 };
83
84 struct endpoint_request {
85         struct media_endpoint   *endpoint;
86         DBusMessage             *msg;
87         DBusPendingCall         *call;
88         media_endpoint_cb_t     cb;
89         GDestroyNotify          destroy;
90         void                    *user_data;
91 };
92
93 struct media_endpoint {
94         struct a2dp_sep         *sep;
95         char                    *sender;        /* Endpoint DBus bus id */
96         char                    *path;          /* Endpoint object path */
97         char                    *uuid;          /* Endpoint property UUID */
98         uint8_t                 codec;          /* Endpoint codec */
99         uint8_t                 *capabilities;  /* Endpoint property capabilities */
100         size_t                  size;           /* Endpoint capabilities size */
101         guint                   hs_watch;
102         guint                   ag_watch;
103         guint                   watch;
104         GSList                  *requests;
105         struct media_adapter    *adapter;
106         GSList                  *transports;
107 };
108
109 struct media_player {
110         struct media_adapter    *adapter;
111         struct avrcp_player     *player;
112         char                    *sender;        /* Player DBus bus id */
113         char                    *path;          /* Player object path */
114         GHashTable              *settings;      /* Player settings */
115         GHashTable              *track;         /* Player current track */
116         guint                   watch;
117         guint                   properties_watch;
118         guint                   seek_watch;
119 #ifdef __TIZEN_PATCH__
120         guint                   sink_watch;
121 #endif
122         char                    *status;
123         uint32_t                position;
124         uint32_t                duration;
125         uint8_t                 volume;
126         GTimer                  *timer;
127         bool                    play;
128         bool                    pause;
129         bool                    next;
130         bool                    previous;
131         bool                    control;
132 };
133
134 static GSList *adapters = NULL;
135
136 #ifdef __TIZEN_PATCH__
137 static gboolean set_avrcp_status = FALSE;
138 static gboolean send_track_changed_event = FALSE;
139
140 static int media_set_sink_callback(struct btd_device *device,
141                                 struct media_player *mp);
142 static void media_sink_state_changed_cb(struct btd_service *service,
143                                 sink_state_t old_state,
144                                 sink_state_t new_state,
145                                 void *user_data);
146 void media_stop_suspend_timer(void);
147 struct media_player *media_adapter_get_player(struct media_adapter *adapter);
148 static struct media_adapter *find_adapter(struct btd_device *device);
149 static uint32_t get_position(void *user_data);
150 #endif
151
152 static void endpoint_request_free(struct endpoint_request *request)
153 {
154         if (request->call)
155                 dbus_pending_call_unref(request->call);
156
157         if (request->destroy)
158                 request->destroy(request->user_data);
159
160         dbus_message_unref(request->msg);
161         g_free(request);
162 }
163
164 static void media_endpoint_cancel(struct endpoint_request *request)
165 {
166         struct media_endpoint *endpoint = request->endpoint;
167
168         if (request->call)
169                 dbus_pending_call_cancel(request->call);
170
171         endpoint->requests = g_slist_remove(endpoint->requests, request);
172
173         if (request->cb)
174                 request->cb(endpoint, NULL, -1, request->user_data);
175
176         endpoint_request_free(request);
177 }
178
179 static void media_endpoint_cancel_all(struct media_endpoint *endpoint)
180 {
181         while (endpoint->requests != NULL)
182                 media_endpoint_cancel(endpoint->requests->data);
183 }
184
185 static void media_endpoint_destroy(struct media_endpoint *endpoint)
186 {
187         DBG("sender=%s path=%s", endpoint->sender, endpoint->path);
188
189         media_endpoint_cancel_all(endpoint);
190
191         g_slist_free_full(endpoint->transports,
192                                 (GDestroyNotify) media_transport_destroy);
193
194         g_dbus_remove_watch(btd_get_dbus_connection(), endpoint->watch);
195         g_free(endpoint->capabilities);
196         g_free(endpoint->sender);
197         g_free(endpoint->path);
198         g_free(endpoint->uuid);
199         g_free(endpoint);
200 }
201
202 static struct media_endpoint *media_adapter_find_endpoint(
203                                                 struct media_adapter *adapter,
204                                                 const char *sender,
205                                                 const char *path,
206                                                 const char *uuid)
207 {
208         GSList *l;
209
210         for (l = adapter->endpoints; l; l = l->next) {
211                 struct media_endpoint *endpoint = l->data;
212
213                 if (sender && g_strcmp0(endpoint->sender, sender) != 0)
214                         continue;
215
216                 if (path && g_strcmp0(endpoint->path, path) != 0)
217                         continue;
218
219                 if (uuid && strcasecmp(endpoint->uuid, uuid) != 0)
220                         continue;
221
222                 return endpoint;
223         }
224
225         return NULL;
226 }
227
228 static void media_endpoint_remove(struct media_endpoint *endpoint)
229 {
230         struct media_adapter *adapter = endpoint->adapter;
231
232         if (endpoint->sep) {
233                 a2dp_remove_sep(endpoint->sep);
234                 return;
235         }
236
237         info("Endpoint unregistered: sender=%s path=%s", endpoint->sender,
238                         endpoint->path);
239
240         adapter->endpoints = g_slist_remove(adapter->endpoints, endpoint);
241
242         if (media_adapter_find_endpoint(adapter, NULL, NULL,
243                                                 endpoint->uuid) == NULL)
244                 btd_profile_remove_custom_prop(endpoint->uuid,
245                                                         "MediaEndpoints");
246
247         media_endpoint_destroy(endpoint);
248 }
249
250 static void media_endpoint_exit(DBusConnection *connection, void *user_data)
251 {
252         struct media_endpoint *endpoint = user_data;
253
254         endpoint->watch = 0;
255         media_endpoint_remove(endpoint);
256 }
257
258 static void clear_configuration(struct media_endpoint *endpoint,
259                                         struct media_transport *transport)
260 {
261         DBusMessage *msg;
262         const char *path;
263 #ifdef __TIZEN_PATCH__
264         struct media_player *mp;
265 #endif
266
267         msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
268                                                 MEDIA_ENDPOINT_INTERFACE,
269                                                 "ClearConfiguration");
270         if (msg == NULL) {
271                 error("Couldn't allocate D-Bus message");
272                 goto done;
273         }
274
275         path = media_transport_get_path(transport);
276         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
277                                                         DBUS_TYPE_INVALID);
278         g_dbus_send_message(btd_get_dbus_connection(), msg);
279 done:
280         endpoint->transports = g_slist_remove(endpoint->transports, transport);
281 #ifdef __TIZEN_PATCH__
282         if ((mp = media_adapter_get_player(endpoint->adapter)))
283                 if (mp->sink_watch) {
284                         sink_remove_state_cb(mp->sink_watch);
285                         mp->sink_watch = 0;
286                 }
287         media_stop_suspend_timer();
288 #endif
289         media_transport_destroy(transport);
290 }
291
292 static void clear_endpoint(struct media_endpoint *endpoint)
293 {
294         media_endpoint_cancel_all(endpoint);
295
296         while (endpoint->transports != NULL)
297                 clear_configuration(endpoint, endpoint->transports->data);
298 }
299
300 static void endpoint_reply(DBusPendingCall *call, void *user_data)
301 {
302         struct endpoint_request *request = user_data;
303         struct media_endpoint *endpoint = request->endpoint;
304         DBusMessage *reply;
305         DBusError err;
306         gboolean value;
307         void *ret = NULL;
308         int size = -1;
309
310         /* steal_reply will always return non-NULL since the callback
311          * is only called after a reply has been received */
312         reply = dbus_pending_call_steal_reply(call);
313
314         dbus_error_init(&err);
315         if (dbus_set_error_from_message(&err, reply)) {
316                 error("Endpoint replied with an error: %s",
317                                 err.name);
318
319                 /* Clear endpoint configuration in case of NO_REPLY error */
320                 if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
321                         clear_endpoint(endpoint);
322                         dbus_message_unref(reply);
323                         dbus_error_free(&err);
324                         return;
325                 }
326
327                 dbus_error_free(&err);
328                 goto done;
329         }
330
331         if (dbus_message_is_method_call(request->msg, MEDIA_ENDPOINT_INTERFACE,
332                                 "SelectConfiguration")) {
333                 DBusMessageIter args, array;
334                 uint8_t *configuration;
335
336                 dbus_message_iter_init(reply, &args);
337
338                 dbus_message_iter_recurse(&args, &array);
339
340                 dbus_message_iter_get_fixed_array(&array, &configuration, &size);
341
342                 ret = configuration;
343                 goto done;
344         } else  if (!dbus_message_get_args(reply, &err, DBUS_TYPE_INVALID)) {
345                 error("Wrong reply signature: %s", err.message);
346                 dbus_error_free(&err);
347                 goto done;
348         }
349
350         size = 1;
351         value = TRUE;
352         ret = &value;
353
354 done:
355         dbus_message_unref(reply);
356
357         if (request->cb)
358                 request->cb(endpoint, ret, size, request->user_data);
359
360         endpoint->requests = g_slist_remove(endpoint->requests, request);
361         endpoint_request_free(request);
362 }
363
364 static gboolean media_endpoint_async_call(DBusMessage *msg,
365                                         struct media_endpoint *endpoint,
366                                         media_endpoint_cb_t cb,
367                                         void *user_data,
368                                         GDestroyNotify destroy)
369 {
370         struct endpoint_request *request;
371
372         request = g_new0(struct endpoint_request, 1);
373
374         /* Timeout should be less than avdtp request timeout (4 seconds) */
375         if (g_dbus_send_message_with_reply(btd_get_dbus_connection(),
376                                                 msg, &request->call,
377                                                 REQUEST_TIMEOUT) == FALSE) {
378                 error("D-Bus send failed");
379                 g_free(request);
380                 return FALSE;
381         }
382
383         dbus_pending_call_set_notify(request->call, endpoint_reply, request,
384                                                                         NULL);
385
386         request->endpoint = endpoint;
387         request->msg = msg;
388         request->cb = cb;
389         request->destroy = destroy;
390         request->user_data = user_data;
391
392         endpoint->requests = g_slist_append(endpoint->requests, request);
393
394         DBG("Calling %s: name = %s path = %s", dbus_message_get_member(msg),
395                         dbus_message_get_destination(msg),
396                         dbus_message_get_path(msg));
397
398         return TRUE;
399 }
400
401 static gboolean select_configuration(struct media_endpoint *endpoint,
402                                                 uint8_t *capabilities,
403                                                 size_t length,
404                                                 media_endpoint_cb_t cb,
405                                                 void *user_data,
406                                                 GDestroyNotify destroy)
407 {
408         DBusMessage *msg;
409
410         msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
411                                                 MEDIA_ENDPOINT_INTERFACE,
412                                                 "SelectConfiguration");
413         if (msg == NULL) {
414                 error("Couldn't allocate D-Bus message");
415                 return FALSE;
416         }
417
418         dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
419                                         &capabilities, length,
420                                         DBUS_TYPE_INVALID);
421
422         return media_endpoint_async_call(msg, endpoint, cb, user_data, destroy);
423 }
424
425 static int transport_device_cmp(gconstpointer data, gconstpointer user_data)
426 {
427         struct media_transport *transport = (struct media_transport *) data;
428         const struct btd_device *device = user_data;
429         const struct btd_device *dev = media_transport_get_dev(transport);
430
431         if (device == dev)
432                 return 0;
433
434         return -1;
435 }
436
437 static struct media_transport *find_device_transport(
438                                         struct media_endpoint *endpoint,
439                                         struct btd_device *device)
440 {
441         GSList *match;
442
443         match = g_slist_find_custom(endpoint->transports, device,
444                                                         transport_device_cmp);
445         if (match == NULL)
446                 return NULL;
447
448         return match->data;
449 }
450
451 #ifdef __TIZEN_PATCH__
452 struct media_player * media_adapter_get_player(struct media_adapter * adapter)
453 {
454         GSList *l;
455         DBG(" ");
456
457         for (l = adapter->players; l; l = l->next) {
458                 struct media_player *mp = l->data;
459                 if (mp != NULL)
460                         return mp;
461         }
462         return NULL;
463 }
464
465 void media_stop_suspend_timer(void)
466 {
467         if (suspend_timer_id > 0) {
468                 DBG("Removing sink suspend timer");
469                 g_source_remove(suspend_timer_id);
470                 suspend_timer_id = 0;
471         }
472 }
473
474 gboolean media_reset_mp_status(gpointer user_data)
475 {
476         struct media_player *mp = user_data;
477         DBG(" ");
478
479         /* PlayBackStatus already reset; so return */
480         if (g_strcmp0(mp->status, "playing") != 0)
481                 return FALSE;
482
483         mp->position = get_position(mp);
484         g_timer_start(mp->timer);
485
486         g_free(mp->status);
487         mp->status = g_strdup("paused");
488         suspend_timer_id = 0;
489         avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, mp->status);
490
491         return FALSE;
492 }
493
494 static void media_sink_state_changed_cb(struct btd_service *service,
495                                         sink_state_t old_state,
496                                         sink_state_t new_state,
497                                         void *user_data)
498 {
499         struct media_player *mp = user_data;
500         DBG(" ");
501
502         /* Check if A2DP streaming is suspended */
503         if ((old_state == SINK_STATE_PLAYING) &&
504                 (new_state == SINK_STATE_CONNECTED)) {
505
506                 /* Check AVRCP play back status */
507                 if (g_strcmp0(mp->status, "playing") != 0)
508                         return;
509
510                 media_stop_suspend_timer();
511
512                 /* PlayBackStatus is still PLAYING; start a timer */
513                 suspend_timer_id = g_timeout_add_seconds(SINK_SUSPEND_TIMEOUT,
514                                 media_reset_mp_status, mp);
515                 DBG("SINK SUSPEND TIMEOUT started");
516         }
517
518         /* Check if A2DP streaming is started */
519         if ((old_state == SINK_STATE_CONNECTED) &&
520                 (new_state == SINK_STATE_PLAYING)) {
521
522                 struct btd_device *device = btd_service_get_device(service);
523                 char name[20];
524
525                 media_stop_suspend_timer();
526
527                 /* NULL packet streaming during initial connection */
528                 if (set_avrcp_status == FALSE) {
529                         set_avrcp_status = TRUE;
530                         return;
531                 }
532
533                 /* Check for BMW, Audi, VW car kit */
534                 device_get_name(device, name, sizeof(name));
535                 DBG("Name : %s", name);
536                 if ((g_str_has_prefix(name, "BMW") == TRUE) ||
537                                 (g_str_has_prefix(name, "Audi") == TRUE) ||
538                                 (g_str_has_prefix(name, "VW BT") == TRUE)) {
539
540                         /* Check AVRCP play back status */
541                         if (g_strcmp0(mp->status, "playing") == 0)
542                                 return;
543
544                         g_free(mp->status);
545                         mp->status = g_strdup("playing");
546                         avrcp_player_event(mp->player,
547                                 AVRCP_EVENT_STATUS_CHANGED, mp->status);
548                 }
549         }
550 }
551
552 static int media_set_sink_callback(struct btd_device *device,
553                                         struct media_player *mp)
554 {
555         struct btd_service *service;
556         DBG(" ");
557
558         service = btd_device_get_service(device, A2DP_SINK_UUID);
559         if (service == NULL)
560                 return -EINVAL;
561
562         mp->sink_watch = sink_add_state_cb(service, media_sink_state_changed_cb, mp);
563
564         return 0;
565 }
566 #endif
567
568 struct a2dp_config_data {
569         struct a2dp_setup *setup;
570         a2dp_endpoint_config_t cb;
571 };
572
573 static gboolean set_configuration(struct media_endpoint *endpoint,
574                                         uint8_t *configuration, size_t size,
575                                         media_endpoint_cb_t cb,
576                                         void *user_data,
577                                         GDestroyNotify destroy)
578 {
579         struct a2dp_config_data *data = user_data;
580         struct btd_device *device = a2dp_setup_get_device(data->setup);
581         DBusConnection *conn = btd_get_dbus_connection();
582         DBusMessage *msg;
583         const char *path;
584         DBusMessageIter iter;
585         struct media_transport *transport;
586 #ifdef __TIZEN_PATCH__
587         struct media_adapter *adapter;
588         struct media_player *mp;
589 #endif
590
591         transport = find_device_transport(endpoint, device);
592
593         if (transport != NULL)
594                 return FALSE;
595
596         transport = media_transport_create(device, configuration, size,
597                                                                 endpoint);
598         if (transport == NULL)
599                 return FALSE;
600
601         msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
602                                                 MEDIA_ENDPOINT_INTERFACE,
603                                                 "SetConfiguration");
604         if (msg == NULL) {
605                 error("Couldn't allocate D-Bus message");
606                 media_transport_destroy(transport);
607                 return FALSE;
608         }
609
610 #ifdef __TIZEN_PATCH__
611         set_avrcp_status = FALSE;
612         adapter = find_adapter(device);
613         if ((mp = media_adapter_get_player(adapter)))
614                 media_set_sink_callback(device, mp);
615 #endif
616
617         endpoint->transports = g_slist_append(endpoint->transports, transport);
618
619         dbus_message_iter_init_append(msg, &iter);
620
621         path = media_transport_get_path(transport);
622         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
623
624         g_dbus_get_properties(conn, path, "org.bluez.MediaTransport1", &iter);
625
626         return media_endpoint_async_call(msg, endpoint, cb, user_data, destroy);
627 }
628
629 static void release_endpoint(struct media_endpoint *endpoint)
630 {
631         DBusMessage *msg;
632
633         DBG("sender=%s path=%s", endpoint->sender, endpoint->path);
634
635         /* already exit */
636         if (endpoint->watch == 0)
637                 goto done;
638
639         clear_endpoint(endpoint);
640
641         msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
642                                                 MEDIA_ENDPOINT_INTERFACE,
643                                                 "Release");
644         if (msg == NULL) {
645                 error("Couldn't allocate D-Bus message");
646                 return;
647         }
648
649         g_dbus_send_message(btd_get_dbus_connection(), msg);
650
651 done:
652         media_endpoint_remove(endpoint);
653 }
654
655 static const char *get_name(struct a2dp_sep *sep, void *user_data)
656 {
657         struct media_endpoint *endpoint = user_data;
658
659         return endpoint->sender;
660 }
661
662 static size_t get_capabilities(struct a2dp_sep *sep, uint8_t **capabilities,
663                                                         void *user_data)
664 {
665         struct media_endpoint *endpoint = user_data;
666
667         *capabilities = endpoint->capabilities;
668         return endpoint->size;
669 }
670
671 struct a2dp_select_data {
672         struct a2dp_setup *setup;
673         a2dp_endpoint_select_t cb;
674 };
675
676 static void select_cb(struct media_endpoint *endpoint, void *ret, int size,
677                                                         void *user_data)
678 {
679         struct a2dp_select_data *data = user_data;
680
681         data->cb(data->setup, ret, size);
682 }
683
684 static int select_config(struct a2dp_sep *sep, uint8_t *capabilities,
685                                 size_t length, struct a2dp_setup *setup,
686                                 a2dp_endpoint_select_t cb, void *user_data)
687 {
688         struct media_endpoint *endpoint = user_data;
689         struct a2dp_select_data *data;
690
691         data = g_new0(struct a2dp_select_data, 1);
692         data->setup = setup;
693         data->cb = cb;
694
695         if (select_configuration(endpoint, capabilities, length,
696                                         select_cb, data, g_free) == TRUE)
697                 return 0;
698
699         g_free(data);
700         return -ENOMEM;
701 }
702
703 static void config_cb(struct media_endpoint *endpoint, void *ret, int size,
704                                                         void *user_data)
705 {
706         struct a2dp_config_data *data = user_data;
707
708         data->cb(data->setup, ret ? TRUE : FALSE);
709 }
710
711 static int set_config(struct a2dp_sep *sep, uint8_t *configuration,
712                                 size_t length,
713                                 struct a2dp_setup *setup,
714                                 a2dp_endpoint_config_t cb,
715                                 void *user_data)
716 {
717         struct media_endpoint *endpoint = user_data;
718         struct a2dp_config_data *data;
719
720         data = g_new0(struct a2dp_config_data, 1);
721         data->setup = setup;
722         data->cb = cb;
723
724         if (set_configuration(endpoint, configuration, length, config_cb, data,
725                                                         g_free) == TRUE)
726                 return 0;
727
728         g_free(data);
729         return -ENOMEM;
730 }
731
732 static void clear_config(struct a2dp_sep *sep, void *user_data)
733 {
734         struct media_endpoint *endpoint = user_data;
735
736         clear_endpoint(endpoint);
737 }
738
739 static void set_delay(struct a2dp_sep *sep, uint16_t delay, void *user_data)
740 {
741         struct media_endpoint *endpoint = user_data;
742
743         if (endpoint->transports == NULL)
744                 return;
745
746         media_transport_update_delay(endpoint->transports->data, delay);
747 }
748
749 static struct a2dp_endpoint a2dp_endpoint = {
750         .get_name = get_name,
751         .get_capabilities = get_capabilities,
752         .select_configuration = select_config,
753         .set_configuration = set_config,
754         .clear_configuration = clear_config,
755         .set_delay = set_delay
756 };
757
758 static void a2dp_destroy_endpoint(void *user_data)
759 {
760         struct media_endpoint *endpoint = user_data;
761
762         endpoint->sep = NULL;
763         release_endpoint(endpoint);
764 }
765
766 static gboolean endpoint_init_a2dp_source(struct media_endpoint *endpoint,
767                                                 gboolean delay_reporting,
768                                                 int *err)
769 {
770         endpoint->sep = a2dp_add_sep(endpoint->adapter->btd_adapter,
771                                         AVDTP_SEP_TYPE_SOURCE, endpoint->codec,
772                                         delay_reporting, &a2dp_endpoint,
773                                         endpoint, a2dp_destroy_endpoint, err);
774         if (endpoint->sep == NULL)
775                 return FALSE;
776
777         return TRUE;
778 }
779
780 static gboolean endpoint_init_a2dp_sink(struct media_endpoint *endpoint,
781                                                 gboolean delay_reporting,
782                                                 int *err)
783 {
784         endpoint->sep = a2dp_add_sep(endpoint->adapter->btd_adapter,
785                                         AVDTP_SEP_TYPE_SINK, endpoint->codec,
786                                         delay_reporting, &a2dp_endpoint,
787                                         endpoint, a2dp_destroy_endpoint, err);
788         if (endpoint->sep == NULL)
789                 return FALSE;
790
791         return TRUE;
792 }
793
794 static struct media_adapter *find_adapter(struct btd_device *device)
795 {
796         GSList *l;
797
798         for (l = adapters; l; l = l->next) {
799                 struct media_adapter *adapter = l->data;
800
801                 if (adapter->btd_adapter == device_get_adapter(device))
802                         return adapter;
803         }
804
805         return NULL;
806 }
807
808 static bool endpoint_properties_exists(const char *uuid,
809                                                 struct btd_device *dev,
810                                                 void *user_data)
811 {
812         struct media_adapter *adapter;
813
814         adapter = find_adapter(dev);
815         if (adapter == NULL)
816                 return false;
817
818         if (media_adapter_find_endpoint(adapter, NULL, NULL, uuid) == NULL)
819                 return false;
820
821         return true;
822 }
823
824 static void append_endpoint(struct media_endpoint *endpoint,
825                                                 DBusMessageIter *dict)
826 {
827         DBusMessageIter entry, var, props;
828
829         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
830                                                         NULL, &entry);
831
832         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
833                                                 &endpoint->sender);
834
835         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}",
836                                                                 &var);
837
838         dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY,
839                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
840                                         DBUS_TYPE_STRING_AS_STRING
841                                         DBUS_TYPE_VARIANT_AS_STRING
842                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
843                                         &props);
844
845         dict_append_entry(&props, "Path", DBUS_TYPE_OBJECT_PATH,
846                                                         &endpoint->path);
847         dict_append_entry(&props, "Codec", DBUS_TYPE_BYTE, &endpoint->codec);
848         dict_append_array(&props, "Capabilities", DBUS_TYPE_BYTE,
849                                 &endpoint->capabilities, endpoint->size);
850
851         dbus_message_iter_close_container(&var, &props);
852         dbus_message_iter_close_container(&entry, &var);
853         dbus_message_iter_close_container(dict, &entry);
854 }
855
856 static bool endpoint_properties_get(const char *uuid,
857                                                 struct btd_device *dev,
858                                                 DBusMessageIter *iter,
859                                                 void *user_data)
860 {
861         struct media_adapter *adapter;
862         DBusMessageIter dict;
863         GSList *l;
864
865         adapter = find_adapter(dev);
866         if (adapter == NULL)
867                 return false;
868
869         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
870                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
871                                         DBUS_TYPE_STRING_AS_STRING
872                                         DBUS_TYPE_VARIANT_AS_STRING
873                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
874                                         &dict);
875
876         for (l = adapter->endpoints; l; l = l->next) {
877                 struct media_endpoint *endpoint = l->data;
878
879                 if (strcasecmp(endpoint->uuid, uuid) != 0)
880                         continue;
881
882                 append_endpoint(endpoint, &dict);
883         }
884
885         dbus_message_iter_close_container(iter, &dict);
886
887         return true;
888 }
889
890 static struct media_endpoint *media_endpoint_create(struct media_adapter *adapter,
891                                                 const char *sender,
892                                                 const char *path,
893                                                 const char *uuid,
894                                                 gboolean delay_reporting,
895                                                 uint8_t codec,
896                                                 uint8_t *capabilities,
897                                                 int size,
898                                                 int *err)
899 {
900         struct media_endpoint *endpoint;
901         gboolean succeeded;
902
903         endpoint = g_new0(struct media_endpoint, 1);
904         endpoint->sender = g_strdup(sender);
905         endpoint->path = g_strdup(path);
906         endpoint->uuid = g_strdup(uuid);
907         endpoint->codec = codec;
908
909         if (size > 0) {
910                 endpoint->capabilities = g_new(uint8_t, size);
911                 memcpy(endpoint->capabilities, capabilities, size);
912                 endpoint->size = size;
913         }
914
915         endpoint->adapter = adapter;
916
917         if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0)
918                 succeeded = endpoint_init_a2dp_source(endpoint,
919                                                         delay_reporting, err);
920         else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0)
921                 succeeded = endpoint_init_a2dp_sink(endpoint,
922                                                         delay_reporting, err);
923         else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
924                                         strcasecmp(uuid, HSP_AG_UUID) == 0)
925                 succeeded = TRUE;
926         else if (strcasecmp(uuid, HFP_HS_UUID) == 0 ||
927                                         strcasecmp(uuid, HSP_HS_UUID) == 0)
928                 succeeded = TRUE;
929         else {
930                 succeeded = FALSE;
931
932                 if (err)
933                         *err = -EINVAL;
934         }
935
936         if (!succeeded) {
937                 media_endpoint_destroy(endpoint);
938                 return NULL;
939         }
940
941         endpoint->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
942                                                 sender, media_endpoint_exit,
943                                                 endpoint, NULL);
944
945         if (media_adapter_find_endpoint(adapter, NULL, NULL, uuid) == NULL) {
946                 btd_profile_add_custom_prop(uuid, "a{sv}", "MediaEndpoints",
947                                                 endpoint_properties_exists,
948                                                 endpoint_properties_get,
949                                                 NULL);
950         }
951
952         adapter->endpoints = g_slist_append(adapter->endpoints, endpoint);
953         info("Endpoint registered: sender=%s path=%s", sender, path);
954
955         if (err)
956                 *err = 0;
957         return endpoint;
958 }
959
960 static int parse_properties(DBusMessageIter *props, const char **uuid,
961                                 gboolean *delay_reporting, uint8_t *codec,
962                                 uint8_t **capabilities, int *size)
963 {
964         gboolean has_uuid = FALSE;
965         gboolean has_codec = FALSE;
966
967         while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
968                 const char *key;
969                 DBusMessageIter value, entry;
970                 int var;
971
972                 dbus_message_iter_recurse(props, &entry);
973                 dbus_message_iter_get_basic(&entry, &key);
974
975                 dbus_message_iter_next(&entry);
976                 dbus_message_iter_recurse(&entry, &value);
977
978                 var = dbus_message_iter_get_arg_type(&value);
979                 if (strcasecmp(key, "UUID") == 0) {
980                         if (var != DBUS_TYPE_STRING)
981                                 return -EINVAL;
982                         dbus_message_iter_get_basic(&value, uuid);
983                         has_uuid = TRUE;
984                 } else if (strcasecmp(key, "Codec") == 0) {
985                         if (var != DBUS_TYPE_BYTE)
986                                 return -EINVAL;
987                         dbus_message_iter_get_basic(&value, codec);
988                         has_codec = TRUE;
989                 } else if (strcasecmp(key, "DelayReporting") == 0) {
990                         if (var != DBUS_TYPE_BOOLEAN)
991                                 return -EINVAL;
992                         dbus_message_iter_get_basic(&value, delay_reporting);
993                 } else if (strcasecmp(key, "Capabilities") == 0) {
994                         DBusMessageIter array;
995
996                         if (var != DBUS_TYPE_ARRAY)
997                                 return -EINVAL;
998
999                         dbus_message_iter_recurse(&value, &array);
1000                         dbus_message_iter_get_fixed_array(&array, capabilities,
1001                                                         size);
1002                 }
1003
1004                 dbus_message_iter_next(props);
1005         }
1006
1007         return (has_uuid && has_codec) ? 0 : -EINVAL;
1008 }
1009
1010 static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg,
1011                                         void *data)
1012 {
1013         struct media_adapter *adapter = data;
1014         DBusMessageIter args, props;
1015         const char *sender, *path, *uuid;
1016         gboolean delay_reporting = FALSE;
1017         uint8_t codec;
1018         uint8_t *capabilities;
1019         int size = 0;
1020         int err;
1021
1022         sender = dbus_message_get_sender(msg);
1023
1024         dbus_message_iter_init(msg, &args);
1025
1026         dbus_message_iter_get_basic(&args, &path);
1027         dbus_message_iter_next(&args);
1028
1029         if (media_adapter_find_endpoint(adapter, sender, path, NULL) != NULL)
1030                 return btd_error_already_exists(msg);
1031
1032         dbus_message_iter_recurse(&args, &props);
1033         if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
1034                 return btd_error_invalid_args(msg);
1035
1036         if (parse_properties(&props, &uuid, &delay_reporting, &codec,
1037                                                 &capabilities, &size) < 0)
1038                 return btd_error_invalid_args(msg);
1039
1040         if (media_endpoint_create(adapter, sender, path, uuid, delay_reporting,
1041                                 codec, capabilities, size, &err) == NULL) {
1042                 if (err == -EPROTONOSUPPORT)
1043                         return btd_error_not_supported(msg);
1044                 else
1045                         return btd_error_invalid_args(msg);
1046         }
1047
1048         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1049 }
1050
1051 static DBusMessage *unregister_endpoint(DBusConnection *conn, DBusMessage *msg,
1052                                         void *data)
1053 {
1054         struct media_adapter *adapter = data;
1055         struct media_endpoint *endpoint;
1056         const char *sender, *path;
1057
1058         if (!dbus_message_get_args(msg, NULL,
1059                                 DBUS_TYPE_OBJECT_PATH, &path,
1060                                 DBUS_TYPE_INVALID))
1061                 return btd_error_invalid_args(msg);
1062
1063         sender = dbus_message_get_sender(msg);
1064
1065         endpoint = media_adapter_find_endpoint(adapter, sender, path, NULL);
1066         if (endpoint == NULL)
1067                 return btd_error_does_not_exist(msg);
1068
1069         media_endpoint_remove(endpoint);
1070
1071         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1072 }
1073
1074 static struct media_player *media_adapter_find_player(
1075                                                 struct media_adapter *adapter,
1076                                                 const char *sender,
1077                                                 const char *path)
1078 {
1079         GSList *l;
1080
1081         for (l = adapter->players; l; l = l->next) {
1082                 struct media_player *mp = l->data;
1083
1084                 if (sender && g_strcmp0(mp->sender, sender) != 0)
1085                         continue;
1086
1087                 if (path && g_strcmp0(mp->path, path) != 0)
1088                         continue;
1089
1090                 return mp;
1091         }
1092
1093         return NULL;
1094 }
1095
1096 static void release_player(struct media_player *mp)
1097 {
1098         DBusMessage *msg;
1099
1100         DBG("sender=%s path=%s", mp->sender, mp->path);
1101
1102         msg = dbus_message_new_method_call(mp->sender, mp->path,
1103                                                 MEDIA_PLAYER_INTERFACE,
1104                                                 "Release");
1105         if (msg == NULL) {
1106                 error("Couldn't allocate D-Bus message");
1107                 return;
1108         }
1109
1110         g_dbus_send_message(btd_get_dbus_connection(), msg);
1111 }
1112
1113 static void media_player_free(gpointer data)
1114 {
1115         DBusConnection *conn = btd_get_dbus_connection();
1116         struct media_player *mp = data;
1117         struct media_adapter *adapter = mp->adapter;
1118
1119         if (mp->player) {
1120                 adapter->players = g_slist_remove(adapter->players, mp);
1121                 release_player(mp);
1122         }
1123
1124         g_dbus_remove_watch(conn, mp->watch);
1125         g_dbus_remove_watch(conn, mp->properties_watch);
1126         g_dbus_remove_watch(conn, mp->seek_watch);
1127
1128         if (mp->track)
1129                 g_hash_table_unref(mp->track);
1130
1131         if (mp->settings)
1132                 g_hash_table_unref(mp->settings);
1133
1134 #ifdef __TIZEN_PATCH__
1135         media_stop_suspend_timer();
1136
1137         if (mp->sink_watch)
1138                 sink_remove_state_cb(mp->sink_watch);
1139 #endif
1140
1141         g_timer_destroy(mp->timer);
1142         g_free(mp->sender);
1143         g_free(mp->path);
1144         g_free(mp->status);
1145         g_free(mp);
1146 }
1147
1148 static void media_player_destroy(struct media_player *mp)
1149 {
1150         struct media_adapter *adapter = mp->adapter;
1151
1152         DBG("sender=%s path=%s", mp->sender, mp->path);
1153
1154         if (mp->player) {
1155                 struct avrcp_player *player = mp->player;
1156                 mp->player = NULL;
1157                 adapter->players = g_slist_remove(adapter->players, mp);
1158                 avrcp_unregister_player(player);
1159                 return;
1160         }
1161
1162         media_player_free(mp);
1163 }
1164
1165 static void media_player_remove(struct media_player *mp)
1166 {
1167         info("Player unregistered: sender=%s path=%s", mp->sender, mp->path);
1168
1169         media_player_destroy(mp);
1170 }
1171
1172 static GList *list_settings(void *user_data)
1173 {
1174         struct media_player *mp = user_data;
1175
1176         DBG("");
1177
1178         if (mp->settings == NULL)
1179                 return NULL;
1180
1181         return g_hash_table_get_keys(mp->settings);
1182 }
1183
1184 static const char *get_setting(const char *key, void *user_data)
1185 {
1186         struct media_player *mp = user_data;
1187
1188         DBG("%s", key);
1189
1190         return g_hash_table_lookup(mp->settings, key);
1191 }
1192
1193 static void set_shuffle_setting(DBusMessageIter *iter, const char *value)
1194 {
1195         const char *key = "Shuffle";
1196         dbus_bool_t val;
1197         DBusMessageIter var;
1198
1199         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
1200         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1201                                                 DBUS_TYPE_BOOLEAN_AS_STRING,
1202                                                 &var);
1203         val = strcasecmp(value, "off") != 0;
1204         dbus_message_iter_append_basic(&var, DBUS_TYPE_BOOLEAN, &val);
1205         dbus_message_iter_close_container(iter, &var);
1206 }
1207
1208 static const char *repeat_to_loop_status(const char *value)
1209 {
1210         if (strcasecmp(value, "off") == 0)
1211                 return "None";
1212         else if (strcasecmp(value, "singletrack") == 0)
1213                 return "Track";
1214         else if (strcasecmp(value, "alltracks") == 0)
1215                 return "Playlist";
1216         else if (strcasecmp(value, "group") == 0)
1217                 return "Playlist";
1218
1219         return NULL;
1220 }
1221
1222 static void set_repeat_setting(DBusMessageIter *iter, const char *value)
1223 {
1224         const char *key = "LoopStatus";
1225         const char *val;
1226         DBusMessageIter var;
1227
1228         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
1229         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1230                                                 DBUS_TYPE_STRING_AS_STRING,
1231                                                 &var);
1232         val = repeat_to_loop_status(value);
1233         dbus_message_iter_append_basic(&var, DBUS_TYPE_STRING, &val);
1234         dbus_message_iter_close_container(iter, &var);
1235 }
1236
1237 static int set_setting(const char *key, const char *value, void *user_data)
1238 {
1239         struct media_player *mp = user_data;
1240         const char *iface = MEDIA_PLAYER_INTERFACE;
1241         DBusMessage *msg;
1242         DBusMessageIter iter;
1243         const char *curval;
1244
1245         DBG("%s = %s", key, value);
1246
1247         curval = g_hash_table_lookup(mp->settings, key);
1248         if (!curval)
1249                 return -EINVAL;
1250
1251         if (strcasecmp(curval, value) == 0)
1252                 return 0;
1253
1254         msg = dbus_message_new_method_call(mp->sender, mp->path,
1255                                         DBUS_INTERFACE_PROPERTIES, "Set");
1256         if (msg == NULL) {
1257                 error("Couldn't allocate D-Bus message");
1258                 return -ENOMEM;
1259         }
1260
1261         dbus_message_iter_init_append(msg, &iter);
1262         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &iface);
1263
1264         if (strcasecmp(key, "Shuffle") == 0)
1265                 set_shuffle_setting(&iter, value);
1266         else if (strcasecmp(key, "Repeat") == 0)
1267                 set_repeat_setting(&iter, value);
1268
1269         g_dbus_send_message(btd_get_dbus_connection(), msg);
1270
1271         return 0;
1272 }
1273
1274 static GList *list_metadata(void *user_data)
1275 {
1276         struct media_player *mp = user_data;
1277
1278         DBG("");
1279
1280         if (mp->track == NULL)
1281                 return NULL;
1282
1283         return g_hash_table_get_keys(mp->track);
1284 }
1285
1286 static uint64_t get_uid(void *user_data)
1287 {
1288         struct media_player *mp = user_data;
1289
1290         DBG("%p", mp->track);
1291
1292         if (mp->track == NULL)
1293                 return UINT64_MAX;
1294
1295 #ifdef __TIZEN_PATCH__
1296         if (!g_hash_table_lookup(mp->track, "Title"))
1297                 return UINT64_MAX;
1298 #endif
1299
1300         return 0;
1301 }
1302
1303 static const char *get_metadata(const char *key, void *user_data)
1304 {
1305         struct media_player *mp = user_data;
1306
1307         DBG("%s", key);
1308
1309         if (mp->track == NULL)
1310                 return NULL;
1311
1312         return g_hash_table_lookup(mp->track, key);
1313 }
1314
1315 static const char *get_status(void *user_data)
1316 {
1317         struct media_player *mp = user_data;
1318
1319         return mp->status;
1320 }
1321
1322 static uint32_t get_position(void *user_data)
1323 {
1324         struct media_player *mp = user_data;
1325         double timedelta;
1326         uint32_t sec, msec;
1327
1328         if (mp->status == NULL || strcasecmp(mp->status, "Playing") != 0)
1329                 return mp->position;
1330
1331         timedelta = g_timer_elapsed(mp->timer, NULL);
1332
1333         sec = (uint32_t) timedelta;
1334         msec = (uint32_t) ((timedelta - sec) * 1000);
1335
1336         return mp->position + sec * 1000 + msec;
1337 }
1338
1339 static uint32_t get_duration(void *user_data)
1340 {
1341         struct media_player *mp = user_data;
1342
1343         return mp->duration;
1344 }
1345
1346 static void set_volume(uint8_t volume, struct btd_device *dev, void *user_data)
1347 {
1348         struct media_player *mp = user_data;
1349         GSList *l;
1350
1351         if (mp->volume == volume)
1352                 return;
1353
1354         mp->volume = volume;
1355
1356         for (l = mp->adapter->endpoints; l; l = l->next) {
1357                 struct media_endpoint *endpoint = l->data;
1358                 struct media_transport *transport;
1359
1360                 /* Volume is A2DP only */
1361                 if (endpoint->sep == NULL)
1362                         continue;
1363
1364                 transport = find_device_transport(endpoint, dev);
1365                 if (transport == NULL)
1366                         continue;
1367
1368                 media_transport_update_volume(transport, volume);
1369         }
1370 }
1371
1372 static bool media_player_send(struct media_player *mp, const char *name)
1373 {
1374         DBusMessage *msg;
1375
1376         msg = dbus_message_new_method_call(mp->sender, mp->path,
1377                                         MEDIA_PLAYER_INTERFACE, name);
1378         if (msg == NULL) {
1379                 error("Couldn't allocate D-Bus message");
1380                 return false;
1381         }
1382
1383         g_dbus_send_message(btd_get_dbus_connection(), msg);
1384
1385         return true;
1386 }
1387
1388 static bool play(void *user_data)
1389 {
1390         struct media_player *mp = user_data;
1391
1392         DBG("");
1393
1394         if (!mp->play || !mp->control)
1395                 return false;
1396
1397         return media_player_send(mp, "Play");
1398 }
1399
1400 static bool stop(void *user_data)
1401 {
1402         struct media_player *mp = user_data;
1403
1404         DBG("");
1405
1406         if (!mp->control)
1407                 return false;
1408
1409         return media_player_send(mp, "Stop");
1410 }
1411
1412 static bool pause(void *user_data)
1413 {
1414         struct media_player *mp = user_data;
1415
1416         DBG("");
1417
1418         if (!mp->pause || !mp->control)
1419                 return false;
1420
1421         return media_player_send(mp, "Pause");
1422 }
1423
1424 static bool next(void *user_data)
1425 {
1426         struct media_player *mp = user_data;
1427
1428         DBG("");
1429
1430         if (!mp->next || !mp->control)
1431                 return false;
1432
1433         return media_player_send(mp, "Next");
1434 }
1435
1436 static bool previous(void *user_data)
1437 {
1438         struct media_player *mp = user_data;
1439
1440         DBG("");
1441
1442         if (!mp->previous || !mp->control)
1443                 return false;
1444
1445         return media_player_send(mp, "Previous");
1446 }
1447
1448 static struct avrcp_player_cb player_cb = {
1449         .list_settings = list_settings,
1450         .get_setting = get_setting,
1451         .set_setting = set_setting,
1452         .list_metadata = list_metadata,
1453         .get_uid = get_uid,
1454         .get_metadata = get_metadata,
1455         .get_position = get_position,
1456         .get_duration = get_duration,
1457         .get_status = get_status,
1458         .set_volume = set_volume,
1459         .play = play,
1460         .stop = stop,
1461         .pause = pause,
1462         .next = next,
1463         .previous = previous,
1464 };
1465
1466 static void media_player_exit(DBusConnection *connection, void *user_data)
1467 {
1468         struct media_player *mp = user_data;
1469
1470         mp->watch = 0;
1471         media_player_remove(mp);
1472 }
1473
1474 static gboolean set_status(struct media_player *mp, DBusMessageIter *iter)
1475 {
1476         const char *value;
1477 #ifdef __TIZEN_PATCH__
1478         uint32_t playback_position;
1479 #endif
1480
1481         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
1482                 return FALSE;
1483
1484         dbus_message_iter_get_basic(iter, &value);
1485         DBG("Status=%s", value);
1486
1487         if (g_strcmp0(mp->status, value) == 0)
1488                 return TRUE;
1489
1490         mp->position = get_position(mp);
1491         g_timer_start(mp->timer);
1492
1493         g_free(mp->status);
1494         mp->status = g_strdup(value);
1495
1496         avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, mp->status);
1497 #ifdef __TIZEN_PATCH__
1498         if (strcasecmp(mp->status, "reverse-seek") != 0) {
1499                 playback_position = get_position(mp);
1500                 avrcp_player_event(mp->player, AVRCP_EVENT_PLAYBACK_POS_CHANGED,
1501                                                         &playback_position);
1502         }
1503 #endif
1504
1505         return TRUE;
1506 }
1507
1508 static gboolean set_position(struct media_player *mp, DBusMessageIter *iter)
1509 {
1510 #ifdef __TIZEN_PATCH__
1511         uint32_t value;
1512 #else
1513         uint64_t value;
1514         const char *status;
1515 #endif
1516 #ifdef __TIZEN_PATCH__
1517         uint32_t playback_position;
1518 #endif
1519
1520 #ifndef __TIZEN_PATCH__
1521         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INT64)
1522                 return FALSE;
1523 #else
1524         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
1525                 return FALSE;
1526 #endif
1527         dbus_message_iter_get_basic(iter, &value);
1528
1529 #ifndef __TIZEN_PATCH__
1530         value /= 1000;
1531 #endif
1532         DBG("Value %d", value);
1533 #ifndef __TIZEN_PATCH__
1534         if (value > get_position(mp))
1535                 status = "forward-seek";
1536         else
1537                 status = "reverse-seek";
1538 #endif
1539
1540         mp->position = value;
1541         g_timer_start(mp->timer);
1542
1543         DBG("Position=%u", mp->position);
1544
1545         if (!mp->position) {
1546                 avrcp_player_event(mp->player,
1547                                         AVRCP_EVENT_TRACK_REACHED_START, NULL);
1548 #ifdef __TIZEN_PATCH__
1549                 playback_position = get_position(mp);
1550                 avrcp_player_event(mp->player, AVRCP_EVENT_PLAYBACK_POS_CHANGED,
1551                                                 &playback_position);
1552 #endif
1553
1554                 return TRUE;
1555         }
1556
1557         /*
1558          * If position is the maximum value allowed or greater than track's
1559          * duration, we send a track-reached-end event.
1560          */
1561         if (mp->position == UINT32_MAX || mp->position >= mp->duration) {
1562                 avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_END,
1563                                                                         NULL);
1564 #ifdef __TIZEN_PATCH__
1565                 playback_position = get_position(mp);
1566                 avrcp_player_event(mp->player, AVRCP_EVENT_PLAYBACK_POS_CHANGED,
1567                                                 &playback_position);
1568 #endif
1569                 return TRUE;
1570         }
1571
1572 #ifndef __TIZEN_PATCH__
1573         /* Send a status change to force resync the position */
1574         avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, status);
1575 #endif
1576 #ifdef __TIZEN_PATCH__
1577         playback_position = get_position(mp);
1578         avrcp_player_event(mp->player, AVRCP_EVENT_PLAYBACK_POS_CHANGED,
1579                                                 &playback_position);
1580 #endif
1581
1582         return TRUE;
1583 }
1584
1585 static void set_metadata(struct media_player *mp, const char *key,
1586                                                         const char *value)
1587 {
1588 #ifdef __TIZEN_PATCH__
1589         const char *current_value = NULL;
1590
1591         current_value = g_hash_table_lookup(mp->track, key);
1592
1593         if ((g_strcmp0(value, current_value) != 0) &&
1594                 (send_track_changed_event == FALSE))
1595                 send_track_changed_event = TRUE;
1596 #endif
1597         DBG("%s=%s", key, value);
1598         g_hash_table_replace(mp->track, g_strdup(key), g_strdup(value));
1599 }
1600
1601 static gboolean parse_string_metadata(struct media_player *mp, const char *key,
1602                                                         DBusMessageIter *iter)
1603 {
1604         const char *value;
1605
1606         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
1607                 return FALSE;
1608
1609         dbus_message_iter_get_basic(iter, &value);
1610
1611         set_metadata(mp, key, value);
1612
1613         return TRUE;
1614 }
1615
1616 static gboolean parse_array_metadata(struct media_player *mp, const char *key,
1617                                                         DBusMessageIter *iter)
1618 {
1619         DBusMessageIter array;
1620         const char *value;
1621
1622         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
1623                 return FALSE;
1624
1625         dbus_message_iter_recurse(iter, &array);
1626
1627         if (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_INVALID)
1628                 return TRUE;
1629
1630         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING)
1631                 return FALSE;
1632
1633         dbus_message_iter_get_basic(&array, &value);
1634
1635         set_metadata(mp, key, value);
1636
1637         return TRUE;
1638 }
1639
1640 static gboolean parse_int64_metadata(struct media_player *mp, const char *key,
1641                                                         DBusMessageIter *iter)
1642 {
1643         uint64_t value;
1644         char valstr[20];
1645         int type;
1646
1647         type = dbus_message_iter_get_arg_type(iter);
1648         if (type == DBUS_TYPE_UINT64)
1649                 warn("expected DBUS_TYPE_INT64 got DBUS_TYPE_UINT64");
1650         else if (type != DBUS_TYPE_INT64)
1651                 return FALSE;
1652
1653         dbus_message_iter_get_basic(iter, &value);
1654
1655         if (strcasecmp(key, "Duration") == 0) {
1656 #ifndef __TIZEN_PATCH__
1657                 value /= 1000;
1658 #endif
1659                 mp->duration = value;
1660         }
1661
1662         snprintf(valstr, 20, "%" PRIu64, value);
1663
1664         set_metadata(mp, key, valstr);
1665
1666         return TRUE;
1667 }
1668
1669 static gboolean parse_int32_metadata(struct media_player *mp, const char *key,
1670                                                         DBusMessageIter *iter)
1671 {
1672         uint32_t value;
1673         char valstr[20];
1674         int type;
1675
1676         type = dbus_message_iter_get_arg_type(iter);
1677         if (type == DBUS_TYPE_UINT32)
1678                 warn("expected DBUS_TYPE_INT32 got DBUS_TYPE_UINT32");
1679         else if (type != DBUS_TYPE_INT32)
1680                 return FALSE;
1681
1682         dbus_message_iter_get_basic(iter, &value);
1683
1684         snprintf(valstr, 20, "%u", value);
1685
1686         set_metadata(mp, key, valstr);
1687
1688         return TRUE;
1689 }
1690
1691 static gboolean parse_player_metadata(struct media_player *mp,
1692                                                         DBusMessageIter *iter)
1693 {
1694         DBusMessageIter dict;
1695         DBusMessageIter var;
1696         int ctype;
1697         gboolean title = FALSE;
1698         uint64_t uid;
1699 #ifdef __TIZEN_PATCH__
1700         uint32_t playback_position;
1701 #endif
1702
1703         ctype = dbus_message_iter_get_arg_type(iter);
1704         if (ctype != DBUS_TYPE_ARRAY)
1705                 return FALSE;
1706
1707         dbus_message_iter_recurse(iter, &dict);
1708
1709 #ifndef __TIZEN_PATCH__
1710         if (mp->track != NULL)
1711                 g_hash_table_unref(mp->track);
1712
1713         mp->track = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
1714                                                                 g_free);
1715 #endif
1716
1717         while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
1718                                                         DBUS_TYPE_INVALID) {
1719                 DBusMessageIter entry;
1720                 const char *key;
1721
1722                 if (ctype != DBUS_TYPE_DICT_ENTRY)
1723                         return FALSE;
1724
1725                 dbus_message_iter_recurse(&dict, &entry);
1726                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1727                         return FALSE;
1728
1729                 dbus_message_iter_get_basic(&entry, &key);
1730                 dbus_message_iter_next(&entry);
1731
1732                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
1733                         return FALSE;
1734
1735                 dbus_message_iter_recurse(&entry, &var);
1736
1737                 if (strcasecmp(key, "xesam:title") == 0) {
1738                         if (!parse_string_metadata(mp, "Title", &var))
1739                                 return FALSE;
1740                         title = TRUE;
1741                 } else if (strcasecmp(key, "xesam:artist") == 0) {
1742                         if (!parse_array_metadata(mp, "Artist", &var))
1743                                 return FALSE;
1744                 } else if (strcasecmp(key, "xesam:album") == 0) {
1745                         if (!parse_string_metadata(mp, "Album", &var))
1746                                 return FALSE;
1747                 } else if (strcasecmp(key, "xesam:genre") == 0) {
1748                         if (!parse_array_metadata(mp, "Genre", &var))
1749                                 return FALSE;
1750                 } else if (strcasecmp(key, "mpris:length") == 0) {
1751                         if (!parse_int64_metadata(mp, "Duration", &var))
1752                                 return FALSE;
1753 #ifdef __TIZEN_PATCH__
1754                 } else if (strcasecmp(key, "xesam:totalTracks") == 0) {
1755                         if (!parse_int32_metadata(mp, "NumberOfTracks", &var))
1756                                 return FALSE;
1757 #endif
1758                 } else if (strcasecmp(key, "xesam:trackNumber") == 0) {
1759                         if (!parse_int32_metadata(mp, "TrackNumber", &var))
1760                                 return FALSE;
1761                 } else
1762                         DBG("%s not supported, ignoring", key);
1763
1764                 dbus_message_iter_next(&dict);
1765         }
1766
1767         if (title == FALSE)
1768                 g_hash_table_insert(mp->track, g_strdup("Title"),
1769                                                                 g_strdup(""));
1770
1771 #ifdef __TIZEN_PATCH__
1772         if (send_track_changed_event) {
1773                 uid = get_uid(mp);
1774                 avrcp_player_event(mp->player,
1775                         AVRCP_EVENT_TRACK_CHANGED, &uid);
1776                 send_track_changed_event = FALSE;
1777
1778                 playback_position = get_position(mp);
1779                 avrcp_player_event(mp->player,
1780                         AVRCP_EVENT_PLAYBACK_POS_CHANGED, &playback_position);
1781         }
1782 #else
1783         mp->position = 0;
1784         g_timer_start(mp->timer);
1785         uid = get_uid(mp);
1786
1787         avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_CHANGED, &uid);
1788         avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_START, NULL);
1789 #endif
1790         return TRUE;
1791 }
1792
1793 static gboolean set_property(struct media_player *mp, const char *key,
1794                                                         const char *value)
1795 {
1796         const char *curval;
1797
1798         curval = g_hash_table_lookup(mp->settings, key);
1799         if (g_strcmp0(curval, value) == 0)
1800                 return TRUE;
1801
1802         DBG("%s=%s", key, value);
1803
1804         g_hash_table_replace(mp->settings, g_strdup(key), g_strdup(value));
1805
1806         avrcp_player_event(mp->player, AVRCP_EVENT_SETTINGS_CHANGED, key);
1807
1808         return TRUE;
1809 }
1810
1811 static gboolean set_shuffle(struct media_player *mp, DBusMessageIter *iter)
1812 {
1813         dbus_bool_t value;
1814         const char *strvalue;
1815
1816         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
1817                 return FALSE;
1818
1819         dbus_message_iter_get_basic(iter, &value);
1820
1821         strvalue = value ? "alltracks" : "off";
1822
1823         return set_property(mp, "Shuffle", strvalue);
1824 }
1825
1826 static const char *loop_status_to_repeat(const char *value)
1827 {
1828         if (strcasecmp(value, "None") == 0)
1829                 return "off";
1830         else if (strcasecmp(value, "Track") == 0)
1831                 return "singletrack";
1832         else if (strcasecmp(value, "Playlist") == 0)
1833                 return "alltracks";
1834
1835         return NULL;
1836 }
1837
1838 static gboolean set_repeat(struct media_player *mp, DBusMessageIter *iter)
1839 {
1840         const char *value;
1841
1842         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
1843                 return FALSE;
1844
1845         dbus_message_iter_get_basic(iter, &value);
1846
1847         value = loop_status_to_repeat(value);
1848         if (value == NULL)
1849                 return FALSE;
1850
1851         return set_property(mp, "Repeat", value);
1852 }
1853
1854 static gboolean set_flag(struct media_player *mp, DBusMessageIter *iter,
1855                                                                 bool *var)
1856 {
1857         dbus_bool_t value;
1858
1859         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
1860                 return FALSE;
1861
1862         dbus_message_iter_get_basic(iter, &value);
1863
1864         *var = value;
1865
1866         return TRUE;
1867 }
1868
1869 static gboolean set_player_property(struct media_player *mp, const char *key,
1870                                                         DBusMessageIter *entry)
1871 {
1872         DBusMessageIter var;
1873
1874         if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
1875                 return FALSE;
1876
1877         dbus_message_iter_recurse(entry, &var);
1878
1879         if (strcasecmp(key, "PlaybackStatus") == 0)
1880                 return set_status(mp, &var);
1881
1882         if (strcasecmp(key, "Position") == 0)
1883                 return set_position(mp, &var);
1884
1885         if (strcasecmp(key, "Metadata") == 0)
1886                 return parse_player_metadata(mp, &var);
1887
1888         if (strcasecmp(key, "Shuffle") == 0)
1889                 return set_shuffle(mp, &var);
1890
1891         if (strcasecmp(key, "LoopStatus") == 0)
1892                 return set_repeat(mp, &var);
1893
1894         if (strcasecmp(key, "CanPlay") == 0)
1895                 return set_flag(mp, &var, &mp->play);
1896
1897         if (strcasecmp(key, "CanPause") == 0)
1898                 return set_flag(mp, &var, &mp->pause);
1899
1900         if (strcasecmp(key, "CanGoNext") == 0)
1901                 return set_flag(mp, &var, &mp->next);
1902
1903         if (strcasecmp(key, "CanGoPrevious") == 0)
1904                 return set_flag(mp, &var, &mp->previous);
1905
1906         if (strcasecmp(key, "CanControl") == 0)
1907                 return set_flag(mp, &var, &mp->control);
1908
1909         DBG("%s not supported, ignoring", key);
1910
1911         return TRUE;
1912 }
1913
1914 static gboolean parse_player_properties(struct media_player *mp,
1915                                                         DBusMessageIter *iter)
1916 {
1917         DBusMessageIter dict;
1918         int ctype;
1919
1920         ctype = dbus_message_iter_get_arg_type(iter);
1921         if (ctype != DBUS_TYPE_ARRAY)
1922                 return FALSE;
1923
1924         dbus_message_iter_recurse(iter, &dict);
1925
1926         while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
1927                                                         DBUS_TYPE_INVALID) {
1928                 DBusMessageIter entry;
1929                 const char *key;
1930
1931                 if (ctype != DBUS_TYPE_DICT_ENTRY)
1932                         return FALSE;
1933
1934                 dbus_message_iter_recurse(&dict, &entry);
1935                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1936                         return FALSE;
1937
1938                 dbus_message_iter_get_basic(&entry, &key);
1939                 dbus_message_iter_next(&entry);
1940
1941                 if (set_player_property(mp, key, &entry) == FALSE)
1942                         return FALSE;
1943
1944                 dbus_message_iter_next(&dict);
1945         }
1946
1947         return TRUE;
1948 }
1949
1950 static gboolean properties_changed(DBusConnection *connection, DBusMessage *msg,
1951                                                         void *user_data)
1952 {
1953         struct media_player *mp = user_data;
1954         DBusMessageIter iter;
1955
1956         DBG("sender=%s path=%s", mp->sender, mp->path);
1957
1958         dbus_message_iter_init(msg, &iter);
1959
1960         dbus_message_iter_next(&iter);
1961
1962         parse_player_properties(mp, &iter);
1963
1964         return TRUE;
1965 }
1966
1967 static gboolean position_changed(DBusConnection *connection, DBusMessage *msg,
1968                                                         void *user_data)
1969 {
1970         struct media_player *mp = user_data;
1971         DBusMessageIter iter;
1972
1973         DBG("sender=%s path=%s", mp->sender, mp->path);
1974
1975         dbus_message_iter_init(msg, &iter);
1976
1977         set_position(mp, &iter);
1978
1979         return TRUE;
1980 }
1981
1982 static struct media_player *media_player_create(struct media_adapter *adapter,
1983                                                 const char *sender,
1984                                                 const char *path,
1985                                                 int *err)
1986 {
1987         DBusConnection *conn = btd_get_dbus_connection();
1988         struct media_player *mp;
1989
1990         mp = g_new0(struct media_player, 1);
1991         mp->adapter = adapter;
1992         mp->sender = g_strdup(sender);
1993         mp->path = g_strdup(path);
1994         mp->timer = g_timer_new();
1995
1996         mp->watch = g_dbus_add_disconnect_watch(conn, sender,
1997                                                 media_player_exit, mp,
1998                                                 NULL);
1999         mp->properties_watch = g_dbus_add_properties_watch(conn, sender,
2000                                                 path, MEDIA_PLAYER_INTERFACE,
2001                                                 properties_changed,
2002                                                 mp, NULL);
2003         mp->seek_watch = g_dbus_add_signal_watch(conn, sender,
2004                                                 path, MEDIA_PLAYER_INTERFACE,
2005                                                 "Seeked", position_changed,
2006                                                 mp, NULL);
2007         mp->player = avrcp_register_player(adapter->btd_adapter, &player_cb,
2008                                                         mp, media_player_free);
2009         if (!mp->player) {
2010                 if (err)
2011                         *err = -EPROTONOSUPPORT;
2012                 media_player_destroy(mp);
2013                 return NULL;
2014         }
2015
2016         mp->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
2017                                                                 g_free);
2018 #ifdef __TIZEN_PATCH__
2019         mp->track = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
2020                                                                 g_free);
2021 #endif
2022
2023         adapter->players = g_slist_append(adapter->players, mp);
2024
2025         info("Player registered: sender=%s path=%s", sender, path);
2026
2027         if (err)
2028                 *err = 0;
2029
2030         return mp;
2031 }
2032
2033 static DBusMessage *register_player(DBusConnection *conn, DBusMessage *msg,
2034                                         void *data)
2035 {
2036         struct media_adapter *adapter = data;
2037         struct media_player *mp;
2038         DBusMessageIter args;
2039         const char *sender, *path;
2040         int err;
2041
2042         sender = dbus_message_get_sender(msg);
2043
2044         dbus_message_iter_init(msg, &args);
2045
2046         dbus_message_iter_get_basic(&args, &path);
2047         dbus_message_iter_next(&args);
2048
2049         if (media_adapter_find_player(adapter, sender, path) != NULL)
2050                 return btd_error_already_exists(msg);
2051
2052         mp = media_player_create(adapter, sender, path, &err);
2053         if (mp == NULL) {
2054                 if (err == -EPROTONOSUPPORT)
2055                         return btd_error_not_supported(msg);
2056                 else
2057                         return btd_error_invalid_args(msg);
2058         }
2059
2060         if (parse_player_properties(mp, &args) == FALSE) {
2061                 media_player_destroy(mp);
2062                 return btd_error_invalid_args(msg);
2063         }
2064
2065         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2066 }
2067
2068 static DBusMessage *unregister_player(DBusConnection *conn, DBusMessage *msg,
2069                                         void *data)
2070 {
2071         struct media_adapter *adapter = data;
2072         struct media_player *player;
2073         const char *sender, *path;
2074
2075         if (!dbus_message_get_args(msg, NULL,
2076                                 DBUS_TYPE_OBJECT_PATH, &path,
2077                                 DBUS_TYPE_INVALID))
2078                 return btd_error_invalid_args(msg);
2079
2080         sender = dbus_message_get_sender(msg);
2081
2082         player = media_adapter_find_player(adapter, sender, path);
2083         if (player == NULL)
2084                 return btd_error_does_not_exist(msg);
2085
2086         media_player_remove(player);
2087
2088         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2089 }
2090
2091 static const GDBusMethodTable media_methods[] = {
2092         { GDBUS_METHOD("RegisterEndpoint",
2093                 GDBUS_ARGS({ "endpoint", "o" }, { "properties", "a{sv}" }),
2094                 NULL, register_endpoint) },
2095         { GDBUS_METHOD("UnregisterEndpoint",
2096                 GDBUS_ARGS({ "endpoint", "o" }), NULL, unregister_endpoint) },
2097 #ifndef __TIZEN_PATCH__
2098         { GDBUS_EXPERIMENTAL_METHOD("RegisterPlayer",
2099                 GDBUS_ARGS({ "player", "o" }, { "properties", "a{sv}" }),
2100                 NULL, register_player) },
2101         { GDBUS_EXPERIMENTAL_METHOD("UnregisterPlayer",
2102                 GDBUS_ARGS({ "player", "o" }), NULL, unregister_player) },
2103 #else
2104         { GDBUS_METHOD("RegisterPlayer",
2105                 GDBUS_ARGS({ "player", "o" }, { "properties", "a{sv}" }),
2106                 NULL, register_player) },
2107         { GDBUS_METHOD("UnregisterPlayer",
2108                 GDBUS_ARGS({ "player", "o" }), NULL, unregister_player) },
2109 #endif /* __TIZEN_PATCH__ */
2110         { },
2111 };
2112
2113 static void path_free(void *data)
2114 {
2115         struct media_adapter *adapter = data;
2116
2117         while (adapter->endpoints)
2118                 release_endpoint(adapter->endpoints->data);
2119
2120         while (adapter->players)
2121                 media_player_destroy(adapter->players->data);
2122
2123         adapters = g_slist_remove(adapters, adapter);
2124
2125         btd_adapter_unref(adapter->btd_adapter);
2126         g_free(adapter);
2127 }
2128
2129 int media_register(struct btd_adapter *btd_adapter)
2130 {
2131         struct media_adapter *adapter;
2132
2133         adapter = g_new0(struct media_adapter, 1);
2134         adapter->btd_adapter = btd_adapter_ref(btd_adapter);
2135
2136         if (!g_dbus_register_interface(btd_get_dbus_connection(),
2137                                         adapter_get_path(btd_adapter),
2138                                         MEDIA_INTERFACE,
2139                                         media_methods, NULL, NULL,
2140                                         adapter, path_free)) {
2141                 error("D-Bus failed to register %s path",
2142                                                 adapter_get_path(btd_adapter));
2143                 path_free(adapter);
2144                 return -1;
2145         }
2146
2147         adapters = g_slist_append(adapters, adapter);
2148
2149         return 0;
2150 }
2151
2152 void media_unregister(struct btd_adapter *btd_adapter)
2153 {
2154         GSList *l;
2155
2156         for (l = adapters; l; l = l->next) {
2157                 struct media_adapter *adapter = l->data;
2158
2159                 if (adapter->btd_adapter == btd_adapter) {
2160                         g_dbus_unregister_interface(btd_get_dbus_connection(),
2161                                                 adapter_get_path(btd_adapter),
2162                                                 MEDIA_INTERFACE);
2163                         return;
2164                 }
2165         }
2166 }
2167
2168 struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint)
2169 {
2170         return endpoint->sep;
2171 }
2172
2173 const char *media_endpoint_get_uuid(struct media_endpoint *endpoint)
2174 {
2175         return endpoint->uuid;
2176 }
2177
2178 uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint)
2179 {
2180         return endpoint->codec;
2181 }