start work webrtc adapter
This commit is contained in:
		
							
								
								
									
										219
									
								
								format/webrtc/adapter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								format/webrtc/adapter.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,219 @@ | ||||
| package webrtc | ||||
|  | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/deepch/vdk/av" | ||||
| 	"github.com/deepch/vdk/codec/h264parser" | ||||
| 	"github.com/pion/webrtc/v3" | ||||
| 	"github.com/pion/webrtc/v3/pkg/media" | ||||
| 	"math/rand" | ||||
| ) | ||||
|  | ||||
| type Muxer struct { | ||||
| 	streams map[int8]*Stream | ||||
| } | ||||
| type Stream struct { | ||||
| 	codec av.CodecData | ||||
| 	track *webrtc.Track | ||||
| } | ||||
| func NewMuxer() *Muxer { | ||||
| 	return &Muxer{streams: make(map[int8]*Stream)} | ||||
| } | ||||
| func (self *Muxer) WriteHeader(streams []av.CodecData, sdp64 string) (string, error) { | ||||
| 	if len(streams) == 0 { | ||||
| 		return "",errors.New("No Stream Forund") | ||||
| 	} | ||||
| 	mediaEngine := webrtc.MediaEngine{} | ||||
| 	sdpB, err := base64.StdEncoding.DecodeString(sdp64) | ||||
| 	if err != nil { | ||||
| 		return "",err | ||||
| 	} | ||||
| 	offer := webrtc.SessionDescription{ | ||||
| 		Type: webrtc.SDPTypeOffer, | ||||
| 		SDP:  string(sdpB), | ||||
| 	} | ||||
| 	if err = mediaEngine.PopulateFromSDP(offer); err != nil { | ||||
| 		return "",err | ||||
| 	} | ||||
| 	api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine)) | ||||
| 	peerConnection, err := api.NewPeerConnection(webrtc.Configuration{ | ||||
| 		ICEServers: []webrtc.ICEServer{ | ||||
| 			{ | ||||
| 				URLs: []string{"stun:stun.l.google.com:19302"}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return "",err | ||||
| 	} | ||||
| 	for i, i2 := range streams { | ||||
| 		var track *webrtc.Track | ||||
| 		if i2.Type().IsVideo() { | ||||
| 			track, err = peerConnection.NewTrack(getPayloadType(mediaEngine, webrtc.RTPCodecTypeVideo, i2.Type().String()), rand.Uint32(), "video", "pion") | ||||
| 			if err != nil { | ||||
| 				return "",err | ||||
| 			} | ||||
| 		} else if i2.Type().IsAudio() { | ||||
| 			track, err = peerConnection.NewTrack(getPayloadType(mediaEngine, webrtc.RTPCodecTypeAudio, i2.Type().String()), rand.Uint32(), "audio", "pion") | ||||
| 			if err != nil { | ||||
| 				return "",err | ||||
| 			} | ||||
| 		} | ||||
| 		_, err = peerConnection.AddTransceiverFromTrack(track, | ||||
| 			webrtc.RtpTransceiverInit{ | ||||
| 				Direction: webrtc.RTPTransceiverDirectionSendonly, | ||||
| 			}, | ||||
| 		) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		_, err = peerConnection.AddTrack(track); | ||||
| 		if err != nil { | ||||
| 			return "",err | ||||
| 		} | ||||
| 		self.streams[int8(i)] = &Stream{track: track , codec: i2} | ||||
| 	} | ||||
| 	//iceConnectedCtx, iceConnectedCtxCancel := context.WithCancel(context.Background()) | ||||
| 	peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { | ||||
| 		fmt.Printf("Connection State has changed %s \n", connectionState.String()) | ||||
| 		if connectionState == webrtc.ICEConnectionStateConnected { | ||||
| 		//	iceConnectedCtxCancel() | ||||
| 		} | ||||
| 	}) | ||||
| 	if err = peerConnection.SetRemoteDescription(offer); err != nil { | ||||
| 		return "",err | ||||
| 	} | ||||
| 	answer, err := peerConnection.CreateAnswer(nil) | ||||
| 	if err != nil { | ||||
| 		return "",err | ||||
| 	} | ||||
| 	//gatherComplete := webrtc.GatheringCompletePromise(peerConnection) | ||||
| 	if err = peerConnection.SetLocalDescription(answer); err != nil { | ||||
| 		return "",err | ||||
| 	} | ||||
| 	//<-gatherComplete | ||||
|  | ||||
|  | ||||
| 	return  base64.StdEncoding.EncodeToString([]byte(answer.SDP)), nil | ||||
| } | ||||
| func (self *Muxer) WritePacket(pkt av.Packet) (err error) { | ||||
| 	if tmp, ok := self.streams[pkt.Idx]; ok { | ||||
| 		switch tmp.codec.Type() { | ||||
| 		case av.H264: | ||||
| 			codec := tmp.codec.(h264parser.CodecData) | ||||
| 			if pkt.IsKeyFrame { | ||||
| 				pkt.Data = append([]byte("\000\000\001"+string(codec.SPS())+"\000\000\001"+string(codec.PPS())+"\000\000\001"), pkt.Data[4:]...) | ||||
|  | ||||
| 			} else { | ||||
| 				pkt.Data = pkt.Data[4:] | ||||
| 			} | ||||
| 			return tmp.track.WriteSample(media.Sample{Data: pkt.Data, Samples: 90000}) | ||||
| 		default: | ||||
| 			return errors.New("Media Track Not Found") | ||||
| 		} | ||||
| 	} | ||||
| 	return errors.New("Media Track Not Found") | ||||
| } | ||||
| func getPayloadType(m webrtc.MediaEngine, codecType webrtc.RTPCodecType, codecName string) uint8 { | ||||
| 	for _, codec := range m.GetCodecsByKind(codecType) { | ||||
| 		if codec.Name == codecName { | ||||
| 			return codec.PayloadType | ||||
| 		} | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("Remote peer does not support %s", codecName)) | ||||
| } | ||||
|  | ||||
| /* | ||||
| //MuxerRTC muxer | ||||
| type MuxerRTC struct { | ||||
| 	Peer  *webrtc.PeerConnection | ||||
| 	Muxer string | ||||
| 	Track []*webrtc.Track | ||||
| } | ||||
|  | ||||
| //NewWebRT adapter | ||||
| func NewWebRT() *MuxerRTC { | ||||
| 	peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{ | ||||
| 		ICEServers: []webrtc.ICEServer{ | ||||
| 			{ | ||||
| 				URLs: []string{"stun:stun.l.google.com:19302"}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	log.Println(peerConnection) | ||||
| 	return &MuxerRTC{Peer: peerConnection} | ||||
| } | ||||
|  | ||||
| //AddTrackVideo video | ||||
| func (element *MuxerRTC) AddTrackVideo() error { | ||||
| 	Track, err := element.Peer.NewTrack(webrtc.DefaultPayloadTypeH264, rand.Uint32(), "video", "video") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = element.Peer.AddTrack(Track) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	element.Track = append(element.Track, Track) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //AddTrackAudio audio | ||||
| func (element *MuxerRTC) AddTrackAudio() error { | ||||
| 	Track, err := element.Peer.NewTrack(webrtc.DefaultPayloadTypePCMA, rand.Uint32(), "audio", "audio") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = element.Peer.AddTrack(Track) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = element.Peer.AddTransceiverFromTrack(Track, webrtc.RtpTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendonly}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	element.Track = append(element.Track, Track) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //CreateAnswer func | ||||
| func (element *MuxerRTC) CreateAnswer(data string) ([]byte, error) { | ||||
| 	//	log.Println(string(data)) | ||||
|  | ||||
| 	//	sd, err := base64.StdEncoding.DecodeString(data) | ||||
| 	//	if err != nil { | ||||
| 	//		log.Println("DecodeString", err) | ||||
| 	//		return nil, err | ||||
| 	//	} | ||||
| 	offer := webrtc.SessionDescription{ | ||||
| 		Type: webrtc.SDPTypeOffer, | ||||
| 		SDP:  data, | ||||
| 	} | ||||
| 	if err := element.Peer.SetRemoteDescription(offer); err != nil { | ||||
| 		log.Println("SetRemoteDescription", err) | ||||
|  | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	answer, err := element.Peer.CreateAnswer(nil) | ||||
| 	if err != nil { | ||||
| 		log.Println("CreateAnswer", err) | ||||
|  | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return []byte(answer.SDP), nil | ||||
| } | ||||
|  | ||||
| //WritePacket to stream | ||||
| func (element *MuxerRTC) WritePacket(id int, data []byte, smaple uint32) error { | ||||
| 	err := element.Track[id].WriteSample(media.Sample{Data: data, Samples: smaple}) | ||||
| 	return err | ||||
| } | ||||
| func (element *MuxerRTC) Close() { | ||||
| 	return | ||||
| } | ||||
| */ | ||||
		Reference in New Issue
	
	Block a user
	 Andrey Semochkin
					Andrey Semochkin