Skip to content

Commit

Permalink
Changed up initialize to be more savon like
Browse files Browse the repository at this point in the history
  • Loading branch information
turboladen committed Apr 8, 2011
1 parent d1f8a11 commit 91c4818
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 66 deletions.
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ source :rubygems

gemspec
gem 'sdp', '~> 0.2.2'
gem 'eventmachine', '~> 0.12.10'

gem 'simplecov', '>= 0.4.0', :require => false, :group => :test

Expand Down
5 changes: 3 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ PATH
remote: .
specs:
rtsp (0.1.0)
eventmachine (~> 0.12.10)
eventmachine (~> 0.12.10)
rtsp
sdp (~> 0.2.0)
sdp (~> 0.2.2)

Expand Down Expand Up @@ -34,7 +37,6 @@ GEM
erubis (2.6.6)
abstract (>= 1.0.0)
eventmachine (0.12.10)
eventmachine (0.12.10-java)
fattr (2.2.0)
flay (1.4.2)
ruby_parser (~> 2.0)
Expand Down Expand Up @@ -131,7 +133,6 @@ DEPENDENCIES
bundler (~> 1.0.0)
code_statistics (~> 0.2.13)
cucumber
eventmachine (~> 0.12.10)
infinity_test
jeweler (~> 1.5.0)
metric_fu
Expand Down
6 changes: 3 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ rescue Bundler::BundlerError => e
exit e.status_code
end

#require 'ore/specification'
require 'ore/specification'
require 'jeweler'
Jeweler::Tasks.new(Ore::Specification.new)

#require 'ore/tasks'
#Ore::Tasks.new
require 'ore/tasks'
Ore::Tasks.new

require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |t|
Expand Down
1 change: 0 additions & 1 deletion gemspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ has_yard: true

dependencies:
sdp: ~> 0.2.0
eventmachine: ~>0.12.10

development_dependencies:
bundler: ~> 1.0.0
Expand Down
44 changes: 33 additions & 11 deletions lib/rtsp/capturer.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,46 @@
require_relative 'exception'
require 'tempfile'
require 'eventmachine'
require 'socket'

module RTSP
class Capturer < EventMachine::Connection

class Capturer
DEFAULT_CAPFILE_NAME = "rtsp_capture.rtsp"

attr_reader :capture_file
attr_accessor :media_file
attr_accessor :port
attr_accessor :protocol
attr_accessor :broadcast_type

# @param [Symbol] protocol :udp or :tcp
def initialize(protocol=:udp, rtp_port=9000, capture_file=nil)
if protocol == :udp
init_udp_server(rtp_port)
elsif protocol == :tcp
init_tcp_server(rtp_port)
else
raise RTSP::Exception
end

def initialize(capture_file=nil)
@capture_file = capture_file || Tempfile.new(DEFAULT_CAPFILE_NAME)
end

def post_init
puts "client connected"
def run
loop do
data = @server.recvfrom(MAX_BYTES_TO_RECEIVE).first
puts data.size
@capture_file.write data
end
end

def init_udp_server(rtp_port)
@server = UDPSocket.open
#opt = [1].pack("i")
#@server.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, opt)
@server.bind('0.0.0.0', rtp_port)
end

def receive_data data
p data.size
@capture_file.write data
def init_tcp_server(rtp_port)
@server = TCPSocket.new('0.0.0.0', rtp_port)
end
end
end
end
98 changes: 52 additions & 46 deletions lib/rtsp/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'tempfile'
require 'timeout'

require_relative 'transport_parser'
require File.expand_path(File.dirname(__FILE__) + '/capturer')
require File.expand_path(File.dirname(__FILE__) + '/exception')
require File.expand_path(File.dirname(__FILE__) + '/global')
Expand All @@ -24,6 +25,8 @@ class Client
attr_reader :session
attr_reader :supported_methods
attr_accessor :tracks
attr_accessor :connection
attr_accessor :capturer

# TODO: Break Stream out in to its own class.
# See RFC section A.1.
Expand All @@ -36,6 +39,7 @@ def self.configure

