vidibus-recording 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ cli
5
+ recordings
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in vidibus-rtmpdump.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,75 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vidibus-recording (0.0.1)
5
+ delayed_job_mongoid
6
+ mongoid (~> 2.0.0.beta.20)
7
+ open4
8
+ robustthread
9
+ vidibus-uuid
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ activemodel (3.0.3)
15
+ activesupport (= 3.0.3)
16
+ builder (~> 2.1.2)
17
+ i18n (~> 0.4)
18
+ activesupport (3.0.3)
19
+ bson (1.2.0)
20
+ builder (2.1.2)
21
+ daemons (1.1.0)
22
+ delayed_job (2.1.3)
23
+ activesupport (~> 3.0)
24
+ daemons
25
+ delayed_job_mongoid (1.0.2)
26
+ delayed_job (~> 2.1.1)
27
+ mongoid (~> 2.0.0.rc)
28
+ diff-lcs (1.1.2)
29
+ i18n (0.5.0)
30
+ macaddr (1.0.0)
31
+ mongo (1.2.0)
32
+ bson (>= 1.2.0)
33
+ mongoid (2.0.0.rc.6)
34
+ activemodel (~> 3.0)
35
+ mongo (~> 1.2)
36
+ tzinfo (~> 0.3.22)
37
+ will_paginate (~> 3.0.pre)
38
+ open4 (1.0.1)
39
+ rake (0.8.7)
40
+ relevance-rcov (0.9.2.1)
41
+ robustthread (0.5.2)
42
+ rr (1.0.2)
43
+ rspec (2.0.1)
44
+ rspec-core (~> 2.0.1)
45
+ rspec-expectations (~> 2.0.1)
46
+ rspec-mocks (~> 2.0.1)
47
+ rspec-core (2.0.1)
48
+ rspec-expectations (2.0.1)
49
+ diff-lcs (>= 1.1.2)
50
+ rspec-mocks (2.0.1)
51
+ rspec-core (~> 2.0.1)
52
+ rspec-expectations (~> 2.0.1)
53
+ tzinfo (0.3.24)
54
+ uuid (2.3.1)
55
+ macaddr (~> 1.0)
56
+ vidibus-uuid (0.3.8)
57
+ mongoid (~> 2.0.0.beta.20)
58
+ uuid (~> 2.3.1)
59
+ will_paginate (3.0.pre2)
60
+
61
+ PLATFORMS
62
+ ruby
63
+
64
+ DEPENDENCIES
65
+ bundler (>= 1.0.0)
66
+ delayed_job_mongoid
67
+ mongoid (~> 2.0.0.beta.20)
68
+ open4
69
+ rake
70
+ relevance-rcov
71
+ robustthread
72
+ rr
73
+ rspec (~> 2.0.0.beta.20)
74
+ vidibus-recording!
75
+ vidibus-uuid
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Andre Pankratz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,10 @@
1
+ = Vidibus::Recording
2
+
3
+ Allows recording of RTMP video streams. Uses RTMPdump.
4
+ Further description goes here.
5
+
6
+
7
+
8
+ == Copyright
9
+
10
+ Copyright (c) 2011 Andre Pankratz. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,4 @@
1
+ class Recording
2
+ include Mongoid::Document
3
+ include Vidibus::Recording::Mongoid
4
+ end
@@ -0,0 +1,66 @@
1
+ module Vidibus::Recording::Backend
2
+ class Rtmpdump
3
+
4
+ PROTOCOLS = %[rtmp rtmpt rtmpe rtmpte rtmps rtmpts]
5
+
6
+ attr_accessor :stream, :file, :live, :metadata
7
+
8
+ def initialize(attributes)
9
+ self.stream = attributes[:stream] or raise ConfigurationError.new("No input stream given")
10
+ self.file = attributes[:file] or raise ConfigurationError.new("No output file defined")
11
+ self.live = attributes[:live]
12
+ end
13
+
14
+ # Command for starting the recording.
15
+ # Required options:
16
+ # :stream, :file
17
+ # Optional:
18
+ # :live
19
+ #
20
+ def command(options = {})
21
+ c = %(rtmpdump -r "#{stream}" -o #{file})
22
+ c << " --live" if live
23
+ c
24
+ end
25
+
26
+ # Extract metadata from stdout or stderr.
27
+ # Output delivered by rtmpdump looks like this:
28
+ #
29
+ # RTMPDump v2.2
30
+ # (c) 2010 Andrej Stepanchuk, Howard Chu, The Flvstreamer Team; license: GPL
31
+ # Connecting ...
32
+ # ERROR: rtmp server sent error
33
+ # Starting Live Stream
34
+ # Metadata:
35
+ # author
36
+ # copyright
37
+ # description
38
+ # keywords
39
+ # rating
40
+ # title
41
+ # presetname Custom
42
+ # creationdate Mon Jan 17 15:22:50 2011
43
+ # videodevice Osprey-210 Video Device 1
44
+ # framerate 25.00
45
+ # width 680.00
46
+ # height 394.00
47
+ # videocodecid avc1
48
+ # videodatarate 650.00
49
+ # avclevel 31.00
50
+ # avcprofile 66.00
51
+ # videokeyframe_frequency5.00
52
+ # audiodevice Osprey-210 Audio Device 1
53
+ # audiosamplerate 22050.00
54
+ # audiochannels 1.00
55
+ # audioinputvolume 75.00
56
+ # audiocodecid .mp3
57
+ # audiodatarate 48.00
58
+ #
59
+ def extract_metadata(std)
60
+ if metadata = std.match(/Metadata\:\n\s+(.+)\Z/m)
61
+ tuples = $1.scan(/([^\n\s\d]+)\s*([^\n]+)\n/m)
62
+ self.metadata = Hash[tuples]
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,25 @@
1
+ module Vidibus::Recording
2
+ module Backend
3
+ class ConfigurationError < StandardError; end
4
+ class ProtocolError < ConfigurationError; end
5
+
6
+ BACKENDS = %[rtmpdump]
7
+
8
+ # Returns an instance of a backend processor
9
+ # that is able to record the given stream.
10
+ def self.load(attributes)
11
+ stream = attributes[:stream] or raise ConfigurationError.new("No input stream given")
12
+ protocol = stream.match(/^[^:]+/).to_s
13
+ raise ProtocolError.new(%(No protocol could be derived stream "#{stream}")) if protocol == ""
14
+
15
+ for backend in BACKENDS
16
+ require "recording/backend/#{backend}"
17
+ backend_class = "Vidibus::Recording::Backend::#{backend.classify}".constantize
18
+ if backend_class::PROTOCOLS.include?(protocol)
19
+ return backend_class.new(attributes)
20
+ end
21
+ end
22
+ raise ProtocolError.new(%(No recording backend available for "#{protocol}" protocol.))
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ module Vidibus::Recording
2
+ module Helpers
3
+
4
+ # Recursively fixes classes of value strings
5
+ def fix_value_classes!(value)
6
+ c = value.class
7
+
8
+ # Get nested items in Hash
9
+ if c == Hash
10
+ value.each do |v|
11
+ value[v[0]] = fix_value_classes!(v[1])
12
+ end
13
+
14
+ # Get nested items in Array
15
+ elsif c == Array
16
+ value.each_with_index do |v,i|
17
+ value[i] = fix_value_classes!(v)
18
+ end
19
+
20
+ # Fix classes of values
21
+ else
22
+ if value.match /^\d+[\.,]\d+$/
23
+ value = value.to_f
24
+ elsif value.match /^\d+$/
25
+ value = value.to_i
26
+ elsif value.match /^true$/
27
+ value = true
28
+ elsif value.match /^false$/
29
+ value = false
30
+ end
31
+ end
32
+ value
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,103 @@
1
+ module Vidibus::Recording
2
+ class Job
3
+ include Open4
4
+
5
+ class ProcessError < StandardError; end
6
+
7
+ attr_accessor :recording, :pid
8
+
9
+ def initialize(recording)
10
+ self.recording = recording
11
+ self.pid = recording.pid
12
+ end
13
+
14
+ def start
15
+ start_logger
16
+ self.pid = fork do
17
+ start_thread
18
+ end
19
+ Process.detach(pid)
20
+ pid
21
+ end
22
+
23
+ def stop
24
+ if pid and running?
25
+ Process.kill("SIGTERM", pid)
26
+ sleep 2
27
+ raise ProcessError.new("Recording job is still running!") if running?
28
+ end
29
+ end
30
+
31
+ def running?
32
+ pid and self.class.running?(pid)
33
+ end
34
+
35
+ def self.running?(pid)
36
+ begin
37
+ Process.kill(0, pid)
38
+ return true
39
+ rescue Errno::ESRCH
40
+ return false
41
+ rescue Errno::EPERM
42
+ raise ProcessError.new("No permission to check #{pid}")
43
+ rescue
44
+ raise ProcessError.new("Unable to determine status for #{pid}: #{$!}")
45
+ end
46
+ end
47
+
48
+ protected
49
+
50
+ def start_thread
51
+ stdin = ""
52
+ stdout = ""
53
+ stderr = ""
54
+ last_stderr = ""
55
+ last_stdout = ""
56
+ task = background(recording.backend.command, 0=>stdin, 1=>stdout, 2=>stderr)
57
+
58
+ waiter = Thread.new {y(task.pid => task.exitstatus)} # t.exitstatus is a blocking call!
59
+ timeout = 5
60
+
61
+ while(status = task.status)
62
+ unless stderr == last_stderr
63
+ metadata = extract_metadata(stderr)
64
+ last_stderr = stderr
65
+ end
66
+
67
+ unless stdout == last_stdout
68
+ metadata = extract_metadata(stdout)
69
+ last_stdout = stdout
70
+ end
71
+
72
+ unless metadata
73
+ timeout -= 1
74
+ if timeout == 0
75
+ recording.fail("No Metadata has been received. This stream does not work.")
76
+ return
77
+ end
78
+ end
79
+
80
+ sleep 2
81
+ end
82
+
83
+ waiter.join
84
+ end
85
+
86
+ def extract_metadata(std)
87
+ metadata = recording.backend.extract_metadata(std)
88
+ if metadata
89
+ File.open(recording.yml_file, "w") do |file|
90
+ file.write(metadata.to_yaml)
91
+ end
92
+ end
93
+ metadata
94
+ end
95
+
96
+ def start_logger
97
+ RobustThread.logger = Logger.new(recording.log_file)
98
+ RobustThread.exception_handler do |exception|
99
+ RobustThread.log exception
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,195 @@
1
+ module Vidibus::Recording
2
+ module Mongoid
3
+ extend ActiveSupport::Concern
4
+
5
+ class ProcessError < StandardError; end
6
+ class StreamError < StandardError; end
7
+
8
+ included do
9
+ include Vidibus::Recording::Helpers
10
+ include Vidibus::Uuid::Mongoid
11
+
12
+ field :name
13
+ field :stream
14
+ field :live, :type => Boolean
15
+ field :pid, :type => Integer
16
+ field :info, :type => Hash
17
+ field :size, :type => Integer
18
+ field :duration, :type => Integer
19
+ field :log
20
+ field :error
21
+ field :scheduled_at, :type => DateTime
22
+ field :started_at, :type => DateTime
23
+ field :stopped_at, :type => DateTime
24
+ field :failed_at, :type => DateTime
25
+
26
+ validates :name, :presence => true
27
+ validates :stream, :format => {:with => /^rtmp.*?:\/\/.+$/}
28
+
29
+ before_destroy :cleanup
30
+ end
31
+
32
+ # Starts a recording job now, unless it has been done already.
33
+ # Provide a Time object to schedule start.
34
+ def start(time = :now)
35
+ return false if done? or started?
36
+ if time == :now
37
+ job.start
38
+ update_attributes(:pid => job.pid, :started_at => Time.now)
39
+ job.pid
40
+ else
41
+ schedule(time)
42
+ end
43
+ end
44
+
45
+ # Resets data and stars anew.
46
+ def restart(time = :now)
47
+ stop
48
+ reset
49
+ start(time)
50
+ end
51
+
52
+ # Stops the recording job and starts postprocessing.
53
+ def stop
54
+ return false if !started_at? or done?
55
+ job.stop
56
+ self.pid = nil
57
+ self.stopped_at = Time.now
58
+ postprocess
59
+ end
60
+
61
+ # Receives an error from recording job and stores it.
62
+ # The job gets stopped and postprocessing is started.
63
+ def fail(msg)
64
+ return if done?
65
+ job.stop
66
+ self.pid = nil
67
+ self.error = msg
68
+ self.failed_at = Time.now
69
+ postprocess
70
+ end
71
+
72
+ # Removes all acquired data
73
+ def reset
74
+ remove_files
75
+ blank = {}
76
+ [:started_at, :stopped_at, :failed_at, :info, :log, :error, :size, :duration].map {|a| blank[a] = nil }
77
+ update_attributes(blank)
78
+ end
79
+
80
+ # Returns an instance of the recording job.
81
+ def job
82
+ @job ||= Vidibus::Recording::Job.new(self)
83
+ end
84
+
85
+ # Returns an instance of a fitting recording backend.
86
+ def backend
87
+ @backend ||= Vidibus::Recording::Backend.load(:stream => stream, :file => file, :live => live)
88
+ end
89
+
90
+ # Returns true if recording has either been stopped or failed.
91
+ def done?
92
+ stopped_at or failed?
93
+ end
94
+
95
+ # Returns true if recording has failed.
96
+ def failed?
97
+ !!failed_at
98
+ end
99
+
100
+ # Returns true if if job has been started.
101
+ def started?
102
+ !!started_at
103
+ end
104
+
105
+ # Returns true if recording job is still running.
106
+ def running?
107
+ started? and job.running?
108
+ end
109
+
110
+ # Return folder to store recordings in.
111
+ def folder
112
+ @folder ||= begin
113
+ f = ["recordings"]
114
+ f.unshift(Rails.root) if defined?(Rails)
115
+ path = File.join(f)
116
+ FileUtils.mkdir_p(path) unless File.exist?(path)
117
+ path
118
+ end
119
+ end
120
+
121
+ # Returns the file name of this recording.
122
+ def file
123
+ @file ||= "#{folder}/#{uuid}.rec"
124
+ end
125
+
126
+ # Returns the log file name for this recording.
127
+ def log_file
128
+ @log_file ||= file.gsub(/\.[^\.]+$/, ".log")
129
+ end
130
+
131
+ # Returns the YAML file name for this recording.
132
+ def yml_file
133
+ @info_file ||= file.gsub(/\.[^\.]+$/, ".yml")
134
+ end
135
+
136
+ protected
137
+
138
+ def schedule(time)
139
+ self.delay(:run_at => time).start
140
+ end
141
+
142
+ def postprocess
143
+ process_log_file
144
+ process_yml_file
145
+ set_size
146
+ set_duration
147
+ save!
148
+ end
149
+
150
+ def process_log_file
151
+ if str = read_file(log_file)
152
+ str.gsub!(/\A[^\n]+\n/, "") # remove first line
153
+ unless str == ""
154
+ self.log = str
155
+ end
156
+ end
157
+ end
158
+
159
+ def process_yml_file
160
+ if str = read_file(yml_file)
161
+ if values = YAML::load(str)
162
+ fix_value_classes!(values)
163
+ self.info = values
164
+ end
165
+ end
166
+ end
167
+
168
+ def set_size
169
+ self.size = File.exists?(file) ? File.size(file) : nil
170
+ end
171
+
172
+ def set_duration
173
+ self.duration = failed? ? 0 : Time.now - started_at
174
+ end
175
+
176
+ def read_file(file)
177
+ if File.exists?(file)
178
+ str = File.read(file)
179
+ File.delete(file)
180
+ str
181
+ end
182
+ end
183
+
184
+ def cleanup
185
+ job.stop
186
+ remove_files
187
+ end
188
+
189
+ def remove_files
190
+ [file, log_file, yml_file].each do |f|
191
+ File.delete(f) if File.exists?(f)
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,5 @@
1
+ module Vidibus
2
+ module Recording
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ require "recording/job"
2
+ require "recording/backend"
3
+ require "recording/helpers"
4
+ require "recording/mongoid"
@@ -0,0 +1,17 @@
1
+ require "open4"
2
+ require "yaml"
3
+ require "robustthread"
4
+ require "delayed_job_mongoid"
5
+ require "active_support/core_ext"
6
+ require "vidibus-uuid"
7
+
8
+ module Vidibus
9
+ module Recording
10
+ if defined?(Rails)
11
+ class Engine < ::Rails::Engine; end
12
+ end
13
+ end
14
+ end
15
+
16
+ $:.unshift(File.join(File.dirname(__FILE__), "vidibus"))
17
+ require "recording"
@@ -0,0 +1,38 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
3
+
4
+ require "rubygems"
5
+ require "rspec"
6
+ require "rr"
7
+ require "mongoid"
8
+
9
+ require "vidibus-recording"
10
+ require "app/models/recording"
11
+
12
+ Mongoid.configure do |config|
13
+ name = "vidibus-recording_test"
14
+ host = "localhost"
15
+ config.master = Mongo::Connection.new.db(name)
16
+ config.logger = nil
17
+ end
18
+
19
+ RSpec.configure do |config|
20
+ config.mock_with :rr
21
+ config.before(:each) do
22
+ Mongoid.master.collections.select {|c| c.name !~ /system/}.each(&:drop)
23
+ end
24
+ end
25
+
26
+ # Helper for stubbing time. Define String to be set as Time.now.
27
+ # Usage:
28
+ # stub_time('01.01.2010 14:00')
29
+ # stub_time(2.days.ago)
30
+ #
31
+ def stub_time(string = nil)
32
+ string ||= Time.now.to_s(:db)
33
+ now = Time.parse(string.to_s)
34
+ stub(Time).now { now }
35
+ now
36
+ end
37
+
38
+ #I18n.load_path += Dir[File.join('config', 'locales', '**', '*.{rb,yml}')]
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe "Vidibus::Recording::Backend" do
4
+
5
+ describe ".load" do
6
+ it "should return an error unless a stream attribute is given" do
7
+ expect {
8
+ Vidibus::Recording::Backend.load({})
9
+ }.to raise_error(Vidibus::Recording::Backend::ConfigurationError)
10
+ end
11
+
12
+ it "should return a backend instance for given stream protocol" do
13
+ Vidibus::Recording::Backend.load(:stream => "rtmp://something", :file => "test").
14
+ should be_an_instance_of(Vidibus::Recording::Backend::Rtmpdump)
15
+ end
16
+
17
+ it "should return an error unless a stream attribute with consumable protocol is given" do
18
+ expect {
19
+ Vidibus::Recording::Backend.load({:stream => "mms://something", :file => "test"})
20
+ }.to raise_error(Vidibus::Recording::Backend::ProtocolError)
21
+ end
22
+
23
+ it "should return an error unless a stream attribute with a protocol is given" do
24
+ expect {
25
+ Vidibus::Recording::Backend.load({:stream => "something", :file => "test"})
26
+ }.to raise_error(Vidibus::Recording::Backend::ProtocolError)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,111 @@
1
+ require "spec_helper"
2
+
3
+ describe "Vidibus::Recording::Mongoid" do
4
+
5
+ let(:this) do
6
+ Recording.new(:name => "N-TV Live", :stream => "rtmp://fms.rtl.de/ntvlive/livestream/channel1", :live => true)
7
+ end
8
+
9
+ def cleanup(recording)
10
+ Process.kill("SIGTERM", recording.pid) if recording.pid
11
+ delete_safely(recording.file)
12
+ delete_safely(recording.log_file)
13
+ delete_safely(recording.yml_file)
14
+ end
15
+
16
+ def delete_safely(file)
17
+ return unless file.match(/.{32}\..{3}/)
18
+ File.delete(file) if File.exists?(file)
19
+ end
20
+
21
+ describe "validation" do
22
+ it "should pass with valid attributes" do
23
+ this.should be_valid
24
+ end
25
+
26
+ it "should fail without a stream" do
27
+ this.stream = nil
28
+ this.should be_invalid
29
+ end
30
+
31
+ it "should fail without a valid stream address" do
32
+ this.stream = "something"
33
+ this.should be_invalid
34
+ end
35
+
36
+ it "should fail without a valid rtmp stream address" do
37
+ this.stream = "rtmp://something"
38
+ this.should be_valid
39
+ end
40
+
41
+ it "should fail without a name" do
42
+ this.name = nil
43
+ this.should be_invalid
44
+ end
45
+ end
46
+
47
+ describe "job" do
48
+ it "should return a job instance" do
49
+ this.job.should be_an_instance_of(Vidibus::Recording::Job)
50
+ end
51
+ end
52
+
53
+ describe "backend" do
54
+ it "should return a backend instance for given stream protocol" do
55
+ this.backend.should be_an_instance_of(Vidibus::Recording::Backend::Rtmpdump)
56
+ end
57
+ end
58
+
59
+ describe "start" do
60
+ before {this.save}
61
+
62
+ it "should return a process id" do
63
+ this.start.should be_a(Fixnum)
64
+ end
65
+
66
+ context "without params" do
67
+ it "should start a recording job now" do
68
+ pid = this.start
69
+ Vidibus::Recording::Job.running?(pid).should be_true
70
+ end
71
+ end
72
+
73
+ context "with a given Time" do
74
+ it "should schedule a recording job" do
75
+ stub_time("2011-01-12 00:00")
76
+ run_at = 10.minutes.since
77
+ this.start(run_at)
78
+ Delayed::Backend::Mongoid::Job.count.should eql(1)
79
+ Delayed::Backend::Mongoid::Job.first.run_at.should eql(run_at)
80
+ end
81
+ end
82
+
83
+ after {cleanup(this)}
84
+ end
85
+
86
+ describe "stop" do
87
+ before {this.save}
88
+
89
+ it "should return false unless recording has been started" do
90
+ this.stop.should be_false
91
+ end
92
+
93
+ it "should return false if recording is done" do
94
+ this.stopped_at = Time.now
95
+ this.stop.should be_false
96
+ end
97
+
98
+ context "with started job" do
99
+ before {this.start}
100
+
101
+ it "should stop the recording job" do
102
+ pid = this.pid
103
+ this.stop
104
+ sleep 1
105
+ Vidibus::Recording::Job.running?(pid).should be_false
106
+ end
107
+
108
+ after {cleanup(this)}
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/vidibus/recording/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "vidibus-recording"
6
+ s.rubyforge_project = "vidibus-recording"
7
+ s.version = Vidibus::Recording::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = "Andre Pankratz"
10
+ s.email = "andre@vidibus.com"
11
+ s.homepage = "http://rubygems.org/gems/vidibus-rtmpdump"
12
+ s.summary = "Video stream recording tools"
13
+ s.description = "Allows recording of RTMP video streams. Uses RTMPdump."
14
+
15
+ s.required_rubygems_version = ">= 1.3.6"
16
+
17
+ s.add_dependency "mongoid", "~> 2.0.0.beta.20"
18
+ s.add_dependency "open4"
19
+ s.add_dependency "robustthread"
20
+ s.add_dependency "delayed_job_mongoid"
21
+
22
+ s.add_dependency "vidibus-uuid"
23
+
24
+ s.add_development_dependency "bundler", ">= 1.0.0"
25
+ s.add_development_dependency "rake"
26
+ s.add_development_dependency "rspec", "~> 2.0.0.beta.20"
27
+ s.add_development_dependency "rr"
28
+ s.add_development_dependency "relevance-rcov"
29
+
30
+ s.files = `git ls-files`.split("\n")
31
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
32
+ s.require_path = 'lib'
33
+ end
metadata ADDED
@@ -0,0 +1,236 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vidibus-recording
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Andre Pankratz
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-23 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: mongoid
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 62196427
30
+ segments:
31
+ - 2
32
+ - 0
33
+ - 0
34
+ - beta
35
+ - 20
36
+ version: 2.0.0.beta.20
37
+ type: :runtime
38
+ version_requirements: *id001
39
+ - !ruby/object:Gem::Dependency
40
+ name: open4
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
50
+ version: "0"
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: robustthread
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ type: :runtime
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: delayed_job_mongoid
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :runtime
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ name: vidibus-uuid
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ type: :runtime
94
+ version_requirements: *id005
95
+ - !ruby/object:Gem::Dependency
96
+ name: bundler
97
+ prerelease: false
98
+ requirement: &id006 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 23
104
+ segments:
105
+ - 1
106
+ - 0
107
+ - 0
108
+ version: 1.0.0
109
+ type: :development
110
+ version_requirements: *id006
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ prerelease: false
114
+ requirement: &id007 !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ type: :development
124
+ version_requirements: *id007
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ prerelease: false
128
+ requirement: &id008 !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ hash: 62196427
134
+ segments:
135
+ - 2
136
+ - 0
137
+ - 0
138
+ - beta
139
+ - 20
140
+ version: 2.0.0.beta.20
141
+ type: :development
142
+ version_requirements: *id008
143
+ - !ruby/object:Gem::Dependency
144
+ name: rr
145
+ prerelease: false
146
+ requirement: &id009 !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ hash: 3
152
+ segments:
153
+ - 0
154
+ version: "0"
155
+ type: :development
156
+ version_requirements: *id009
157
+ - !ruby/object:Gem::Dependency
158
+ name: relevance-rcov
159
+ prerelease: false
160
+ requirement: &id010 !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ hash: 3
166
+ segments:
167
+ - 0
168
+ version: "0"
169
+ type: :development
170
+ version_requirements: *id010
171
+ description: Allows recording of RTMP video streams. Uses RTMPdump.
172
+ email: andre@vidibus.com
173
+ executables: []
174
+
175
+ extensions: []
176
+
177
+ extra_rdoc_files: []
178
+
179
+ files:
180
+ - .gitignore
181
+ - Gemfile
182
+ - Gemfile.lock
183
+ - LICENSE
184
+ - README.rdoc
185
+ - Rakefile
186
+ - app/models/recording.rb
187
+ - lib/vidibus-recording.rb
188
+ - lib/vidibus/recording.rb
189
+ - lib/vidibus/recording/backend.rb
190
+ - lib/vidibus/recording/backend/rtmpdump.rb
191
+ - lib/vidibus/recording/helpers.rb
192
+ - lib/vidibus/recording/job.rb
193
+ - lib/vidibus/recording/mongoid.rb
194
+ - lib/vidibus/recording/version.rb
195
+ - spec/spec_helper.rb
196
+ - spec/vidibus/recording/backend_spec.rb
197
+ - spec/vidibus/recording/mongoid_spec.rb
198
+ - vidibus-recording.gemspec
199
+ has_rdoc: true
200
+ homepage: http://rubygems.org/gems/vidibus-rtmpdump
201
+ licenses: []
202
+
203
+ post_install_message:
204
+ rdoc_options: []
205
+
206
+ require_paths:
207
+ - lib
208
+ required_ruby_version: !ruby/object:Gem::Requirement
209
+ none: false
210
+ requirements:
211
+ - - ">="
212
+ - !ruby/object:Gem::Version
213
+ hash: 3
214
+ segments:
215
+ - 0
216
+ version: "0"
217
+ required_rubygems_version: !ruby/object:Gem::Requirement
218
+ none: false
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ hash: 23
223
+ segments:
224
+ - 1
225
+ - 3
226
+ - 6
227
+ version: 1.3.6
228
+ requirements: []
229
+
230
+ rubyforge_project: vidibus-recording
231
+ rubygems_version: 1.3.7
232
+ signing_key:
233
+ specification_version: 3
234
+ summary: Video stream recording tools
235
+ test_files: []
236
+