From cafa9fd8227d5a680b9bb7130562519c426159bf Mon Sep 17 00:00:00 2001
From: Calvin Walton <calvin.walton@kepstin.ca>
Date: Mon, 12 Feb 2018 16:33:37 -0500
Subject: [PATCH] Rework audio processing to avoid seeking past end of file

In some cases when there is a slight mismatch between audio file
duration and event timestamp difference, and we have a record
status or chapter break event in a certain location, it could
trigger a seek past the end of an audio file. Detect this
condition and just render silence instead.

Also adjust the thresholds for the audio length scaling - they
were being triggered on short recordings that should be correct.
---
 .../core/lib/recordandplayback/edl/audio.rb   | 61 +++++++++++--------
 1 file changed, 37 insertions(+), 24 deletions(-)

diff --git a/record-and-playback/core/lib/recordandplayback/edl/audio.rb b/record-and-playback/core/lib/recordandplayback/edl/audio.rb
index 316a7d0795..32e4ed373b 100644
--- a/record-and-playback/core/lib/recordandplayback/edl/audio.rb
+++ b/record-and-playback/core/lib/recordandplayback/edl/audio.rb
@@ -92,40 +92,53 @@ module BigBlueButton
           audio = entry[:audio]
           duration = entry[:next_timestamp] - entry[:timestamp]
 
-          if audio
+          # Check for and handle audio files with mismatched lengths (generated
+          # by buggy versions of freeswitch in old BigBlueButton
+          if audio and entry[:original_duration] and
+               (audioinfo[audio[:filename]][:duration].to_f / entry[:original_duration]) < 0.997 and
+               ((entry[:original_duration] - audioinfo[audio[:filename]][:duration]).to_f /
+                      entry[:original_duration]).abs < 0.05
+            speed = audioinfo[audio[:filename]][:duration].to_f / entry[:original_duration]
             BigBlueButton.logger.info "  Using input #{audio[:filename]}"
 
+            BigBlueButton.logger.warn "  Audio file length mismatch, adjusting speed to #{speed}"
+
+            # Have to calculate the start point after the atempo filter in this case,
+            # since it can affect the audio start time.
+            # Also reset the pts to start at 0, so the duration trim works correctly.
             filter = "[#{input_index}] "
+            filter << "atempo=#{speed},atrim=start=#{ms_to_s(audio[:timestamp])},"
+            filter << "asetpts=PTS-STARTPTS,"
+            filter << "#{FFMPEG_AFORMAT},apad,atrim=end=#{ms_to_s(duration)} [out#{output_index}]"
+            ffmpeg_filters << filter
 
-            if entry[:original_duration] and
-                 (audioinfo[audio[:filename]][:duration].to_f / entry[:original_duration]) < 0.999 and
-                 ((entry[:original_duration] - audioinfo[audio[:filename]][:duration]).to_f /
-                        entry[:original_duration]).abs < 0.05
-              speed = audioinfo[audio[:filename]][:duration].to_f / entry[:original_duration]
-              BigBlueButton.logger.warn "  Audio file length mismatch, adjusting speed to #{speed}"
-
-              # Have to calculate the start point after the atempo filter in this case,
-              # since it can affect the audio start time.
-              # Also reset the pts to start at 0, so the duration trim works correctly.
-              filter << "atempo=#{speed},atrim=start=#{ms_to_s(audio[:timestamp])},"
-              filter << "asetpts=PTS-STARTPTS,"
-
-              ffmpeg_inputs << {
-                :filename => audio[:filename],
-                :seek => 0
-              }
-            else
-              ffmpeg_inputs << {
-                :filename => audio[:filename],
-                :seek => audio[:timestamp]
-              }
-            end
+            ffmpeg_inputs << {
+              :filename => audio[:filename],
+              :seek => 0
+            }
 
+            input_index += 1
+            output_index += 1
+
+            # Normal audio input handling. Skip this input and generate silence
+            # if the seekpoint is past the end of the audio, which can happen
+            # if events are slightly misaligned and you get unlucky with a
+            # start/stop or chapter break.
+          elsif audio and audio[:timestamp] < audioinfo[audio[:filename]][:duration]
+            BigBlueButton.logger.info "  Using input #{audio[:filename]}"
+
+            filter = "[#{input_index}] "
             filter << "#{FFMPEG_AFORMAT},apad,atrim=end=#{ms_to_s(duration)} [out#{output_index}]"
             ffmpeg_filters << filter
 
+            ffmpeg_inputs << {
+              :filename => audio[:filename],
+              :seek => audio[:timestamp]
+            }
+
             input_index += 1
             output_index += 1
+
           else
             BigBlueButton.logger.info "  Generating silence"
 
-- 
GitLab