80 lines
2.9 KiB
Go
80 lines
2.9 KiB
Go
package rtmp
|
|
|
|
import (
|
|
"net"
|
|
"encoding/binary"
|
|
"time"
|
|
)
|
|
|
|
// counterpart to the read_basic_header from chunk.go, basically the reverse of that
|
|
func write_basic_header(chunk_buffer *[]byte, format uint8, csid uint32) {
|
|
if csid < 64 {
|
|
(*chunk_buffer)[0] = (format << 6) + uint8(csid)
|
|
} else if csid < 320 {
|
|
(*chunk_buffer)[0] = format << 6
|
|
(*chunk_buffer)[1] = uint8(csid - 64)
|
|
} else {
|
|
(*chunk_buffer)[0] = (format << 6) + 1
|
|
binary.LittleEndian.PutUint16((*chunk_buffer)[1:3], uint16(csid - 64))
|
|
}
|
|
}
|
|
|
|
// only consider writing format 0 for new, or format 3 for cut off. As the server only has to send
|
|
// protocol messages, no real point optimizing for a demo
|
|
func write_message_header_0(chunk_buffer *[]byte, msg_strmid uint32, msg_ptr *Message, basic_header_size uint32) {
|
|
msg_len_inter := make([]byte, 4) // uint32 to uint24 hack
|
|
binary.BigEndian.PutUint32(msg_len_inter, msg_ptr.msg_len)
|
|
copy((*chunk_buffer)[basic_header_size + 3:basic_header_size + 6], msg_len_inter[1:]) // skip timestamp since it will always be 0 for protocol and control msgs
|
|
(*chunk_buffer)[basic_header_size + 6] = msg_ptr.msg_type
|
|
binary.LittleEndian.PutUint32((*chunk_buffer)[basic_header_size + 7:basic_header_size + 11], msg_strmid)
|
|
}
|
|
|
|
// write the actual data
|
|
func write_chunk_data(chunk_buffer *[]byte, data []byte, bytes_buffered *uint32, chunk_data_size uint32, header_size uint32) {
|
|
copy((*chunk_buffer)[header_size:header_size+chunk_data_size], data[*bytes_buffered:*bytes_buffered + chunk_data_size])
|
|
*bytes_buffered += chunk_data_size
|
|
}
|
|
|
|
// chunk writing wrapper
|
|
func WriteChunk(conn net.Conn, csid uint32, msg_strmid uint32, msg_ptr *Message, chunk_size uint32) (error) {
|
|
conn.SetDeadline(time.Now().Add(10 * time.Second))
|
|
|
|
var i uint32 = 0 // track number of bytes written
|
|
for i < msg_ptr.msg_len { // until message is fully sent
|
|
var chunk_data_size uint32
|
|
// check if remaining message needs to be chunked or not
|
|
if msg_ptr.msg_len - i > chunk_size {
|
|
chunk_data_size = chunk_size
|
|
} else {
|
|
chunk_data_size = msg_ptr.msg_len - i
|
|
}
|
|
|
|
basic_header_size := uint32(1)
|
|
if csid >= 64 {
|
|
basic_header_size += 1
|
|
}
|
|
if csid >= 320 {
|
|
basic_header_size += 1
|
|
}
|
|
|
|
var chunk_buffer []byte
|
|
var header_size uint32
|
|
if i == 0 { // if chunkstream is to be opened/reset (format 0 = message header)
|
|
chunk_buffer = make([]byte, basic_header_size + 11 + chunk_data_size)
|
|
write_basic_header(&chunk_buffer, 0, csid)
|
|
write_message_header_0(&chunk_buffer, msg_strmid, msg_ptr, basic_header_size)
|
|
header_size = basic_header_size + 11
|
|
} else {
|
|
chunk_buffer = make([]byte, basic_header_size + chunk_data_size)
|
|
write_basic_header(&chunk_buffer, 3, csid)
|
|
header_size = basic_header_size
|
|
}
|
|
write_chunk_data(&chunk_buffer, msg_ptr.data, &i, chunk_data_size, header_size)
|
|
if _, err := conn.Write(chunk_buffer); err != nil { // expunge buffer over network connection
|
|
return err
|
|
}
|
|
}
|
|
conn.SetDeadline(time.Time{})
|
|
|
|
return nil
|
|
}
|