github.com/cnotch/ipchub@v1.1.0/service/rtsp/session_roles.go (about) 1 // Copyright (c) 2019,CAOHONGJU All rights reserved. 2 // Use of this source code is governed by a MIT-style 3 // license that can be found in the LICENSE file. 4 5 package rtsp 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "net" 12 13 "github.com/cnotch/ipchub/config" 14 "github.com/cnotch/ipchub/media" 15 "github.com/cnotch/ipchub/network" 16 "github.com/cnotch/ipchub/utils" 17 "github.com/cnotch/xlog" 18 ) 19 20 var ( 21 errModeBehavior = errors.New("Play mode can't send rtp pack") 22 defaultStream mediaStream = emptyStream{} 23 defaultConsumer media.Consumer = emptyConsumer{} 24 ) 25 26 // 媒体流 27 type mediaStream interface { 28 Close() error 29 WritePacket(pack *RTPPack) error 30 } 31 32 // 占位流,简化判断 33 type emptyStream struct { 34 } 35 36 func (s emptyStream) Close() error { return nil } 37 func (s emptyStream) WritePacket(*RTPPack) error { return errModeBehavior } 38 39 // 占位消费者,简化判断 40 type emptyConsumer struct { 41 } 42 43 func (c emptyConsumer) Consume(p Pack) {} 44 func (c emptyConsumer) Close() error { return nil } 45 46 type tcpPushStream struct { 47 closed bool 48 stream *media.Stream 49 } 50 51 func (s *tcpPushStream) Close() error { 52 if s.closed { 53 return nil 54 } 55 56 s.closed = true 57 media.Unregist(s.stream) 58 s.stream = nil 59 return nil 60 } 61 62 func (s *tcpPushStream) WritePacket(p *RTPPack) error { 63 return s.stream.WriteRtpPacket(p) 64 } 65 66 type tcpConsumer struct { 67 *Session 68 closed bool 69 source *media.Stream 70 cid media.CID 71 } 72 73 func (c *tcpConsumer) Consume(p Pack) { 74 if c.closed { 75 return 76 } 77 78 p2 := p.(*RTPPack) 79 var err error 80 81 if c.wsconn != nil { 82 buf := buffers.Get().(*bytes.Buffer) 83 buf.Reset() 84 defer buffers.Put(buf) 85 86 p2.Write(buf, c.transport.Channels[:]) 87 88 c.lockW.Lock() 89 _, err = c.wsconn.Write(buf.Bytes()) 90 c.lockW.Unlock() 91 } else { 92 c.lockW.Lock() 93 err = p2.Write(c.conn, c.transport.Channels[:]) 94 c.lockW.Unlock() 95 } 96 97 if err != nil { 98 c.logger.Errorf("send pack error = %v , close socket", err) 99 c.Close() 100 return 101 } 102 } 103 104 func (c *tcpConsumer) Close() error { 105 if c.closed { 106 return nil 107 } 108 c.closed = true 109 c.source.StopConsume(c.cid) 110 c.source = nil 111 return nil 112 } 113 114 type udpConsumer struct { 115 *Session 116 closed bool 117 source *media.Stream 118 cid media.CID 119 udpConn *net.UDPConn // 用于Player的UDP单播 120 destAddr [rtpChannelCount]*net.UDPAddr 121 } 122 123 func (c *udpConsumer) Consume(p Pack) { 124 if c.closed { 125 return 126 } 127 128 p2 := p.(*RTPPack) 129 addr := c.destAddr[int(p2.Channel)] 130 if addr != nil { 131 _, err := c.udpConn.WriteToUDP(p2.Data, addr) 132 if err != nil { 133 c.logger.Warn(err.Error()) 134 return 135 } 136 } 137 } 138 139 func (c *udpConsumer) Close() error { 140 if c.closed { 141 return nil 142 } 143 c.closed = true 144 145 c.source.StopConsume(c.cid) 146 c.udpConn.Close() 147 c.source = nil 148 return nil 149 } 150 151 func (c *udpConsumer) prepareUDP(destIP string, destPorts [rtpChannelCount]int) error { 152 // 如果还没准备 Socket 153 if c.udpConn == nil { 154 udpConn, err := net.ListenUDP("udp", &net.UDPAddr{}) 155 if err != nil { 156 return err 157 } 158 c.udpConn = udpConn 159 err = udpConn.SetWriteBuffer(config.NetBufferSize()) 160 } 161 162 for i, port := range destPorts { 163 if port > 0 { 164 c.destAddr[i], _ = net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", destIP, port)) 165 } 166 } 167 return nil 168 } 169 170 type multicastConsumer struct { 171 *Session 172 closed bool 173 source *media.Stream 174 } 175 176 func (c *multicastConsumer) Consume(p Pack) {} 177 func (c *multicastConsumer) Close() error { 178 if c.closed { 179 return nil 180 } 181 c.closed = true 182 183 c.source.Multicastable().ReleaseMember(c.Session) 184 c.source = nil 185 c.Session = nil 186 return nil 187 } 188 189 // 将Session作为Pusher角色 190 func (s *Session) asTCPPusher() { 191 pusher := &tcpPushStream{} 192 193 mproxy := &multicastProxy{ 194 path: s.path, 195 bufferSize: config.NetBufferSize(), 196 multicastIP: utils.Multicast.NextIP(), // 设置组播IP 197 ttl: config.MulticastTTL(), 198 logger: s.logger.With(xlog.Fields( 199 xlog.F("path", s.path), 200 xlog.F("type", "multicast-proxy"))), 201 } 202 203 s.logger = s.logger.With(xlog.Fields( 204 xlog.F("path", s.path), 205 xlog.F("type", "pusher"))) 206 207 for i := rtpChannelMin; i < rtpChannelCount; i++ { 208 mproxy.ports[i] = utils.Multicast.NextPort() 209 } 210 211 pusher.stream = media.NewStream(s.path, s.rawSdp, 212 media.Attr("addr", s.conn.RemoteAddr().String()), 213 media.Multicast(mproxy)) 214 215 media.Regist(pusher.stream) 216 // 设置Session字段 217 s.stream = pusher 218 } 219 220 func (s *Session) asTCPConsumer(stream *media.Stream, resp *Response) (err error) { 221 if s.wsconn != nil { 222 s.logger = s.logger.With(xlog.Fields( 223 xlog.F("path", s.path), 224 xlog.F("type", "websocket-player"))) 225 } else { 226 s.logger = s.logger.With(xlog.Fields( 227 xlog.F("path", s.path), 228 xlog.F("type", "tcp-player"))) 229 } 230 231 c := &tcpConsumer{ 232 Session: s, 233 source: stream, 234 } 235 236 err = s.response(resp) 237 if err != nil { 238 return err 239 } 240 s.timeout = 0 // play 只需发送不用接收,因此设置不超时 241 s.consumer = c 242 if s.wsconn != nil { 243 c.cid = stream.StartConsumeNoGopCache(s, media.RTPPacket, "net=rtsp-websocket") 244 } else { 245 c.cid = stream.StartConsume(s, media.RTPPacket, "net=rtsp-tcp") 246 } 247 return 248 } 249 250 func (s *Session) asUDPConsumer(stream *media.Stream, resp *Response) (err error) { 251 c := &udpConsumer{ 252 Session: s, 253 source: stream, 254 } 255 256 // 创建udp连接 257 err = c.prepareUDP(network.GetIP(s.conn.RemoteAddr()), s.transport.ClientPorts) 258 if err != nil { 259 resp.StatusCode = StatusInternalServerError 260 err = s.response(resp) 261 if err != nil { 262 return err 263 } 264 return nil 265 } 266 267 s.logger = s.logger.With(xlog.Fields( 268 xlog.F("path", s.path), 269 xlog.F("type", "udp-player"))) 270 err = s.response(resp) 271 if err != nil { 272 return err 273 } 274 275 s.timeout = 0 // play 只需发送不用接收,因此设置不超时 276 s.consumer = c 277 278 c.cid = stream.StartConsume(s, media.RTPPacket, "net=rtsp-udp") 279 return nil 280 } 281 282 func (s *Session) asMulticastConsumer(stream *media.Stream, resp *Response) (err error) { 283 c := &multicastConsumer{ 284 Session: s, 285 source: stream, 286 } 287 ma := stream.Multicastable() 288 if ma == nil { // 不支持组播 289 resp.StatusCode = StatusUnsupportedTransport 290 err = s.response(resp) 291 if err != nil { 292 return err 293 } 294 return nil 295 } 296 297 s.logger = s.logger.With(xlog.Fields( 298 xlog.F("path", s.path), 299 xlog.F("type", "multicast-player"))) 300 err = s.response(resp) 301 if err != nil { 302 return err 303 } 304 305 c.timeout = 0 // play 只需发送不用接收,因此设置不超时 306 s.consumer = c 307 308 ma.AddMember(s) 309 return nil 310 }