mirror of
				https://github.com/pion/webrtc.git
				synced 2025-10-31 10:46:39 +08:00 
			
		
		
		
	 1be721e5fa
			
		
	
	1be721e5fa
	
	
	
		
			
			Candidates are now generated with real priority, and actually pay attention to the inbound messages. Next we just need to pluck use-candidate + ice-controlling from the messages and we will have a full-ice implementation (but we are not controlling) We then need to add timers to alert when the peer goes away OR when we need to send again.
		
			
				
	
	
		
			219 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package webrtc
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"math/rand"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/pions/webrtc/internal/network"
 | |
| 	"github.com/pions/webrtc/internal/sdp"
 | |
| 	"github.com/pions/webrtc/pkg/ice"
 | |
| 	"github.com/pions/webrtc/pkg/rtp"
 | |
| )
 | |
| 
 | |
| 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 {
 | |
| 	sync.RWMutex
 | |
| 
 | |
| 	// ICE
 | |
| 	OnICEConnectionStateChange func(iceConnectionState ice.ConnectionState)
 | |
| 
 | |
| 	config RTCConfiguration
 | |
| 
 | |
| 	networkManager *network.Manager
 | |
| 
 | |
| 	// 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)
 | |
| 
 | |
| 	// DataChannels
 | |
| 	dataChannels  map[uint16]*RTCDataChannel
 | |
| 	Ondatachannel func(*RTCDataChannel)
 | |
| }
 | |
| 
 | |
| // Public
 | |
| 
 | |
| // New creates a new RTCPeerConfiguration with the provided configuration
 | |
| func New(config RTCConfiguration) (*RTCPeerConnection, error) {
 | |
| 	r := &RTCPeerConnection{
 | |
| 		config:          config,
 | |
| 		signalingState:  RTCSignalingStateStable,
 | |
| 		connectionState: RTCPeerConnectionStateNew,
 | |
| 		mediaEngine:     DefaultMediaEngine,
 | |
| 		dataChannels:    make(map[uint16]*RTCDataChannel),
 | |
| 	}
 | |
| 	var err error
 | |
| 	r.networkManager, err = network.NewManager(r.generateChannel, r.dataChannelEventHandler, r.iceStateChange)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if err := r.SetConfiguration(config); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	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.networkManager.Close()
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| /* Everything below is 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
 | |
| }
 | |
| 
 | |
| func (r *RTCPeerConnection) iceStateChange(newState ice.ConnectionState) {
 | |
| 	r.Lock()
 | |
| 	defer r.Unlock()
 | |
| 
 | |
| 	// if r.OnICEConnectionStateChange != nil && r.iceState != newState {
 | |
| 	// 	r.OnICEConnectionStateChange(newState)
 | |
| 	// }
 | |
| 	// r.iceState = newState
 | |
| }
 | |
| 
 | |
| func (r *RTCPeerConnection) dataChannelEventHandler(e network.DataChannelEvent) {
 | |
| 	r.Lock()
 | |
| 	defer r.Unlock()
 | |
| 
 | |
| 	switch event := e.(type) {
 | |
| 	case *network.DataChannelCreated:
 | |
| 		newDataChannel := &RTCDataChannel{ID: event.StreamIdentifier(), Label: event.Label, rtcPeerConnection: r}
 | |
| 		r.dataChannels[e.StreamIdentifier()] = newDataChannel
 | |
| 		if r.Ondatachannel != nil {
 | |
| 			go r.Ondatachannel(newDataChannel)
 | |
| 		} else {
 | |
| 			fmt.Println("Ondatachannel is unset, discarding message")
 | |
| 		}
 | |
| 	case *network.DataChannelMessage:
 | |
| 		if datachannel, ok := r.dataChannels[e.StreamIdentifier()]; ok {
 | |
| 			datachannel.RLock()
 | |
| 			defer datachannel.RUnlock()
 | |
| 
 | |
| 			if datachannel.Onmessage != nil {
 | |
| 				go datachannel.Onmessage(event.Payload)
 | |
| 			} else {
 | |
| 				fmt.Printf("Onmessage has not been set for Datachannel %s %d \n", datachannel.Label, e.StreamIdentifier())
 | |
| 			}
 | |
| 		} else {
 | |
| 			fmt.Printf("No datachannel found for streamIdentifier %d \n", e.StreamIdentifier())
 | |
| 
 | |
| 		}
 | |
| 	default:
 | |
| 		fmt.Printf("Unhandled DataChannelEvent %v \n", event)
 | |
| 	}
 | |
| }
 |