Implement SDP generation for each track

This is still a WIP, this deserves a well thought out rewrite in the
future
This commit is contained in:
Sean DuBois
2018-07-02 23:09:20 -07:00
parent 093a4efac4
commit 6cda3cc488
3 changed files with 77 additions and 22 deletions

View File

@@ -17,7 +17,7 @@ func (p *Port) Send(packet *rtp.Packet) {
p.srtpContextsLock.Lock()
srtpContext, ok := p.srtpContexts[contextMapKey]
if !ok {
srtpContext, err = srtp.CreateContext([]byte(authed.pair.ClientWriteKey[0:16]), []byte(authed.pair.ClientWriteKey[16:]), authed.pair.Profile, 2581832418)
srtpContext, err = srtp.CreateContext([]byte(authed.pair.ClientWriteKey[0:16]), []byte(authed.pair.ClientWriteKey[16:]), authed.pair.Profile, packet.SSRC)
if err != nil {
fmt.Println("Failed to build SRTP context")
continue

View File

@@ -1,15 +1,31 @@
package sdp
import (
"fmt"
"math/rand"
"strconv"
"strings"
)
// SessionBuilderTrack represents a single track in a SessionBuilder
type SessionBuilderTrack struct {
SSRC uint32
IsAudio bool
}
// SessionBuilder provides an easy way to build an SDP for an RTCPeerConnection
type SessionBuilder struct {
IceUsername, IcePassword, Fingerprint string
Candidates []string
Tracks []*SessionBuilderTrack
}
// BaseSessionDescription generates a default SDP response that is ice-lite, initiates the DTLS session and supports VP8, VP9 and Opus
func BaseSessionDescription(iceUsername, icePassword, fingerprint string, candidates []string) *SessionDescription {
func BaseSessionDescription(b *SessionBuilder) *SessionDescription {
addMediaCandidates := func(m *MediaDescription) *MediaDescription {
m.Attributes = append(m.Attributes, candidates...)
m.Attributes = append(m.Attributes, b.Candidates...)
m.Attributes = append(m.Attributes, "end-of-candidates")
return m
}
@@ -21,10 +37,10 @@ func BaseSessionDescription(iceUsername, icePassword, fingerprint string, candid
"setup:active",
"mid:audio",
"sendrecv",
"ice-ufrag:" + iceUsername,
"ice-pwd:" + icePassword,
"ice-ufrag:" + b.IceUsername,
"ice-pwd:" + b.IcePassword,
"ice-lite",
"fingerprint:sha-256 " + fingerprint,
"fingerprint:sha-256 " + b.Fingerprint,
"rtcp-mux",
"rtcp-rsize",
"rtpmap:111 opus/48000/2",
@@ -39,10 +55,10 @@ func BaseSessionDescription(iceUsername, icePassword, fingerprint string, candid
"setup:active",
"mid:video",
"sendrecv",
"ice-ufrag:" + iceUsername,
"ice-pwd:" + icePassword,
"ice-ufrag:" + b.IceUsername,
"ice-pwd:" + b.IcePassword,
"ice-lite",
"fingerprint:sha-256 " + fingerprint,
"fingerprint:sha-256 " + b.Fingerprint,
"rtcp-mux",
"rtcp-rsize",
"rtpmap:96 VP8/90000",
@@ -50,6 +66,26 @@ func BaseSessionDescription(iceUsername, icePassword, fingerprint string, candid
},
}
mediaStreamsAttribute := "msid-semantic: WMS"
for i, track := range b.Tracks {
var attributes *[]string
if track.IsAudio {
attributes = &audioMediaDescription.Attributes
} else {
attributes = &videoMediaDescription.Attributes
}
appendAttr := func(attr string) {
*attributes = append(*attributes, attr)
}
appendAttr("ssrc:" + fmt.Sprint(track.SSRC) + " cname:pion" + strconv.Itoa(i))
appendAttr("ssrc:" + fmt.Sprint(track.SSRC) + " msid:pion" + strconv.Itoa(i) + " pion" + strconv.Itoa(i))
appendAttr("ssrc:" + fmt.Sprint(track.SSRC) + " mslabel:pion" + strconv.Itoa(i))
appendAttr("ssrc:" + fmt.Sprint(track.SSRC) + " label:pion" + strconv.Itoa(i))
mediaStreamsAttribute += " pion" + strconv.Itoa(i)
}
sessionID := strconv.FormatUint(uint64(rand.Uint32())<<32+uint64(rand.Uint32()), 10)
return &SessionDescription{
ProtocolVersion: 0,
@@ -58,7 +94,7 @@ func BaseSessionDescription(iceUsername, icePassword, fingerprint string, candid
Timing: []string{"0 0"},
Attributes: []string{
"group:BUNDLE audio video",
"msid-semantic: WMS",
mediaStreamsAttribute,
},
MediaDescriptions: []*MediaDescription{
addMediaCandidates(audioMediaDescription),

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"math/rand"
"sync"
"time"
"github.com/pions/webrtc/internal/dtls"
"github.com/pions/webrtc/internal/network"
@@ -11,11 +12,15 @@ import (
"github.com/pions/webrtc/internal/util"
"github.com/pions/webrtc/pkg/ice"
"github.com/pions/webrtc/pkg/rtp"
"github.com/pions/webrtc/pkg/rtp/codecs"
"github.com/pkg/errors"
)
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
// TrackType determines the type of media we are sending receiving
type TrackType int
@@ -55,6 +60,8 @@ type RTCPeerConnection struct {
ports []*network.Port
remoteDescription *sdp.SessionDescription
localTracks []*sdp.SessionBuilderTrack
}
// Public
@@ -96,7 +103,13 @@ func (r *RTCPeerConnection) CreateOffer() error {
r.ports = append(r.ports, port)
}
r.LocalDescription = sdp.BaseSessionDescription(r.iceUsername, r.icePassword, r.tlscfg.Fingerprint(), candidates)
r.LocalDescription = sdp.BaseSessionDescription(&sdp.SessionBuilder{
IceUsername: r.iceUsername,
IcePassword: r.icePassword,
Fingerprint: r.tlscfg.Fingerprint(),
Candidates: candidates,
Tracks: r.localTracks,
})
return nil
}
@@ -105,20 +118,26 @@ func (r *RTCPeerConnection) CreateOffer() error {
// This function returns a channel to push buffers on, and an error if the channel can't be added
// Closing the channel ends this stream
func (r *RTCPeerConnection) AddTrack(mediaType TrackType) (buffers chan<- []byte, err error) {
if mediaType != VP8 {
panic("TODO Discarding packet, need media parsing")
}
trackInput := make(chan []byte, 15)
go func() {
packetizer := rtp.NewPacketizer(1500, 96, 123, &codecs.VP8Payloader{}, rtp.NewRandomSequencer())
ssrc := rand.Uint32()
sdpTrack := &sdp.SessionBuilderTrack{SSRC: ssrc}
if mediaType == Opus {
sdpTrack.IsAudio = true
}
r.localTracks = append(r.localTracks, sdpTrack)
packetizer := rtp.NewPacketizer(1500, 96, ssrc, &codecs.VP8Payloader{}, rtp.NewRandomSequencer())
for {
if mediaType == VP8 {
packets := packetizer.Packetize(<-trackInput)
for _, p := range packets {
for _, port := range r.ports {
port.Send(p)
}
packets := packetizer.Packetize(<-trackInput)
for _, p := range packets {
for _, port := range r.ports {
port.Send(p)
}
} else {
<-trackInput
fmt.Println("TODO Discarding packet, need media parsing")
}
}
}()