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