Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

screenshare: add rap processing for screen streams with audio (complements #11622) #11626

Merged
merged 9 commits into from
Mar 24, 2021
19 changes: 19 additions & 0 deletions record-and-playback/core/lib/recordandplayback/edl/audio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ def self.dump(edl)
end
end

def self.mixer(inputs, output_basename)
BigBlueButton.logger.debug "Mixing audio files"

ffmpeg_cmd = [*FFMPEG]
inputs.each do |input|
ffmpeg_cmd += ['-i', input]
end
ffmpeg_cmd += ['-filter_complex', "amix"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should explicitly set the number of inputs to the amix filter here, in case a number of inputs ≠ 2 is provided.

Suggested change
ffmpeg_cmd += ['-filter_complex', "amix"]
ffmpeg_cmd += ['-filter_complex', "amix=inputs=#{inputs.length}"]


output = "#{output_basename}.#{WF_EXT}"
ffmpeg_cmd += [*FFMPEG_WF_ARGS, output]

BigBlueButton.logger.info "Running audio mixer..."
exitstatus = BigBlueButton.exec_ret(*ffmpeg_cmd)
raise "ffmpeg failed, exit code #{exitstatus}" if exitstatus != 0

output
end

def self.render(edl, output_basename)
audioinfo = {}

Expand Down
65 changes: 65 additions & 0 deletions record-and-playback/core/lib/recordandplayback/generators/audio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,70 @@ def self.create_audio_edl(events, archive_dir)
return audio_edl
end

def self.create_deskshare_audio_edl(events, deskshare_dir)
audio_edl = []

initial_timestamp = BigBlueButton::Events.first_event_timestamp(events)
final_timestamp = BigBlueButton::Events.last_event_timestamp(events)
filename = ""

# Initially start with silence
audio_edl << {
:timestamp => 0,
:audio => nil
}

events.xpath('/recording/event[@module="Deskshare" or (@module="bbb-webrtc-sfu" and (@eventname="StartWebRTCDesktopShareEvent" or @eventname="StopWebRTCDesktopShareEvent"))]').each do |event|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the "Deskshare" module (I think that's the old java screensharing?) can ever have audio, so this should only look at the WebRTC events.

filename = event.at_xpath('filename').text
# Determine the audio filename
case event['eventname']
when 'DeskshareStartedEvent', 'DeskshareStoppedEvent'
filename = event.at_xpath('file').text
filename = "#{deskshare_dir}/#{File.basename(filename)}"
when 'StartWebRTCDesktopShareEvent', 'StopWebRTCDesktopShareEvent'
uri = event.at_xpath('filename').text
filename = "#{deskshare_dir}/#{File.basename(uri)}"
end
raise "Couldn't determine audio filename" if filename.nil?
# check if deskshare has audio
fileHasAudio = !BigBlueButton::EDL::Audio.audio_info(filename)[:audio].nil?
if (fileHasAudio)
timestamp = event['timestamp'].to_i - initial_timestamp
# Add the audio to the EDL
case event['eventname']
when 'DeskshareStartedEvent', 'StartWebRTCDesktopShareEvent'
audio_edl << {
:timestamp => timestamp,
:audio => { :filename => filename, :timestamp => 0 }
}
when 'DeskshareStoppedEvent', 'StopWebRTCDesktopShareEvent'
if audio_edl.last[:audio] && audio_edl.last[:audio][:filename] == filename
# Fill in the original/expected audo duration when available
duration = event.at_xpath('duration')
if !duration.nil?
duration = duration.text.to_i
audio_edl.last[:original_duration] = duration * 1000
else
audio_edl.last[:original_duration] = timestamp - audio_edl.last[:timestamp]
end
audio_edl << {
:timestamp => timestamp,
:audio => nil
}
end
end
else
BigBlueButton.logger.debug " Screenshare without audio, ignoring..."
end
end

audio_edl << {
:timestamp => final_timestamp - initial_timestamp,
:audio => nil
}

return audio_edl
end

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class AudioProcessor
def self.process(archive_dir, file_basename)
BigBlueButton.logger.info("AudioProcessor.process: Processing audio...")

audio_dir = "#{archive_dir}/audio"
events_xml = "#{archive_dir}/events.xml"
events = Nokogiri::XML(File.open(events_xml))

Expand All @@ -52,12 +51,36 @@ def self.process(archive_dir, file_basename)
BigBlueButton::EDL::Audio.dump(audio_edl)

target_dir = File.dirname(file_basename)
audio_dir = "#{archive_dir}/audio"
events_xml = "#{archive_dir}/events.xml"

# getting users audio...
@audio_file = BigBlueButton::EDL::Audio.render(
audio_edl, File.join(target_dir, 'recording'))

# and mixing it with deskshare audio
deskshare_dir = "#{archive_dir}/deskshare"
if BigBlueButton::Events.screenshare_has_audio?(events_xml, deskshare_dir)
BigBlueButton.logger.info("AudioProcessor.process: processing Deskshare audio...")

mixed_dir = "#{archive_dir}/mixed"

deskshare_audio_edl = BigBlueButton::AudioEvents.create_deskshare_audio_edl(events, deskshare_dir)
BigBlueButton::EDL::Audio.dump(deskshare_audio_edl)

BigBlueButton.logger.info "Applying recording start/stop events to Deskshare audio"
deskshare_audio_edl = BigBlueButton::Events.edl_match_recording_marks_audio(
deskshare_audio_edl, events, start_time, end_time)
BigBlueButton.logger.debug "Trimmed Deskshare Audio EDL:"
BigBlueButton::EDL::Audio.dump(deskshare_audio_edl)

audio_inputs = []
audio_inputs << @audio_file
audio_inputs << BigBlueButton::EDL::Audio.render(deskshare_audio_edl, deskshare_dir)

@audio_file = BigBlueButton::EDL::Audio.mixer(audio_inputs, mixed_dir)
else
BigBlueButton.logger.info("AudioProcessor.process: no Deskshare audio to process.")
end

ogg_format = {
:extension => 'ogg',
:parameters => [ [ '-c:a', 'copy', '-f', 'ogg' ] ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -692,5 +692,19 @@ def self.bbb_version_compare(events, major, minor=nil, micro=nil)
end
end

# Check if any screenshare files has audio
def self.screenshare_has_audio?(events_xml, deskshare_dir)
events = Nokogiri::XML(File.open(events_xml))
events.xpath('/recording/event[@eventname="StartWebRTCDesktopShareEvent"]').each do |event|
filename = event.at_xpath('filename').text
filename = "#{deskshare_dir}/#{File.basename(filename)}"
fileHasAudio = !BigBlueButton::EDL::Audio.audio_info(filename)[:audio].nil?
if fileHasAudio
return true
end
end
return false
end

end
end