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  }