mirror of https://bitbucket.org/ausocean/av.git
167 lines
3.9 KiB
Go
167 lines
3.9 KiB
Go
|
/*
|
||
|
Copyright (c) 2015, T. Jameson Little <t.jameson.little@gmail.com>
|
||
|
All rights reserved.
|
||
|
|
||
|
Redistribution and use in source and binary forms, with or without modification,
|
||
|
are permitted provided that the following conditions are met:
|
||
|
|
||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||
|
list of conditions and the following disclaimer.
|
||
|
|
||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||
|
other materials provided with the distribution.
|
||
|
|
||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||
|
may be used to endorse or promote products derived from this software without
|
||
|
specific prior written permission.
|
||
|
|
||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||
|
|
||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||
|
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
package rtp
|
||
|
|
||
|
import (
|
||
|
"net"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
RTP_VERSION = 2
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
hasRtpPadding = 1 << 5
|
||
|
hasRtpExt = 1 << 4
|
||
|
)
|
||
|
|
||
|
type RtpPacket struct {
|
||
|
Version byte
|
||
|
Padding bool
|
||
|
Ext bool
|
||
|
Marker bool
|
||
|
PayloadType byte
|
||
|
SequenceNumber uint
|
||
|
Timestamp uint
|
||
|
SyncSource uint
|
||
|
CSRC []uint
|
||
|
ExtHeader uint
|
||
|
ExtData []byte
|
||
|
Payload []byte
|
||
|
}
|
||
|
|
||
|
type Session struct {
|
||
|
Rtp net.PacketConn
|
||
|
Rtcp net.PacketConn
|
||
|
RtpChan <-chan RtpPacket
|
||
|
RtcpChan <-chan []byte
|
||
|
rtpChan chan<- RtpPacket
|
||
|
rtcpChan chan<- []byte
|
||
|
}
|
||
|
|
||
|
func New(rtp, rtcp net.PacketConn) *Session {
|
||
|
rtpChan := make(chan RtpPacket, 10)
|
||
|
rtcpChan := make(chan []byte, 10)
|
||
|
s := &Session{
|
||
|
Rtp: rtp,
|
||
|
Rtcp: rtcp,
|
||
|
RtpChan: rtpChan,
|
||
|
RtcpChan: rtcpChan,
|
||
|
rtpChan: rtpChan,
|
||
|
rtcpChan: rtcpChan,
|
||
|
}
|
||
|
go s.HandleRtpConn(rtp)
|
||
|
go s.HandleRtcpConn(rtcp)
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
func toUint(arr []byte) (ret uint) {
|
||
|
for i, b := range arr {
|
||
|
ret |= uint(b) << (8 * uint(len(arr)-i-1))
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func (s *Session) HandleRtpConn(conn net.PacketConn) {
|
||
|
buf := make([]byte, 4096)
|
||
|
for {
|
||
|
n, _, err := conn.ReadFrom(buf)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
cpy := make([]byte, n)
|
||
|
copy(cpy, buf)
|
||
|
go s.handleRtp(cpy)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *Session) HandleRtcpConn(conn net.PacketConn) {
|
||
|
buf := make([]byte, 4096)
|
||
|
for {
|
||
|
n, _, err := conn.ReadFrom(buf)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
cpy := make([]byte, n)
|
||
|
copy(cpy, buf)
|
||
|
go s.handleRtcp(cpy)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *Session) handleRtp(buf []byte) {
|
||
|
fmt.Println(buf)
|
||
|
packet := RtpPacket{
|
||
|
Version: (buf[0] & 0xC0)>>6,
|
||
|
Padding: buf[0]&hasRtpPadding != 0,
|
||
|
Ext: buf[0]&hasRtpExt != 0,
|
||
|
Marker: buf[1]&1 != 0,
|
||
|
PayloadType: buf[1] >> 1,
|
||
|
SequenceNumber: toUint(buf[2:4]),
|
||
|
Timestamp: toUint(buf[4:8]),
|
||
|
SyncSource: toUint(buf[8:12]),
|
||
|
CSRC: make([]uint, buf[0]>>4),
|
||
|
}
|
||
|
|
||
|
if packet.Version != RTP_VERSION {
|
||
|
fmt.Printf("Packet version: %v", packet.Version)
|
||
|
panic("Unsupported version")
|
||
|
}
|
||
|
|
||
|
|
||
|
i := 12
|
||
|
|
||
|
for j := range packet.CSRC {
|
||
|
packet.CSRC[j] = toUint(buf[i : i+4])
|
||
|
i += 4
|
||
|
}
|
||
|
|
||
|
if packet.Ext {
|
||
|
packet.ExtHeader = toUint(buf[i : i+2])
|
||
|
length := toUint(buf[i+2 : i+4])
|
||
|
i += 4
|
||
|
if length > 0 {
|
||
|
packet.ExtData = buf[i : i+int(length)*4]
|
||
|
i += int(length) * 4
|
||
|
}
|
||
|
}
|
||
|
|
||
|
packet.Payload = buf[i:]
|
||
|
|
||
|
s.rtpChan <- packet
|
||
|
}
|
||
|
|
||
|
func (s *Session) handleRtcp(buf []byte) {
|
||
|
// TODO: implement rtcp
|
||
|
}
|