Add favorite list on action menu
[profile/tv/apps/native/air_livetv.git] / src / tv.c
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <app.h>
19 #include <iconv.h>
20 #include <math.h>
21 #include <app_debug.h>
22 #include <app_contents.h>
23
24 #include <tv_service_proxy.h>
25 #include <tv_service_proxy_epg.h>
26
27 #include <glib.h>
28 #include <glib-object.h>
29
30 #include "define.h"
31 #include "tv.h"
32
33 #define DEFAULT_SERVICE 1
34
35 /**
36  * The Storage structure to used by tv related functions and events.
37  */
38 struct _tv_info {
39         /**< The handle to use tv service live api. */
40         TvServiceLive live_svc;
41         /**< The handle to use tv service epg api. */
42         TvServiceEpg epg_svc;
43
44         /**< Stores service id if tune to locked channel was succeeded. */
45         int viewing_locked_channel;
46
47         /**< The function pointer to pass tv signal event */
48         void (*signal_cb)(void *data, int is_signal);
49         /**< An Additional data to passed to tv signal event */
50         void *signal_cb_data;
51 };
52
53 static struct _tv_info g_tv_info;
54
55 /**
56  * Gets the tv_channel_info with supplied TvServiceChannel.
57  *
58  * Abstracts tv service data structure.
59  *
60  * @param channel The channel data defined by tv service
61  * @return Channel information, or NULL if fails
62  */
63 static struct tv_channel_info *_tv_channel_get_info(TvServiceChannel *channel)
64 {
65         struct tv_channel_info *channel_info = NULL;
66
67         if (!channel) {
68                 _ERR("failed to get channel");
69                 return NULL;
70         }
71
72         channel_info = calloc(1, sizeof(*channel_info));
73         if (!channel_info) {
74                 _ERR("failed to calloc channel info");
75                 return NULL;
76         }
77
78         channel_info->service_id = channel->service_id;
79         channel_info->channel_major = channel->major;
80         channel_info->channel_minor = channel->minor;
81         channel_info->channel_type = channel->channel_type;
82         channel_info->locked = channel->locked;
83         channel_info->digital = channel->digital;
84         channel_info->favorite = channel->favorite;
85         channel_info->remembered = channel->remembered;
86         strncpy(channel_info->channel_name, channel->program_name,
87                 CHANNEL_NAME_MAX);
88
89         if (channel->service_id == g_tv_info.viewing_locked_channel)
90                 channel_info->tune_locked = EINA_TRUE;
91
92         return channel_info;
93 }
94
95 /**
96  * Clones the tv_channel_info.
97  *
98  * @param channel_info tv_channel_info pointer to be cloned
99  * @return Channel information, or NULL if fails
100  */
101 const struct tv_channel_info *tv_channel_clone_info(
102                 const struct tv_channel_info *channel_info)
103 {
104         struct tv_channel_info *new_channel_info = NULL;
105
106         if (!channel_info) {
107                 _ERR("failed to get channel info");
108                 return NULL;
109         }
110
111         new_channel_info = calloc(1, sizeof(*channel_info));
112         if (!new_channel_info) {
113                 _ERR("failed to calloc channel info");
114                 return NULL;
115         }
116
117         memcpy(new_channel_info, channel_info, sizeof(*new_channel_info));
118
119         return new_channel_info;
120 }
121
122 /**
123  * Frees the tv_channel_info.
124  *
125  * @param channel_info tv_channel_info pointer to be freed
126  */
127 void tv_channel_del_info(const struct tv_channel_info *channel_info)
128 {
129         if (!channel_info) {
130                 _ERR("failed to get channel info");
131                 return;
132         }
133
134         free((void *)channel_info);
135 }
136
137 /**
138  * Gets current channel's TvServiceChannel data from tv service.
139  *
140  * @param channel The pointer to store TvServiceChannel
141  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
142  */
143 static int _tv_get_channel(TvServiceChannel *channel)
144 {
145         gint svc_id;
146         int r;
147
148         if (!g_tv_info.live_svc) {
149                 _ERR("failed to get live service");
150                 return -1;
151         }
152
153         r = tv_service_live_get_service_id(g_tv_info.live_svc, &svc_id);
154         if (r < 0) {
155                 _ERR("failed to get service id");
156                 return -1;
157         }
158
159         r = tv_service_get_channel(svc_id, channel);
160         if (r < 0) {
161                 _ERR("failed to get channel");
162                 return -1;
163         }
164
165         return 0;
166 }
167
168 /**
169  * Returns current channel's info.
170  *
171  * tv_channel_get_info retrieves current channel's information
172  * from tv service.
173  *
174  * @return Returns current channel info, or NULL if fails
175  */
176 const struct tv_channel_info *tv_channel_get_info(void)
177 {
178         const struct tv_channel_info *channel_info;
179         TvServiceChannel channel;
180         int r;
181
182         r = _tv_get_channel(&channel);
183         if (r < 0) {
184                 _ERR("failed to get channel");
185                 return NULL;
186         }
187
188         channel_info = _tv_channel_get_info(&channel);
189
190         return channel_info;
191 }
192
193 /**
194  * Returns tv_program_info with supplied TvServiceEpgEventData.
195  *
196  * Abstracts tv service data structure.
197  *
198  * @param prog TvServiceEpgEventData passed from tv service
199  * @return Returns tv_program_info, or NULL if fails
200  */
201 static struct tv_program_info *_tv_get_program_info(TvServiceEpgEventData *prog)
202 {
203         struct tv_program_info *prog_info;
204
205         prog_info = calloc(1, sizeof(*prog_info));
206         if (!prog_info) {
207                 _ERR("failed to calloc program info");
208                 return NULL;
209         }
210
211         prog_info->service_id = prog->service_id;
212         prog_info->start_time = prog->start_time;
213         prog_info->end_time = prog->start_time + prog->length_in_seconds;
214         prog_info->duration = prog->length_in_seconds;
215         prog_info->current_time = prog->current_time;
216         strncpy(prog_info->prog_title, (char *)prog->title_text,
217                         sizeof(prog_info->prog_title) - 1);
218         strncpy(prog_info->prog_description, (char *)prog->extended_text,
219                         sizeof(prog_info->prog_description) - 1);
220
221         return prog_info;
222 }
223
224 /**
225  * Gets current channel's service id from tv service.
226  *
227  * @param service_id The pointer to store service id
228  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
229  */
230 int tv_get_current_service_id(int *service_id)
231 {
232         int r;
233
234         if (!g_tv_info.live_svc) {
235                 _ERR("failed to get live service");
236                 return -1;
237         }
238
239         r = tv_service_live_get_service_id(g_tv_info.live_svc, service_id);
240         if (r != TVS_ERROR_OK) {
241                 _ERR("failed to get current service info");
242                 return -1;
243         }
244
245         return 0;
246 }
247
248 /**
249  * Frees epg list.
250  *
251  * @param epg_list Eina_List to be freed
252  */
253 static void _tv_epg_del_list(Eina_List *epg_list)
254 {
255         struct tv_program_info *data;
256
257         EINA_LIST_FREE(epg_list, data)
258                 free(data);
259 }
260
261 /**
262  * Callback function to get EPG program list from tv service.
263  *
264  * _tv_epg_event_cb is called from tv service when banner
265  * have requested to get program data.
266  * If this function is called, then derives program list from epg_list
267  * and calls banner's callback function which included in user_data.
268  *
269  * @param type Event type
270  * @param epg_list EPG program list
271  * @param user_data tv_program_request to handle request
272  */
273 static void _tv_epg_event_cb(tvs_epg_event_e type, GList *epg_list,
274                 void *user_data)
275 {
276         int i;
277         Eina_List *list = NULL;
278         TvServiceEpgEventData *epg_data;
279         struct tv_program_info *prog_info;
280         struct tv_program_request *request;
281
282         if (!user_data) {
283                 _ERR("failed to get user_data");
284                 return;
285         }
286
287         for (i = 0; i < g_list_length(epg_list); i++) {
288                 epg_data = (TvServiceEpgEventData *)
289                                 g_list_nth_data(epg_list, i);
290
291                 if (!epg_data)
292                         continue;
293
294                 prog_info = _tv_get_program_info(epg_data);
295                 if (prog_info)
296                         list = eina_list_append(list, prog_info);
297         }
298
299         request = (struct tv_program_request *) user_data;
300         if (request->tv_program_cb)
301                 request->tv_program_cb(list, request->user_data);
302
303         if (list)
304                 _tv_epg_del_list(list);
305
306         free(request);
307 }
308
309 /**
310  * Send a request to tv service to get a current program with supplied service_id.
311  *
312  * Beware that service_id should be current tuned channel.
313  * If not, calling this function may cause unexpected behavior.
314  * And note that get a EPG program is asynchronous operation.
315  * So tv_program_request should be supplied to get a result from tv service.
316  *
317  * @param service_id The channel id to get current program
318  * @param request The structure for return program data which contains function pointer
319  *        and additional data for banner
320  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
321  */
322 int tv_epg_get_program(int service_id, struct tv_program_request *request)
323 {
324         int r;
325
326         if (!g_tv_info.epg_svc) {
327                 _ERR("failed to get epg service");
328                 return -1;
329         }
330
331         if (!request) {
332                 _ERR("failed to get tv_program_request");
333                 return -1;
334         }
335
336         r = tv_service_epg_get_current_program(g_tv_info.epg_svc, service_id,
337                         (TvServiceEpgCallback) _tv_epg_event_cb, request);
338         if (r != TVS_ERROR_OK) {
339                 _ERR("failed to get epg get current program : %d", service_id);
340                 free(request);
341                 return -1;
342         }
343
344         return 0;
345 }
346
347 /**
348  * Gets a cached current program with supplied service_id from tv service.
349  *
350  * Note that this function is vaild only when tv service having a cached data
351  * on that channel.
352  * To have a cached data, the channel ever been tuned before calling
353  * this function.
354  *
355  * @param service_id The channel id to get current program
356  * @param request The structure for return program data which contains
357  *        function pointer and additional data for banner
358  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
359  */
360 int tv_epg_get_cache_program(int service_id, struct tv_program_request *request)
361 {
362         Eina_List *list = NULL;
363         TvServiceEpgEventData epg_data;
364         struct tv_program_info *prog_info;
365
366         int r;
367
368         if (!g_tv_info.epg_svc) {
369                 _ERR("failed to get epg service");
370                 return -1;
371         }
372
373         if (!request) {
374                 _ERR("failed to get tv_program_request");
375                 return -1;
376         }
377
378         r = tv_service_epg_get_cache_current_program(
379                         g_tv_info.epg_svc, service_id, &epg_data);
380         if (r != TVS_ERROR_OK) {
381                 _ERR("failed to get epg get cached current program : %d",
382                                 service_id);
383                 return -1;
384         }
385
386         prog_info = _tv_get_program_info(&epg_data);
387         if (prog_info)
388                 list = eina_list_append(list, prog_info);
389
390         if (request->tv_program_cb)
391                 request->tv_program_cb(list, request->user_data);
392
393         if (list)
394                 _tv_epg_del_list(list);
395
396         free(request);
397
398         return 0;
399 }
400
401 /**
402  * Sends a request to tv service to get programs with supplied service_id.
403  *
404  * Beware that service_id should be current tuned channel.
405  * If not, calling this function may cause unexpected behavior.
406  * And note that get a EPG program is asynchronous operation.
407  * So tv_program_request should be supplied to get a result from tv service.
408  *
409  * @param service_id The channel id to get current program
410  * @param request The structure for return program data which contains function pointer and additional data for banner
411  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
412  */
413 int tv_epg_get_program_list(int service_id,
414                 struct tv_program_request *request)
415 {
416         int r;
417
418         if (!g_tv_info.epg_svc) {
419                 _ERR("failed to get epg service");
420                 return -1;
421         }
422
423         if (!request) {
424                 _ERR("failed to get tv_program_request");
425                 return -1;
426         }
427
428         r = tv_service_epg_get_program_list(g_tv_info.epg_svc, service_id,
429                         TVS_EPG_CURRENT_TIME, EPG_PROGRAM_OFFSET,
430                         (TvServiceEpgCallback) _tv_epg_event_cb, request);
431         if (r != TVS_ERROR_OK) {
432                 _ERR("failed to get epg get current program");
433                 return -1;
434         }
435
436         return 0;
437 }
438
439 /**
440  * Frees the TvServiceFilterNode.
441  *
442  * @param data TvServiceFilterNode pointer to be freed
443  */
444 static void _tv_channel_free_filter(gpointer data)
445 {
446         TvServiceFilterNode *filter_node;
447
448         if (!data)
449                 return;
450
451         filter_node = (TvServiceFilterNode *) data;
452
453         g_value_unset(filter_node->value);
454         g_free(filter_node->value);
455         g_free(filter_node);
456 }
457
458 /**
459  * Gets a available channel list.
460  *
461  * Note that deleted channels and service channels are excluded by default.
462  *
463  * @return Available channel list, or NULL if fails
464  */
465 Eina_List *tv_channel_get_list()
466 {
467         GList *tvs_list = NULL;
468         Eina_List *channel_list = NULL;
469         TvServiceChannel *tvs_data = NULL;
470         const struct tv_channel_info *channel_info;
471         int r, i;
472
473         r = tv_service_get_channel_list(
474                         TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG,
475                         TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list);
476         if (r != TVS_ERROR_OK) {
477                 _ERR("failed to get channel list");
478                 return NULL;
479         }
480
481         for (i = 0; i < g_list_length(tvs_list); i++) {
482                 tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, i);
483                 if (tvs_data) {
484                         channel_info = _tv_channel_get_info(tvs_data);
485                         if (channel_info)
486                                 channel_list = eina_list_append(channel_list,
487                                                 channel_info);
488                         free(tvs_data);
489                 }
490         }
491
492         return channel_list;
493 }
494
495 /**
496  * Gets a favorite channel list.
497  *
498  * @return Favorite channel list, or NULL if fails
499  */
500 Eina_List *tv_channel_get_favorite_list()
501 {
502         GList *tvs_list = NULL;
503         Eina_List *channel_list = NULL;
504         TvServiceChannel *tvs_data = NULL;
505         const struct tv_channel_info *channel_info;
506         int r, i;
507
508         r = tv_service_get_channel_list(
509                         TV_SERVICE_CHANNEL_MODE_FAVORITE,
510                         TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list);
511         if (r != TVS_ERROR_OK) {
512                 _ERR("failed to get channel list");
513                 return NULL;
514         }
515
516         for (i = 0; i < g_list_length(tvs_list); i++) {
517                 tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, i);
518                 if (tvs_data) {
519                         channel_info = _tv_channel_get_info(tvs_data);
520                         if (channel_info)
521                                 channel_list = eina_list_append(channel_list,
522                                                 channel_info);
523                         free(tvs_data);
524                 }
525         }
526
527         return channel_list;
528 }
529
530 TvServiceFilterNode *_tv_channel_get_filter(
531                 TvServiceChannelDataAttr attribute, int type, void *data)
532 {
533         TvServiceFilterNode *filter;
534         GValue *value;
535
536         filter = g_malloc0(sizeof(*filter));
537         if (!filter)
538                 return NULL;
539
540         filter->attribute = attribute;
541
542         value = g_malloc0(sizeof(GValue));
543         if (!value) {
544                 g_free(filter);
545                 return NULL;
546         }
547
548         switch (type) {
549         case G_TYPE_STRING:
550                 g_value_init(value, G_TYPE_STRING);
551                 g_value_set_string(value, data);
552
553                 filter->match_type = CHANNEL_FILTER_MATCH_CONTAIN;
554                 break;
555         case G_TYPE_INT:
556                 g_value_init(value, G_TYPE_INT);
557                 g_value_set_int(value, (gint) data);
558
559                 filter->match_type = CHANNEL_FILTER_MATCH_EQUAL;
560                 break;
561         }
562         filter->value = value;
563
564         return filter;
565 }
566
567 /**
568  * Search channels that are starts with supplied major and minor number.
569  *
570  * Note that deleted channels and service channels are excluded by default.
571  *
572  * @param major Major channel number to search
573  * @param minor Minor channel number to search
574  * @return Found channel list, or NULL if fails
575  */
576 Eina_List *tv_channel_search_by_number(long major, long minor)
577 {
578         char buf[CHANNEL_FILTER_STRING_MAX_LEN];
579         GList *tvs_list = NULL, *filter = NULL;
580         TvServiceFilterNode *filter_node;
581         TvServiceChannel *tvs_data;
582         Eina_List *channel_list = NULL;
583         const struct tv_channel_info *channel_info;
584         int i, r;
585
586         if (major > 0 && major < MAJOR_MAX) {
587                 snprintf(buf, CHANNEL_FILTER_STRING_MAX_LEN, "%ld", major);
588
589                 filter_node = _tv_channel_get_filter(
590                                 TV_SERVICE_CHANNEL_DATA_MAJOR_NUMBER,
591                                 G_TYPE_STRING, buf);
592                 if (filter_node)
593                         filter = g_list_append(filter, (gpointer)filter_node);
594         }
595
596         if (minor > 0 && minor < MINOR_MAX) {
597                 snprintf(buf, CHANNEL_FILTER_STRING_MAX_LEN, "%ld", minor);
598
599                 filter_node = _tv_channel_get_filter(
600                                 TV_SERVICE_CHANNEL_DATA_MINOR_NUMBER,
601                                 G_TYPE_STRING, buf);
602                 if (filter_node)
603                         filter = g_list_append(filter, (gpointer)filter_node);
604         }
605
606         if (!filter) {
607                 _ERR("failed to get filter");
608                 return NULL;
609         }
610
611         r = tv_service_get_channel_list_ex(
612                         TV_SERVICE_CHANNEL_MODE_ALL_DIGITAL_ANALOG,
613                         TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list, filter, 0);
614         if (r != TVS_ERROR_OK) {
615                 _ERR("failed to get channel list");
616                 goto free;
617         }
618
619         for (i = 0; i < g_list_length(tvs_list); i++) {
620                 tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, i);
621                 if (!tvs_data)
622                         continue;
623
624                 channel_info = _tv_channel_get_info(tvs_data);
625                 if (channel_info)
626                         channel_list = eina_list_append(channel_list,
627                                         channel_info);
628                 free(tvs_data);
629         }
630
631 free:
632         if (tvs_list)
633                 g_list_free(tvs_list);
634
635         g_list_foreach(filter, (GFunc) _tv_channel_free_filter, NULL);
636         g_list_free(filter);
637
638         return channel_list;
639 }
640
641 /**
642  * Frees the tv_channel_info.
643  *
644  * @param channel_list channel_list pointer to be freed
645  */
646 void tv_channel_del_list(Eina_List *channel_list)
647 {
648         struct tv_channel_info *data;
649
650         EINA_LIST_FREE(channel_list, data)
651                 free(data);
652 }
653
654 void _tv_channel_add_history(int service_id)
655 {
656         char buf[128];
657
658         snprintf(buf, sizeof(buf), "%d", service_id);
659         app_contents_recent_add(CONTENTS_CHANNEL, buf);
660 }
661
662 /**
663  * Tunes to specific channel with service id.
664  *
665  * @param service_id The channel id
666  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
667  */
668 int tv_channel_tune_with_service_id(int service_id)
669 {
670         int r;
671
672         if (!g_tv_info.live_svc) {
673                 _ERR("failed to get live service");
674                 return -1;
675         }
676
677         r = tv_service_live_tune(g_tv_info.live_svc, service_id);
678         if (r != TVS_ERROR_OK) {
679                 _ERR("failed to set service");
680                 return -1;
681         }
682
683         _tv_channel_add_history(service_id);
684
685         g_tv_info.viewing_locked_channel = -1;
686
687         return 0;
688 }
689
690 /**
691  * Tunes to last viewed channel.
692  *
693  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
694  */
695 int tv_channel_tune(void)
696 {
697         int service_id;
698         int r;
699
700         if (!g_tv_info.live_svc) {
701                 _ERR("failed to get live service");
702                 return -1;
703         }
704
705         r = tv_service_live_get_last_channel(&service_id);
706         if (r < 0 || service_id < 1) {
707                 _ERR("failed to get current service id");
708                 service_id = DEFAULT_SERVICE;
709         }
710
711         r = tv_service_live_tune(g_tv_info.live_svc, service_id);
712         if (r != TVS_ERROR_OK) {
713                 _ERR("failed to set service");
714                 return -1;
715         }
716
717         _tv_channel_add_history(service_id);
718
719         g_tv_info.viewing_locked_channel = -1;
720
721         return 0;
722 }
723
724 /**
725  * Tunes to specific channel with major and minor.
726  *
727  * @param service_id The channel id
728  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
729  */
730 int tv_channel_direct_tune(long major, long minor)
731 {
732         GList *tvs_list = NULL, *filter = NULL;
733         TvServiceFilterNode *filter_node;
734         TvServiceChannel *tvs_data;
735         int r;
736
737         if (major > 0 && major < MAJOR_MAX) {
738                 filter_node = _tv_channel_get_filter(
739                                 TV_SERVICE_CHANNEL_DATA_MAJOR_NUMBER,
740                                 G_TYPE_INT, (void *) major);
741                 if (filter_node)
742                         filter = g_list_append(filter, (gpointer)filter_node);
743         }
744
745         if (minor > 0 && minor < MINOR_MAX) {
746                 filter_node = _tv_channel_get_filter(
747                                 TV_SERVICE_CHANNEL_DATA_MINOR_NUMBER,
748                                 G_TYPE_INT, (void *) minor);
749                 if (filter_node)
750                         filter = g_list_append(filter, (gpointer)filter_node);
751         }
752
753         if (!filter) {
754                 _ERR("failed to get filter");
755                 return -1;
756         }
757
758         r = tv_service_get_channel_list_ex(
759                         TV_SERVICE_CHANNEL_MODE_ALL_DIGITAL_ANALOG,
760                         TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list, filter, 0);
761         if (r != TVS_ERROR_OK)
762                 goto free;
763
764         tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, 0);
765         if (tvs_data)
766                 r = tv_channel_tune_with_service_id(tvs_data->service_id);
767         else {
768                 _ERR("failed to get tvs_data");
769                 r = -1;
770         }
771
772         if (r == TVS_ERROR_OK)
773                 g_tv_info.viewing_locked_channel = -1;
774
775         g_list_foreach(tvs_list, (GFunc) g_free, NULL);
776         g_list_free(tvs_list);
777
778 free:
779         g_list_foreach(filter, (GFunc) _tv_channel_free_filter, NULL);
780         g_list_free(filter);
781
782         return r;
783 }
784
785 /**
786  * Tunes to locked channel.
787  *
788  * @param service_id The channel id
789  * @param password 4 digit password
790  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
791  */
792 int tv_channel_tune_locked_channel(int service_id, char *password)
793 {
794         int r;
795
796         if (!g_tv_info.live_svc) {
797                 _ERR("failed to get live service");
798                 return -1;
799         }
800
801         r = tv_service_live_tune_locked_channel(g_tv_info.live_svc,
802                         service_id, password);
803         if (r != TVS_ERROR_OK) {
804                 _ERR("failed to set service");
805                 return -1;
806         }
807
808         _tv_channel_add_history(service_id);
809
810         g_tv_info.viewing_locked_channel = service_id;
811
812         return 0;
813 }
814
815 /**
816  * Tunes to next channel.
817  *
818  * Note that deleted channels and service channels will skipped.
819  *
820  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
821  */
822 int tv_channel_next(void)
823 {
824         TvServiceAntenna antenna_type;
825         int service_id, r;
826
827         if (!g_tv_info.live_svc) {
828                 _ERR("failed to get live service");
829                 return -1;
830         }
831
832         r = tv_service_live_get_antenna_type(g_tv_info.live_svc, &antenna_type);
833         if (r < 0) {
834                 _ERR("failed to get antenna type");
835                 return -1;
836         }
837
838         r = tv_service_live_tune_up(g_tv_info.live_svc,
839                         TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, antenna_type);
840         if (r < 0) {
841                 _ERR("failed to tune up");
842                 return -1;
843         }
844
845         g_tv_info.viewing_locked_channel = -1;
846
847         r = tv_service_live_get_service_id(g_tv_info.live_svc, &service_id);
848         if (r < 0) {
849                 _ERR("failed to get service id");
850                 return -1;
851         }
852
853         _tv_channel_add_history(service_id);
854
855         return 0;
856 }
857
858 /**
859  * Tunes to previous channel.
860  *
861  * Note that deleted channels and service channels will skipped.
862  *
863  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
864  */
865 int tv_channel_prev(void)
866 {
867         TvServiceAntenna antenna_type;
868         int service_id, r;
869
870         if (!g_tv_info.live_svc) {
871                 _ERR("failed to get live service");
872                 return -1;
873         }
874
875         r = tv_service_live_get_antenna_type(g_tv_info.live_svc, &antenna_type);
876         if (r < 0) {
877                 _ERR("failed to get antenna type");
878                 return -1;
879         }
880
881         r = tv_service_live_tune_down(g_tv_info.live_svc,
882                         TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, antenna_type);
883         if (r < 0) {
884                 _ERR("failed to tune down");
885                 return -1;
886         }
887
888         g_tv_info.viewing_locked_channel = -1;
889
890         r = tv_service_live_get_service_id(g_tv_info.live_svc, &service_id);
891         if (r < 0) {
892                 _ERR("failed to get service id");
893                 return -1;
894         }
895
896         _tv_channel_add_history(service_id);
897
898         return 0;
899 }
900
901 /**
902  * Sets the channel's favorite status.
903  *
904  * @param service_id The channel id
905  * @param flag The value to be set
906  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
907  */
908 int tv_channel_set_favorite(int service_id, Eina_Bool flag)
909 {
910         int r;
911
912         if (flag) {
913                 r = tv_service_add_favorite_channel(service_id);
914                 if (r < 0) {
915                         _ERR("failed to add favorite channel");
916                         return -1;
917                 }
918         } else {
919                 r = tv_service_delete_favorite_channel(service_id);
920                 if (r < 0) {
921                         _ERR("failed to delete favorite channel");
922                         return -1;
923                 }
924         }
925
926         return 0;
927 }
928
929 /**
930  * Adds the channel.
931  *
932  * If channel is added, the channel will be included at
933  * tv_channel_next, tv_channel_prev and tv_channel_get_list.
934  *
935  * @param service_id The channel id
936  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
937  */
938 int tv_channel_add_channel(int service_id)
939 {
940         int r;
941
942         r = tv_service_add_channel(service_id);
943         if (r < 0) {
944                 _ERR("failed to add channel");
945                 return -1;
946         }
947
948         return 0;
949 }
950
951 /**
952  * Deletes the channel.
953  *
954  * If channel is deleted, the channel will be omitted at
955  * tv_channel_next, tv_channel_prev and tv_channel_get_list.
956  *
957  * @param service_id The channel id
958  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
959  */
960 int tv_channel_del_channel(int service_id)
961 {
962         int r;
963
964         r = tv_service_delete_channel(service_id);
965         if (r < 0) {
966                 _ERR("failed to delete channel");
967                 return -1;
968         }
969
970         return 0;
971 }
972
973 /**
974  * Locks the channel.
975  *
976  * @param service_id The channel id
977  * @param password 4 digits password
978  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
979  */
980 int tv_channel_lock_channel(int service_id, char *password)
981 {
982         int r;
983
984         r = tv_service_lock_channel(service_id, password);
985         if (r < 0) {
986                 _ERR("failed to lock channel");
987                 return -1;
988         }
989
990         return 0;
991 }
992
993 /**
994  * Unlocks the channel.
995  *
996  * @param service_id The channel id
997  * @param password 4 digits password
998  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
999  */
1000 int tv_channel_unlock_channel(int service_id, char *password)
1001 {
1002         int r;
1003
1004         r = tv_service_unlock_channel(service_id, password);
1005         if (r < 0) {
1006                 _ERR("failed to unlock channel");
1007                 return -1;
1008         }
1009
1010         return 0;
1011 }
1012
1013 /**
1014  * Callback function for receives tv service events.
1015  *
1016  * @param event Event type
1017  * @param user_data Not in use
1018  * @param data Event specific detailed data
1019  */
1020 void _tv_service_event_cb(TvServiceLiveEvent event,
1021                 gpointer user_data, const gpointer data)
1022 {
1023         gboolean *lock_status;
1024
1025         switch (event) {
1026         case TV_SERVICE_LIVE_EVENT_TUNER_LOCK:
1027                 if (!data) {
1028                         _ERR("failed to get data");
1029                         break;
1030                 }
1031
1032                 lock_status = (gboolean *) data;
1033                 if (g_tv_info.signal_cb)
1034                         g_tv_info.signal_cb(g_tv_info.signal_cb_data,
1035                                         *lock_status);
1036                 break;
1037         case TV_SERVICE_LIVE_EVENT_AUTO_DESTROY:
1038                 g_tv_info.live_svc = NULL;
1039                 break;
1040         case TV_SERVICE_LIVE_EVENT_RESOLUTION:
1041         case TV_SERVICE_LIVE_EVENT_BEGIN:
1042         case TV_SERVICE_LIVE_EVENT_CHANNEL_LOCK:
1043         case TV_SERVICE_LIVE_EVENT_CHANNEL_UNLOCK:
1044                 break;
1045         }
1046 }
1047
1048 /**
1049  * Sets tv signal callback function.
1050  *
1051  * @param cb The function pointer to get callback
1052  * @param data An Additional data to passed to callback
1053  */
1054 void tv_signal_cb_set(void (*cb)(void *data, int is_signal), void *data)
1055 {
1056         g_tv_info.signal_cb = cb;
1057         g_tv_info.signal_cb_data = data;
1058 }
1059
1060 /**
1061  * Destory the tv service handles.
1062  *
1063  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1064  */
1065 int tv_destroy(void)
1066 {
1067         int r;
1068
1069         if (g_tv_info.live_svc)
1070                 g_tv_info.live_svc = NULL;
1071
1072         r = tv_service_channel_info_destroy();
1073         if (r < 0)
1074                 _ERR("failed to destroy channel info service");
1075
1076         if (g_tv_info.epg_svc) {
1077                 r = tv_service_epg_destroy(g_tv_info.epg_svc);
1078                 if (r != 0)
1079                         _ERR("failed to destroy epg service");
1080                 g_tv_info.epg_svc = NULL;
1081         }
1082
1083         return 0;
1084 }
1085
1086 /**
1087  * Create the tv service handles.
1088  *
1089  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1090  */
1091 int tv_create(void)
1092 {
1093         int r;
1094
1095         r = tv_service_live_create(&g_tv_info.live_svc);
1096         if (r != TVS_ERROR_OK) {
1097                 _ERR("failed to create live service");
1098                 goto err;
1099         }
1100
1101         r = tv_service_live_register_callback(g_tv_info.live_svc,
1102                         _tv_service_event_cb, NULL);
1103         if (r != TVS_ERROR_OK) {
1104                 _ERR("failed to register live callback");
1105                 goto err;
1106         }
1107
1108         r = tv_service_channel_info_create();
1109         if (r != TVS_ERROR_OK) {
1110                 _ERR("failed to create channel info service");
1111                 goto err;
1112         }
1113
1114         r = tv_service_epg_create(&g_tv_info.epg_svc);
1115         if (r != TVS_ERROR_OK) {
1116                 _ERR("failed to create epg service");
1117                 goto err;
1118         }
1119
1120         return 0;
1121 err:
1122         tv_destroy();
1123         return -1;
1124 }
1125
1126 /**
1127  * Pause the tv service handles.
1128  *
1129  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1130  */
1131 int tv_pause(void)
1132 {
1133         int r;
1134
1135         if (g_tv_info.live_svc) {
1136                 r = tv_service_live_tune_pause(g_tv_info.live_svc);
1137                 if (r != TVS_ERROR_OK)
1138                         _ERR("failed to pause live service");
1139         }
1140
1141         return 0;
1142 }
1143
1144 /**
1145  * Resume the tv service handles.
1146  *
1147  * Live service could be destroyed by tv service while app is pausing.
1148  * If live service is destroyed, then _tv_service_event_cb sets
1149  * g_tv_info.live_svc to NULL.
1150  * So if g_tv_info.live_svc is NULL, then recreates live service and returns 1.
1151  * Therefore, if tv_resume returns 1, then app needs to be set overlay and tune.
1152  * Or returns 0, then app just needs to set overlay.
1153  *
1154  * @return 0 if successful; 1 if live service was destroyed; otherwise negative value is returned
1155  */
1156 int tv_resume(void)
1157 {
1158         int r;
1159
1160         if (!g_tv_info.live_svc) {
1161                 r = tv_service_live_create(&g_tv_info.live_svc);
1162                 if (r != TVS_ERROR_OK) {
1163                         _ERR("failed to create live service");
1164                         goto err;
1165                 } else {
1166                         return 1;
1167                 }
1168         }
1169
1170         r = tv_service_live_tune_resume(g_tv_info.live_svc);
1171         if (r != TVS_ERROR_OK) {
1172                 _ERR("failed to create live service");
1173                 goto err;
1174         }
1175
1176         r = tv_service_live_register_callback(g_tv_info.live_svc,
1177                         _tv_service_event_cb, NULL);
1178         if (r != TVS_ERROR_OK) {
1179                 _ERR("failed to register live callback");
1180                 goto err;
1181         }
1182
1183         return 0;
1184
1185 err:
1186         tv_destroy();
1187         return -1;
1188 }