ecf5049b412ddba46768f947a8e8bbb04dd61eca
[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 TvServiceFilterNode *_tv_channel_get_filter(
496                 TvServiceChannelDataAttr attribute, int type, void *data)
497 {
498         TvServiceFilterNode *filter;
499         GValue *value;
500
501         filter = g_malloc0(sizeof(*filter));
502         if (!filter)
503                 return NULL;
504
505         filter->attribute = attribute;
506
507         value = g_malloc0(sizeof(GValue));
508         if (!value) {
509                 g_free(filter);
510                 return NULL;
511         }
512
513         switch (type) {
514         case G_TYPE_STRING:
515                 g_value_init(value, G_TYPE_STRING);
516                 g_value_set_string(value, data);
517
518                 filter->match_type = CHANNEL_FILTER_MATCH_CONTAIN;
519                 break;
520         case G_TYPE_INT:
521                 g_value_init(value, G_TYPE_INT);
522                 g_value_set_int(value, (gint) data);
523
524                 filter->match_type = CHANNEL_FILTER_MATCH_EQUAL;
525                 break;
526         }
527         filter->value = value;
528
529         return filter;
530 }
531
532 /**
533  * Search channels that are starts with supplied major and minor number.
534  *
535  * Note that deleted channels and service channels are excluded by default.
536  *
537  * @param major Major channel number to search
538  * @param minor Minor channel number to search
539  * @return Found channel list, or NULL if fails
540  */
541 Eina_List *tv_channel_search_by_number(long major, long minor)
542 {
543         char buf[CHANNEL_FILTER_STRING_MAX_LEN];
544         GList *tvs_list = NULL, *filter = NULL;
545         TvServiceFilterNode *filter_node;
546         TvServiceChannel *tvs_data;
547         Eina_List *channel_list = NULL;
548         const struct tv_channel_info *channel_info;
549         int i, r;
550
551         if (major > 0 && major < MAJOR_MAX) {
552                 snprintf(buf, CHANNEL_FILTER_STRING_MAX_LEN, "%ld", major);
553
554                 filter_node = _tv_channel_get_filter(
555                                 TV_SERVICE_CHANNEL_DATA_MAJOR_NUMBER,
556                                 G_TYPE_STRING, buf);
557                 if (filter_node)
558                         filter = g_list_append(filter, (gpointer)filter_node);
559         }
560
561         if (minor > 0 && minor < MINOR_MAX) {
562                 snprintf(buf, CHANNEL_FILTER_STRING_MAX_LEN, "%ld", minor);
563
564                 filter_node = _tv_channel_get_filter(
565                                 TV_SERVICE_CHANNEL_DATA_MINOR_NUMBER,
566                                 G_TYPE_STRING, buf);
567                 if (filter_node)
568                         filter = g_list_append(filter, (gpointer)filter_node);
569         }
570
571         if (!filter) {
572                 _ERR("failed to get filter");
573                 return NULL;
574         }
575
576         r = tv_service_get_channel_list_ex(
577                         TV_SERVICE_CHANNEL_MODE_ALL_DIGITAL_ANALOG,
578                         TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list, filter, 0);
579         if (r != TVS_ERROR_OK) {
580                 _ERR("failed to get channel list");
581                 goto free;
582         }
583
584         for (i = 0; i < g_list_length(tvs_list); i++) {
585                 tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, i);
586                 if (!tvs_data)
587                         continue;
588
589                 channel_info = _tv_channel_get_info(tvs_data);
590                 if (channel_info)
591                         channel_list = eina_list_append(channel_list,
592                                         channel_info);
593                 free(tvs_data);
594         }
595
596 free:
597         if (tvs_list)
598                 g_list_free(tvs_list);
599
600         g_list_foreach(filter, (GFunc) _tv_channel_free_filter, NULL);
601         g_list_free(filter);
602
603         return channel_list;
604 }
605
606 /**
607  * Frees the tv_channel_info.
608  *
609  * @param channel_list channel_list pointer to be freed
610  */
611 void tv_channel_del_list(Eina_List *channel_list)
612 {
613         struct tv_channel_info *data;
614
615         EINA_LIST_FREE(channel_list, data)
616                 free(data);
617 }
618
619 void _tv_channel_add_history(int service_id)
620 {
621         char buf[128];
622
623         snprintf(buf, sizeof(buf), "%d", service_id);
624         app_contents_recent_add(CONTENTS_CHANNEL, buf);
625 }
626
627 /**
628  * Tunes to specific channel with service id.
629  *
630  * @param service_id The channel id
631  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
632  */
633 int tv_channel_tune_with_service_id(int service_id)
634 {
635         int r;
636
637         if (!g_tv_info.live_svc) {
638                 _ERR("failed to get live service");
639                 return -1;
640         }
641
642         r = tv_service_live_tune(g_tv_info.live_svc, service_id);
643         if (r != TVS_ERROR_OK) {
644                 _ERR("failed to set service");
645                 return -1;
646         }
647
648         _tv_channel_add_history(service_id);
649
650         g_tv_info.viewing_locked_channel = -1;
651
652         return 0;
653 }
654
655 /**
656  * Tunes to last viewed channel.
657  *
658  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
659  */
660 int tv_channel_tune(void)
661 {
662         int service_id;
663         int r;
664
665         if (!g_tv_info.live_svc) {
666                 _ERR("failed to get live service");
667                 return -1;
668         }
669
670         r = tv_service_live_get_last_channel(&service_id);
671         if (r < 0 || service_id < 1) {
672                 _ERR("failed to get current service id");
673                 service_id = DEFAULT_SERVICE;
674         }
675
676         r = tv_service_live_tune(g_tv_info.live_svc, service_id);
677         if (r != TVS_ERROR_OK) {
678                 _ERR("failed to set service");
679                 return -1;
680         }
681
682         _tv_channel_add_history(service_id);
683
684         g_tv_info.viewing_locked_channel = -1;
685
686         return 0;
687 }
688
689 /**
690  * Tunes to specific channel with major and minor.
691  *
692  * @param service_id The channel id
693  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
694  */
695 int tv_channel_direct_tune(long major, long minor)
696 {
697         GList *tvs_list = NULL, *filter = NULL;
698         TvServiceFilterNode *filter_node;
699         TvServiceChannel *tvs_data;
700         int r;
701
702         if (major > 0 && major < MAJOR_MAX) {
703                 filter_node = _tv_channel_get_filter(
704                                 TV_SERVICE_CHANNEL_DATA_MAJOR_NUMBER,
705                                 G_TYPE_INT, (void *) major);
706                 if (filter_node)
707                         filter = g_list_append(filter, (gpointer)filter_node);
708         }
709
710         if (minor > 0 && minor < MINOR_MAX) {
711                 filter_node = _tv_channel_get_filter(
712                                 TV_SERVICE_CHANNEL_DATA_MINOR_NUMBER,
713                                 G_TYPE_INT, (void *) minor);
714                 if (filter_node)
715                         filter = g_list_append(filter, (gpointer)filter_node);
716         }
717
718         if (!filter) {
719                 _ERR("failed to get filter");
720                 return -1;
721         }
722
723         r = tv_service_get_channel_list_ex(
724                         TV_SERVICE_CHANNEL_MODE_ALL_DIGITAL_ANALOG,
725                         TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list, filter, 0);
726         if (r != TVS_ERROR_OK)
727                 goto free;
728
729         tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, 0);
730         if (tvs_data)
731                 r = tv_channel_tune_with_service_id(tvs_data->service_id);
732         else {
733                 _ERR("failed to get tvs_data");
734                 r = -1;
735         }
736
737         if (r == TVS_ERROR_OK)
738                 g_tv_info.viewing_locked_channel = -1;
739
740         g_list_foreach(tvs_list, (GFunc) g_free, NULL);
741         g_list_free(tvs_list);
742
743 free:
744         g_list_foreach(filter, (GFunc) _tv_channel_free_filter, NULL);
745         g_list_free(filter);
746
747         return r;
748 }
749
750 /**
751  * Tunes to locked channel.
752  *
753  * @param service_id The channel id
754  * @param password 4 digit password
755  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
756  */
757 int tv_channel_tune_locked_channel(int service_id, char *password)
758 {
759         int r;
760
761         if (!g_tv_info.live_svc) {
762                 _ERR("failed to get live service");
763                 return -1;
764         }
765
766         r = tv_service_live_tune_locked_channel(g_tv_info.live_svc,
767                         service_id, password);
768         if (r != TVS_ERROR_OK) {
769                 _ERR("failed to set service");
770                 return -1;
771         }
772
773         _tv_channel_add_history(service_id);
774
775         g_tv_info.viewing_locked_channel = service_id;
776
777         return 0;
778 }
779
780 /**
781  * Tunes to next channel.
782  *
783  * Note that deleted channels and service channels will skipped.
784  *
785  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
786  */
787 int tv_channel_next(void)
788 {
789         TvServiceAntenna antenna_type;
790         int service_id, r;
791
792         if (!g_tv_info.live_svc) {
793                 _ERR("failed to get live service");
794                 return -1;
795         }
796
797         r = tv_service_live_get_antenna_type(g_tv_info.live_svc, &antenna_type);
798         if (r < 0) {
799                 _ERR("failed to get antenna type");
800                 return -1;
801         }
802
803         r = tv_service_live_tune_up(g_tv_info.live_svc,
804                         TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, antenna_type);
805         if (r < 0) {
806                 _ERR("failed to tune up");
807                 return -1;
808         }
809
810         g_tv_info.viewing_locked_channel = -1;
811
812         r = tv_service_live_get_service_id(g_tv_info.live_svc, &service_id);
813         if (r < 0) {
814                 _ERR("failed to get service id");
815                 return -1;
816         }
817
818         _tv_channel_add_history(service_id);
819
820         return 0;
821 }
822
823 /**
824  * Tunes to previous channel.
825  *
826  * Note that deleted channels and service channels will skipped.
827  *
828  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
829  */
830 int tv_channel_prev(void)
831 {
832         TvServiceAntenna antenna_type;
833         int service_id, r;
834
835         if (!g_tv_info.live_svc) {
836                 _ERR("failed to get live service");
837                 return -1;
838         }
839
840         r = tv_service_live_get_antenna_type(g_tv_info.live_svc, &antenna_type);
841         if (r < 0) {
842                 _ERR("failed to get antenna type");
843                 return -1;
844         }
845
846         r = tv_service_live_tune_down(g_tv_info.live_svc,
847                         TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, antenna_type);
848         if (r < 0) {
849                 _ERR("failed to tune down");
850                 return -1;
851         }
852
853         g_tv_info.viewing_locked_channel = -1;
854
855         r = tv_service_live_get_service_id(g_tv_info.live_svc, &service_id);
856         if (r < 0) {
857                 _ERR("failed to get service id");
858                 return -1;
859         }
860
861         _tv_channel_add_history(service_id);
862
863         return 0;
864 }
865
866 /**
867  * Sets the channel's favorite status.
868  *
869  * @param service_id The channel id
870  * @param flag The value to be set
871  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
872  */
873 int tv_channel_set_favorite(int service_id, Eina_Bool flag)
874 {
875         int r;
876
877         if (flag) {
878                 r = tv_service_add_favorite_channel(service_id);
879                 if (r < 0) {
880                         _ERR("failed to add favorite channel");
881                         return -1;
882                 }
883         } else {
884                 r = tv_service_delete_favorite_channel(service_id);
885                 if (r < 0) {
886                         _ERR("failed to delete favorite channel");
887                         return -1;
888                 }
889         }
890
891         return 0;
892 }
893
894 /**
895  * Adds the channel.
896  *
897  * If channel is added, the channel will be included at
898  * tv_channel_next, tv_channel_prev and tv_channel_get_list.
899  *
900  * @param service_id The channel id
901  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
902  */
903 int tv_channel_add_channel(int service_id)
904 {
905         int r;
906
907         r = tv_service_add_channel(service_id);
908         if (r < 0) {
909                 _ERR("failed to add channel");
910                 return -1;
911         }
912
913         return 0;
914 }
915
916 /**
917  * Deletes the channel.
918  *
919  * If channel is deleted, the channel will be omitted at
920  * tv_channel_next, tv_channel_prev and tv_channel_get_list.
921  *
922  * @param service_id The channel id
923  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
924  */
925 int tv_channel_del_channel(int service_id)
926 {
927         int r;
928
929         r = tv_service_delete_channel(service_id);
930         if (r < 0) {
931                 _ERR("failed to delete channel");
932                 return -1;
933         }
934
935         return 0;
936 }
937
938 /**
939  * Locks the channel.
940  *
941  * @param service_id The channel id
942  * @param password 4 digits password
943  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
944  */
945 int tv_channel_lock_channel(int service_id, char *password)
946 {
947         int r;
948
949         r = tv_service_lock_channel(service_id, password);
950         if (r < 0) {
951                 _ERR("failed to lock channel");
952                 return -1;
953         }
954
955         return 0;
956 }
957
958 /**
959  * Unlocks the channel.
960  *
961  * @param service_id The channel id
962  * @param password 4 digits password
963  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
964  */
965 int tv_channel_unlock_channel(int service_id, char *password)
966 {
967         int r;
968
969         r = tv_service_unlock_channel(service_id, password);
970         if (r < 0) {
971                 _ERR("failed to unlock channel");
972                 return -1;
973         }
974
975         return 0;
976 }
977
978 /**
979  * Callback function for receives tv service events.
980  *
981  * @param event Event type
982  * @param user_data Not in use
983  * @param data Event specific detailed data
984  */
985 void _tv_service_event_cb(TvServiceLiveEvent event,
986                 gpointer user_data, const gpointer data)
987 {
988         gboolean *lock_status;
989
990         switch (event) {
991         case TV_SERVICE_LIVE_EVENT_TUNER_LOCK:
992                 if (!data) {
993                         _ERR("failed to get data");
994                         break;
995                 }
996
997                 lock_status = (gboolean *) data;
998                 if (g_tv_info.signal_cb)
999                         g_tv_info.signal_cb(g_tv_info.signal_cb_data,
1000                                         *lock_status);
1001                 break;
1002         case TV_SERVICE_LIVE_EVENT_AUTO_DESTROY:
1003                 g_tv_info.live_svc = NULL;
1004                 break;
1005         case TV_SERVICE_LIVE_EVENT_RESOLUTION:
1006         case TV_SERVICE_LIVE_EVENT_BEGIN:
1007         case TV_SERVICE_LIVE_EVENT_CHANNEL_LOCK:
1008         case TV_SERVICE_LIVE_EVENT_CHANNEL_UNLOCK:
1009                 break;
1010         }
1011 }
1012
1013 /**
1014  * Sets tv signal callback function.
1015  *
1016  * @param cb The function pointer to get callback
1017  * @param data An Additional data to passed to callback
1018  */
1019 void tv_signal_cb_set(void (*cb)(void *data, int is_signal), void *data)
1020 {
1021         g_tv_info.signal_cb = cb;
1022         g_tv_info.signal_cb_data = data;
1023 }
1024
1025 /**
1026  * Sets window id for tv overlay.
1027  *
1028  * @param window_id The window id to overlay
1029  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1030  */
1031 int tv_overlay_set(void *window_id)
1032 {
1033         int r;
1034
1035         if (!g_tv_info.live_svc) {
1036                 _ERR("failed to get live service");
1037                 return -1;
1038         }
1039
1040         r = tv_service_live_set_window_overlay(g_tv_info.live_svc, window_id);
1041         if (r < 0) {
1042                 _ERR("failed to set overlay");
1043                 return -1;
1044         }
1045
1046         return 0;
1047 }
1048
1049 /**
1050  * Destory the tv service handles.
1051  *
1052  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1053  */
1054 int tv_destroy(void)
1055 {
1056         int r;
1057
1058         if (g_tv_info.live_svc)
1059                 g_tv_info.live_svc = NULL;
1060
1061         r = tv_service_channel_info_destroy();
1062         if (r < 0)
1063                 _ERR("failed to destroy channel info service");
1064
1065         if (g_tv_info.epg_svc) {
1066                 r = tv_service_epg_destroy(g_tv_info.epg_svc);
1067                 if (r != 0)
1068                         _ERR("failed to destroy epg service");
1069                 g_tv_info.epg_svc = NULL;
1070         }
1071
1072         return 0;
1073 }
1074
1075 /**
1076  * Create the tv service handles.
1077  *
1078  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1079  */
1080 int tv_create(void)
1081 {
1082         int r;
1083
1084         r = tv_service_live_create(&g_tv_info.live_svc);
1085         if (r != TVS_ERROR_OK) {
1086                 _ERR("failed to create live service");
1087                 goto err;
1088         }
1089
1090         r = tv_service_live_register_callback(g_tv_info.live_svc,
1091                         _tv_service_event_cb, NULL);
1092         if (r != TVS_ERROR_OK) {
1093                 _ERR("failed to register live callback");
1094                 goto err;
1095         }
1096
1097         r = tv_service_channel_info_create();
1098         if (r != TVS_ERROR_OK) {
1099                 _ERR("failed to create channel info service");
1100                 goto err;
1101         }
1102
1103         r = tv_service_epg_create(&g_tv_info.epg_svc);
1104         if (r != TVS_ERROR_OK) {
1105                 _ERR("failed to create epg service");
1106                 goto err;
1107         }
1108
1109         return 0;
1110 err:
1111         tv_destroy();
1112         return -1;
1113 }
1114
1115 /**
1116  * Pause the tv service handles.
1117  *
1118  * @return If the operation was sucessful 0 is returned; otherwise negative value is returned
1119  */
1120 int tv_pause(void)
1121 {
1122         int r;
1123
1124         if (g_tv_info.live_svc) {
1125                 r = tv_service_live_tune_pause(g_tv_info.live_svc);
1126                 if (r != TVS_ERROR_OK)
1127                         _ERR("failed to pause live service");
1128         }
1129
1130         return 0;
1131 }
1132
1133 /**
1134  * Resume the tv service handles.
1135  *
1136  * Live service could be destroyed by tv service while app is pausing.
1137  * If live service is destroyed, then _tv_service_event_cb sets
1138  * g_tv_info.live_svc to NULL.
1139  * So if g_tv_info.live_svc is NULL, then recreates live service and returns 1.
1140  * Therefore, if tv_resume returns 1, then app needs to be set overlay and tune.
1141  * Or returns 0, then app just needs to set overlay.
1142  *
1143  * @return 0 if successful; 1 if live service was destroyed; otherwise negative value is returned
1144  */
1145 int tv_resume(void)
1146 {
1147         int r;
1148
1149         if (!g_tv_info.live_svc) {
1150                 r = tv_service_live_create(&g_tv_info.live_svc);
1151                 if (r != TVS_ERROR_OK) {
1152                         _ERR("failed to create live service");
1153                         goto err;
1154                 } else {
1155                         return 1;
1156                 }
1157         }
1158
1159         r = tv_service_live_tune_resume(g_tv_info.live_svc);
1160         if (r != TVS_ERROR_OK) {
1161                 _ERR("failed to create live service");
1162                 goto err;
1163         }
1164
1165         r = tv_service_live_register_callback(g_tv_info.live_svc,
1166                         _tv_service_event_cb, NULL);
1167         if (r != TVS_ERROR_OK) {
1168                 _ERR("failed to register live callback");
1169                 goto err;
1170         }
1171
1172         return 0;
1173
1174 err:
1175         tv_destroy();
1176         return -1;
1177 }