Skip to content

Commit

Permalink
In the middle of refactoring message code out in to Message
Browse files Browse the repository at this point in the history
  • Loading branch information
turboladen committed Mar 19, 2011
1 parent 30e178c commit 0e6d081
Show file tree
Hide file tree
Showing 9 changed files with 615 additions and 648 deletions.
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ GEM
abstract (1.0.0)
activesupport (3.0.5)
arrayfields (4.7.4)
blankslate (2.1.2.3)
blankslate (2.1.2.4)
builder (3.0.0)
chronic (0.3.0)
churn (0.0.13)
Expand Down Expand Up @@ -80,7 +80,7 @@ GEM
ore-core (~> 0.1.0)
parslet (1.1.1)
blankslate (~> 2.0)
rails_best_practices (0.7.1)
rails_best_practices (0.7.2)
activesupport
colored (~> 1.2)
erubis (~> 2.6.6)
Expand Down Expand Up @@ -120,7 +120,7 @@ GEM
syntax (1.0.0)
term-ansicolor (1.0.5)
watchr (0.7)
yard (0.6.4)
yard (0.6.5)

PLATFORMS
java
Expand Down
33 changes: 32 additions & 1 deletion lib/rtsp/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'tempfile'

require File.expand_path(File.dirname(__FILE__) + '/request')
require File.expand_path(File.dirname(__FILE__) + '/message')
require File.expand_path(File.dirname(__FILE__) + '/helpers')
require File.expand_path(File.dirname(__FILE__) + '/exception')
require File.expand_path(File.dirname(__FILE__) + '/global')
Expand Down Expand Up @@ -56,6 +57,7 @@ def server_url=(new_url)
#
# @param [Hash] additional_headers
# @return [RTSP::Response]
=begin
def options additional_headers={}
headers = ( { :cseq => @cseq }).merge(additional_headers)
args = { :method => :options, :resource_url => @server_uri,
Expand All @@ -65,7 +67,15 @@ def options additional_headers={}
@supported_methods = extract_supported_methods_from response.public
end
end
=end

def options(additional_headers={})
message = RTSP::Message.new(:options, @server_uri) do
header :cseq, @cseq
additional_headers.each_pair { |h| header h.key, h.value }
end
execute_request(message.to_s)
end
# TODO: get tracks, IP's, ports, multicast/unicast
# Sends the DESCRIBE request, then extracts the SDP description into
# @session_description, extracts the session @start_time and @stop_time,
Expand Down Expand Up @@ -238,6 +248,16 @@ def set_parameter(track, parameters, additional_headers={})
execute_request(args)
end

def set_parameter_two(track, parameters, additional_headers={})
message = RTSP::Message.new(:set_parameter, track) do
header :cseq, @cseq
header :content_length, parameters.size
additional_headers.each_pair { |h| header h.key, h.value }
body parameters
end
execute_request(message)
end

# Sends the RECORD request and sets @session_state to :recording.
#
# @param [String] track
Expand All @@ -253,6 +273,16 @@ def record(track, additional_headers={})
execute_request(args) { @session_state = :recording }
end

def record_two(track, additional_headers={})
message = RTSP::Message.new(:record, track) do
header :cseq, @cseq
header :session, @session
additional_headers.each_pair { |h| header h.key, h.value }
end
execute_request(message) { @session_state = :recording }
end

# TODO: #ensure_session_and should occur just after receiving the response, not before sending a request.
# Executes the Request with the arguments passed in, yields the response to
# the calling block, checks the cseq response and the session response,
# then increments @cseq by 1. Handles any exceptions raised during the
Expand All @@ -267,7 +297,8 @@ def execute_request new_args
@session_state = :init
end

response = RTSP::Request.execute(@args.merge(new_args))
#response = RTSP::Request.execute(@args.merge(new_args))
response = RTSP::Request.execute(new_args)

compare_sequence_number response.cseq

Expand Down
175 changes: 175 additions & 0 deletions lib/rtsp/message.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
require File.expand_path(File.dirname(__FILE__) + '/helpers')
require File.expand_path(File.dirname(__FILE__) + '/exception')

module RTSP
class Message
include RTSP::Helpers

RTSP_ACCEPT_TYPE = "application/sdp"
RTSP_DEFAULT_NPT = "0.000-"
RTSP_DEFAULT_SEQUENCE_NUMBER = 1
RTP_DEFAULT_CLIENT_PORT = 9000
RTP_DEFAULT_PACKET_TYPE = "RTP/AVP"
RTP_DEFAULT_ROUTING = "unicast"
USER_AGENT = "RubyRTSP/#{RTSP::VERSION} (Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"

attr_reader :headers
attr_reader :body
attr_writer :rtsp_version

# @param [Symbol] :method_type The RTSP method to build and send.
# @param [String] request_uri The URL to communicate to.
def initialize(method_type, request_uri, &block)
@method = method_type
@request_uri = build_resource_uri_from request_uri
@headers = default_headers
@body = ""
@version = DEFAULT_VERSION

self.instance_eval &block if block_given?

to_s
end

# Adds the header and its value to the list of headers for the message.
#
# @param [Symbol] type The header type.
# @param [] value The value to set the header field to.
def header(type, value)
if type.is_a? Symbol
headers[type] = value
else
raise RTSP::Exception, "Header type must be a Symbol (i.e. :cseq)."
end
end

# @param [String] value Content to send as the body of the message.
# Generally this will be a String of some sort, but could be binary data as
# well.
def body value
headers[:content_length] = value.length
@body = value
end

def to_s
message.to_s
end

###########################################################################
# PRIVATES
private

def message
message = "#{@method.to_s.upcase} #{@request_uri} RTSP/#{@version}\r\n"
message << headers_to_s(@headers)
message << "\r\n"
message << "#{@body}" unless @body.nil?

#message.each_line { |line| RTSP::Client.log line.strip }

message
end

# Returns the required/default headers for the provided method.
#
# @return [Hash] The default headers for the given method.
def default_headers
headers = {}

headers[:cseq] ||= RTSP_DEFAULT_SEQUENCE_NUMBER
headers[:user_agent] ||= USER_AGENT

case @method
when :describe
headers[:accept] = RTSP_ACCEPT_TYPE
when :announce
headers[:content_type] = RTSP_ACCEPT_TYPE
when :setup
transport = "#{RTP_DEFAULT_PACKET_TYPE};"
transport << "#{RTP_DEFAULT_ROUTING};"
transport << "client_port=#{RTP_DEFAULT_CLIENT_PORT}-#{RTP_DEFAULT_CLIENT_PORT + 1}"

headers[:transport] = transport
when :play
headers[:range] = "npt=#{RTSP_DEFAULT_NPT}"
else
{}
end

headers
end

# Turns headers from Hash(es) into a String, where each element
# is a String in the form: [Header Type]: value(s)\r\n.
#
# @param [Hash] headers The headers to put to string.
# @return [String]
def headers_to_s headers
header_string = headers.inject("") do |result, (key, value)|
header_name = key.to_s.split(/_/).map { |header| header.capitalize }.join('-')

header_name = "CSeq" if header_name == "Cseq"

if value.is_a?(Hash) || value.is_a?(Array)
if header_name == "Content-Type"
values = values_to_s(value, ", ")
else
values = values_to_s(value)
end

result << "#{header_name}: #{values}\r\n"
else
result << "#{header_name}: #{value}\r\n"
end

result
end

arr = header_string.split "\r\n"
# Move the Session header to the top
session_index = arr.index { |a| a =~ /Session/ }
unless session_index.nil?
session = arr.delete_at(session_index)
arr.unshift(session)
end

# Move the User-Agent header to the top
user_agent_index = arr.index { |a| a =~ /User-Agent/ }
unless user_agent_index.nil?
user_agent = arr.delete_at(user_agent_index)
arr.unshift(user_agent)
end

# Move the CSeq header to the top
cseq_index = arr.index { |a| a =~ /CSeq/ }
cseq = arr.delete_at(cseq_index)
arr.unshift(cseq)

# Put it all back to a String
header_string = arr.join("\r\n")
header_string << "\r\n"
end

# Turns header values into a single string.
#
# @param [] values The header values to put to string.
# @param [String] separator The character to use to separate multiple values
# that define a header.
# @return [String] The header values as a single string.
def values_to_s(values, separator=";")
result = values.inject("") do |values_string, (header_field, header_field_value)|
if header_field.is_a? Symbol
values_string << "#{header_field}=#{header_field_value}"
elsif header_field.is_a? Hash
values_string << values_to_s(header_field)
else
values_string << header_field.to_s
end

values_string + separator
end

result.sub!(/#{separator}$/, '') if result.end_with? separator
end
end
end
Loading

0 comments on commit 0e6d081

Please sign in to comment.