mirror of
https://github.com/pion/webrtc.git
synced 2025-12-24 11:51:03 +08:00
Add RTPTransceiver.Mid()
Refactor existing code for Unified Plan to ensure the same transceiver will always be associated with the media description by mid.
This commit is contained in:
@@ -1692,7 +1692,12 @@ func (pc *PeerConnection) generateUnmatchedSDP(useIdentity bool) (*sdp.SessionDe
|
||||
mediaSections = append(mediaSections, mediaSection{id: "data", data: true})
|
||||
} else {
|
||||
for _, t := range pc.GetTransceivers() {
|
||||
mediaSections = append(mediaSections, mediaSection{id: strconv.Itoa(len(mediaSections)), transceivers: []*RTPTransceiver{t}})
|
||||
mid := strconv.Itoa(len(mediaSections))
|
||||
err := t.setMid(mid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mediaSections = append(mediaSections, mediaSection{id: mid, transceivers: []*RTPTransceiver{t}})
|
||||
}
|
||||
|
||||
mediaSections = append(mediaSections, mediaSection{id: strconv.Itoa(len(mediaSections)), data: true})
|
||||
@@ -1741,43 +1746,58 @@ func (pc *PeerConnection) generateMatchedSDP(useIdentity bool, includeUnmatched
|
||||
continue
|
||||
}
|
||||
|
||||
t, localTransceivers = satisfyTypeAndDirection(kind, direction, localTransceivers)
|
||||
mediaTransceivers := []*RTPTransceiver{t}
|
||||
switch pc.configuration.SDPSemantics {
|
||||
case SDPSemanticsUnifiedPlanWithFallback:
|
||||
// If no match, process as unified-plan
|
||||
if !detectedPlanB {
|
||||
break
|
||||
}
|
||||
// If there was a match, fall through to plan-b
|
||||
fallthrough
|
||||
case SDPSemanticsPlanB:
|
||||
sdpSemantics := pc.configuration.SDPSemantics
|
||||
|
||||
switch {
|
||||
case sdpSemantics == SDPSemanticsPlanB || sdpSemantics == SDPSemanticsUnifiedPlanWithFallback && detectedPlanB:
|
||||
if !detectedPlanB {
|
||||
return nil, &rtcerr.TypeError{Err: ErrIncorrectSDPSemantics}
|
||||
}
|
||||
// If we're responding to a plan-b offer, then we should try to fill up this
|
||||
// media entry with all matching local transceivers
|
||||
mediaTransceivers := []*RTPTransceiver{}
|
||||
for {
|
||||
// keep going until we can't get any more
|
||||
t, localTransceivers = satisfyTypeAndDirection(kind, direction, localTransceivers)
|
||||
if t.Direction() == RTPTransceiverDirectionInactive {
|
||||
if t == nil {
|
||||
if len(mediaTransceivers) == 0 {
|
||||
t = &RTPTransceiver{kind: kind}
|
||||
t.setDirection(RTPTransceiverDirectionInactive)
|
||||
mediaTransceivers = append(mediaTransceivers, t)
|
||||
}
|
||||
break
|
||||
}
|
||||
mediaTransceivers = append(mediaTransceivers, t)
|
||||
}
|
||||
case SDPSemanticsUnifiedPlan:
|
||||
mediaSections = append(mediaSections, mediaSection{id: midValue, transceivers: mediaTransceivers})
|
||||
case sdpSemantics == SDPSemanticsUnifiedPlan || sdpSemantics == SDPSemanticsUnifiedPlanWithFallback:
|
||||
if detectedPlanB {
|
||||
return nil, &rtcerr.TypeError{Err: ErrIncorrectSDPSemantics}
|
||||
}
|
||||
t, localTransceivers = findByMid(midValue, localTransceivers)
|
||||
if t == nil {
|
||||
t, localTransceivers = satisfyTypeAndDirection(kind, direction, localTransceivers)
|
||||
}
|
||||
if t == nil {
|
||||
t = pc.newRTPTransceiver(nil, nil, RTPTransceiverDirectionInactive, kind)
|
||||
}
|
||||
if t.Mid() == "" {
|
||||
_ = t.setMid(midValue)
|
||||
}
|
||||
mediaTransceivers := []*RTPTransceiver{t}
|
||||
mediaSections = append(mediaSections, mediaSection{id: midValue, transceivers: mediaTransceivers})
|
||||
}
|
||||
|
||||
mediaSections = append(mediaSections, mediaSection{id: midValue, transceivers: mediaTransceivers})
|
||||
}
|
||||
|
||||
// If we are offering also include unmatched local transceivers
|
||||
if !detectedPlanB && includeUnmatched {
|
||||
for _, t := range localTransceivers {
|
||||
mediaSections = append(mediaSections, mediaSection{id: strconv.Itoa(len(mediaSections)), transceivers: []*RTPTransceiver{t}})
|
||||
mid := strconv.Itoa(len(mediaSections))
|
||||
err := t.setMid(mid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mediaSections = append(mediaSections, mediaSection{id: mid, transceivers: []*RTPTransceiver{t}})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -403,20 +403,20 @@ func TestPeerConnection_satisfyTypeAndDirection(t *testing.T) {
|
||||
[]RTPCodecType{RTPCodecTypeVideo},
|
||||
[]RTPTransceiverDirection{RTPTransceiverDirectionSendrecv},
|
||||
[]*RTPTransceiver{createTransceiver(RTPCodecTypeAudio, RTPTransceiverDirectionSendrecv)},
|
||||
[]*RTPTransceiver{createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionInactive)},
|
||||
[]*RTPTransceiver{nil},
|
||||
},
|
||||
{
|
||||
"No local Transceivers, every remote should get an inactive",
|
||||
"No local Transceivers, every remote should get nil",
|
||||
[]RTPCodecType{RTPCodecTypeVideo, RTPCodecTypeAudio, RTPCodecTypeVideo, RTPCodecTypeVideo},
|
||||
[]RTPTransceiverDirection{RTPTransceiverDirectionSendrecv, RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendonly, RTPTransceiverDirectionInactive},
|
||||
|
||||
[]*RTPTransceiver{},
|
||||
|
||||
[]*RTPTransceiver{
|
||||
createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionInactive),
|
||||
createTransceiver(RTPCodecTypeAudio, RTPTransceiverDirectionInactive),
|
||||
createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionInactive),
|
||||
createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionInactive),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -228,12 +228,12 @@ func TestPeerConnection_Media_Shutdown(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeAudio, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
_, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeAudio, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -288,13 +288,13 @@ func TestPeerConnection_Media_Shutdown(t *testing.T) {
|
||||
}
|
||||
|
||||
receivers := pc.GetReceivers()
|
||||
if len(receivers) != 1 {
|
||||
t.Errorf("Each PeerConnection should have one RTPReceivers, we have %d", len(receivers))
|
||||
if len(receivers) != 2 {
|
||||
t.Errorf("Each PeerConnection should have two RTPReceivers, we have %d", len(receivers))
|
||||
}
|
||||
|
||||
transceivers := pc.GetTransceivers()
|
||||
if len(transceivers) != 1 {
|
||||
t.Errorf("Each PeerConnection should have one RTPTransceivers, we have %d", len(transceivers))
|
||||
if len(transceivers) != 2 {
|
||||
t.Errorf("Each PeerConnection should have two RTPTransceivers, we have %d", len(transceivers))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
// RTPTransceiver represents a combination of an RTPSender and an RTPReceiver that share a common mid.
|
||||
type RTPTransceiver struct {
|
||||
mid atomic.Value // string
|
||||
sender atomic.Value // *RTPSender
|
||||
receiver atomic.Value // *RTPReceiver
|
||||
direction atomic.Value // RTPTransceiverDirection
|
||||
@@ -39,6 +40,28 @@ func (t *RTPTransceiver) Receiver() *RTPReceiver {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setMid sets the RTPTransceiver's mid. If it was already set, will return an error.
|
||||
func (t *RTPTransceiver) setMid(mid string) error {
|
||||
if currentMid := t.Mid(); currentMid != "" {
|
||||
return fmt.Errorf("cannot change transceiver mid from: %s to %s", currentMid, mid)
|
||||
}
|
||||
t.mid.Store(mid)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mid gets the Transceiver's mid value. When not already set, this value will be set in CreateOffer or CreateAnswer.
|
||||
func (t *RTPTransceiver) Mid() string {
|
||||
if v := t.mid.Load(); v != nil {
|
||||
return v.(string)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Kind returns RTPTransceiver's kind.
|
||||
func (t *RTPTransceiver) Kind() RTPCodecType {
|
||||
return t.kind
|
||||
}
|
||||
|
||||
// Direction returns the RTPTransceiver's current direction
|
||||
func (t *RTPTransceiver) Direction() RTPTransceiverDirection {
|
||||
return t.direction.Load().(RTPTransceiverDirection)
|
||||
@@ -90,6 +113,16 @@ func (t *RTPTransceiver) setSendingTrack(track *Track) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findByMid(mid string, localTransceivers []*RTPTransceiver) (*RTPTransceiver, []*RTPTransceiver) {
|
||||
for i, t := range localTransceivers {
|
||||
if t.Mid() == mid {
|
||||
return t, append(localTransceivers[:i], localTransceivers[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, localTransceivers
|
||||
}
|
||||
|
||||
// Given a direction+type pluck a transceiver from the passed list
|
||||
// if no entry satisfies the requested type+direction return a inactive Transceiver
|
||||
func satisfyTypeAndDirection(remoteKind RTPCodecType, remoteDirection RTPTransceiverDirection, localTransceivers []*RTPTransceiver) (*RTPTransceiver, []*RTPTransceiver) {
|
||||
@@ -109,19 +142,11 @@ func satisfyTypeAndDirection(remoteKind RTPCodecType, remoteDirection RTPTransce
|
||||
for _, possibleDirection := range getPreferredDirections() {
|
||||
for i := range localTransceivers {
|
||||
t := localTransceivers[i]
|
||||
if t.kind != remoteKind || possibleDirection != t.Direction() {
|
||||
continue
|
||||
if t.Mid() == "" && t.kind == remoteKind && possibleDirection == t.Direction() {
|
||||
return t, append(localTransceivers[:i], localTransceivers[i+1:]...)
|
||||
}
|
||||
|
||||
return t, append(localTransceivers[:i], localTransceivers[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
d := atomic.Value{}
|
||||
d.Store(RTPTransceiverDirectionInactive)
|
||||
|
||||
return &RTPTransceiver{
|
||||
kind: remoteKind,
|
||||
direction: d,
|
||||
}, localTransceivers
|
||||
return nil, localTransceivers
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user