# @param [String] rtsp_url URL to the resource to stream. If no scheme is
# given, "rtsp" is assumed. If no port is given, 554 is assumed.
=begin
def initialize(rtsp_url, args={})
@server_uri = build_resource_uri_from rtsp_url
@cseq = 1
Expand All @@ -47,10 +51,36 @@ def initialize(rtsp_url, args={})
@capture_data = args[:capture_data] || true
@capture_file = args[:capture_file] || Tempfile.new(DEFAULT_CAPFILE_NAME)
@transport = {}
@transport[:client_port] = args[:client_port] || 9000
@transport[:specifier] = args[:transport_specifier] || "RTP/AVP"
@transport[:routing] = args[:routing] || "unicast"
@transport_request = {}
@transport_request[:client_port_request] = args[:client_port_request] || 9000
@transport_request[:protocol] = args[:protocol] || "RTP"
@transport_request[:profile] = args[:profile] || "AVP"
@transport_request[:broadcast_type_request] = args[:broadcast_type_request] || "unicast"
end
=end
# TODO: Use server_url everywhere; just use URI to ensure the port & rtspu.
def initialize(server_url=nil)
Struct.new("Connection", :server_url, :timeout, :socket,
:do_capture, :interleave)
@connection = Struct::Connection.new
@capturer = RTSP::Capturer.new

yield(connection, capturer) if block_given?

@connection.server_url = server_url || @connection.server_url
@server_uri = build_resource_uri_from(@connection.server_url)
@connection.timeout ||= 30
@connection.socket ||= TCPSocket.new(@server_uri.host, @server_uri.port)
@connection.do_capture ||= true
@connection.interleave ||= false
@capturer.port ||= 9000
@capturer.protocol ||= :udp
@capturer.broadcast_type ||= :unicast
@capturer.media_file ||= Tempfile.new(DEFAULT_CAPFILE_NAME)

@play_thread = nil
@cseq = 1
reset_state
end

# The URL for the RTSP server to talk to can change if multiple servers are
Expand All @@ -71,13 +101,13 @@ def send_message message
message.to_s.each_line { |line| RTSP::Client.log line.strip }

begin
response = Timeout::timeout(@timeout) do
@socket.send(message.to_s, 0)
socket_data = @socket.recvfrom MAX_BYTES_TO_RECEIVE
response = Timeout::timeout(@connection.timeout) do
@connection.socket.send(message.to_s, 0)
socket_data = @connection.socket.recvfrom MAX_BYTES_TO_RECEIVE
RTSP::Response.new socket_data.first
end
rescue Timeout::Error
raise RTSP::Exception, "Request took more than #{@timeout} seconds to send."
raise RTSP::Exception, "Request took more than #{@connection.timeout} seconds to send."
end

RTSP::Client.log "Received response:"
Expand Down Expand Up @@ -142,7 +172,11 @@ def announce(request_url, description, additional_headers={})
request(message)
end

# TODO: parse Transport header (http://tools.ietf.org/html/rfc2326#section-12.39)
def request_transport
value = "RTP/AVP;#{@capturer.broadcast_type};client_port="
value << "#{@capturer.port}-#{@capturer.port + 1}"
end

# TODO: @session numbers are relevant to tracks, and a client can play multiple tracks at the same time.
# Sends the SETUP request, then sets @session to the value returned in the
# Session header from the server, then sets the @session_state to :ready.
Expand All @@ -151,12 +185,8 @@ def announce(request_url, description, additional_headers={})
# @param [Hash] additional_headers
# @return [RTSP::Response] The response formatted as a Hash.
def setup(track, additional_headers={})
transport_value = "#{@transport[:specifier]};#{@transport[:routing]};"
transport_value << "client_port=#{@transport[:client_port]}-"
transport_value << "#{@transport[:client_port] + 1}"

message = RTSP::Message.setup(track).with_headers({
cseq: @cseq, transport: transport_value })
cseq: @cseq, transport: request_transport})
message.add_headers additional_headers

request(message) do |response|
Expand All @@ -165,29 +195,9 @@ def setup(track, additional_headers={})
end

