github.com/cnotch/ipchub@v1.1.0/media/consumption.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 media
     6  
     7  import (
     8  	"io"
     9  	"runtime/debug"
    10  	"time"
    11  
    12  	"github.com/cnotch/ipchub/stats"
    13  	"github.com/cnotch/queue"
    14  	"github.com/cnotch/xlog"
    15  )
    16  
    17  // Consumer 消费者接口
    18  type Consumer interface {
    19  	Consume(pack Pack)
    20  	io.Closer
    21  }
    22  
    23  // consumption 流媒体消费者
    24  type consumption struct {
    25  	startOn    time.Time        // 启动时间
    26  	stream     *Stream          // 被消费的流
    27  	cid        CID              // 消费ID
    28  	consumer   Consumer         // 消费者
    29  	packetType PacketType       // 消费的包类型
    30  	extra      string           // 消费者额外信息
    31  	recvQueue  *queue.SyncQueue // 接收媒体源数据的队列
    32  	closed     bool             // 消费者是否关闭
    33  	Flow       stats.Flow       // 流量统计
    34  	logger     *xlog.Logger     // 日志对象
    35  	discarding bool             // 媒体包丢弃中
    36  	maxQLen    int
    37  }
    38  
    39  func (c *consumption) ID() CID {
    40  	return c.cid
    41  }
    42  
    43  // Close 关闭消费者
    44  func (c *consumption) Close() error {
    45  	if c.closed {
    46  		return nil
    47  	}
    48  
    49  	c.closed = true
    50  	c.recvQueue.Signal()
    51  	return nil
    52  }
    53  
    54  // 向消费者发送媒体包
    55  func (c *consumption) send(pack Pack, keyframe bool) {
    56  	if keyframe { // 是 key frame
    57  		n := c.recvQueue.Len()
    58  		if c.discarding && n < c.maxQLen {
    59  			c.discarding = false
    60  		} else if !c.discarding && n > c.maxQLen {
    61  			c.discarding = true
    62  		}
    63  	}
    64  
    65  	if !c.discarding {
    66  		c.recvQueue.Push(pack)
    67  		c.Flow.AddIn(int64(pack.Size()))
    68  	}
    69  }
    70  
    71  // 向消费者发送一个图像组
    72  func (c *consumption) sendGop(cache packCache) int {
    73  	bytes := cache.PushTo(c.recvQueue)
    74  	c.Flow.AddIn(int64(bytes))
    75  	return bytes
    76  }
    77  
    78  func (c *consumption) consume() {
    79  	defer func() {
    80  		defer func() { // 避免 handler 再 panic
    81  			recover()
    82  		}()
    83  
    84  		if r := recover(); r != nil {
    85  			c.logger.Errorf("consume routine panic;r = %v \n %s", r, debug.Stack())
    86  		}
    87  
    88  		// 停止消费
    89  		c.stream.StopConsume(c.cid)
    90  		c.consumer.Close()
    91  
    92  		// 尽早通知GC,回收内存
    93  		c.recvQueue.Reset()
    94  		c.stream = nil
    95  	}()
    96  
    97  	for !c.closed {
    98  		p := c.recvQueue.Pop()
    99  		if p == nil {
   100  			if !c.closed {
   101  				c.logger.Warn("receive nil pack")
   102  			}
   103  			continue
   104  		}
   105  
   106  		pack := p.(Pack)
   107  		c.consumer.Consume(pack)
   108  		c.Flow.AddOut(int64(pack.Size()))
   109  	}
   110  }
   111  
   112  // ConsumptionInfo 消费者信息
   113  type ConsumptionInfo struct {
   114  	ID         uint32           `json:"id"`
   115  	StartOn    string           `json:"start_on"`
   116  	PacketType string           `json:"packet_type"`
   117  	Extra      string           `json:"extra"`
   118  	Flow       stats.FlowSample `json:"flow"` // 转换成 K
   119  }
   120  
   121  // Info 获取消费者信息
   122  func (c *consumption) Info() ConsumptionInfo {
   123  	flow := c.Flow.GetSample()
   124  	flow.InBytes /= 1024
   125  	flow.OutBytes /= 1024
   126  
   127  	return ConsumptionInfo{
   128  		ID:         uint32(c.cid),
   129  		StartOn:    c.startOn.Format(time.RFC3339Nano),
   130  		PacketType: c.packetType.String(),
   131  		Extra:      c.extra,
   132  		Flow:       flow,
   133  	}
   134  }