Module: RTSP::SocatStreaming

Includes:
Global
Included in:
StreamServer
Defined in:
lib/rtsp/socat_streaming.rb

Constant Summary collapse

RTCP_SOURCE =
["80c80006072dee6ad42c300f76c3b928377e99e5006c461ba92d8a3" +
"081ca0006072dee6a010e49583330444e2d41414a4248513600000000"]
MP4_RTP_MAP =
"96 MP4V-ES/30000"
MP4_FMTP =
"96 profile-level-id=5;config=000001b005000001b50900000100000" +
"0012000c888ba9860fa22c087828307"
H264_RTP_MAP =
"96 H264/90000"
H264_FMTP =
"96 packetization-mode=1;profile-level-id=428032;" +
"sprop-parameter-sets=Z0KAMtoAgAMEwAQAAjKAAAr8gYAAAYhMAABMS0IvfjAA" +
"ADEJgAAJiWhF78CA,aM48gA=="
SOCAT_OPTIONS =
"rcvbuf=2500000,sndbuf=2500000,sndtimeo=0.00001,rcvtimeo=0.00001"
BLOCK_SIZE =
2000
BSD_OPTIONS =
"setsockopt-int=0xffff:0x200:0x01"

Constants included from Global

Global::DEFAULT_RTSP_PORT, Global::DEFAULT_VERSION

Instance Attribute Summary collapse

Attributes included from Global

#log, #log_level, #logger, #raise_errors

Instance Method Summary collapse

Methods included from Global

#log?, #raise_errors?, #reset_config!, #rtsp_version

Instance Attribute Details

#fmtpArray<String>

Returns Media format attributes.

Returns:

  • (Array<String>)

    Media format attributes.



52
53
54
# File 'lib/rtsp/socat_streaming.rb', line 52

def fmtp
  @fmtp
end

#interface_ipString

Returns IP address of the interface of the RTSP streamer.

Returns:

  • (String)

    IP address of the interface of the RTSP streamer.



37
38
39
# File 'lib/rtsp/socat_streaming.rb', line 37

def interface_ip
  @interface_ip
end

#pidsHash (readonly)

Returns Hash of session IDs and pids.

Returns:

  • (Hash)

    Hash of session IDs and pids.



25
26
27
# File 'lib/rtsp/socat_streaming.rb', line 25

def pids
  @pids
end

#rtcp_source_identifierString

Returns RTCP source identifier.

Returns:

  • (String)

    RTCP source identifier.



46
47
48
# File 'lib/rtsp/socat_streaming.rb', line 46

def rtcp_source_identifier
  @rtcp_source_identifier
end

#rtcp_threadsHash (readonly)

Returns Hash of session IDs and RTCP threads.

Returns:

  • (Hash)

    Hash of session IDs and RTCP threads.



28
29
30
# File 'lib/rtsp/socat_streaming.rb', line 28

def rtcp_threads
  @rtcp_threads
end

#rtp_mapArray<String>

Returns Media type attributes.

Returns:

  • (Array<String>)

    Media type attributes.



49
50
51
# File 'lib/rtsp/socat_streaming.rb', line 49

def rtp_map
  @rtp_map
end

#rtp_sequenceFixnum

Returns RTP sequence number of the source stream.

Returns:

  • (Fixnum)

    RTP sequence number of the source stream.



43
44
45
# File 'lib/rtsp/socat_streaming.rb', line 43

def rtp_sequence
  @rtp_sequence
end

#rtp_timestampFixnum

Returns RTP timestamp of the source stream.

Returns:

  • (Fixnum)

    RTP timestamp of the source stream.



40
41
42
# File 'lib/rtsp/socat_streaming.rb', line 40

def rtp_timestamp
  @rtp_timestamp
end

#sessionsHash

Returns Hash of session IDs and SOCAT commands.

Returns:

  • (Hash)

    Hash of session IDs and SOCAT commands.



22
23
24
# File 'lib/rtsp/socat_streaming.rb', line 22

def sessions
  @sessions
end

#source_ipArray<String>

Returns IP address of the source camera.

Returns:

  • (Array<String>)

    IP address of the source camera.



31
32
33
# File 'lib/rtsp/socat_streaming.rb', line 31

def source_ip
  @source_ip
end

#source_portArray<Fixnum>

Returns Port where the source camera is streaming.

Returns:

  • (Array<Fixnum>)

    Port where the source camera is streaming.



34
35
36
# File 'lib/rtsp/socat_streaming.rb', line 34

def source_port
  @source_port
end

Instance Method Details

#description(multicast = false, stream_index = 1) ⇒ Object

Returns the default stream description.

@param multicast True if the description is for a multicast stream.

Parameters:

  • stream_index (Fixnum) (defaults to: 1)

    Index of the stream type.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/rtsp/socat_streaming.rb', line 123

