mirror of
				https://github.com/pion/webrtc.git
				synced 2025-10-31 10:46:39 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			221 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package webrtc
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"math/rand"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/pions/webrtc/internal/dtls"
 | |
| 	"github.com/pions/webrtc/internal/network"
 | |
| 	"github.com/pions/webrtc/internal/sdp"
 | |
| 	"github.com/pions/webrtc/pkg/ice"
 | |
| 	"github.com/pions/webrtc/pkg/rtp"
 | |
| 
 | |
| 	"github.com/pkg/errors"
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	rand.Seed(time.Now().UTC().UnixNano())
 | |
| }
 | |
| 
 | |
| // RTCPeerConnectionState indicates the state of the peer connection
 | |
| type RTCPeerConnectionState int
 | |
| 
 | |
| const (
 | |
| 
 | |
| 	// RTCPeerConnectionStateNew indicates some of the ICE or DTLS transports are in status new
 | |
| 	RTCPeerConnectionStateNew RTCPeerConnectionState = iota + 1
 | |
| 
 | |
| 	// RTCPeerConnectionStateConnecting indicates some of the ICE or DTLS transports are in status connecting or checking
 | |
| 	RTCPeerConnectionStateConnecting
 | |
| 
 | |
| 	// RTCPeerConnectionStateConnected indicates all of the ICE or DTLS transports are in status connected or completed
 | |
| 	RTCPeerConnectionStateConnected
 | |
| 
 | |
| 	// RTCPeerConnectionStateDisconnected indicates some of the ICE or DTLS transports are in status disconnected
 | |
| 	RTCPeerConnectionStateDisconnected
 | |
| 
 | |
| 	// RTCPeerConnectionStateFailed indicates some of the ICE or DTLS transports are in status failed
 | |
| 	RTCPeerConnectionStateFailed
 | |
| 
 | |
| 	// RTCPeerConnectionStateClosed indicates the peer connection is closed
 | |
| 	RTCPeerConnectionStateClosed
 | |
| )
 | |
| 
 | |
