diff --git a/main.go b/main.go index 5b0633b..b267f6e 100644 --- a/main.go +++ b/main.go @@ -48,10 +48,6 @@ var config struct { // port int // } -var m MediaEngine -var api *API -var SSRC uint32 -var SSRCMap = make(map[string]uint32) var ssrcLock sync.Mutex var playWaitList WaitList @@ -75,15 +71,7 @@ func (wl *WaitList) Get(k string) *WebRTC { return wl.m[k] } func init() { - m.RegisterCodec(NewRTPCodec(RTPCodecTypeVideo, - H264, - 90000, - 0, - "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f", - DefaultPayloadTypeH264, - new(avformat.H264))) - //m.RegisterCodec(NewRTPPCMUCodec(DefaultPayloadTypePCMU, 8000)) - api = NewAPI(WithMediaEngine(m)) + InstallPlugin(&PluginConfig{ Config: &config, Name: "WebRTC", @@ -97,11 +85,52 @@ type WebRTC struct { *PeerConnection RemoteAddr string videoTrack *Track + m MediaEngine + api *API // codecs.H264Packet // *os.File } func (rtc *WebRTC) Play(streamPath string) bool { + var sub Subscriber + sub.ID = rtc.RemoteAddr + sub.Type = "WebRTC" + var lastTimeStamp uint32 + sub.OnData = func(packet *avformat.SendPacket) error { + if packet.Type == avformat.FLV_TAG_TYPE_AUDIO { + return nil + } + if packet.IsSequence { + } else { + var s uint32 + if lastTimeStamp > 0 { + s = packet.Timestamp - lastTimeStamp + } + if packet.IsKeyFrame { + rtc.videoTrack.WriteSample(media.Sample{ + Data: sub.SPS, + Samples: 0, + }) + rtc.videoTrack.WriteSample(media.Sample{ + Data: sub.PPS, + Samples: 0, + }) + } + for payload := packet.Payload[5:]; len(payload) > 4; { + var naulLen = int(util.BigEndian.Uint32(payload)) + payload = payload[4:] + rtc.videoTrack.WriteSample(media.Sample{ + Data: payload[:naulLen], + Samples: s * 90, + }) + s = 0 + payload = payload[naulLen:] + } + } + lastTimeStamp = packet.Timestamp + return nil + } + // go sub.Subscribe(streamPath) rtc.OnICEConnectionStateChange(func(connectionState ICEConnectionState) { Printf("%s Connection State has changed %s ", streamPath, connectionState.String()) switch connectionState { @@ -110,51 +139,23 @@ func (rtc *WebRTC) Play(streamPath string) bool { rtc.Stream.Close() } case ICEConnectionStateConnected: - var sub Subscriber - sub.ID = rtc.RemoteAddr - sub.Type = "WebRTC" - var lastTimeStamp uint32 - sub.OnData = func(packet *avformat.SendPacket) error { - if packet.Type == avformat.FLV_TAG_TYPE_AUDIO { - return nil - } - if packet.IsSequence { - } else { - var s uint32 - if lastTimeStamp > 0 { - s = packet.Timestamp - lastTimeStamp - } - if packet.IsKeyFrame { - rtc.videoTrack.WriteSample(media.Sample{ - Data: sub.SPS, - Samples: 0, - }) - rtc.videoTrack.WriteSample(media.Sample{ - Data: sub.PPS, - Samples: 0, - }) - } - for payload := packet.Payload[5:]; len(payload) > 4; { - var naulLen = int(util.BigEndian.Uint32(payload)) - payload = payload[4:] - rtc.videoTrack.WriteSample(media.Sample{ - Data: payload[:naulLen], - Samples: s * 90, - }) - s = 0 - payload = payload[naulLen:] - } - } - lastTimeStamp = packet.Timestamp - return nil - } - go sub.Subscribe(streamPath) + //rtc.videoTrack = rtc.GetSenders()[0].Track() + sub.Subscribe(streamPath) } }) return true } func (rtc *WebRTC) Publish(streamPath string) bool { - peerConnection, err := api.NewPeerConnection(Configuration{ + rtc.m.RegisterCodec(NewRTPCodec(RTPCodecTypeVideo, + H264, + 90000, + 0, + "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f", + DefaultPayloadTypeH264, + new(avformat.H264))) + //m.RegisterCodec(NewRTPPCMUCodec(DefaultPayloadTypePCMU, 8000)) + rtc.api = NewAPI(WithMediaEngine(rtc.m)) + peerConnection, err := rtc.api.NewPeerConnection(Configuration{ ICEServers: []ICEServer{ { URLs: config.ICEServers, @@ -233,79 +234,84 @@ func (rtc *WebRTC) GetAnswer(localSdp SessionDescription) ([]byte, error) { func run() { http.HandleFunc("/webrtc/play", func(w http.ResponseWriter, r *http.Request) { streamPath := r.URL.Query().Get("streamPath") - offer := SessionDescription{} + var offer SessionDescription bytes, err := ioutil.ReadAll(r.Body) err = json.Unmarshal(bytes, &offer) + defer func() { + if err != nil { + Println(err) + fmt.Fprint(w, err) + return + } + }() if err != nil { - Println(err) return } if rtc := playWaitList.Get(streamPath); rtc != nil { if err := rtc.SetRemoteDescription(offer); err != nil { - Println(err) return } - if rtc.Play(streamPath) { - w.Write([]byte(`success`)) - } else { - w.Write([]byte(`{"errmsg":"bad name"}`)) - } + rtc.Play(streamPath) } else { - w.Write([]byte(`{"errmsg":"bad name"}`)) + w.Write([]byte("bad name")) } }) http.HandleFunc("/webrtc/preparePlay", func(w http.ResponseWriter, r *http.Request) { streamPath := r.URL.Query().Get("streamPath") + pli := "42001f" + if stream := FindStream(streamPath); stream != nil { + pli = fmt.Sprintf("%x", stream.SPS[1:4]) + } rtc := new(WebRTC) - peerConnection, err := api.NewPeerConnection(Configuration{ + rtc.m.RegisterCodec(NewRTPCodec(RTPCodecTypeVideo, + H264, + 90000, + 0, + "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="+pli, + DefaultPayloadTypeH264, + new(avformat.H264))) + //m.RegisterCodec(NewRTPPCMUCodec(DefaultPayloadTypePCMU, 8000)) + rtc.api = NewAPI(WithMediaEngine(rtc.m)) + peerConnection, err := rtc.api.NewPeerConnection(Configuration{ ICEServers: []ICEServer{ { URLs: config.ICEServers, }, }, }) - if _, err = peerConnection.AddTransceiverFromKind(RTPCodecTypeVideo); err != nil { + rtc.PeerConnection = peerConnection + rtc.OnICECandidate(func(ice *ICECandidate) { + if ice != nil { + println(ice.ToJSON().Candidate) + } + }) + if r, err := peerConnection.AddTransceiverFromKind(RTPCodecTypeVideo); err == nil { + rtc.videoTrack = r.Sender().Track() + } else { + Println(err) + } + defer func() { if err != nil { Println(err) + fmt.Fprintf(w, `{"errmsg":"%s"}`, err.Error()) return } - } + }() if err != nil { return } - - rtc.PeerConnection = peerConnection - // Create a video track, using the same SSRC as the incoming RTP Packet - ssrcLock.Lock() - if _, ok := SSRCMap[streamPath]; !ok { - SSRC++ - SSRCMap[streamPath] = SSRC - } - ssrcLock.Unlock() - videoTrack, err := rtc.NewTrack(DefaultPayloadTypeH264, SSRC, "video", "monibuca") - if err != nil { - Println(err) - return - } - if _, err = rtc.AddTrack(videoTrack); err != nil { - Println(err) - return - } - rtc.videoTrack = videoTrack playWaitList.Set(streamPath, rtc) rtc.RemoteAddr = r.RemoteAddr offer, err := rtc.CreateOffer(nil) if err != nil { - Println(err) return } if bytes, err := rtc.GetAnswer(offer); err == nil { w.Write(bytes) } else { - Println(err) - w.Write([]byte(err.Error())) return } + }) http.HandleFunc("/webrtc/publish", func(w http.ResponseWriter, r *http.Request) { streamPath := r.URL.Query().Get("streamPath") diff --git a/ui/dist/plugin-webrtc.common.js b/ui/dist/plugin-webrtc.common.js index 0b5eb5b..35f6997 100644 --- a/ui/dist/plugin-webrtc.common.js +++ b/ui/dist/plugin-webrtc.common.js @@ -221,12 +221,12 @@ var staticRenderFns = [] // CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=50fea0bc&scoped=true& -// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"7d106341-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Player.vue?vue&type=template&id=edf62584& -var Playervue_type_template_id_edf62584_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('Modal',_vm._g(_vm._b({attrs:{"draggable":"","title":_vm.streamPath},on:{"on-ok":_vm.onClosePreview,"on-cancel":_vm.onClosePreview}},'Modal',_vm.$attrs,false),_vm.$listeners),[_c('video',{ref:"webrtc",attrs:{"width":"488","height":"275","autoplay":"","muted":"","controls":""},domProps:{"srcObject":_vm.stream,"muted":true}}),_c('div',{attrs:{"slot":"footer"},slot:"footer"},[(_vm.remoteSDP)?_c('mu-badge',[_c('a',{attrs:{"slot":"content","href":_vm.remoteSDPURL,"download":"remoteSDP.txt"},slot:"content"},[_vm._v("remoteSDP")])]):_vm._e(),(_vm.localSDP)?_c('mu-badge',[_c('a',{attrs:{"slot":"content","href":_vm.localSDPURL,"download":"localSDP.txt"},slot:"content"},[_vm._v("localSDP")])]):_vm._e()],1)])} -var Playervue_type_template_id_edf62584_staticRenderFns = [] +// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"7d106341-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Player.vue?vue&type=template&id=6aea3512& +var Playervue_type_template_id_6aea3512_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('Modal',_vm._g(_vm._b({attrs:{"draggable":"","title":_vm.streamPath},on:{"on-ok":_vm.onClosePreview,"on-cancel":_vm.onClosePreview}},'Modal',_vm.$attrs,false),_vm.$listeners),[_c('video',{ref:"webrtc",attrs:{"width":"488","height":"275","autoplay":"","muted":"","controls":""},domProps:{"srcObject":_vm.stream,"muted":true}}),_c('div',{attrs:{"slot":"footer"},slot:"footer"},[(_vm.remoteSDP)?_c('mu-badge',[_c('a',{attrs:{"slot":"content","href":_vm.remoteSDPURL,"download":"remoteSDP.txt"},slot:"content"},[_vm._v("remoteSDP")])]):_vm._e(),(_vm.localSDP)?_c('mu-badge',[_c('a',{attrs:{"slot":"content","href":_vm.localSDPURL,"download":"localSDP.txt"},slot:"content"},[_vm._v("localSDP")])]):_vm._e()],1)])} +var Playervue_type_template_id_6aea3512_staticRenderFns = [] -// CONCATENATED MODULE: ./src/components/Player.vue?vue&type=template&id=edf62584& +// CONCATENATED MODULE: ./src/components/Player.vue?vue&type=template&id=6aea3512& // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Player.vue?vue&type=script&lang=js& // @@ -263,56 +263,57 @@ let pc = null; streamPath: "" }; }, - methods: { - async play(streamPath) { - pc = new RTCPeerConnection(); - this.streamPath = streamPath; - pc.onsignalingstatechange = e => { - console.log(e); - }; - pc.oniceconnectionstatechange = e => { - this.$toast.info(pc.iceConnectionState); - this.iceConnectionState = pc.iceConnectionState; - }; - pc.onicecandidate = event => {}; - const result = await this.ajax({ - url: "/webrtc/preparePlay?streamPath=" + this.streamPath, - dataType: "json" - }); - if (result.errmsg) { - this.$toast.error(result.errmsg); - return; - } else { - this.remoteSDP = result.sdp; - this.remoteSDPURL = URL.createObjectURL( - new Blob([this.remoteSDP], { type: "text/plain" }) - ); - } - pc.ontrack = event => { - console.log(event); - if (event.streams[0].id == "monibuca") this.stream = event.streams[0]; - }; - await pc.setRemoteDescription(new RTCSessionDescription(result)); - await pc.setLocalDescription(await pc.createAnswer()); - this.localSDP = pc.localDescription.sdp; - this.localSDPURL = URL.createObjectURL( - new Blob([this.localSDP], { type: "text/plain" }) - ); - result = await this.ajax({ - type: "POST", - processData: false, - data: JSON.stringify(pc.localDescription), - url: "/webrtc/play?streamPath=" + this.streamPath, - dataType: "json" - }); - if (result != "success") { - this.$toast.error(result.errmsg || result); - } - }, - onClosePreview() { - pc.close(); + + methods: { + async play(streamPath) { + pc = new RTCPeerConnection(); + this.streamPath = streamPath; + pc.onsignalingstatechange = e => { + //console.log(e); + }; + pc.oniceconnectionstatechange = e => { + this.$toast.info(pc.iceConnectionState); + this.iceConnectionState = pc.iceConnectionState; + }; + pc.onicecandidate = event => { + console.log(event) + }; + let result = await this.ajax({ + url: "/webrtc/preparePlay?streamPath=" + this.streamPath, + dataType: "json" + }); + if (result.errmsg) { + this.$toast.error(result.errmsg); + return; + } else { + this.remoteSDP = result.sdp; + this.remoteSDPURL = URL.createObjectURL(new Blob([this.remoteSDP], { type: "text/plain" })); + } + pc.ontrack = event => { + // console.log(event); + if (event.track.kind == "video") + this.stream = event.streams[0]; + }; + await pc.setRemoteDescription(new RTCSessionDescription(result)); + await pc.setLocalDescription(await pc.createAnswer()); + this.localSDP = pc.localDescription.sdp; + this.localSDPURL = URL.createObjectURL( + new Blob([this.localSDP], { type: "text/plain" }) + ); + result = await this.ajax({ + type: "POST", + processData: false, + data: JSON.stringify(pc.localDescription.toJSON()), + url: "/webrtc/play?streamPath=" + this.streamPath, + }); + if (result != "success") { + this.$toast.error(result); + } + }, + onClosePreview() { + pc.close(); + } } - } }); // CONCATENATED MODULE: ./src/components/Player.vue?vue&type=script&lang=js& @@ -427,8 +428,8 @@ function normalizeComponent ( var component = normalizeComponent( components_Playervue_type_script_lang_js_, - Playervue_type_template_id_edf62584_render, - Playervue_type_template_id_edf62584_staticRenderFns, + Playervue_type_template_id_6aea3512_render, + Playervue_type_template_id_6aea3512_staticRenderFns, false, null, null, diff --git a/ui/dist/plugin-webrtc.common.js.map b/ui/dist/plugin-webrtc.common.js.map index 36aea52..5e00ef9 100644 --- a/ui/dist/plugin-webrtc.common.js.map +++ b/ui/dist/plugin-webrtc.common.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://plugin-webrtc/webpack/bootstrap","webpack://plugin-webrtc/./src/App.vue?5d0d","webpack://plugin-webrtc/./node_modules/@soda/get-current-script/index.js","webpack://plugin-webrtc/./src/App.vue?76f0","webpack://plugin-webrtc/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://plugin-webrtc/./src/App.vue?962c","webpack://plugin-webrtc/./src/components/Player.vue?d38a","webpack://plugin-webrtc/src/components/Player.vue","webpack://plugin-webrtc/./src/components/Player.vue?42e4","webpack://plugin-webrtc/./node_modules/vue-loader/lib/runtime/componentNormalizer.js","webpack://plugin-webrtc/./src/components/Player.vue","webpack://plugin-webrtc/src/App.vue","webpack://plugin-webrtc/./src/App.vue?8b47","webpack://plugin-webrtc/./src/App.vue","webpack://plugin-webrtc/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js"],"names":[],"mappings":";;QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA,0CAA0C,gCAAgC;QAC1E;QACA;;QAEA;QACA;QACA;QACA,wDAAwD,kBAAkB;QAC1E;QACA,iDAAiD,cAAc;QAC/D;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,iCAAiC;QAC1E,gHAAgH,mBAAmB,EAAE;QACrI;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;;QAGA;QACA;;;;;;;;;AClFA;AAAA;AAAA;AAAgc,CAAgB,ggBAAG,EAAC,C;;;;;;;ACApd;AACA;AACA;;AAEA;;AAEA;AACA,MAAM,IAA0C;AAChD,IAAI,iCAAO,EAAE,oCAAE,OAAO;AAAA;AAAA;AAAA,oGAAC;AACvB,GAAG,MAAM,EAIN;AACH,CAAC;AACD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAA0D;;AAE1D;AACA;AACA,+DAA+D,qBAAqB;AACpF;AACA;;AAEA,qBAAqB,oBAAoB;AACzC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,CAAC;;;;;;;;ACvED,uC;;;;;;;;;;;;ACAA;;AAEA;AACA;AACA,MAAM,IAAuC;AAC7C,2BAA2B,mBAAO,CAAC,MAA0B;AAC7D;;AAEA;AACA;AACA,wDAAwD,wBAAwB;AAChF;AACA;;AAEA;AACA;AACA,IAAI,qBAAuB;AAC3B;AACA;;AAEA;AACe,sDAAI;;;ACrBnB,0BAA0B,aAAa,0BAA0B,wBAAwB,iFAAiF,OAAO,qBAAqB,QAAQ,gDAAgD,mBAAmB,0BAA0B,kCAAkC,IAAI,qBAAqB,qCAAqC,IAAI,yBAAyB,0DAA0D,OAAO,oEAAoE,gBAAgB,yEAAyE,OAAO,kEAAkE,gBAAgB,uDAAuD,oBAAoB,sDAAsD,WAAW,qCAAqC,2DAA2D,qBAAqB,iCAAiC,uBAAuB,IAAI,yBAAyB,4BAA4B,4BAA4B,GAAG,sLAAsL,oBAAoB,uDAAuD,0BAA0B,iCAAiC;AAC56C;;;;;;ACDA,IAAI,0CAAM,gBAAgB,aAAa,0BAA0B,wBAAwB,iCAAiC,OAAO,sCAAsC,KAAK,2DAA2D,wDAAwD,oBAAoB,oEAAoE,WAAW,qCAAqC,YAAY,OAAO,gBAAgB,eAAe,yCAAyC,OAAO,oEAAoE,gBAAgB,yEAAyE,OAAO,kEAAkE,gBAAgB;AAC/vB,IAAI,mDAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;ACoBnB;AACe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;ACpF6K,CAAgB,4GAAG,EAAC,C;;ACAnM;;AAEA;AACA;AACA;;AAEe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;ACjGqF;AAC3B;AACL;;;AAGrD;AAC0F;AAC1F,gBAAgB,kBAAU;AAC1B,EAAE,yCAAM;AACR,EAAE,0CAAM;AACR,EAAE,mDAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,4D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACS+B;AAC9C;AACA,IAAI,6BAAE;AACN;AACA;AACe;AACf;AACA,QAAQ,oBAAY;AACpB;AACA;AACA;AACA,sBAAsB,6BAAE,IAAI,6BAAE,qBAAqB,6BAAE;AACrD,uBAAuB,6BAAE,IAAI,6BAAE,sBAAsB,6BAAE;AACvD;AACA,gCAAgC,6BAAE,IAAI,6BAAE;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,6BAAE;AACd,kBAAkB,6BAAE,2BAA2B,6BAAE;AACjD,4BAA4B,6BAAE;AAC9B;AACA;AACA;AACA;AACA,qCAAqC,6BAAE;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,6BAAE;AACd;AACA;AACA,YAAY,6BAAE;AACd,YAAY,6BAAE;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,6BAAE;AACV;AACA;AACA,QAAQ,6BAAE;AACV,6BAA6B,6BAAE;AAC/B,sCAAsC,6BAAE;AACxC;AACA,QAAQ,6BAAE;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;ACtGoK,CAAgB,+FAAG,EAAC,C;;;;;ACA5F;AACvC;AACL;AACqC;;;AAGvF;AACuF;AACvF,IAAI,aAAS,GAAG,kBAAU;AAC1B,EAAE,+BAAM;AACR,EAAE,MAAM;AACR,EAAE,eAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,qDAAS,Q;;ACnBA;AACA;AACT,kFAAG;AACI","file":"plugin-webrtc.common.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"fb15\");\n","import mod from \"-!../node_modules/mini-css-extract-plugin/dist/loader.js??ref--6-oneOf-1-0!../node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/postcss-loader/src/index.js??ref--6-oneOf-1-2!../node_modules/cache-loader/dist/cjs.js??ref--0-0!../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=style&index=0&id=50fea0bc&scoped=true&lang=css&\"; export default mod; export * from \"-!../node_modules/mini-css-extract-plugin/dist/loader.js??ref--6-oneOf-1-0!../node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/postcss-loader/src/index.js??ref--6-oneOf-1-2!../node_modules/cache-loader/dist/cjs.js??ref--0-0!../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=style&index=0&id=50fea0bc&scoped=true&lang=css&\"","// addapted from the document.currentScript polyfill by Adam Miller\n// MIT license\n// source: https://github.com/amiller-gh/currentScript-polyfill\n\n// added support for Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1620505\n\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n define([], factory);\n } else if (typeof module === 'object' && module.exports) {\n module.exports = factory();\n } else {\n root.getCurrentScript = factory();\n }\n}(typeof self !== 'undefined' ? self : this, function () {\n function getCurrentScript () {\n if (document.currentScript) {\n return document.currentScript\n }\n \n // IE 8-10 support script readyState\n // IE 11+ & Firefox support stack trace\n try {\n throw new Error();\n }\n catch (err) {\n // Find the second match for the \"at\" string to get file src url from stack.\n var ieStackRegExp = /.*at [^(]*\\((.*):(.+):(.+)\\)$/ig,\n ffStackRegExp = /@([^@]*):(\\d+):(\\d+)\\s*$/ig,\n stackDetails = ieStackRegExp.exec(err.stack) || ffStackRegExp.exec(err.stack),\n scriptLocation = (stackDetails && stackDetails[1]) || false,\n line = (stackDetails && stackDetails[2]) || false,\n currentLocation = document.location.href.replace(document.location.hash, ''),\n pageSource,\n inlineScriptSourceRegExp,\n inlineScriptSource,\n scripts = document.getElementsByTagName('script'); // Live NodeList collection\n \n if (scriptLocation === currentLocation) {\n pageSource = document.documentElement.outerHTML;\n inlineScriptSourceRegExp = new RegExp('(?:[^\\\\n]+?\\\\n){0,' + (line - 2) + '}[^<]*","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Player.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Player.vue?vue&type=script&lang=js&\"","/* globals __VUE_SSR_CONTEXT__ */\n\n// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).\n// This module is a runtime utility for cleaner component module output and will\n// be included in the final webpack user bundle.\n\nexport default function normalizeComponent (\n scriptExports,\n render,\n staticRenderFns,\n functionalTemplate,\n injectStyles,\n scopeId,\n moduleIdentifier, /* server only */\n shadowMode /* vue-cli only */\n) {\n // Vue.extend constructor export interop\n var options = typeof scriptExports === 'function'\n ? scriptExports.options\n : scriptExports\n\n // render functions\n if (render) {\n options.render = render\n options.staticRenderFns = staticRenderFns\n options._compiled = true\n }\n\n // functional template\n if (functionalTemplate) {\n options.functional = true\n }\n\n // scopedId\n if (scopeId) {\n options._scopeId = 'data-v-' + scopeId\n }\n\n var hook\n if (moduleIdentifier) { // server build\n hook = function (context) {\n // 2.3 injection\n context =\n context || // cached call\n (this.$vnode && this.$vnode.ssrContext) || // stateful\n (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional\n // 2.2 with runInNewContext: true\n if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\n context = __VUE_SSR_CONTEXT__\n }\n // inject component styles\n if (injectStyles) {\n injectStyles.call(this, context)\n }\n // register component module identifier for async chunk inferrence\n if (context && context._registeredComponents) {\n context._registeredComponents.add(moduleIdentifier)\n }\n }\n // used by ssr in case component is cached and beforeCreate\n // never gets called\n options._ssrRegister = hook\n } else if (injectStyles) {\n hook = shadowMode\n ? function () {\n injectStyles.call(\n this,\n (options.functional ? this.parent : this).$root.$options.shadowRoot\n )\n }\n : injectStyles\n }\n\n if (hook) {\n if (options.functional) {\n // for template-only hot-reload because in that case the render fn doesn't\n // go through the normalizer\n options._injectStyles = hook\n // register for functional component in vue file\n var originalRender = options.render\n options.render = function renderWithStyleInjection (h, context) {\n hook.call(context)\n return originalRender(h, context)\n }\n } else {\n // inject component registration as beforeCreate hook\n var existing = options.beforeCreate\n options.beforeCreate = existing\n ? [].concat(existing, hook)\n : [hook]\n }\n }\n\n return {\n exports: scriptExports,\n options: options\n }\n}\n","import { render, staticRenderFns } from \"./Player.vue?vue&type=template&id=edf62584&\"\nimport script from \"./Player.vue?vue&type=script&lang=js&\"\nexport * from \"./Player.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","