From: Jaroslav Kysela Date: Wed, 20 May 2015 08:54:17 +0000 (+0200) Subject: DVR: centralize status updates, fix dvr_rec_subscribe error path, fixes#2857 X-Git-Tag: v4.2.1~2517 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee69d63454627e12a83ea1a2ba241efb70f4736a;p=thirdparty%2Ftvheadend.git DVR: centralize status updates, fix dvr_rec_subscribe error path, fixes#2857 --- diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 540a0ba67..75d19def5 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -419,6 +419,11 @@ void dvr_entry_save(dvr_entry_t *de); void dvr_entry_destroy_by_config(dvr_config_t *cfg, int delconf); +int dvr_entry_set_state(dvr_entry_t *de, dvr_entry_sched_state_t state, + dvr_rs_state_t rec_state, int error_code); + +void dvr_entry_completed(dvr_entry_t *de, int error_code); + const char *dvr_entry_status(dvr_entry_t *de); const char *dvr_entry_schedstatus(dvr_entry_t *de); @@ -460,9 +465,9 @@ dvr_entry_update( dvr_entry_t *de, void dvr_destroy_by_channel(channel_t *ch, int delconf); -void dvr_rec_subscribe(dvr_entry_t *de); +int dvr_rec_subscribe(dvr_entry_t *de); -void dvr_rec_unsubscribe(dvr_entry_t *de, int stopcode); +void dvr_rec_unsubscribe(dvr_entry_t *de); void dvr_event_replaced(epg_broadcast_t *e, epg_broadcast_t *new_e); diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 8672cc5c7..20cb3c72c 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -50,17 +50,23 @@ static int dvr_entry_class_disp_subtitle_set(void *o, const void *v); /* * */ -static int -dvr_entry_assign_sched_state(dvr_entry_t *de, int state) +int +dvr_entry_set_state(dvr_entry_t *de, dvr_entry_sched_state_t state, + dvr_rs_state_t rec_state, int error_code) { char id[16]; - if (de->de_sched_state != state) { + if (de->de_sched_state != state || + de->de_rec_state != rec_state || + de->de_last_error != error_code) { if (de->de_bcast) { snprintf(id, sizeof(id), "%u", de->de_bcast->id); notify_delayed(id, "epg", "dvr_update"); } de->de_sched_state = state; + de->de_rec_state = rec_state; + de->de_last_error = error_code; idnode_notify_changed(&de->de_id); + htsp_dvr_entry_update(de); return 1; } return 0; @@ -201,10 +207,10 @@ dvr_dbus_timer_cb( void *aux ) /* * Completed */ -static void -_dvr_entry_completed(dvr_entry_t *de) +void +dvr_entry_completed(dvr_entry_t *de, int error_code) { - dvr_entry_assign_sched_state(de, DVR_COMPLETED); + dvr_entry_set_state(de, DVR_COMPLETED, DVR_RS_PENDING, error_code); #if ENABLE_INOTIFY dvr_inotify_add(de); #endif @@ -348,9 +354,9 @@ dvr_entry_set_timer(dvr_entry_t *de) if(now >= stop || de->de_dont_reschedule) { if(htsmsg_is_empty(de->de_files)) - dvr_entry_assign_sched_state(de, DVR_MISSED_TIME); + dvr_entry_set_state(de, DVR_MISSED_TIME, DVR_RS_PENDING, de->de_last_error); else - _dvr_entry_completed(de); + dvr_entry_completed(de, de->de_last_error); gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, de->de_stop + dvr_entry_get_retention(de) * 86400); @@ -360,7 +366,7 @@ dvr_entry_set_timer(dvr_entry_t *de) } else if (de->de_channel && de->de_channel->ch_enabled) { - dvr_entry_assign_sched_state(de, DVR_SCHEDULED); + dvr_entry_set_state(de, DVR_SCHEDULED, DVR_RS_PENDING, de->de_last_error); tvhtrace("dvr", "entry timer scheduled for %"PRItime_t, start); gtimer_arm_abs(&de->de_timer, dvr_timer_start_recording, de, start); @@ -370,7 +376,7 @@ dvr_entry_set_timer(dvr_entry_t *de) } else { - dvr_entry_assign_sched_state(de, DVR_NOSTATE); + dvr_entry_set_state(de, DVR_NOSTATE, DVR_RS_PENDING, de->de_last_error); } } @@ -718,7 +724,9 @@ static dvr_entry_t* _dvr_duplicate_event(dvr_entry_t* de) continue; // only successful earlier recordings qualify as master - if (de2->de_sched_state == DVR_MISSED_TIME || (de2->de_sched_state == DVR_COMPLETED && de2->de_last_error != SM_CODE_OK)) + if (de2->de_sched_state == DVR_MISSED_TIME || + (de2->de_sched_state == DVR_COMPLETED && + de2->de_last_error != SM_CODE_OK)) continue; // if titles are not defined or do not match, don't dedup @@ -1122,14 +1130,16 @@ void dvr_event_updated ( epg_broadcast_t *e ) static void dvr_stop_recording(dvr_entry_t *de, int stopcode, int saveconf) { - if (de->de_rec_state == DVR_RS_PENDING || - de->de_rec_state == DVR_RS_WAIT_PROGRAM_START || + dvr_rs_state_t rec_state = de->de_rec_state; + + dvr_rec_unsubscribe(de); + + if (rec_state == DVR_RS_PENDING || + rec_state == DVR_RS_WAIT_PROGRAM_START || htsmsg_is_empty(de->de_files)) - dvr_entry_assign_sched_state(de, DVR_MISSED_TIME); + dvr_entry_set_state(de, DVR_MISSED_TIME, DVR_RS_PENDING, stopcode); else - _dvr_entry_completed(de); - - dvr_rec_unsubscribe(de, stopcode); + dvr_entry_completed(de, stopcode); tvhlog(LOG_INFO, "dvr", "\"%s\" on \"%s\": " "End of program: %s", @@ -1138,8 +1148,6 @@ dvr_stop_recording(dvr_entry_t *de, int stopcode, int saveconf) if (saveconf) dvr_entry_save(de); - idnode_notify_changed(&de->de_id); - htsp_dvr_entry_update(de); gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, de->de_stop + dvr_entry_get_retention(de) * 86400); @@ -1152,7 +1160,7 @@ dvr_stop_recording(dvr_entry_t *de, int stopcode, int saveconf) static void dvr_timer_stop_recording(void *aux) { - dvr_stop_recording(aux, 0, 1); + dvr_stop_recording(aux, SM_CODE_OK, 1); } @@ -1166,7 +1174,7 @@ dvr_timer_start_recording(void *aux) dvr_entry_t *de = aux; if (de->de_channel == NULL || !de->de_channel->ch_enabled) { - dvr_entry_assign_sched_state(de, DVR_NOSTATE); + dvr_entry_set_state(de, DVR_NOSTATE, DVR_RS_PENDING, de->de_last_error); return; } @@ -1176,16 +1184,13 @@ dvr_timer_start_recording(void *aux) return; } - dvr_entry_assign_sched_state(de, DVR_RECORDING); - de->de_rec_state = DVR_RS_PENDING; - de->de_last_error = SM_CODE_OK; + dvr_entry_set_state(de, DVR_RECORDING, DVR_RS_PENDING, SM_CODE_OK); tvhlog(LOG_INFO, "dvr", "\"%s\" on \"%s\" recorder starting", lang_str_get(de->de_title, NULL), DVR_CH_NAME(de)); - idnode_changed(&de->de_id); - htsp_dvr_entry_update(de); - dvr_rec_subscribe(de); + if (dvr_rec_subscribe(de)) + dvr_entry_completed(de, SM_CODE_BAD_SOURCE); gtimer_arm_abs(&de->de_timer, dvr_timer_stop_recording, de, dvr_entry_get_stop_time(de)); diff --git a/src/dvr/dvr_rec.c b/src/dvr/dvr_rec.c index 46bc2e398..4408beca4 100644 --- a/src/dvr/dvr_rec.c +++ b/src/dvr/dvr_rec.c @@ -58,7 +58,7 @@ const static int prio2weight[6] = { /** * */ -void +int dvr_rec_subscribe(dvr_entry_t *de) { char buf[100]; @@ -82,7 +82,8 @@ dvr_rec_subscribe(dvr_entry_t *de) if (profile_chain_open(prch, &de->de_config->dvr_muxcnf, 0, 0)) { tvherror("dvr", "unable to create new channel streaming chain for '%s'", channel_get_name(de->de_channel)); - return; + free(prch); + return -1; } de->de_s = subscription_create_from_channel(prch, NULL, weight, @@ -93,20 +94,20 @@ dvr_rec_subscribe(dvr_entry_t *de) channel_get_name(de->de_channel)); profile_chain_close(prch); free(prch); - de->de_chain = NULL; - return; + return -1; } de->de_chain = prch; tvhthread_create(&de->de_thread, NULL, dvr_thread, de); + return 0; } /** * */ void -dvr_rec_unsubscribe(dvr_entry_t *de, int stopcode) +dvr_rec_unsubscribe(dvr_entry_t *de) { profile_chain_t *prch = de->de_chain; @@ -123,8 +124,6 @@ dvr_rec_unsubscribe(dvr_entry_t *de, int stopcode) de->de_chain = NULL; profile_chain_close(prch); free(prch); - - de->de_last_error = stopcode; } @@ -320,9 +319,9 @@ dvr_rec_fatal_error(dvr_entry_t *de, const char *fmt, ...) * */ static void -dvr_notify(dvr_entry_t *de, int now) +dvr_notify(dvr_entry_t *de) { - if (now || de->de_last_notify + 5 < dispatch_clock) { + if (de->de_last_notify + 5 < dispatch_clock) { idnode_notify_changed(&de->de_id); de->de_last_notify = dispatch_clock; htsp_dvr_entry_update(de); @@ -335,19 +334,9 @@ dvr_notify(dvr_entry_t *de, int now) static void dvr_rec_set_state(dvr_entry_t *de, dvr_rs_state_t newstate, int error) { - int notify = 0; - if(de->de_rec_state != newstate) { - de->de_rec_state = newstate; - notify = 1; - } - if(de->de_last_error != error) { - de->de_last_error = error; - notify = 1; - if(error) - de->de_errors++; - } - if (notify) - dvr_notify(de, 1); + if (de->de_last_error != error && error) + de->de_errors++; + dvr_entry_set_state(de, de->de_sched_state, newstate, error); } /** @@ -524,14 +513,14 @@ dvr_thread(void *aux) pb = ((th_pkt_t*)sm->sm_data)->pkt_payload; if (((th_pkt_t*)sm->sm_data)->pkt_err) { de->de_data_errors += ((th_pkt_t*)sm->sm_data)->pkt_err; - dvr_notify(de, 0); + dvr_notify(de); } } else if (sm->sm_type == SMT_MPEGTS) { pb = sm->sm_data; if (pb->pb_err) { de->de_data_errors += pb->pb_err; - dvr_notify(de, 0); + dvr_notify(de); } } if (pb) @@ -562,7 +551,7 @@ dvr_thread(void *aux) if(started) { muxer_write_pkt(prch->prch_muxer, sm->sm_type, sm->sm_data); sm->sm_data = NULL; - dvr_notify(de, 0); + dvr_notify(de); } break; @@ -571,7 +560,7 @@ dvr_thread(void *aux) dvr_rec_set_state(de, DVR_RS_RUNNING, 0); muxer_write_pkt(prch->prch_muxer, sm->sm_type, sm->sm_data); sm->sm_data = NULL; - dvr_notify(de, 0); + dvr_notify(de); } break; @@ -591,11 +580,8 @@ dvr_thread(void *aux) if(!started) { pthread_mutex_lock(&global_lock); dvr_rec_set_state(de, DVR_RS_WAIT_PROGRAM_START, 0); - if(dvr_rec_start(de, sm->sm_data) == 0) { + if(dvr_rec_start(de, sm->sm_data) == 0) started = 1; - idnode_changed(&de->de_id); - htsp_dvr_entry_update(de); - } pthread_mutex_unlock(&global_lock); } break; @@ -607,7 +593,7 @@ dvr_thread(void *aux) } else if(sm->sm_code == 0) { // Recording is completed - de->de_last_error = SM_CODE_OK; + dvr_entry_set_state(de, de->de_sched_state, de->de_rec_state, SM_CODE_OK); tvhlog(LOG_INFO, "dvr", "Recording completed: \"%s\"", dvr_get_filename(de) ?: lang_str_get(de->de_title, NULL)); @@ -754,7 +740,6 @@ dvr_thread_epilog(dvr_entry_t *de) muxer_close(prch->prch_muxer); muxer_destroy(prch->prch_muxer); prch->prch_muxer = NULL; - dvr_notify(de, 1); dvr_config_t *cfg = de->de_config; if(cfg && cfg->dvr_postproc)