| func (t RTCPeerConnectionState) String() string {
 | |
| 	switch t {
 | |
| 	case RTCPeerConnectionStateNew:
 | |
| 		return "new"
 | |
| 	case RTCPeerConnectionStateConnecting:
 | |
| 		return "connecting"
 | |
| 	case RTCPeerConnectionStateConnected:
 | |
| 		return "connected"
 | |
| 	case RTCPeerConnectionStateDisconnected:
 | |
| 		return "disconnected"
 | |
| 	case RTCPeerConnectionStateFailed:
 | |
| 		return "failed"
 | |
| 	case RTCPeerConnectionStateClosed:
 | |
| 		return "closed"
 | |
| 	default:
 | |
| 		return "Unknown"
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // RTCPeerConnection represents a WebRTC connection between itself and a remote peer
 | |
| type RTCPeerConnection struct {
 | |
| 	// ICE
 | |
| 	OnICEConnectionStateChange func(iceConnectionState ice.ConnectionState)
 | |
| 
 | |
| 	config RTCConfiguration
 | |
| 	tlscfg *dtls.TLSCfg
 | |
| 
 | |
| 	// ICE: TODO: Move to ICEAgent
 | |
| 	iceAgent           *ice.Agent
 | |
| 	iceState           ice.ConnectionState
 | |
| 	iceGatheringState  ice.GatheringState
 | |
| 	iceConnectionState ice.ConnectionState
 | |
| 
 | |
| 	portsLock sync.RWMutex
 | |
| 	ports     []*network.Port
 | |
| 
 | |
| 	// Signaling
 | |
| 	// pendingLocalDescription *RTCSessionDescription
 | |
| 	// currentLocalDescription *RTCSessionDescription
 | |
| 	LocalDescription *sdp.SessionDescription
 | |
| 
 | |
| 	// pendingRemoteDescription *RTCSessionDescription
 | |
| 	currentRemoteDescription *RTCSessionDescription
 | |
| 	remoteDescription        *sdp.SessionDescription
 | |
| 
 | |
| 	idpLoginURL *string
 | |
| 
 | |
| 	IsClosed          bool
 | |
| 	NegotiationNeeded bool
 | |
| 
 | |
| 	// lastOffer  string
 | |
| 	// lastAnswer string
 | |
| 
 | |
| 	signalingState  RTCSignalingState
 | |
| 	connectionState RTCPeerConnectionState
 | |
| 
 | |
| 	// Media
 | |
| 	mediaEngine     *MediaEngine
 | |
| 	rtpTransceivers []*RTCRtpTransceiver
 | |
| 	Ontrack         func(*RTCTrack)
 | |
| }
 | |
| 
 | |
| // Public
 | |
| 
 | |
| // New creates a new RTCPeerConfiguration with the provided configuration
 | |
| func New(config RTCConfiguration) (*RTCPeerConnection, error) {
 | |
| 	r := &RTCPeerConnection{
 | |
| 		config:             config,
 | |
| 		signalingState:     RTCSignalingStateStable,
 | |
| 		iceAgent:           ice.NewAgent(),
 | |
| 		iceGatheringState:  ice.GatheringStateNew,
 | |
| 		iceConnectionState: ice.ConnectionStateNew,
 | |
| 		connectionState:    RTCPeerConnectionStateNew,
 | |
| 		mediaEngine:        DefaultMediaEngine,
 | |
| 	}
 | |
| 	err := r.SetConfiguration(config)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	r.tlscfg = dtls.NewTLSCfg()
 | |
| 
 | |
| 	return r, nil
 | |
| }
 | |
| 
 | |
| // SetMediaEngine allows overwriting the default media engine used by the RTCPeerConnection
 | |
| // This enables RTCPeerConnection with support for different codecs
 | |
| func (r *RTCPeerConnection) SetMediaEngine(m *MediaEngine) {
 | |
| 	r.mediaEngine = m
 | |
| }
 | |
| 
 | |
| // SetIdentityProvider is used to configure an identity provider to generate identity assertions
 | |
| func (r *RTCPeerConnection) SetIdentityProvider(provider string) error {
 | |
| 	panic("TODO SetIdentityProvider")
 | |
| }
 | |
| 
 | |
| // Close ends the RTCPeerConnection
 | |
| func (r *RTCPeerConnection) Close() error {
 | |
| 	r.portsLock.Lock()
 | |
| 	defer r.portsLock.Unlock()
 | |
| 
 | |
| 	// Walk all ports remove and close them
 | |
| 	for _, p := range r.ports {
 | |
| 		if err := p.Close(); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	r.ports = nil
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Private
 | |
| func (r *RTCPeerConnection) generateChannel(ssrc uint32, payloadType uint8) (buffers chan<- *rtp.Packet) {
 | |
| 	if r.Ontrack == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	sdpCodec, err := r.remoteDescription.GetCodecForPayloadType(payloadType)
 | |
| 	if err != nil {
 | |
| 		fmt.Printf("No codec could be found in RemoteDescription for payloadType %d \n", payloadType)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	codec, err := r.mediaEngine.getCodecSDP(sdpCodec)
 | |
| 	if err != nil {
 | |
| 		fmt.Printf("Codec %s in not registered\n", sdpCodec)
 | |
| 	}
 | |
| 
 | |
| 	bufferTransport := make(chan *rtp.Packet, 15)
 | |
| 
 | |
| 	track := &RTCTrack{
 | |
| 		PayloadType: payloadType,
 | |
| 		Kind:        codec.Type,
 | |
| 		ID:          "0", // TODO extract from remoteDescription
 | |
| 		Label:       "",  // TODO extract from remoteDescription
 | |
| 		Ssrc:        ssrc,
 | |
| 		Codec:       codec,
 | |
| 		Packets:     bufferTransport,
 | |
| 	}
 | |
| 
 | |
| 	// TODO: Register the receiving Track
 | |
| 
 | |
| 	go r.Ontrack(track)
 | |
| 	return bufferTransport
 | |
| }
 | |
| 
 | |
| // Private
 | |
| func (r *RTCPeerConnection) iceStateChange(p *network.Port) {
 | |
| 	updateAndNotify := func(newState ice.ConnectionState) {
 | |
| 		if r.OnICEConnectionStateChange != nil && r.iceState != newState {
 | |
| 			r.OnICEConnectionStateChange(newState)
 | |
| 		}
 | |
| 		r.iceState = newState
 | |
| 	}
 | |
| 
 | |
| 	if p.ICEState == ice.ConnectionStateFailed {
 | |
| 		if err := p.Close(); err != nil {
 | |
| 			fmt.Println(errors.Wrap(err, "Failed to close Port when ICE went to failed"))
 | |
| 		}
 | |
| 
 | |
| 		r.portsLock.Lock()
 | |
| 		defer r.portsLock.Unlock()
 | |
| 		for i := len(r.ports) - 1; i >= 0; i-- {
 | |
| 			if r.ports[i] == p {
 | |
| 				r.ports = append(r.ports[:i], r.ports[i+1:]...)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if len(r.ports) == 0 {
 | |
| 			updateAndNotify(ice.ConnectionStateDisconnected)
 | |
| 		}
 | |
| 	} else {
 | |
| 		updateAndNotify(ice.ConnectionStateConnected)
 | |
| 	}
 | |
| }
 | 
