class RTSP::Server
Instantiates an RTSP
Server
Streaming is performed using socat. All you need is the multicast source RTP host and port.
require ‘rtsp/server’ server = RTSP::Server.new
“10.221.222.90”, 8554
This is for the stream at index 1 (rtsp://10.221.222.90:8554/stream1) RTSP::StreamServer.instance.source_ip << “239.221.222.241” RTSP::StreamServer.instance.source_port << 6780 RTSP::StreamServer.instance.fmtp << “96 packetization-mode=1…” RTSP::StreamServer.instance.rtp_map << “96 H264/90000”
This is for the stream at index 2 (rtsp://10.221.222.90:8554/stream2) RTSP::StreamServer.instance.source_ip << “239.221.222.141” RTSP::StreamServer.instance.source_port << 6740 RTSP::StreamServer.instance.fmtp << “96 packetization-mode=1…” RTSP::StreamServer.instance.rtp_map << “96 MP4/90000”
Now start the server server.start
Constants
- OPTIONS_LIST
Attributes
Public Class Methods
Initializes the the Stream Server
.
@param [Fixnum] host IP interface to bind. @param [Fixnum] port RTSP
port.
# File lib/rtsp/server.rb, line 45 def initialize(host, port=554) @session = rand(99999999) @stream_server = RTSP::StreamServer.instance @interface_ip = host @stream_server.interface_ip = host @tcp_server = TCPServer.new(host, port) @udp_server = UDPSocket.new @udp_server.bind(host, port) @agent = {} end
Public Instance Methods
Adds the headers to the response.
@param [RTSP::Request] request @param [Array<String>] response Response
headers @param [String] body Response
body @param [String] status Response
status @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 274 def add_headers(request, response, body, status="200 OK") result = [] version ||= SUPPORTED_VERSION result << "RTSP/#{version} #{status}" result << "CSeq: #{request.cseq}" unless body.nil? result << "Content-Type: #{request.accept}" rescue NoMethodError result << "Content-Base: #{request.url}/" rescue NoMethodError result << "Content-Length: #{body.size}" end result << "Date: #{Time.now.gmtime.strftime('%a, %b %d %Y %H:%M:%S GMT')}" result << response.join("\r\n") unless response.nil? result << body unless body.nil? result.flatten.join "\r\n" end
Handles the announce request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 160 def announce(request) [] end
Handles the describe request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 149 def describe(request) RTSP::Server.log "Received DESCRIBE request from #{request.remote_host}" description = @stream_server.description(request.multicast?, request.stream_index) [[], description] end
Handles the get_parameter
request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 209 def get_parameter(request) RTSP::Server.log "Received GET_PARAMETER request from #{request.remote_host}" " Pending Implementation" [[]] end
Handles unsupported RTSP
requests.
@param [Symbol] method_name Method name to be called. @param [Array] args Arguments to be passed in to the method. @param [Proc] block A block of code to be passed to a method.
# File lib/rtsp/server.rb, line 298 def method_missing(method_name, *args, &block) RTSP::Server.log("Received request for #{method_name} (not implemented)", :warn) [[], "Not Implemented"] end
Handles the options request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 136 def options(request) RTSP::Server.log "Received OPTIONS request from #{request.remote_host}" response = [] response << "Public: #{OPTIONS_LIST.join ','}" response << "\r\n" [response] end
Handles a pause request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 256 def pause(request) RTSP::Server.log "Received PAUSE request from #{request.remote_host}" response = [] sid = request.session[:session_id] rescue NoMethodError response << "Session: #{sid}" response << "\r\n" @stream_server.disconnect sid [response] end
Handles the play request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 187 def play(request) RTSP::Server.log "Received PLAY request from #{request.remote_host}" sid = request.session[:session_id] rescue NoMethodError response = [] response << "Session: #{sid}" response << "Range: #{request.range}" rescue NoMethodError index = request.stream_index - 1 rescue NoMethodError index = 1 unless index.is_a?(Fixnum) rtp_sequence, rtp_timestamp = @stream_server.parse_sequence_number( @stream_server.source_ip[index], @stream_server.source_port[index]) @stream_server.start_streaming sid response << "RTP-Info: url=#{request.url}/track1;" + "seq=#{rtp_sequence + 6} ;rtptime=#{rtp_timestamp}" response << "\r\n" [response] end
Process an RTSP
request
@param [String] request_str RTSP
request. @param [String] remote_address IP address of sender. @return [String] Response
.
# File lib/rtsp/server.rb, line 122 def process_request(request_str, io) remote_address = io.remote_address.ip_address /(?<action>.*) rtsp:\/\// =~ request_str request = RTSP::Request.new(request_str, remote_address) @agent[io] = request.user_agent rescue NoMethodError response, body = send(action.downcase.to_sym, request) add_headers(request, response, body) end
Handles the redirect request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 231 def redirect(request) RTSP::Server.log "Received REDIRECT request from #{request.remote_host}" " Pending Implementation" [[]] end
Serves a client request.
@param [IO] io Request/response socket object.
# File lib/rtsp/server.rb, line 87 def serve io request_str = "" count = 0 begin request_str << io.read_nonblock(500) rescue IO::WaitReadable, EOFError => ex return(-1) if ex.is_a?(EOFError) count += 1 sleep 0.001 sleep 1 if count > 10 count = 0 unless request_str == "" retry if count < 70 return -1 if request_str == "" end responses = [] puts "REQUEST **********************************" p request_str request_str.split("\r\n\r\n").each do |r| responses << process_request(r, io) end puts "RESPONSE **********************************" p responses io.send(responses.join, 0) return(-1) if request_str.include?("TEARDOWN") end
Handles the set_parameter
request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 220 def set_parameter(request) RTSP::Server.log "Received SET_PARAMETER request from #{request.remote_host}" " Pending Implementation" [[]] end
Handles the setup request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 168 def setup(request) RTSP::Server.log "Received SETUP request from #{request.remote_host}" @session = @session.next multicast_check = request.transport.include?('multicast') server_port = @stream_server.setup_streamer(@session, request, request.stream_index, multicast_check) response = [] transport = generate_transport(request, server_port, request.stream_index) response << "Transport: #{transport.join}" response << "Session: #{@session}; timeout=60" response << "\r\n" [response] end
Starts accepting TCP connections
# File lib/rtsp/server.rb, line 57 def start Thread.start { udp_listen } loop do client = @tcp_server.accept Thread.start do begin loop { break if serve(client) == -1 } rescue EOFError # do nothing ensure client.close unless @agent[client].include? "QuickTime" end end end end
Handles the teardown request.
@param [RTSP::Request] request @return [Array<Array<String>>] Response
headers and body.
# File lib/rtsp/server.rb, line 242 def teardown(request) RTSP::Server.log "Received TEARDOWN request from #{request.remote_host}" sid = request.session[:session_id] rescue NoMethodError @stream_server.stop_streaming sid response = [] response << "\r\n" [response] end
Listens on the UDP socket for RTSP
requests.
# File lib/rtsp/server.rb, line 76 def udp_listen loop do data, sender = @udp_server.recvfrom(500) response = process_request(data, sender[3]) @udp_server.send(response, 0, sender[3], sender[1]) end end
Private Instance Methods
Generates the transport headers for the response.
@param [RTSP::Request] Request
object. @param [Fixnum] server_port Port on which the stream_server is streaming from.
# File lib/rtsp/server.rb, line 310 def generate_transport request, server_port, index=1 port_specifier = 'client_port' if request.transport.include?(port_specifier) transport = request.transport.split(port_specifier) transport[1] = port_specifier + transport[1] transport[1] = "" if request.transport.include?("multicast") /client_port=(?<p1>\d*)-(?<p2>\d*)/ =~ request.transport transport[1] << ";port=#{p1}-#{p2}" unless p1.nil? transport[1] << ";port=#{server_port}-#{server_port+1}" if p1.nil? else transport = [request.transport + ';', "port=#{server_port}-#{server_port + 1}"] end if request.transport.include?("unicast") transport[0] << "destination=#{request.remote_host};" transport[1] << ";server_port=#{server_port}-#{server_port+1}" else transport[0] << "destination=#{@stream_server.source_ip[index - 1]};" transport[1] << ";ttl=10" end transport[0] << "source=#{@stream_server.interface_ip};" transport end