lib/rtsp/client.rb in rtsp-0.4.1 vs lib/rtsp/client.rb in rtsp-0.4.2

- old
+ new

@@ -77,11 +77,11 @@ # @return [Struct::Connection] attr_accessor :connection # Use to get/set an object for capturing received data. - # @param [RTP::Receiver] + # # @return [RTP::Receiver] attr_accessor :capturer # @return [Symbol] See {RFC section A.1.}[http://tools.ietf.org/html/rfc2326#page-76] attr_reader :session_state @@ -110,25 +110,20 @@ end @connection = Struct::Connection.new @capturer = RTP::Receiver.new - yield(connection, capturer) if block_given? + 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.rtp_port ||= 9000 - @capturer.transport_protocol ||= :UDP - @capturer.broadcast_type ||= :unicast - @capturer.rtp_file ||= Tempfile.new(RTP::Receiver::DEFAULT_CAPFILE_NAME) + @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 - @play_thread = nil - @cseq = 1 + @cseq = 1 reset_state end # The URL for the RTSP server to talk to can change if multiple servers are # involved in delivering content. This method can be used to change the @@ -151,22 +146,20 @@ begin response = Timeout::timeout(@connection.timeout) do @connection.socket.send(message.to_s, 0) socket_data = @connection.socket.recvfrom MAX_BYTES_TO_RECEIVE + + RTSP::Client.log "Received response:" + socket_data.first.each_line { |line| RTSP::Client.log line.strip } + RTSP::Response.new socket_data.first end rescue Timeout::Error raise RTSP::Error, "Request took more than #{@connection.timeout} seconds to send." end - RTSP::Client.log "Received response:" - - if response - response.to_s.each_line { |line| RTSP::Client.log line.strip } - end - response end # Sends an OPTIONS message to the server specified by +@server_uri+. Sets # +@supported_methods+ based on the list of supported methods returned in @@ -233,12 +226,12 @@ # the Client instance. # # @return [String] The String to use with the Transport header. # @see http://tools.ietf.org/html/rfc2326#page-58 RFC 2326, Section 12.39. def request_transport - value = "RTP/AVP;#{@capturer.broadcast_type};client_port=" - value << "#{@capturer.rtp_port}-#{@capturer.rtp_port + 1}\r\n" + value = "RTP/AVP;#{@capturer.ip_addressing_type};client_port=" + value << "#{@capturer.rtp_port}-#{@capturer.rtcp_port}\r\n" end # 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+. # @@ -258,18 +251,18 @@ @session_state = :ready end @session = response.session parser = RTSP::TransportParser.new - @transport = parser.parse response.transport + @transport = parser.parse(response.transport) unless @transport[:transport_protocol].nil? @capturer.transport_protocol = @transport[:transport_protocol] end - @capturer.rtp_port = @transport[:client_port][:rtp].to_i - @capturer.broadcast_type = @transport[:broadcast_type] + @capturer.rtp_port = @transport[:client_port][:rtp].to_i + @capturer.ip_address = @transport[:destination].to_s end end # Sends the PLAY request and sets +@session_state+ to +:playing+. # @@ -279,30 +272,22 @@ # @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. # @raise [RTSP::Error] If +#play+ is called but the session hasn't yet been # set up via +#setup+. # @see http://tools.ietf.org/html/rfc2326#page-34 RFC 2326, Section 10.5. - def play(track, additional_headers={}) + def play(track, additional_headers={}, &block) message = RTSP::Message.play(track).with_headers({ cseq: @cseq, session: @session[:session_id] }) message.add_headers additional_headers request(message) do unless @session_state == :ready raise RTSP::Error, "Session not set up yet. Run #setup first." end - if @play_thread.nil? - RTSP::Client.log "Capturing RTP data on port #{@transport[:client_port][:rtp]}" - - unless @capturer.running? - @play_thread = Thread.new do - @capturer.run - end - end - end - + RTSP::Client.log "Capturing RTP data on port #{@transport[:client_port][:rtp]}" + @capturer.start(&block) @session_state = :playing end end # Sends the PAUSE request and sets +@session_state+ to +:ready+. @@ -311,11 +296,11 @@ # @param [Hash] additional_headers # @return [RTSP::Response] # @see http://tools.ietf.org/html/rfc2326#page-36 RFC 2326, Section 10.6. def pause(track, additional_headers={}) message = RTSP::Message.pause(track).with_headers({ - cseq: @cseq, session: @session[:session_id] }) + cseq: @cseq, session: @session[:session_id] }) message.add_headers additional_headers request(message) do if [:playing, :recording].include? @session_state @session_state = :ready @@ -334,37 +319,24 @@ message = RTSP::Message.teardown(track).with_headers({ cseq: @cseq, session: @session[:session_id] }) message.add_headers additional_headers request(message) do + @capturer.stop reset_state - - if @play_thread - @capturer.stop - @capturer.rtp_file.close - @play_thread.exit - end end end - # Sets state related variables back to their starting values; - # +@session_state+ is set to +:init+; +@session+ is set to 0. - def reset_state - @session_state = :init - @session = {} - end - # Sends the GET_PARAMETERS request. # # @param [String] track The presentation or media track to ping. # @param [String] body The string containing the parameters to send. # @param [Hash] additional_headers # @return [RTSP::Response] # @see http://tools.ietf.org/html/rfc2326#page-37 RFC 2326, Section 10.8. def get_parameter(track, body="", additional_headers={}) - message = RTSP::Message.get_parameter(track).with_headers({ - cseq: @cseq }) + message = RTSP::Message.get_parameter(track).with_headers({ cseq: @cseq }) message.add_headers additional_headers message.body = body request(message) end @@ -375,12 +347,11 @@ # @param [String] parameters The string containing the parameters to send. # @param [Hash] additional_headers # @return [RTSP::Response] # @see http://tools.ietf.org/html/rfc2326#page-38 RFC 2326, Section 10.9. def set_parameter(track, parameters, additional_headers={}) - message = RTSP::Message.set_parameter(track).with_headers({ - cseq: @cseq }) + message = RTSP::Message.set_parameter(track).with_headers({ cseq: @cseq }) message.add_headers additional_headers message.body = parameters request(message) end @@ -402,11 +373,11 @@ # 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 # Request. # - # @param [Hash] new_args + # @param [RTSP::Message] message # @yield [RTSP::Response] # @return [RTSP::Response] # @raise [RTSP::Error] All 4xx & 5xx response codes & their messages. def request message response = send_message message @@ -432,19 +403,10 @@ end response end - # Ensures that +@session+ is set before continuing on. - # - # @raise [RTSP::Error] Raises if @session isn't set. - def ensure_session - if @session.empty? - raise RTSP::Error, "Session number not retrieved from server yet. Run SETUP first." - end - end - # Extracts the URL associated with the "control" attribute from the main # section of the session description. # # @return [String] The URL as a String. def aggregate_control_track @@ -476,45 +438,67 @@ end tracks end - # Compares the sequence number passed in to the current client sequence - # number ( +@cseq+ ) and raises if they're not equal. If that's the case, the - # server responded to a different request. + private + + # Sets state related variables back to their starting values; + # +@session_state+ is set to +:init+; +@session+ is set to 0. + def reset_state + @session_state = :init + @session = {} + end + + # Takes the methods returned from the Public header from an OPTIONS response + # and puts them to an Array. # - # @param [Fixnum] server_cseq Sequence number returned by the server. - # @raise [RTSP::Error] If the server returns a CSeq value that's different - # from what the client sent. - def compare_sequence_number server_cseq - if @cseq != server_cseq - message = "Sequence number mismatch. Client: #{@cseq}, Server: #{server_cseq}" - raise RTSP::Error, message - end + # @param [String] method_list The string returned from the server containing + # the list of methods it supports. + # @return [Array<Symbol>] The list of methods as symbols. + # @see #options + def extract_supported_methods_from method_list + method_list.downcase.split(', ').map { |m| m.to_sym } end # Compares the session number passed in to the current client session # number ( +@session+ ) and raises if they're not equal. If that's the case, # the server responded to a different request. # + # @todo Remove this--it's not used. # @param [Fixnum] server_session Session number returned by the server. # @raise [RTSP::Error] If the server returns a Session value that's different # from what the client sent. def compare_session_number server_session if @session[:session_id] != server_session message = "Session number mismatch. Client: #{@session[:session_id]}, Server: #{server_session}" raise RTSP::Error, message end end - # Takes the methods returned from the Public header from an OPTIONS response - # and puts them to an Array. + # Compares the sequence number passed in to the current client sequence + # number ( +@cseq+ ) and raises if they're not equal. If that's the case, the + # server responded to a different request. # - # @param [String] method_list The string returned from the server containing - # the list of methods it supports. - # @return [Array<Symbol>] The list of methods as symbols. - # @see #options - def extract_supported_methods_from method_list - method_list.downcase.split(', ').map { |m| m.to_sym } + # @param [Fixnum] server_cseq Sequence number returned by the server. + # @raise [RTSP::Error] If the server returns a CSeq value that's different + # from what the client sent. + def compare_sequence_number server_cseq + if @cseq != server_cseq + message = "Sequence number mismatch. Client: #{@cseq}, Server: #{server_cseq}" + raise RTSP::Error, message + end end + + # Ensures that +@session+ is set before continuing on. + # + # @raise [RTSP::Error] Raises if @session isn't set. + def ensure_session + if @session.empty? + raise RTSP::Error, "Session number not retrieved from server yet. Run SETUP first." + end + end + end end + +RTSP::Client.log = false