def description multicast=false, stream_index=1
  rtp_map = @rtp_map[stream_index - 1] || H264_RTP_MAP
  fmtp = @fmtp[stream_index - 1] || H264_FMTP

  <<EOF
v=0\r
o=- 1345481255966282 1 IN IP4 #{@interface_ip}\r
s=Session streamed by "Streaming Server"\r
i=stream1\r
t=0 0\r
a=tool:LIVE555 Streaming Media v2007.07.09\r
a=type:broadcast\r
a=control:*\r
a=range:npt=0-\r
a=x-qt-text-nam:Session streamed by "Streaming Server"\r
a=x-qt-text-inf:stream1\r
m=video 0 RTP/AVP 96\r
c=IN IP4 #{multicast ? "#{multicast_ip(stream_index)}/10" : "0.0.0.0"}\r
a=rtpmap:#{rtp_map}\r
a=fmtp:#{fmtp}\r
a=control:track1\r
EOF
end

#disconnect(sid) ⇒ Object

Disconnects the stream matching the session ID.

Parameters:

  • sid (String)

    Session ID.



150
151
152
153
154
155
156
157
# File 'lib/rtsp/socat_streaming.rb', line 150

def disconnect sid
  pid = @pids[sid].to_i
  @pids.delete(sid)
  @sessions.delete(sid)
  Process.kill(9, pid) if pid > 1000
rescue Errno::ESRCH
  log "Tried to kill dead process: #{pid}"
end

#generate_rtcp_source_id(friendly_name) ⇒ String

Generates a RTCP source ID based on the friendly name. This ID is used in the RTCP communication with the client. The default RTCP_SOURCE will be used if one is not provided.

Parameters:

  • friendly_name (String)

    Name to be used in the RTCP source ID.

Returns:

  • (String)

    rtcp_source_id RTCP Source ID.



60
61
62
63
# File 'lib/rtsp/socat_streaming.rb', line 60

def generate_rtcp_source_id friendly_name
  ["80c80006072dee6ad42c300f76c3b928377e99e5006c461ba92d8a3081ca0006072dee6a010e" +
    friendly_name.unpack("H*").first + "00000000"].pack("H*")
end

#parse_sequence_number(src_ip, src_port) ⇒ Array<Fixnum>

Parses the headers from an RTP stream.

Parameters:

  • src_ip (String)

    Multicast IP address of RTP stream.

  • src_port (Fixnum)

    Port of RTP stream.

Returns:

  • (Array<Fixnum>)

    Sequence number and timestamp



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rtsp/socat_streaming.rb', line 164

def parse_sequence_number(src_ip, src_port)
  sock = UDPSocket.new
  ip = IPAddr.new(src_ip).hton + IPAddr.new("0.0.0.0").hton
  sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ip)
  sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
  sock.bind(Socket::INADDR_ANY, src_port)

  begin
    data = sock.recv_nonblock(1500)
  rescue Errno::EAGAIN
    retry
  end

  sock.close
  packet = RTP::Packet.read(data)

  [packet["sequence_number"], packet["timestamp"]]
end

#setup_streamer(sid, transport_url, index = 1) ⇒ Fixnum

Creates a RTP streamer using socat.

Parameters:

  • sid (String)

    Session ID.

  • transport_url (String)

    Destination IP:port.

  • index (Fixnum) (defaults to: 1)

    Stream index.

Returns:

  • (Fixnum)

    The port the streamer will stream on.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rtsp/socat_streaming.rb', line 71

def setup_streamer(sid, transport_url, index=1)
  dest_ip, dest_port = transport_url.split ":"
  @rtcp_source_identifier ||= RTCP_SOURCE.pack("H*")
  local_port = free_port(true)

  @rtcp_threads[sid] = Thread.start do
    s = UDPSocket.new
    s.bind(@interface_ip, local_port+1)

    loop do
      begin
        _, sender = s.recvfrom(36)
        s.send(@rtcp_source_identifier, 0, sender[3], sender[1])
      end
    end
  end

  @cleaner ||= Thread.start { cleanup_defunct }
  @processes ||= Sys::ProcTable.ps.map { |p| p.cmdline }
  @sessions[sid] = build_socat(dest_ip, dest_port, local_port, index)

  local_port
end

#start_streaming(sid) ⇒ Object

Start streaming for the requested session.

Parameters:

  • session (String)

    ID.



102
103
104
# File 'lib/rtsp/socat_streaming.rb', line 102

def start_streaming sid
  spawn_socat(sid, @sessions[sid])
end

#stop_streaming(sid) ⇒ Object

Stop streaming for the requested session.

Parameters:

  • session (String)

    ID.



109
110
111
112
113
114
115
116
117
# File 'lib/rtsp/socat_streaming.rb', line 109

def stop_streaming sid
  if sid.nil?
    disconnect_all_streams
  else
    disconnect sid
    @rtcp_threads[sid].kill unless rtcp_threads[sid].nil?
    @rtcp_threads.delete sid
  end
end