mediamtx/internal/rtmp/rawmessage/writer.go

196 lines
4.5 KiB
Go
Raw Normal View History

2022-06-04 23:06:40 +00:00
package rawmessage
2022-05-13 18:53:52 +00:00
import (
"bufio"
2022-06-08 18:47:36 +00:00
"fmt"
"time"
2022-06-04 23:06:40 +00:00
2023-05-16 14:14:20 +00:00
"github.com/bluenviron/mediamtx/internal/rtmp/bytecounter"
"github.com/bluenviron/mediamtx/internal/rtmp/chunk"
2022-05-13 18:53:52 +00:00
)
2022-06-04 23:06:40 +00:00
type writerChunkStream struct {
mw *Writer
lastMessageStreamID *uint32
lastType *uint8
2022-06-08 18:47:36 +00:00
lastBodyLen *uint32
lastTimestamp *int64
lastTimestampDelta *int64
2022-05-13 18:53:52 +00:00
}
2022-06-08 18:47:36 +00:00
func (wc *writerChunkStream) writeChunk(c chunk.Chunk) error {
2022-07-16 10:42:48 +00:00
// check if we received an acknowledge
if wc.mw.checkAcknowledge && wc.mw.ackWindowSize != 0 {
diff := uint32(wc.mw.w.Count()) - wc.mw.ackValue
2022-07-16 10:42:48 +00:00
if diff > (wc.mw.ackWindowSize * 3 / 2) {
return fmt.Errorf("no acknowledge received within window")
}
}
2022-06-27 15:51:54 +00:00
buf, err := c.Marshal()
2022-06-08 18:47:36 +00:00
if err != nil {
return err
}
_, err = wc.mw.bw.Write(buf)
2022-06-08 18:47:36 +00:00
if err != nil {
return err
}
return nil
}
func (wc *writerChunkStream) writeMessage(msg *Message) error {
bodyLen := uint32(len(msg.Body))
pos := uint32(0)
firstChunk := true
2022-05-13 18:53:52 +00:00
// convert timestamp to milliseconds before splitting message in chunks
/// otherwise timestampDelta gets messed up.
timestamp := int64(msg.Timestamp / time.Millisecond)
var timestampDelta *int64
2022-05-13 22:11:01 +00:00
if wc.lastTimestamp != nil {
diff := timestamp - *wc.lastTimestamp
// use delta only if it is positive
if diff >= 0 {
timestampDelta = &diff
}
2022-05-13 22:11:01 +00:00
}
2022-05-13 18:53:52 +00:00
for {
chunkBodyLen := bodyLen - pos
if chunkBodyLen > wc.mw.chunkSize {
chunkBodyLen = wc.mw.chunkSize
2022-05-13 18:53:52 +00:00
}
if firstChunk {
firstChunk = false
2022-05-13 18:53:52 +00:00
2022-05-13 22:11:01 +00:00
switch {
case wc.lastMessageStreamID == nil || timestampDelta == nil || *wc.lastMessageStreamID != msg.MessageStreamID:
2022-06-08 18:47:36 +00:00
err := wc.writeChunk(&chunk.Chunk0{
2022-05-13 18:53:52 +00:00
ChunkStreamID: msg.ChunkStreamID,
Timestamp: uint32(timestamp),
Type: msg.Type,
2022-05-13 18:53:52 +00:00
MessageStreamID: msg.MessageStreamID,
2022-06-08 18:47:36 +00:00
BodyLen: (bodyLen),
2022-05-13 18:53:52 +00:00
Body: msg.Body[pos : pos+chunkBodyLen],
2022-06-08 18:47:36 +00:00
})
2022-05-13 18:53:52 +00:00
if err != nil {
return err
}
2022-05-13 22:19:43 +00:00
case *wc.lastType != msg.Type || *wc.lastBodyLen != bodyLen:
2022-06-08 18:47:36 +00:00
err := wc.writeChunk(&chunk.Chunk1{
2022-05-13 22:11:01 +00:00
ChunkStreamID: msg.ChunkStreamID,
TimestampDelta: uint32(*timestampDelta),
2022-05-13 22:11:01 +00:00
Type: msg.Type,
2022-06-08 18:47:36 +00:00
BodyLen: (bodyLen),
2022-05-13 22:11:01 +00:00
Body: msg.Body[pos : pos+chunkBodyLen],
2022-06-08 18:47:36 +00:00
})
2022-05-13 22:11:01 +00:00
if err != nil {
return err
}
2022-05-13 22:19:43 +00:00
case wc.lastTimestampDelta == nil || *wc.lastTimestampDelta != *timestampDelta:
2022-06-08 18:47:36 +00:00
err := wc.writeChunk(&chunk.Chunk2{
2022-05-13 22:11:01 +00:00
ChunkStreamID: msg.ChunkStreamID,
TimestampDelta: uint32(*timestampDelta),
2022-05-13 22:11:01 +00:00
Body: msg.Body[pos : pos+chunkBodyLen],
2022-06-08 18:47:36 +00:00
})
2022-05-13 22:11:01 +00:00
if err != nil {
return err
}
default:
2022-06-08 18:47:36 +00:00
err := wc.writeChunk(&chunk.Chunk3{
2022-05-13 18:53:52 +00:00
ChunkStreamID: msg.ChunkStreamID,
Body: msg.Body[pos : pos+chunkBodyLen],
2022-06-08 18:47:36 +00:00
})
2022-05-13 18:53:52 +00:00
if err != nil {
return err
}
}
2022-05-13 22:11:01 +00:00
v1 := msg.MessageStreamID
wc.lastMessageStreamID = &v1
v2 := msg.Type
wc.lastType = &v2
v3 := bodyLen
wc.lastBodyLen = &v3
v4 := timestamp
2022-05-13 22:11:01 +00:00
wc.lastTimestamp = &v4
if timestampDelta != nil {
v5 := *timestampDelta
wc.lastTimestampDelta = &v5
}
2022-05-13 18:53:52 +00:00
} else {
2022-06-08 18:47:36 +00:00
err := wc.writeChunk(&chunk.Chunk3{
2022-05-13 18:53:52 +00:00
ChunkStreamID: msg.ChunkStreamID,
Body: msg.Body[pos : pos+chunkBodyLen],
2022-06-08 18:47:36 +00:00
})
2022-05-13 18:53:52 +00:00
if err != nil {
return err
}
}
pos += chunkBodyLen
if (bodyLen - pos) == 0 {
return wc.mw.bw.Flush()
2022-05-13 18:53:52 +00:00
}
}
}
2022-06-04 23:06:40 +00:00
// Writer is a raw message writer.
type Writer struct {
w *bytecounter.Writer
bw *bufio.Writer
checkAcknowledge bool
chunkSize uint32
ackWindowSize uint32
ackValue uint32
chunkStreams map[byte]*writerChunkStream
}
2022-06-04 23:06:40 +00:00
// NewWriter allocates a Writer.
func NewWriter(w *bytecounter.Writer, checkAcknowledge bool) *Writer {
2022-06-04 23:06:40 +00:00
return &Writer{
w: w,
bw: bufio.NewWriter(w),
checkAcknowledge: checkAcknowledge,
chunkSize: 128,
chunkStreams: make(map[byte]*writerChunkStream),
}
}
// SetChunkSize sets the maximum chunk size.
2022-06-08 18:47:36 +00:00
func (w *Writer) SetChunkSize(v uint32) {
2022-06-04 23:06:40 +00:00
w.chunkSize = v
}
2022-06-08 18:47:36 +00:00
// SetWindowAckSize sets the window acknowledgement size.
func (w *Writer) SetWindowAckSize(v uint32) {
w.ackWindowSize = v
}
// SetAcknowledgeValue sets the acknowledge sequence number.
func (w *Writer) SetAcknowledgeValue(v uint32) {
w.ackValue = v
}
// Write writes a Message.
2022-06-04 23:06:40 +00:00
func (w *Writer) Write(msg *Message) error {
wc, ok := w.chunkStreams[msg.ChunkStreamID]
if !ok {
2022-06-04 23:06:40 +00:00
wc = &writerChunkStream{mw: w}
w.chunkStreams[msg.ChunkStreamID] = wc
}
2022-06-08 18:47:36 +00:00
return wc.writeMessage(msg)
}