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.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/rtsp/socat_streaming.rb', line 131

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#{multicast ? 'm' : ''}\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:stream#{stream_index}#{multicast ? 'm' : ''}\r
m=video #{multicast ? @source_port[stream_index - 1] : 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.



158
159
160
161
162
163
164
165
# File 'lib/rtsp/socat_streaming.rb', line 158

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



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/rtsp/socat_streaming.rb', line 172

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, multicast = false) ⇒ 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
94
95
96
97
98
99
100
101
# File 'lib/rtsp/socat_streaming.rb', line 71

def setup_streamer(sid, transport_url, index=1, multicast=false)
  dest_ip, dest_port = transport_url.split ":" unless multicast

  @rtcp_source_identifier ||= RTCP_SOURCE.pack("H*")
  local_port = multicast ? @source_port[index - 1] : free_port(true)
 
  unless multicast
    @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
  end

  @cleaner ||= Thread.start { cleanup_defunct }
  @processes ||= Sys::ProcTable.ps.map { |p| p.cmdline }

  if multicast
    @sessions[sid] = :multicast
  else
    @sessions[sid] = build_socat(dest_ip, dest_port, local_port, index)
  end

  local_port
end

#start_streaming(sid) ⇒ Object

Start streaming for the requested session.

Parameters:

  • session (String)

    ID.



110
111
112
# File 'lib/rtsp/socat_streaming.rb', line 110

def start_streaming sid
  spawn_socat(sid, @sessions[sid]) unless @sessions[sid] == :multicast
end

#stop_streaming(sid) ⇒ Object

Stop streaming for the requested session.

Parameters:

  • session (String)

    ID.



117
118
119
120
121
122
123
124
125
# File 'lib/rtsp/socat_streaming.rb', line 117

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