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 }