@session = response.session
#@transport = parse_transport_from response.transport
end
end

def parse_transport_from field_string
=begin
fields = field_string.split ";"
transport = {}
specifier = fields.shift
transport[:protocol] = specifier.split("/")[0]
transport[:profile] = specifier.split("/")[1]
transport[:lower_transport] = specifier.split("/")[2].downcase.to_sym || :udp
transport[:network_type] = fields.shift.to_sym || :multicast
extras = fields.inject({}) do |result, field_and_value_string|
field_and_value_array = field_and_value_string.split "="
result[field_and_value_array.first.to_sym] = field_and_value_array.last
result
parser = RTSP::TransportParser.new
@transport = parser.parse response.transport
end
transport.merge! extras
=end
pattern = /(?<transport_protocol>\w+)\/(?<profile>\w+)(\/(?<lower_transport>\w+))?;(?<net_cast>\w+);(?<everything_else>.*)/
transport_match = pattern.match(field_string)
end

# Sends the PLAY request and sets @session_state to :playing.
Expand All @@ -206,16 +216,12 @@ def play(track, additional_headers={})
end
end

# TODO: If playback over UDP doesn't result in any data coming in on the socket,
# re-setup with RTP/AVP/TCP;unicast;interleaved=0-1
def start_capture
rtp_port = 9000

EventMachine.run {
#EventMachine.connect('0.0.0.0', 9000, RTSP::Capturer)
EventMachine.open_datagram_socket('0.0.0.0', rtp_port, RTSP::Capturer, @capture_file)
EventMachine.add_periodic_timer(1) do
RTSP::Client.log "Waiting for UDP data on port #{rtp_port}..."
end
}
log "Capturing on port #{@transport[:client_port]}"
@capturer = RTSP::Capturer.new(:udp, @transport[:client_port], @capture_file)
@capturer.run
end

# Sends the PAUSE request and sets @session_state to :ready.
Expand Down Expand Up @@ -412,4 +418,4 @@ def extract_supported_methods_from method_list
method_list.downcase.split(', ').map { |m| m.to_sym }
end
end
end
end
5 changes: 5 additions & 0 deletions lib/rtsp/transport_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

module RTSP
class TransportParser < Parslet::Parser

def initialize
super
end

rule(:transport_specifier) do
match('[A-Z]').repeat(3).as(:protocol) >> forward_slash >>
match('[A-Z]').repeat(3).as(:profile) >>
Expand Down
1 change: 0 additions & 1 deletion rtsp.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6") if s.respond_to? :required_rubygems_version=
s.authors = ["Steve Loveless, Mike Kirby"]
s.date = %q{2011-03-22}
s.default_executable = %q{rtsp}
s.description = %q{This library intends to follow the RTSP RFC document (2326) to allow for working with RTSP servers. At this point, it's up to you to parse the data from a play call, but we'll get there. ...eventually.
For more information
RTSP: http://www.ietf.org/rfc/rfc2326.txt}
Expand Down
15 changes: 14 additions & 1 deletion soma_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@

#RTSP::Client.log = false

cap_file = File.new("soma_cap.rtsp", "wb")
url = "rtsp://64.202.98.91/sa.sdp"
client = RTSP::Client.new url
client = RTSP::Client.new(url)
client.capturer.media_file = cap_file
# client = RTSP::Client.new(url) do |client, capturer|
# description = SDP.parse(open("http://test/description.sdp"))
# client.timeout = 30
# client.socket = TCPSocket.new
# client.interleave = true
# capturer.file = Tempfile.new "test"
# capturer.capture_port = 8555
# capturer.protocol = :tcp
# end

client.options
client.describe
Expand All @@ -16,8 +27,10 @@

client.setup media_track
#client.setup media_track, :transport => "RTP/AVP;unicast;client_port=9000-9001"
#client.setup media_track, :transport => "RTP/AVP/TCP;unicast;interleaved=0-1"
#client[media_track].setup
#client.media_control_tracks.play
client.play aggregate_track
sleep 5
#client[aggregate_track].play
client.teardown aggregate_track

0 comments on commit 91c4818

Please sign in to comment.