github.com/cnotch/ipchub@v1.1.0/av/format/rtp/packet.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 rtp
     6  
     7  import (
     8  	"bufio"
     9  	"encoding/binary"
    10  	"errors"
    11  	"io"
    12  
    13  	"github.com/pion/rtp"
    14  )
    15  
    16  const (
    17  	// TransferPrefix RTP 包网络传输时的前缀
    18  	TransferPrefix = byte(0x24) // $
    19  )
    20  
    21  // 预定义 RTP 通道类型
    22  const (
    23  	ChannelVideo        = iota         // 视频通道
    24  	ChannelVideoControl                // 视频控制通道
    25  	ChannelAudio                       // 音频通道
    26  	ChannelAudioControl                // 音频控制通道
    27  	ChannelCount                       // 支持的 RTP 通道类型数量
    28  	ChannelMin          = ChannelVideo // 支持的 RTP 通道类型最小值
    29  )
    30  
    31  // DefaultChannelConfig 默认的通道配置
    32  var DefaultChannelConfig = []int{
    33  	ChannelVideo,
    34  	ChannelVideoControl,
    35  	ChannelAudio,
    36  	ChannelAudioControl,
    37  }
    38  
    39  // ChannelName 通道名
    40  func ChannelName(channel int) string {
    41  	switch channel {
    42  	case ChannelAudio:
    43  		return "audio"
    44  	case ChannelVideo:
    45  		return "video"
    46  	case ChannelAudioControl:
    47  		return "audio control"
    48  	case ChannelVideoControl:
    49  		return "video control"
    50  	}
    51  	return "unknow"
    52  }
    53  
    54  // Packet RTP 数据包
    55  type Packet struct {
    56  	Channel    byte   // 通道
    57  	Data       []byte // 数据
    58  	rtp.Header        // Video 、Audio Channel'Header
    59  }
    60  
    61  // PacketWriter 包装 WritePacket 方法的接口
    62  type PacketWriter interface {
    63  	WriteRtpPacket(packet *Packet) error
    64  }
    65  
    66  // ReadPacket 根据规范从 r 中读取 rtp 包.
    67  // channelConfig 提供通道类型所在通道的配置信息
    68  func ReadPacket(r *bufio.Reader, channelConfig []int) (*Packet, error) {
    69  	var err error
    70  
    71  	var prefix [4]byte
    72  	// 读前缀4字节
    73  	if _, err = io.ReadFull(r, prefix[:]); err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	if prefix[0] != TransferPrefix {
    78  		return nil, errors.New("RTP Pack must start with `$`")
    79  	}
    80  
    81  	channel := int(prefix[1])
    82  	rtpLen := int(binary.BigEndian.Uint16(prefix[2:]))
    83  
    84  	// 读取包数据
    85  	rtpBytes := make([]byte, rtpLen)
    86  	if _, err = io.ReadFull(r, rtpBytes); err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	var p = new(Packet)
    91  	p.Data = rtpBytes
    92  	for i, v := range channelConfig {
    93  		if v == channel {
    94  			p.Channel = byte(i)
    95  			if p.Channel == ChannelVideo || p.Channel == ChannelAudio {
    96  				if err = p.Header.Unmarshal(p.Data); err != nil {
    97  					return nil, err
    98  				}
    99  			}
   100  			return p, nil
   101  		}
   102  	}
   103  	return nil, errors.New("RTP Packet illegal channel")
   104  }
   105  
   106  // Write 根据规范将 RTP 包输出到 w
   107  // channelConfig 提供通道类型所在通道的配置信息
   108  func (p *Packet) Write(w io.Writer, channelConfig []int) error {
   109  	if p.Channel >= ChannelCount {
   110  		return errors.New("unknow pack type")
   111  	}
   112  
   113  	ch := channelConfig[p.Channel]
   114  	if ch < 0 || ch > 255 { // 可能是未订阅,忽略
   115  		return nil
   116  	}
   117  
   118  	var prefix [4]byte
   119  	prefix[0] = TransferPrefix // 起始字节
   120  	prefix[1] = byte(ch)       // channel
   121  	binary.BigEndian.PutUint16(prefix[2:], uint16(len(p.Data)))
   122  
   123  	// 写前4个字节
   124  	if _, err := w.Write(prefix[:]); err != nil {
   125  		return err
   126  	}
   127  
   128  	// 写包数据部分
   129  	if _, err := w.Write(p.Data); err != nil {
   130  		return err
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  // Size 包在 RTP 中的传输总大小
   137  func (p *Packet) Size() int {
   138  	return len(p.Data) + 4
   139  }
   140  
   141  // Payload 数据包中实际的载荷
   142  // 如果是控制通道,返回nil
   143  func (p *Packet) Payload() []byte {
   144  	if p.Channel == ChannelVideo || p.Channel == ChannelAudio {
   145  		return p.Data[p.PayloadOffset:]
   146  	}
   147  	return nil
   148  }