Module: RTP::Senders::Socat

Defined in:
lib/rtp/senders/socat.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"

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#fmtpArray<String>

Returns Media format attributes.

Returns:

  • (Array<String>)

    Media format attributes.



54
55
56
# File 'lib/rtp/senders/socat.rb', line 54

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.



39
40
41
# File 'lib/rtp/senders/socat.rb', line 39

def interface_ip
  @interface_ip
end

#pidsHash (readonly)

Returns Hash of session IDs and pids.

Returns:

  • (Hash)

    Hash of session IDs and pids.



27
28
29
# File 'lib/rtp/senders/socat.rb', line 27

def pids
  @pids
end

#rtcp_source_identifierString

Returns RTCP source identifier.

Returns:

  • (String)

    RTCP source identifier.



48
49
50
# File 'lib/rtp/senders/socat.rb', line 48

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.



30
31
32
# File 'lib/rtp/senders/socat.rb', line 30

def rtcp_threads
  @rtcp_threads
end

#rtp_mapArray<String>

Returns Media type attributes.

Returns:

  • (Array<String>)

    Media type attributes.



51
52
53
# File 'lib/rtp/senders/socat.rb', line 51

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.



45
46
47
# File 'lib/rtp/senders/socat.rb', line 45

def rtp_sequence
  @rtp_sequence
end

#rtp_timestampFixnum

Returns RTP timestamp of the source stream.

Returns:

  • (Fixnum)

    RTP timestamp of the source stream.



42
43
44
# File 'lib/rtp/senders/socat.rb', line 42

def rtp_timestamp
  @rtp_timestamp
end

#sessionsHash

Returns Hash of session IDs and SOCAT commands.

Returns:

  • (Hash)

    Hash of session IDs and SOCAT commands.



24
25
26
# File 'lib/rtp/senders/socat.rb', line 24

def sessions
  @sessions
end

#source_ipArray<String>

Returns IP address of the source camera.

Returns:

  • (Array<String>)

    IP address of the source camera.



33
34
35
# File 'lib/rtp/senders/socat.rb', line 33

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.



36
37
38
# File 'lib/rtp/senders/socat.rb', line 36

def source_port
  @source_port
end

Instance Method Details

#disconnect(sid) ⇒ Object

Disconnects the stream matching the session ID.

Parameters:

  • sid (String)

    Session ID.



149
150
151
152
153
154
155
156
# File 'lib/rtp/senders/socat.rb', line 149

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

#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



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/rtp/senders/socat.rb', line 163

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.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rtp/senders/socat.rb', line 73

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

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

    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:

  • sid (String)

    Session ID.



99
100
101
# File 'lib/rtp/senders/socat.rb', line 99

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

#stop_streaming(sid) ⇒ Object

Stop streaming for the requested session.

Parameters:

  • session (String)

    ID.



106
107
108
109
110
111
112
113
114
# File 'lib/rtp/senders/socat.rb', line 106

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