mirror of
				https://github.com/aler9/rtsp-simple-server
				synced 2025-10-31 02:56:29 +08:00 
			
		
		
		
	 8cbbbc05c3
			
		
	
	8cbbbc05c3
	
	
	
		
			
			new features: * support publishing Opus and AC-3 tracks * support publishing more than 2 tracks. This is compatible with OBS multitrack video and OBS VOD audio track
		
			
				
	
	
		
			133 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package message
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/bluenviron/mediamtx/internal/protocols/rtmp/rawmessage"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// AudioChunkStreamID is the chunk stream ID that is usually used to send Audio{}
 | |
| 	AudioChunkStreamID = 4
 | |
| )
 | |
| 
 | |
| // audio codecs
 | |
| const (
 | |
| 	CodecMPEG1Audio = 2
 | |
| 	CodecLPCM       = 3
 | |
| 	CodecPCMA       = 7
 | |
| 	CodecPCMU       = 8
 | |
| 	CodecMPEG4Audio = 10
 | |
| )
 | |
| 
 | |
| // audio rates
 | |
| const (
 | |
| 	Rate5512  = 0
 | |
| 	Rate11025 = 1
 | |
| 	Rate22050 = 2
 | |
| 	Rate44100 = 3
 | |
| )
 | |
| 
 | |
| // audio depths
 | |
| const (
 | |
| 	Depth8  = 0
 | |
| 	Depth16 = 1
 | |
| )
 | |
| 
 | |
| // AudioAACType is the AAC type of a Audio.
 | |
| type AudioAACType uint8
 | |
| 
 | |
| // AudioAACType values.
 | |
| const (
 | |
| 	AudioAACTypeConfig AudioAACType = 0
 | |
| 	AudioAACTypeAU     AudioAACType = 1
 | |
| )
 | |
| 
 | |
| // Audio is an audio message.
 | |
| type Audio struct {
 | |
| 	ChunkStreamID   byte
 | |
| 	DTS             time.Duration
 | |
| 	MessageStreamID uint32
 | |
| 	Codec           uint8
 | |
| 	Rate            uint8
 | |
| 	Depth           uint8
 | |
| 	IsStereo        bool
 | |
| 	AACType         AudioAACType // only for CodecMPEG4Audio
 | |
| 	Payload         []byte
 | |
| }
 | |
| 
 | |
| func (m *Audio) unmarshal(raw *rawmessage.Message) error {
 | |
| 	m.ChunkStreamID = raw.ChunkStreamID
 | |
| 	m.DTS = raw.Timestamp
 | |
| 	m.MessageStreamID = raw.MessageStreamID
 | |
| 
 | |
| 	if len(raw.Body) < 2 {
 | |
| 		return fmt.Errorf("invalid body size")
 | |
| 	}
 | |
| 
 | |
| 	m.Codec = raw.Body[0] >> 4
 | |
| 	switch m.Codec {
 | |
| 	case CodecMPEG4Audio, CodecMPEG1Audio, CodecPCMA, CodecPCMU, CodecLPCM:
 | |
| 	default:
 | |
| 		return fmt.Errorf("unsupported audio codec: %d", m.Codec)
 | |
| 	}
 | |
| 
 | |
| 	m.Rate = (raw.Body[0] >> 2) & 0x03
 | |
| 	m.Depth = (raw.Body[0] >> 1) & 0x01
 | |
| 
 | |
| 	if (raw.Body[0] & 0x01) != 0 {
 | |
| 		m.IsStereo = true
 | |
| 	}
 | |
| 
 | |
| 	if m.Codec == CodecMPEG4Audio {
 | |
| 		m.AACType = AudioAACType(raw.Body[1])
 | |
| 		switch m.AACType {
 | |
| 		case AudioAACTypeConfig, AudioAACTypeAU:
 | |
| 		default:
 | |
| 			return fmt.Errorf("unsupported audio message type: %d", m.AACType)
 | |
| 		}
 | |
| 
 | |
| 		m.Payload = raw.Body[2:]
 | |
| 	} else {
 | |
| 		m.Payload = raw.Body[1:]
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (m Audio) marshalBodySize() int {
 | |
| 	var l int
 | |
| 	if m.Codec == CodecMPEG1Audio {
 | |
| 		l = 1 + len(m.Payload)
 | |
| 	} else {
 | |
| 		l = 2 + len(m.Payload)
 | |
| 	}
 | |
| 	return l
 | |
| }
 | |
| 
 | |
| func (m Audio) marshal() (*rawmessage.Message, error) {
 | |
| 	body := make([]byte, m.marshalBodySize())
 | |
| 
 | |
| 	body[0] = m.Codec<<4 | m.Rate<<2 | m.Depth<<1
 | |
| 
 | |
| 	if m.IsStereo {
 | |
| 		body[0] |= 1
 | |
| 	}
 | |
| 
 | |
| 	if m.Codec == CodecMPEG4Audio {
 | |
| 		body[1] = uint8(m.AACType)
 | |
| 		copy(body[2:], m.Payload)
 | |
| 	} else {
 | |
| 		copy(body[1:], m.Payload)
 | |
| 	}
 | |
| 
 | |
| 	return &rawmessage.Message{
 | |
| 		ChunkStreamID:   m.ChunkStreamID,
 | |
| 		Timestamp:       m.DTS,
 | |
| 		Type:            uint8(TypeAudio),
 | |
| 		MessageStreamID: m.MessageStreamID,
 | |
| 		Body:            body,
 | |
| 	}, nil
 | |
| }
 |