Merge branch 'record-and-playback-feature' of github.com:bigbluebutton/bigbluebutton into record-and-playback-feature
Conflicts: record-and-playback/rap/lib/recordandplayback/collectors/audio.rb
This commit is contained in:
commit
b01211d8f2
@ -36,7 +36,7 @@ GEM
|
||||
rspec-expectations (= 2.0.0)
|
||||
sinatra (1.2.1)
|
||||
rack (~> 1.1)
|
||||
tilt (>= 1.2.2, < 2.0)
|
||||
tilt (< 2.0, >= 1.2.2)
|
||||
term-ansicolor (1.0.5)
|
||||
tilt (1.2.2)
|
||||
vegas (0.1.8)
|
||||
|
31
record-and-playback/rap/audio_gen_test.rb
Executable file
31
record-and-playback/rap/audio_gen_test.rb
Executable file
@ -0,0 +1,31 @@
|
||||
require 'lib/recordandplayback/generators/audio'
|
||||
|
||||
s1 = "/tmp/audio1.wav"
|
||||
s2 = "/tmp/audio2.wav"
|
||||
|
||||
g = Generator::Audio.new
|
||||
g.generate_silence(20, s1, 16000)
|
||||
g.generate_silence(20, s2, 16000)
|
||||
|
||||
d = "/home/firstuser/dev/source/bigbluebutton/record-and-playback/rap/resources/raw/1b199e88-7df7-4842-a5f1-0e84b781c5c8/audio"
|
||||
f1 = "#{d}/1b199e88-7df7-4842-a5f1-0e84b781c5c8-20110202-041247.wav"
|
||||
f2 = "#{d}/1b199e88-7df7-4842-a5f1-0e84b781c5c8-20110202-041415.wav"
|
||||
|
||||
files = [f1, s1, f2, s2]
|
||||
outf = "/tmp/final.wav"
|
||||
|
||||
g.concatenate_audio_files(files, outf)
|
||||
wav_file = outf
|
||||
ogg_file = "/tmp/final.ogg"
|
||||
|
||||
g.wav_to_ogg(wav_file, {:artist => "Budka Suflera",
|
||||
:album => "Za Ostatni Grosz",
|
||||
:track => 1,
|
||||
:title => "Za Ostatni Grosz",
|
||||
:date => "1981-05-01",
|
||||
:composer => "composer=Romuald Lipko, Marek Dutkiewicz"},
|
||||
ogg_file)
|
||||
|
||||
|
||||
|
||||
|
@ -3,11 +3,19 @@ require 'fileutils'
|
||||
module Collector
|
||||
class NoSuchDirectoryException < RuntimeError
|
||||
end
|
||||
|
||||
class NoAudioFileException < RuntimeError
|
||||
end
|
||||
|
||||
class NoVideoFileException < RuntimeError
|
||||
end
|
||||
|
||||
class NoPresentationException < RuntimeError
|
||||
end
|
||||
|
||||
class NoDeskshareException < RuntimeError
|
||||
end
|
||||
|
||||
class Audio
|
||||
def location_exist?(location)
|
||||
FileTest.directory?(location)
|
||||
@ -17,7 +25,8 @@ module Collector
|
||||
Dir.glob("#{location}/#{meeting_id}*.wav").empty?
|
||||
end
|
||||
|
||||
|
||||
# Copies the audio recordings specified by meeting_id
|
||||
# from a directory to a target directory.
|
||||
def collect_audio(meeting_id, from_dir, to_dir)
|
||||
if not location_exist?(from_dir)
|
||||
raise NoSuchDirectoryException, "Directory not found #{from_dir}"
|
||||
@ -47,7 +56,6 @@ module Collector
|
||||
Dir.glob("#{location}/*.flv").empty?
|
||||
end
|
||||
|
||||
|
||||
def collect_video(meeting_id, from_dir, to_dir)
|
||||
if not location_exist?(from_dir)
|
||||
raise NoSuchDirectoryException, "Directory not found #{from_dir}"
|
||||
@ -67,17 +75,44 @@ module Collector
|
||||
end
|
||||
end
|
||||
|
||||
class Presentation
|
||||
def location_exist?(location)
|
||||
FileTest.directory?(location)
|
||||
end
|
||||
|
||||
def presentation_present?(meeting_id, location)
|
||||
Dir.glob("#{location}").empty?
|
||||
end
|
||||
|
||||
def collect_presentation(meeting_id, from_dir, to_dir)
|
||||
if not location_exist?(from_dir)
|
||||
raise NoSuchDirectoryException, "Directory not found #{from_dir}"
|
||||
end
|
||||
|
||||
if not location_exist?(to_dir)
|
||||
raise NoSuchDirectoryException, "Directory not found #{to_dir}"
|
||||
end
|
||||
|
||||
if (presentation_present?(meeting_id, from_dir))
|
||||
raise NoPresentationException, "No video recording for #{meeting_id} in #{from_dir}"
|
||||
end
|
||||
|
||||
Dir.glob("#{from_dir}/*.flv").each { |file|
|
||||
FileUtils.cp(file, to_dir)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class Deskshare
|
||||
def location_exist?(location)
|
||||
FileTest.directory?(location)
|
||||
end
|
||||
|
||||
def video_present?(meeting_id, location)
|
||||
Dir.glob("#{location}/*.flv").empty?
|
||||
def deskshare_present?(meeting_id, location)
|
||||
Dir.glob("#{location}").empty?
|
||||
end
|
||||
|
||||
|
||||
def collect_video(meeting_id, from_dir, to_dir)
|
||||
def collect_deskshare(meeting_id, from_dir, to_dir)
|
||||
if not location_exist?(from_dir)
|
||||
raise NoSuchDirectoryException, "Directory not found #{from_dir}"
|
||||
end
|
||||
@ -86,8 +121,8 @@ module Collector
|
||||
raise NoSuchDirectoryException, "Directory not found #{to_dir}"
|
||||
end
|
||||
|
||||
if (video_present?(meeting_id, from_dir))
|
||||
raise NoVideoFileException, "No video recording for #{meeting_id} in #{from_dir}"
|
||||
if (deskshare_present?(meeting_id, from_dir))
|
||||
raise NoDeskshareException, "No video recording for #{meeting_id} in #{from_dir}"
|
||||
end
|
||||
|
||||
Dir.glob("#{from_dir}/*.flv").each { |file|
|
||||
|
95
record-and-playback/rap/lib/recordandplayback/generators/audio.rb
Executable file
95
record-and-playback/rap/lib/recordandplayback/generators/audio.rb
Executable file
@ -0,0 +1,95 @@
|
||||
require 'fileutils'
|
||||
require 'rubygems'
|
||||
require 'nokogiri'
|
||||
|
||||
module Generator
|
||||
class Audio
|
||||
# Generate a silent wav file.
|
||||
# Params:
|
||||
# millis - length of silence in millis
|
||||
# filename - name of the resulting file (absolute location)
|
||||
# sampling_rate = rate of the audio
|
||||
def generate_silence(millis, filename, sampling_rate)
|
||||
rate_in_ms = sampling_rate / 1000
|
||||
samples = millis * rate_in_ms
|
||||
temp_file = filename + ".dat"
|
||||
f = File.open(temp_file, "wb")
|
||||
# Write the sample rate for this audio file.
|
||||
f.puts('; SampleRate ' + sampling_rate.to_s + '\n')
|
||||
|
||||
1.upto(samples) do |sample|
|
||||
f.puts((sample / rate_in_ms).to_s + "\t0\n")
|
||||
end
|
||||
|
||||
f.close();
|
||||
proc = IO.popen("sox #{temp_file} -b 16 -r 16000 -c 1 -s #{filename}", "w+")
|
||||
# Wait for the process to finish before removing the temp file
|
||||
Process.wait()
|
||||
# Delete the temporary raw audio file
|
||||
FileUtils.rm(temp_file)
|
||||
end
|
||||
|
||||
def concatenate_audio_files(files, out_filename)
|
||||
concat_cmd = 'sox '
|
||||
files.each do |file|
|
||||
concat_cmd += " " + file
|
||||
end
|
||||
|
||||
concat_cmd += " " + out_filename
|
||||
#puts concat_cmd
|
||||
|
||||
proc = IO.popen(concat_cmd, "w+")
|
||||
# Wait for the process to finish
|
||||
Process.wait()
|
||||
end
|
||||
|
||||
def wav_to_ogg(wav_file, atts, ogg_file)
|
||||
proc = IO.popen("oggenc -o #{ogg_file} #{wav_file}", "w+")
|
||||
Process.wait()
|
||||
end
|
||||
end
|
||||
|
||||
class AudioEvents
|
||||
def get_first_timestamp_of_session(events)
|
||||
@doc = Nokogiri::XML(File.open(events))
|
||||
@doc.xpath("events/event").first["timestamp"].to_s
|
||||
end
|
||||
|
||||
def get_last_timestamp_of_session(events)
|
||||
@doc = Nokogiri::XML(File.open(events))
|
||||
@doc.xpath("events/event").last["timestamp"].to_s
|
||||
end
|
||||
|
||||
def get_start_audio_recording_events(events)
|
||||
@doc = Nokogiri::XML(File.open(events))
|
||||
start_events = []
|
||||
@doc.xpath("//event[@name='StartRecordingEvent']").each do |e|
|
||||
start_events << {:start_event_timestamp => e["timestamp"], :bridge => e.xpath("bridge").text,
|
||||
:file => e.xpath("filename").text, :start_record_timestamp => e.xpath("recordingTimestamp").text}
|
||||
end
|
||||
return start_events.sort {|a,b| a[:start_event_timestamp] <=> b[:start_event_timestamp]}
|
||||
end
|
||||
|
||||
def get_stop_audio_recording_events(events)
|
||||
@doc = Nokogiri::XML(File.open(events))
|
||||
stop_events = []
|
||||
@doc.xpath("//event[@name='StopRecordingEvent']").each do |e|
|
||||
stop_events << {:stop_event_timestamp => e["timestamp"], :bridge => e.xpath("bridge").text,
|
||||
:file => e.xpath("filename").text, :stop_record_timestamp => e.xpath("recordingTimestamp").text}
|
||||
end
|
||||
return stop_events.sort {|a,b| a[:stop_event_timestamp] <=> b[:stop_event_timestamp]}
|
||||
end
|
||||
|
||||
def match_start_and_stop_events(start_events, stop_events)
|
||||
audio_events = []
|
||||
start_events.each { |saev|
|
||||
stop_events.each { |soev|
|
||||
if (soev[:file] == saev[:file])
|
||||
puts soev[:file]
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
end
|
||||
end
|
12
record-and-playback/rap/spec/recordandplayback/audio_generator_spec.rb
Executable file
12
record-and-playback/rap/spec/recordandplayback/audio_generator_spec.rb
Executable file
@ -0,0 +1,12 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Generator
|
||||
describe Audio do
|
||||
context "#success" do
|
||||
it "should create a silence file" do
|
||||
ag = Generator::Audio.new
|
||||
ag.generate_silence(2000,"/tmp/audio.dat", 8000)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,52 @@
|
||||
require 'spec_helper'
|
||||
require 'fileutils'
|
||||
|
||||
module Collector
|
||||
describe Deskshare do
|
||||
context "#success" do
|
||||
it "should copy deskshare recordings to archive" do
|
||||
FileTest.stub(:directory?).and_return(true)
|
||||
FileUtils.stub(:cp)
|
||||
Dir.stub(:glob).and_return(['file1.wav', 'file2.wav'])
|
||||
from_dir = 'from'
|
||||
to_dir = 'to'
|
||||
meeting_id = 'meeting-id'
|
||||
archiver = Collector::Deskshare.new
|
||||
expect { archiver.collect_deskshare( meeting_id, from_dir, to_dir ) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context "#fail" do
|
||||
it "should raise from directory not found exception" do
|
||||
FileTest.stub(:directory?).and_return(false)
|
||||
FileUtils.stub(:cp)
|
||||
Dir.stub(:glob).and_return(['file1.wav', 'file2.wav'])
|
||||
from_dir = '/from-dir-not-found'
|
||||
to_dir = 'resources/archive'
|
||||
meeting_id = 'meeting-id'
|
||||
archiver = Collector::Deskshare.new
|
||||
expect {archiver.collect_deskshare( meeting_id, from_dir, to_dir )}.to raise_error(NoSuchDirectoryException)
|
||||
end
|
||||
it "should raise to directory not found exception" do
|
||||
from_dir = 'resources/raw/audio'
|
||||
to_dir = '/to-dir-not-found'
|
||||
meeting_id = 'meeting-id'
|
||||
FileTest.stub(:directory?).and_return(false)
|
||||
FileUtils.stub(:cp)
|
||||
Dir.stub(:glob).and_return(['file1.wav', 'file2.wav'])
|
||||
archiver = Collector::Deskshare.new
|
||||
expect { archiver.collect_deskshare( meeting_id, from_dir, to_dir ) }.to raise_error(NoSuchDirectoryException)
|
||||
end
|
||||
it "should raise deskshare files not found exception" do
|
||||
from_dir = 'resources/raw/audio'
|
||||
to_dir = '/to-dir-not-found'
|
||||
meeting_id = 'meeting-id'
|
||||
FileTest.stub(:directory?).and_return(true)
|
||||
FileUtils.stub(:cp)
|
||||
Dir.stub(:glob).and_return([])
|
||||
archiver = Collector::Deskshare.new
|
||||
expect { archiver.collect_deskshare( meeting_id, from_dir, to_dir ) }.to raise_error(NoDeskshareException)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,52 @@
|
||||
require 'spec_helper'
|
||||
require 'fileutils'
|
||||
|
||||
module Collector
|
||||
describe Presentation do
|
||||
context "#success" do
|
||||
it "should copy presentations to archive" do
|
||||
FileTest.stub(:directory?).and_return(true)
|
||||
FileUtils.stub(:cp)
|
||||
Dir.stub(:glob).and_return(['file1.wav', 'file2.wav'])
|
||||
from_dir = 'from'
|
||||
to_dir = 'to'
|
||||
meeting_id = 'meeting-id'
|
||||
archiver = Collector::Presentation.new
|
||||
expect { archiver.collect_presentation( meeting_id, from_dir, to_dir ) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context "#fail" do
|
||||
it "should raise from directory not found exception" do
|
||||
FileTest.stub(:directory?).and_return(false)
|
||||
FileUtils.stub(:cp)
|
||||
Dir.stub(:glob).and_return(['file1.wav', 'file2.wav'])
|
||||
from_dir = '/from-dir-not-found'
|
||||
to_dir = 'resources/archive'
|
||||
meeting_id = 'meeting-id'
|
||||
archiver = Collector::Presentation.new
|
||||
expect {archiver.collect_presentation( meeting_id, from_dir, to_dir )}.to raise_error(NoSuchDirectoryException)
|
||||
end
|
||||
it "should raise to directory not found exception" do
|
||||
from_dir = 'resources/raw/audio'
|
||||
to_dir = '/to-dir-not-found'
|
||||
meeting_id = 'meeting-id'
|
||||
FileTest.stub(:directory?).and_return(false)
|
||||
FileUtils.stub(:cp)
|
||||
Dir.stub(:glob).and_return(['file1.wav', 'file2.wav'])
|
||||
archiver = Collector::Presentation.new
|
||||
expect { archiver.collect_presentation( meeting_id, from_dir, to_dir ) }.to raise_error(NoSuchDirectoryException)
|
||||
end
|
||||
it "should raise presentation files not found exception" do
|
||||
from_dir = 'resources/raw/audio'
|
||||
to_dir = '/to-dir-not-found'
|
||||
meeting_id = 'meeting-id'
|
||||
FileTest.stub(:directory?).and_return(true)
|
||||
FileUtils.stub(:cp)
|
||||
Dir.stub(:glob).and_return([])
|
||||
archiver = Collector::Presentation.new
|
||||
expect { archiver.collect_presentation( meeting_id, from_dir, to_dir ) }.to raise_error(NoPresentationException)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1 +1,2 @@
|
||||
require 'recordandplayback'
|
||||
require 'recordandplayback/generators/audio.rb'
|
||||
|
14
record-and-playback/rap/test_events.rb
Executable file
14
record-and-playback/rap/test_events.rb
Executable file
@ -0,0 +1,14 @@
|
||||
require 'lib/recordandplayback/generators/audio'
|
||||
|
||||
|
||||
e = 'resources/raw/1b199e88-7df7-4842-a5f1-0e84b781c5c8/events.xml'
|
||||
g = Generator::AudioEvents.new
|
||||
puts g.get_first_timestamp_of_session(e)
|
||||
puts g.get_last_timestamp_of_session(e)
|
||||
puts "Start Events"
|
||||
sd = g.get_start_audio_recording_events(e)
|
||||
|
||||
puts "Stop Events"
|
||||
sf = g.get_stop_audio_recording_events(e)
|
||||
|
||||
g.match_start_and_stop_events(sd, sf)
|
Loading…
Reference in New Issue
Block a user