]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
DVR: centralize status updates, fix dvr_rec_subscribe error path, fixes#2857
authorJaroslav Kysela <perex@perex.cz>
Wed, 20 May 2015 08:54:17 +0000 (10:54 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 20 May 2015 08:54:17 +0000 (10:54 +0200)
src/dvr/dvr.h
src/dvr/dvr_db.c
src/dvr/dvr_rec.c

index 540a0ba6755fc62588b8f7caefba1e617ace6767..75d19def5c96583655acdd5e8f20a6acb871274d 100644 (file)
@@ -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);
 
index 8672cc5c70a238d2e7819fe440289069c35334b5..20cb3c72c37c91d4314b2ef029693bc9c068a1bb 100644 (file)
@@ -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));
index 46bc2e398182209fcff7b999a5ea5f470b166cbb..4408beca43353532bba8eb12834f6a609a608f65 100644 (file)
@@ -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)