/* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include "define.h" #include "tv.h" #define DEFAULT_SERVICE 1 struct _channel_history { int service_id[2]; unsigned int idx; }; /** * The Storage structure to used by tv related functions and events. */ struct _tv_info { /**< The handle to use tv service live api. */ TvServiceLive live_svc; /**< The handle to use tv service epg api. */ TvServiceEpg epg_svc; /**< Stores service id if tune to locked channel was succeeded. */ int viewing_locked_channel; /**< Stores previous service id. */ struct _channel_history history; /**< The function pointer to pass tv signal event */ void (*signal_cb)(void *data, int is_signal); /**< An Additional data to passed to tv signal event */ void *signal_cb_data; }; static struct _tv_info g_tv_info; /** * Gets the tv_channel_info with supplied TvServiceChannel. * * Abstracts tv service data structure. * * @param channel The channel data defined by tv service * @return Channel information, or NULL if fails */ static struct tv_channel_info *_tv_channel_get_info(TvServiceChannel *channel) { struct tv_channel_info *channel_info = NULL; if (!channel) { _ERR("failed to get channel"); return NULL; } channel_info = calloc(1, sizeof(*channel_info)); if (!channel_info) { _ERR("failed to calloc channel info"); return NULL; } channel_info->service_id = channel->service_id; channel_info->channel_major = channel->major; channel_info->channel_minor = channel->minor; channel_info->channel_type = channel->channel_type; channel_info->locked = channel->locked; channel_info->digital = channel->digital; channel_info->favorite = channel->favorite; channel_info->remembered = channel->remembered; strncpy(channel_info->channel_name, channel->program_name, CHANNEL_NAME_MAX); if (channel->service_id == g_tv_info.viewing_locked_channel) channel_info->tune_locked = EINA_TRUE; return channel_info; } /** * Clones the tv_channel_info. * * @param channel_info tv_channel_info pointer to be cloned * @return Channel information, or NULL if fails */ const struct tv_channel_info *tv_channel_clone_info( const struct tv_channel_info *channel_info) { struct tv_channel_info *new_channel_info = NULL; if (!channel_info) { _ERR("failed to get channel info"); return NULL; } new_channel_info = calloc(1, sizeof(*channel_info)); if (!new_channel_info) { _ERR("failed to calloc channel info"); return NULL; } memcpy(new_channel_info, channel_info, sizeof(*new_channel_info)); return new_channel_info; } /** * Frees the tv_channel_info. * * @param channel_info tv_channel_info pointer to be freed */ void tv_channel_del_info(const struct tv_channel_info *channel_info) { if (!channel_info) { _ERR("failed to get channel info"); return; } free((void *)channel_info); } /** * Gets current channel's TvServiceChannel data from tv service. * * @param channel The pointer to store TvServiceChannel * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ static int _tv_get_channel(TvServiceChannel *channel) { gint svc_id; int r; if (!g_tv_info.live_svc) { _ERR("failed to get live service"); return -1; } r = tv_service_live_get_service_id(g_tv_info.live_svc, &svc_id); if (r < 0) { _ERR("failed to get service id"); return -1; } r = tv_service_get_channel(svc_id, channel); if (r < 0) { _ERR("failed to get channel"); return -1; } return 0; } /** * Returns current channel's info. * * tv_channel_get_info retrieves current channel's information * from tv service. * * @return Returns current channel info, or NULL if fails */ const struct tv_channel_info *tv_channel_get_info(void) { const struct tv_channel_info *channel_info; TvServiceChannel channel; int r; r = _tv_get_channel(&channel); if (r < 0) { _ERR("failed to get channel"); return NULL; } channel_info = _tv_channel_get_info(&channel); return channel_info; } /** * Returns tv_program_info with supplied TvServiceEpgEventData. * * Abstracts tv service data structure. * * @param prog TvServiceEpgEventData passed from tv service * @return Returns tv_program_info, or NULL if fails */ static struct tv_program_info *_tv_get_program_info(TvServiceEpgEventData *prog) { struct tv_program_info *prog_info; prog_info = calloc(1, sizeof(*prog_info)); if (!prog_info) { _ERR("failed to calloc program info"); return NULL; } prog_info->service_id = prog->service_id; prog_info->start_time = prog->start_time; prog_info->end_time = prog->start_time + prog->length_in_seconds; prog_info->duration = prog->length_in_seconds; prog_info->current_time = prog->current_time; strncpy(prog_info->prog_title, (char *)prog->title_text, sizeof(prog_info->prog_title) - 1); strncpy(prog_info->prog_description, (char *)prog->extended_text, sizeof(prog_info->prog_description) - 1); return prog_info; } /** * Gets current channel's service id from tv service. * * @param service_id The pointer to store service id * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_get_current_service_id(int *service_id) { int r; if (!g_tv_info.live_svc) { _ERR("failed to get live service"); return -1; } r = tv_service_live_get_service_id(g_tv_info.live_svc, service_id); if (r != TVS_ERROR_OK) { _ERR("failed to get current service info"); return -1; } return 0; } /** * Frees epg list. * * @param epg_list Eina_List to be freed */ static void _tv_epg_del_list(Eina_List *epg_list) { struct tv_program_info *data; EINA_LIST_FREE(epg_list, data) free(data); } /** * Callback function to get EPG program list from tv service. * * _tv_epg_event_cb is called from tv service when banner * have requested to get program data. * If this function is called, then derives program list from epg_list * and calls banner's callback function which included in user_data. * * @param type Event type * @param epg_list EPG program list * @param user_data tv_program_request to handle request */ static void _tv_epg_event_cb(tvs_epg_event_e type, GList *epg_list, void *user_data) { int i; Eina_List *list = NULL; TvServiceEpgEventData *epg_data; struct tv_program_info *prog_info; struct tv_program_request *request; if (!user_data) { _ERR("failed to get user_data"); return; } for (i = 0; i < g_list_length(epg_list); i++) { epg_data = (TvServiceEpgEventData *) g_list_nth_data(epg_list, i); if (!epg_data) continue; prog_info = _tv_get_program_info(epg_data); if (prog_info) list = eina_list_append(list, prog_info); } request = (struct tv_program_request *) user_data; if (request->tv_program_cb) request->tv_program_cb(list, request->user_data); if (list) _tv_epg_del_list(list); free(request); } /** * Send a request to tv service to get a current program with supplied service_id. * * Beware that service_id should be current tuned channel. * If not, calling this function may cause unexpected behavior. * And note that get a EPG program is asynchronous operation. * So tv_program_request should be supplied to get a result from tv service. * * @param service_id The channel id to get current program * @param request The structure for return program data which contains function pointer * and additional data for banner * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_epg_get_program(int service_id, struct tv_program_request *request) { int r; if (!g_tv_info.epg_svc) { _ERR("failed to get epg service"); return -1; } if (!request) { _ERR("failed to get tv_program_request"); return -1; } r = tv_service_epg_get_current_program(g_tv_info.epg_svc, service_id, (TvServiceEpgCallback) _tv_epg_event_cb, request); if (r != TVS_ERROR_OK) { _ERR("failed to get epg get current program : %d", service_id); return -1; } return 0; } /** * Gets a cached current program with supplied service_id from tv service. * * Note that this function is vaild only when tv service having a cached data * on that channel. * To have a cached data, the channel ever been tuned before calling * this function. * * @param service_id The channel id to get current program * @param request The structure for return program data which contains * function pointer and additional data for banner * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_epg_get_cache_program(int service_id, struct tv_program_request *request) { Eina_List *list = NULL; TvServiceEpgEventData epg_data; struct tv_program_info *prog_info; int r; if (!g_tv_info.epg_svc) { _ERR("failed to get epg service"); return -1; } if (!request) { _ERR("failed to get tv_program_request"); return -1; } r = tv_service_epg_get_cache_current_program( g_tv_info.epg_svc, service_id, &epg_data); if (r != TVS_ERROR_OK) { _ERR("failed to get epg get cached current program : %d", service_id); return -1; } prog_info = _tv_get_program_info(&epg_data); if (prog_info) list = eina_list_append(list, prog_info); if (request->tv_program_cb) request->tv_program_cb(list, request->user_data); if (list) _tv_epg_del_list(list); free(request); return 0; } /** * Sends a request to tv service to get programs with supplied service_id. * * Beware that service_id should be current tuned channel. * If not, calling this function may cause unexpected behavior. * And note that get a EPG program is asynchronous operation. * So tv_program_request should be supplied to get a result from tv service. * * @param service_id The channel id to get current program * @param request The structure for return program data which contains function pointer and additional data for banner * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_epg_get_program_list(int service_id, struct tv_program_request *request) { int r; if (!g_tv_info.epg_svc) { _ERR("failed to get epg service"); return -1; } if (!request) { _ERR("failed to get tv_program_request"); return -1; } r = tv_service_epg_get_program_list(g_tv_info.epg_svc, service_id, TVS_EPG_CURRENT_TIME, EPG_PROGRAM_OFFSET, (TvServiceEpgCallback) _tv_epg_event_cb, request); if (r != TVS_ERROR_OK) { _ERR("failed to get epg get current program"); return -1; } return 0; } /** * Frees the TvServiceFilterNode. * * @param data TvServiceFilterNode pointer to be freed */ static void _tv_channel_free_filter(gpointer data) { TvServiceFilterNode *filter_node; if (!data) return; filter_node = (TvServiceFilterNode *) data; g_value_unset(filter_node->value); g_free(filter_node->value); g_free(filter_node); } /** * Gets a available channel list. * * Note that deleted channels and service channels are excluded by default. * * @return Available channel list, or NULL if fails */ Eina_List *tv_channel_get_list() { GList *tvs_list = NULL; Eina_List *channel_list = NULL; TvServiceChannel *tvs_data = NULL; const struct tv_channel_info *channel_info; int r, i; r = tv_service_get_channel_list( TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list); if (r != TVS_ERROR_OK) { _ERR("failed to get channel list"); return NULL; } for (i = 0; i < g_list_length(tvs_list); i++) { tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, i); if (tvs_data) { channel_info = _tv_channel_get_info(tvs_data); if (channel_info) channel_list = eina_list_append(channel_list, channel_info); } } tv_service_free_channel_list(tvs_list); return channel_list; } /** * Gets a favorite channel list. * * @return Favorite channel list, or NULL if fails */ Eina_List *tv_channel_get_favorite_list() { GList *tvs_list = NULL; Eina_List *channel_list = NULL; TvServiceChannel *tvs_data = NULL; const struct tv_channel_info *channel_info; int r, i; r = tv_service_get_channel_list( TV_SERVICE_CHANNEL_MODE_FAVORITE, TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list); if (r != TVS_ERROR_OK) { _ERR("failed to get channel list"); return NULL; } for (i = 0; i < g_list_length(tvs_list); i++) { tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, i); if (tvs_data) { channel_info = _tv_channel_get_info(tvs_data); if (channel_info) channel_list = eina_list_append(channel_list, channel_info); } } tv_service_free_channel_list(tvs_list); return channel_list; } TvServiceFilterNode *_tv_channel_get_filter( TvServiceChannelDataAttr attribute, int type, void *data) { TvServiceFilterNode *filter; GValue *value; filter = g_malloc0(sizeof(*filter)); if (!filter) return NULL; filter->attribute = attribute; value = g_malloc0(sizeof(GValue)); if (!value) { g_free(filter); return NULL; } switch (type) { case G_TYPE_STRING: g_value_init(value, G_TYPE_STRING); g_value_set_string(value, data); filter->match_type = CHANNEL_FILTER_MATCH_CONTAIN; break; case G_TYPE_INT: g_value_init(value, G_TYPE_INT); g_value_set_int(value, (gint) data); filter->match_type = CHANNEL_FILTER_MATCH_EQUAL; break; } filter->value = value; return filter; } /** * Search channels that are starts with supplied major and minor number. * * Note that deleted channels and service channels are excluded by default. * * @param major Major channel number to search * @param minor Minor channel number to search * @return Found channel list, or NULL if fails */ Eina_List *tv_channel_search_by_number(long major, long minor) { char buf[CHANNEL_FILTER_STRING_MAX_LEN]; GList *tvs_list = NULL, *filter = NULL; TvServiceFilterNode *filter_node; TvServiceChannel *tvs_data; Eina_List *channel_list = NULL; const struct tv_channel_info *channel_info; int i, r; if (major > 0 && major < MAJOR_MAX) { snprintf(buf, CHANNEL_FILTER_STRING_MAX_LEN, "%ld", major); filter_node = _tv_channel_get_filter( TV_SERVICE_CHANNEL_DATA_MAJOR_NUMBER, G_TYPE_STRING, buf); if (filter_node) filter = g_list_append(filter, (gpointer)filter_node); } if (minor > 0 && minor < MINOR_MAX) { snprintf(buf, CHANNEL_FILTER_STRING_MAX_LEN, "%ld", minor); filter_node = _tv_channel_get_filter( TV_SERVICE_CHANNEL_DATA_MINOR_NUMBER, G_TYPE_STRING, buf); if (filter_node) filter = g_list_append(filter, (gpointer)filter_node); } if (!filter) { _ERR("failed to get filter"); return NULL; } r = tv_service_get_channel_list_ex( TV_SERVICE_CHANNEL_MODE_ALL_DIGITAL_ANALOG, TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list, filter, 0); if (r != TVS_ERROR_OK) { _ERR("failed to get channel list"); goto free; } for (i = 0; i < g_list_length(tvs_list); i++) { tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, i); if (!tvs_data) continue; channel_info = _tv_channel_get_info(tvs_data); if (channel_info) channel_list = eina_list_append(channel_list, channel_info); } free: tv_service_free_channel_list(tvs_list); g_list_foreach(filter, (GFunc) _tv_channel_free_filter, NULL); g_list_free(filter); return channel_list; } /** * Frees the tv_channel_info. * * @param channel_list channel_list pointer to be freed */ void tv_channel_del_list(Eina_List *channel_list) { struct tv_channel_info *data; EINA_LIST_FREE(channel_list, data) free(data); } static void _tv_channel_add_history(int service_id) { char buf[128]; g_tv_info.history.service_id[g_tv_info.history.idx++ % 2] = service_id; snprintf(buf, sizeof(buf), "%d", service_id); app_contents_recent_add(CONTENTS_CHANNEL, buf); } static int _tv_channel_get_history(void) { int service_id; service_id = g_tv_info.history.service_id[g_tv_info.history.idx % 2]; return service_id; } /** * Tunes to specific channel with service id. * * @param service_id The channel id * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_tune_with_service_id(int service_id) { int r; if (!g_tv_info.live_svc) { _ERR("failed to get live service"); return -1; } r = tv_service_live_tune(g_tv_info.live_svc, service_id); if (r != TVS_ERROR_OK) { _ERR("failed to set service"); return -1; } _tv_channel_add_history(service_id); g_tv_info.viewing_locked_channel = -1; return 0; } /** * Tunes to last viewed channel. * * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_tune(void) { int service_id; int r; if (!g_tv_info.live_svc) { _ERR("failed to get live service"); return -1; } r = tv_service_live_get_last_channel(&service_id); if (r < 0 || service_id < 1) { _ERR("failed to get current service id"); service_id = DEFAULT_SERVICE; } r = tv_service_live_tune(g_tv_info.live_svc, service_id); if (r != TVS_ERROR_OK) { _ERR("failed to set service"); return -1; } _tv_channel_add_history(service_id); g_tv_info.viewing_locked_channel = -1; return 0; } /** * Tunes to previously viewed channel. * * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_tune_prev_channel(void) { int service_id; int r; if (!g_tv_info.live_svc) { _ERR("failed to get live service"); return -1; } service_id = _tv_channel_get_history(); if (service_id < 1) { _ERR("no previous channel"); return -1; } r = tv_service_live_tune(g_tv_info.live_svc, service_id); if (r != TVS_ERROR_OK) { _ERR("failed to set service"); return -1; } _tv_channel_add_history(service_id); g_tv_info.viewing_locked_channel = -1; return 0; } /** * Tunes to specific channel with major and minor. * * @param service_id The channel id * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_direct_tune(long major, long minor) { GList *tvs_list = NULL, *filter = NULL; TvServiceFilterNode *filter_node; TvServiceChannel *tvs_data; int r; if (!g_tv_info.live_svc) { _ERR("failed to get live service"); return -1; } if (major > 0 && major < MAJOR_MAX) { filter_node = _tv_channel_get_filter( TV_SERVICE_CHANNEL_DATA_MAJOR_NUMBER, G_TYPE_INT, (void *) major); if (filter_node) filter = g_list_append(filter, (gpointer)filter_node); } if (minor > 0 && minor < MINOR_MAX) { filter_node = _tv_channel_get_filter( TV_SERVICE_CHANNEL_DATA_MINOR_NUMBER, G_TYPE_INT, (void *) minor); if (filter_node) filter = g_list_append(filter, (gpointer)filter_node); } if (!filter) { _ERR("failed to get filter"); return -1; } r = tv_service_get_channel_list_ex( TV_SERVICE_CHANNEL_MODE_ALL_DIGITAL_ANALOG, TV_SERVICE_ANTENNA_TYPE_ALL, &tvs_list, filter, 0); if (r != TVS_ERROR_OK) goto free; tvs_data = (TvServiceChannel *) g_list_nth_data(tvs_list, 0); if (tvs_data) r = tv_channel_tune_with_service_id(tvs_data->service_id); else { _ERR("failed to get tvs_data"); r = -1; } if (r == TVS_ERROR_OK) g_tv_info.viewing_locked_channel = -1; tv_service_free_channel_list(tvs_list); free: g_list_foreach(filter, (GFunc) _tv_channel_free_filter, NULL); g_list_free(filter); return r; } /** * Tunes to locked channel. * * @param service_id The channel id * @param password 4 digit password * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_tune_locked_channel(int service_id, char *password) { int r; if (!g_tv_info.live_svc) { _ERR("failed to get live service"); return -1; } r = tv_service_live_tune_locked_channel(g_tv_info.live_svc, service_id, password); if (r != TVS_ERROR_OK) { _ERR("failed to set service"); return -1; } _tv_channel_add_history(service_id); g_tv_info.viewing_locked_channel = service_id; return 0; } /** * Sets the channel's favorite status. * * @param service_id The channel id * @param flag The value to be set * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_set_favorite(int service_id, Eina_Bool flag) { int r; if (flag) { r = tv_service_add_favorite_channel(service_id); if (r < 0) { _ERR("failed to add favorite channel"); return -1; } } else { r = tv_service_delete_favorite_channel(service_id); if (r < 0) { _ERR("failed to delete favorite channel"); return -1; } } return 0; } /** * Adds the channel. * * If channel is added, the channel will be included at * tv_channel_next, tv_channel_prev and tv_channel_get_list. * * @param service_id The channel id * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_add_channel(int service_id) { int r; r = tv_service_add_channel(service_id); if (r < 0) { _ERR("failed to add channel"); return -1; } return 0; } /** * Deletes the channel. * * If channel is deleted, the channel will be omitted at * tv_channel_next, tv_channel_prev and tv_channel_get_list. * * @param service_id The channel id * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_del_channel(int service_id) { int r; r = tv_service_delete_channel(service_id); if (r < 0) { _ERR("failed to delete channel"); return -1; } return 0; } /** * Locks the channel. * * @param service_id The channel id * @param password 4 digits password * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_lock_channel(int service_id, char *password) { int r; r = tv_service_lock_channel(service_id, password); if (r < 0) { _ERR("failed to lock channel"); return -1; } return 0; } /** * Unlocks the channel. * * @param service_id The channel id * @param password 4 digits password * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_channel_unlock_channel(int service_id, char *password) { int r; r = tv_service_unlock_channel(service_id, password); if (r < 0) { _ERR("failed to unlock channel"); return -1; } return 0; } /** * Callback function for receives tv service events. * * @param event Event type * @param user_data Not in use * @param data Event specific detailed data */ void _tv_service_event_cb(TvServiceLiveEvent event, gpointer user_data, const gpointer data) { gboolean *lock_status; switch (event) { case TV_SERVICE_LIVE_EVENT_TUNER_LOCK: if (!data) { _ERR("failed to get data"); break; } lock_status = (gboolean *) data; if (g_tv_info.signal_cb) g_tv_info.signal_cb(g_tv_info.signal_cb_data, *lock_status); break; case TV_SERVICE_LIVE_EVENT_AUTO_DESTROY: g_tv_info.live_svc = NULL; break; case TV_SERVICE_LIVE_EVENT_RESOLUTION: case TV_SERVICE_LIVE_EVENT_BEGIN: case TV_SERVICE_LIVE_EVENT_CHANNEL_LOCK: case TV_SERVICE_LIVE_EVENT_CHANNEL_UNLOCK: break; } } /** * Sets tv signal callback function. * * @param cb The function pointer to get callback * @param data An Additional data to passed to callback */ void tv_signal_cb_set(void (*cb)(void *data, int is_signal), void *data) { g_tv_info.signal_cb = cb; g_tv_info.signal_cb_data = data; } /** * Destory the tv service handles. * * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_destroy(void) { int r; if (g_tv_info.live_svc) g_tv_info.live_svc = NULL; r = tv_service_channel_info_destroy(); if (r < 0) _ERR("failed to destroy channel info service"); if (g_tv_info.epg_svc) { r = tv_service_epg_destroy(g_tv_info.epg_svc); if (r != 0) _ERR("failed to destroy epg service"); g_tv_info.epg_svc = NULL; } return 0; } /** * Create the tv service handles. * * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_create(void) { int r; r = tv_service_live_create(&g_tv_info.live_svc); if (r != TVS_ERROR_OK) { _ERR("failed to create live service"); goto err; } r = tv_service_live_register_callback(g_tv_info.live_svc, _tv_service_event_cb, NULL); if (r != TVS_ERROR_OK) { _ERR("failed to register live callback"); goto err; } r = tv_service_channel_info_create(); if (r != TVS_ERROR_OK) { _ERR("failed to create channel info service"); goto err; } r = tv_service_epg_create(&g_tv_info.epg_svc); if (r != TVS_ERROR_OK) { _ERR("failed to create epg service"); goto err; } memset(&g_tv_info.history, 0, sizeof(g_tv_info.history)); return 0; err: tv_destroy(); return -1; } /** * Pause the tv service handles. * * @return If the operation was sucessful 0 is returned; otherwise negative value is returned */ int tv_pause(void) { int r; if (g_tv_info.live_svc) { r = tv_service_live_tune_pause(g_tv_info.live_svc); if (r != TVS_ERROR_OK) _ERR("failed to pause live service"); } return 0; } /** * Resume the tv service handles. * * Live service could be destroyed by tv service while app is pausing. * If live service is destroyed, then _tv_service_event_cb sets * g_tv_info.live_svc to NULL. * So if g_tv_info.live_svc is NULL, then recreates live service and returns 1. * Therefore, if tv_resume returns 1, then app needs to be set overlay and tune. * Or returns 0, then app just needs to set overlay. * * @return 0 if successful; 1 if live service was destroyed; otherwise negative value is returned */ int tv_resume(void) { int r; if (!g_tv_info.live_svc) { r = tv_service_live_create(&g_tv_info.live_svc); if (r != TVS_ERROR_OK) { _ERR("failed to create live service"); goto err; } r = tv_service_live_register_callback(g_tv_info.live_svc, _tv_service_event_cb, NULL); if (r != TVS_ERROR_OK) { _ERR("failed to register live callback"); goto err; } return 1; } r = tv_service_live_tune_resume(g_tv_info.live_svc); if (r != TVS_ERROR_OK) { _ERR("failed to create live service"); goto err; } r = tv_service_live_register_callback(g_tv_info.live_svc, _tv_service_event_cb, NULL); if (r != TVS_ERROR_OK) { _ERR("failed to register live callback"); goto err; } return 0; err: tv_destroy(); return -1; }