package srtp
import (
"net"
"time"
"github.com/pion/logging"
"github.com/pion/rtcp"
)
const defaultSessionSRTCPReplayProtectionWindow = 64
type SessionSRTCP struct {
session
writeStream *WriteStreamSRTCP
}
func NewSessionSRTCP (conn net .Conn , config *Config ) (*SessionSRTCP , error ) {
if config == nil {
return nil , errNoConfig
} else if conn == nil {
return nil , errNoConn
}
loggerFactory := config .LoggerFactory
if loggerFactory == nil {
loggerFactory = logging .NewDefaultLoggerFactory ()
}
localOpts := append (
[]ContextOption {},
config .LocalOptions ...,
)
remoteOpts := append (
[]ContextOption {
SRTCPReplayProtection (defaultSessionSRTCPReplayProtectionWindow ),
},
config .RemoteOptions ...,
)
srtcpSession := &SessionSRTCP {
session : session {
nextConn : conn ,
localOptions : localOpts ,
remoteOptions : remoteOpts ,
readStreams : map [uint32 ]readStream {},
newStream : make (chan readStream ),
acceptStreamTimeout : config .AcceptStreamTimeout ,
started : make (chan interface {}),
closed : make (chan interface {}),
bufferFactory : config .BufferFactory ,
log : loggerFactory .NewLogger ("srtp" ),
},
}
srtcpSession .writeStream = &WriteStreamSRTCP {srtcpSession }
err := srtcpSession .session .start (
config .Keys .LocalMasterKey , config .Keys .LocalMasterSalt ,
config .Keys .RemoteMasterKey , config .Keys .RemoteMasterSalt ,
config .Profile ,
srtcpSession ,
)
if err != nil {
return nil , err
}
return srtcpSession , nil
}
func (s *SessionSRTCP ) OpenWriteStream () (*WriteStreamSRTCP , error ) {
return s .writeStream , nil
}
func (s *SessionSRTCP ) OpenReadStream (ssrc uint32 ) (*ReadStreamSRTCP , error ) {
r , _ := s .session .getOrCreateReadStream (ssrc , s , newReadStreamSRTCP )
if readStream , ok := r .(*ReadStreamSRTCP ); ok {
return readStream , nil
}
return nil , errFailedTypeAssertion
}
func (s *SessionSRTCP ) AcceptStream () (*ReadStreamSRTCP , uint32 , error ) {
stream , ok := <-s .newStream
if !ok {
return nil , 0 , errStreamAlreadyClosed
}
readStream , ok := stream .(*ReadStreamSRTCP )
if !ok {
return nil , 0 , errFailedTypeAssertion
}
return readStream , stream .GetSSRC (), nil
}
func (s *SessionSRTCP ) Close () error {
return s .session .close ()
}
func (s *SessionSRTCP ) write (buf []byte ) (int , error ) {
if _ , ok := <-s .session .started ; ok {
return 0 , errStartedChannelUsedIncorrectly
}
ibuf := bufferpool .Get ()
defer bufferpool .Put (ibuf )
s .session .localContextMutex .Lock ()
encrypted , err := s .localContext .EncryptRTCP (ibuf .([]byte ), buf , nil )
s .session .localContextMutex .Unlock ()
if err != nil {
return 0 , err
}
return s .session .nextConn .Write (encrypted )
}
func (s *SessionSRTCP ) setWriteDeadline (t time .Time ) error {
return s .session .nextConn .SetWriteDeadline (t )
}
func destinationSSRC(pkts []rtcp .Packet ) []uint32 {
ssrcSet := make (map [uint32 ]struct {})
for _ , p := range pkts {
for _ , ssrc := range p .DestinationSSRC () {
ssrcSet [ssrc ] = struct {}{}
}
}
out := make ([]uint32 , 0 , len (ssrcSet ))
for ssrc := range ssrcSet {
out = append (out , ssrc )
}
return out
}
func (s *SessionSRTCP ) decrypt (buf []byte ) error {
decrypted , err := s .remoteContext .DecryptRTCP (buf , buf , nil )
if err != nil {
return err
}
pkt , err := rtcp .Unmarshal (decrypted )
if err != nil {
return err
}
for _ , ssrc := range destinationSSRC (pkt ) {
r , isNew := s .session .getOrCreateReadStream (ssrc , s , newReadStreamSRTCP )
if r == nil {
return nil
} else if isNew {
if !s .session .acceptStreamTimeout .IsZero () {
_ = s .session .nextConn .SetReadDeadline (time .Time {})
}
s .session .newStream <- r
}
readStream , ok := r .(*ReadStreamSRTCP )
if !ok {
return errFailedTypeAssertion
}
_, err = readStream .write (decrypted )
if err != nil {
return err
}
}
return nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .