Do not add to recent when live tv is resumed
[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         g_tv_info.viewing_locked_channel = -1;
718
719         return 0;
720 }
721
722 /**
723  * Tunes to specific channel with major and minor.
724  *
725  * @param service_id The channel id
726  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
727  */
728 int tv_channel_direct_tune(long major, long minor)
729 {
730         GList *tvs_list = NULL, *filter = NULL;
731         TvServiceFilterNode *filter_node;
732         TvServiceChannel *tvs_data;
733         int r;
734
735         if (major > 0 && major < MAJOR_MAX) {
736                 filter_node = _tv_channel_get_filter(
737                                 TV_SERVICE_CHANNEL_DATA_MAJOR_NUMBER,
738                                 G_TYPE_INT, (void *) major);
739                 if (filter_node)
740                         filter = g_list_append(filter, (gpointer)filter_node);
741         }
742
743         if (minor > 0 && minor < MINOR_MAX) {
744                 filter_node = _tv_channel_get_filter(
745                                 TV_SERVICE_CHANNEL_DATA_MINOR_NUMBER,
746                                 G_TYPE_INT, (void *) minor);
747                 if (filter_node)
748                         filter = g_list_append(filter, (gpointer)filter_node);
749         }
750
751         if (!filter) {
752                 _ERR("failed to get filter");
753                 return -1;
754         }
755
756         r = tv_service_get_channel_list_ex(
757                         TV_SERVICE_CHANNEL_MODE_ALL_DIGITAL_ANALOG,
758                         TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list, filter, 0);
759         if (r != TVS_ERROR_OK)
760                 goto free;
761
762         tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, 0);
763         if (tvs_data)
764                 r = tv_channel_tune_with_service_id(tvs_data->service_id);
765         else {
766                 _ERR("failed to get tvs_data");
767                 r = -1;
768         }
769
770         if (r == TVS_ERROR_OK)
771                 g_tv_info.viewing_locked_channel = -1;
772
773         g_list_foreach(tvs_list, (GFunc) g_free, NULL);
774         g_list_free(tvs_list);
775
776 free:
777         g_list_foreach(filter, (GFunc) _tv_channel_free_filter, NULL);
778         g_list_free(filter);
779
780         return r;
781 }
782
783 /**
784  * Tunes to locked channel.
785  *
786  * @param service_id The channel id
787  * @param password 4 digit password
788  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
789  */
790 int tv_channel_tune_locked_channel(int service_id, char *password)
791 {
792         int r;
793
794         if (!g_tv_info.live_svc) {
795                 _ERR("failed to get live service");
796                 return -1;
797         }
798
799         r = tv_service_live_tune_locked_channel(g_tv_info.live_svc,
800                         service_id, password);
801         if (r != TVS_ERROR_OK) {
802                 _ERR("failed to set service");
803                 return -1;
804         }
805
806         _tv_channel_add_history(service_id);
807
808         g_tv_info.viewing_locked_channel = service_id;
809
810         return 0;
811 }
812
813 /**
814  * Tunes to next channel.
815  *
816  * Note that deleted channels and service channels will skipped.
817  *
818  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
819  */
820 int tv_channel_next(void)
821 {
822         TvServiceAntenna antenna_type;
823         int service_id, r;
824
825         if (!g_tv_info.live_svc) {
826                 _ERR("failed to get live service");
827                 return -1;
828         }
829
830         r = tv_service_live_get_antenna_type(g_tv_info.live_svc, &antenna_type);
831         if (r < 0) {
832                 _ERR("failed to get antenna type");
833                 return -1;
834         }
835
836         r = tv_service_live_tune_up(g_tv_info.live_svc,
837                         TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, antenna_type);
838         if (r < 0) {
839                 _ERR("failed to tune up");
840                 return -1;
841         }
842
843         g_tv_info.viewing_locked_channel = -1;
844
845         r = tv_service_live_get_service_id(g_tv_info.live_svc, &service_id);
846         if (r < 0) {
847                 _ERR("failed to get service id");
848                 return -1;
849         }
850
851         _tv_channel_add_history(service_id);
852
853         return 0;
854 }
855
856 /**
857  * Tunes to previous channel.
858  *
859  * Note that deleted channels and service channels will skipped.
860  *
861  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
862  */
863 int tv_channel_prev(void)
864 {
865         TvServiceAntenna antenna_type;
866         int service_id, r;
867
868         if (!g_tv_info.live_svc) {
869                 _ERR("failed to get live service");
870                 return -1;
871         }
872
873         r = tv_service_live_get_antenna_type(g_tv_info.live_svc, &antenna_type);
874         if (r < 0) {
875                 _ERR("failed to get antenna type");
876                 return -1;
877         }
878
879         r = tv_service_live_tune_down(g_tv_info.live_svc,
880                         TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, antenna_type);
881         if (r < 0) {
882                 _ERR("failed to tune down");
883                 return -1;
884         }
885
886         g_tv_info.viewing_locked_channel = -1;
887
888         r = tv_service_live_get_service_id(g_tv_info.live_svc, &service_id);
889         if (r < 0) {
890                 _ERR("failed to get service id");
891                 return -1;
892         }
893
894         _tv_channel_add_history(service_id);
895
896         return 0;
897 }
898
899 /**
900  * Sets the channel's favorite status.
901  *
902  * @param service_id The channel id
903  * @param flag The value to be set
904  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
905  */
906 int tv_channel_set_favorite(int service_id, Eina_Bool flag)
907 {
908         int r;
909
910         if (flag) {
911                 r = tv_service_add_favorite_channel(service_id);
912                 if (r < 0) {
913                         _ERR("failed to add favorite channel");
914                         return -1;
915                 }
916         } else {
917                 r = tv_service_delete_favorite_channel(service_id);
918                 if (r < 0) {
919                         _ERR("failed to delete favorite channel");
920                         return -1;
921                 }
922         }
923
924         return 0;
925 }
926
927 /**
928  * Adds the channel.
929  *
930  * If channel is added, the channel will be included at
931  * tv_channel_next, tv_channel_prev and tv_channel_get_list.
932  *
933  * @param service_id The channel id
934  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
935  */
936 int tv_channel_add_channel(int service_id)
937 {
938         int r;
939
940         r = tv_service_add_channel(service_id);
941         if (r < 0) {
942                 _ERR("failed to add channel");
943                 return -1;
944         }
945
946         return 0;
947 }
948
949 /**
950  * Deletes the channel.
951  *
952  * If channel is deleted, the channel will be omitted at
953  * tv_channel_next, tv_channel_prev and tv_channel_get_list.
954  *
955  * @param service_id The channel id
956  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
957  */
958 int tv_channel_del_channel(int service_id)
959 {
960         int r;
961
962         r = tv_service_delete_channel(service_id);
963         if (r < 0) {
964                 _ERR("failed to delete channel");
965                 return -1;
966         }
967
968         return 0;
969 }
970
971 /**
972  * Locks the channel.
973  *
974  * @param service_id The channel id
975  * @param password 4 digits password
976  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
977  */
978 int tv_channel_lock_channel(int service_id, char *password)
979 {
980         int r;
981
982         r = tv_service_lock_channel(service_id, password);
983         if (r < 0) {
984                 _ERR("failed to lock channel");
985                 return -1;
986         }
987
988         return 0;
989 }
990
991 /**
992  * Unlocks the channel.
993  *
994  * @param service_id The channel id
995  * @param password 4 digits password
996  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
997  */
998 int tv_channel_unlock_channel(int service_id, char *password)
999 {
1000         int r;
1001
1002         r = tv_service_unlock_channel(service_id, password);
1003         if (r < 0) {
1004                 _ERR("failed to unlock channel");
1005                 return -1;
1006         }
1007
1008         return 0;
1009 }
1010
1011 /**
1012  * Callback function for receives tv service events.
1013  *
1014  * @param event Event type
1015  * @param user_data Not in use
1016  * @param data Event specific detailed data
1017  */
1018 void _tv_service_event_cb(TvServiceLiveEvent event,
1019                 gpointer user_data, const gpointer data)
1020 {
1021         gboolean *lock_status;
1022
1023         switch (event) {
1024         case TV_SERVICE_LIVE_EVENT_TUNER_LOCK:
1025                 if (!data) {
1026                         _ERR("failed to get data");
1027                         break;
1028                 }
1029
1030                 lock_status = (gboolean *) data;
1031                 if (g_tv_info.signal_cb)
1032                         g_tv_info.signal_cb(g_tv_info.signal_cb_data,
1033                                         *lock_status);
1034                 break;
1035         case TV_SERVICE_LIVE_EVENT_AUTO_DESTROY:
1036                 g_tv_info.live_svc = NULL;
1037                 break;
1038         case TV_SERVICE_LIVE_EVENT_RESOLUTION:
1039         case TV_SERVICE_LIVE_EVENT_BEGIN:
1040         case TV_SERVICE_LIVE_EVENT_CHANNEL_LOCK:
1041         case TV_SERVICE_LIVE_EVENT_CHANNEL_UNLOCK:
1042                 break;
1043         }
1044 }
1045
1046 /**
1047  * Sets tv signal callback function.
1048  *
1049  * @param cb The function pointer to get callback
1050  * @param data An Additional data to passed to callback
1051  */
1052 void tv_signal_cb_set(void (*cb)(void *data, int is_signal), void *data)
1053 {
1054         g_tv_info.signal_cb = cb;
1055         g_tv_info.signal_cb_data = data;
1056 }
1057
1058 /**
1059  * Destory the tv service handles.
1060  *
1061  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1062  */
1063 int tv_destroy(void)
1064 {
1065         int r;
1066
1067         if (g_tv_info.live_svc)
1068                 g_tv_info.live_svc = NULL;
1069
1070         r = tv_service_channel_info_destroy();
1071         if (r < 0)
1072                 _ERR("failed to destroy channel info service");
1073
1074         if (g_tv_info.epg_svc) {
1075                 r = tv_service_epg_destroy(g_tv_info.epg_svc);
1076                 if (r != 0)
1077                         _ERR("failed to destroy epg service");
1078                 g_tv_info.epg_svc = NULL;
1079         }
1080
1081         return 0;
1082 }
1083
1084 /**
1085  * Create the tv service handles.
1086  *
1087  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1088  */
1089 int tv_create(void)
1090 {
1091         int r;
1092
1093         r = tv_service_live_create(&g_tv_info.live_svc);
1094         if (r != TVS_ERROR_OK) {
1095                 _ERR("failed to create live service");
1096                 goto err;
1097         }
1098
1099         r = tv_service_live_register_callback(g_tv_info.live_svc,
1100                         _tv_service_event_cb, NULL);
1101         if (r != TVS_ERROR_OK) {
1102                 _ERR("failed to register live callback");
1103                 goto err;
1104         }
1105
1106         r = tv_service_channel_info_create();
1107         if (r != TVS_ERROR_OK) {
1108                 _ERR("failed to create channel info service");
1109                 goto err;
1110         }
1111
1112         r = tv_service_epg_create(&g_tv_info.epg_svc);
1113         if (r != TVS_ERROR_OK) {
1114                 _ERR("failed to create epg service");
1115                 goto err;
1116         }
1117
1118         return 0;
1119 err:
1120         tv_destroy();
1121         return -1;
1122 }
1123
1124 /**
1125  * Pause the tv service handles.
1126  *
1127  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1128  */
1129 int tv_pause(void)
1130 {
1131         int r;
1132
1133         if (g_tv_info.live_svc) {
1134                 r = tv_service_live_tune_pause(g_tv_info.live_svc);
1135                 if (r != TVS_ERROR_OK)
1136                         _ERR("failed to pause live service");
1137         }
1138
1139         return 0;
1140 }
1141
1142 /**
1143  * Resume the tv service handles.
1144  *
1145  * Live service could be destroyed by tv service while app is pausing.
1146  * If live service is destroyed, then _tv_service_event_cb sets
1147  * g_tv_info.live_svc to NULL.
1148  * So if g_tv_info.live_svc is NULL, then recreates live service and returns 1.
1149  * Therefore, if tv_resume returns 1, then app needs to be set overlay and tune.
1150  * Or returns 0, then app just needs to set overlay.
1151  *
1152  * @return 0 if successful; 1 if live service was destroyed; otherwise negative value is returned
1153  */
1154 int tv_resume(void)
1155 {
1156         int r;
1157
1158         if (!g_tv_info.live_svc) {
1159                 r = tv_service_live_create(&g_tv_info.live_svc);
1160                 if (r != TVS_ERROR_OK) {
1161                         _ERR("failed to create live service");
1162                         goto err;
1163                 } else {
1164                         return 1;
1165                 }
1166         }
1167
1168         r = tv_service_live_tune_resume(g_tv_info.live_svc);
1169         if (r != TVS_ERROR_OK) {
1170                 _ERR("failed to create live service");
1171                 goto err;
1172         }
1173
1174         r = tv_service_live_register_callback(g_tv_info.live_svc,
1175                         _tv_service_event_cb, NULL);
1176         if (r != TVS_ERROR_OK) {
1177                 _ERR("failed to register live callback");
1178                 goto err;
1179         }
1180
1181         return 0;
1182
1183 err:
1184         tv_destroy();
1185         return -1;
1186 }