Browse Source

开发播放功能

v4
langhuihui 5 years ago
parent
commit
bf56ea418a
  1. 258
      main.go
  2. 221
      ui/dist/plugin-webrtc.common.js
  3. 2
      ui/dist/plugin-webrtc.common.js.map
  4. 2
      ui/dist/plugin-webrtc.css
  5. 221
      ui/dist/plugin-webrtc.umd.js
  6. 2
      ui/dist/plugin-webrtc.umd.js.map
  7. 2
      ui/dist/plugin-webrtc.umd.min.js
  8. 2
      ui/dist/plugin-webrtc.umd.min.js.map
  9. 242
      ui/src/App.vue

258
main.go

@ -111,118 +111,123 @@ func (rtc *WebRTC) Play(streamPath string) bool {
Println(err) Println(err)
return false return false
} }
peerConnection.OnICEConnectionStateChange(func(connectionState ICEConnectionState) { var sequence uint16
Printf("%s Connection State has changed %s ", streamPath, connectionState.String()) var sub Subscriber
switch connectionState { var sps []byte
case ICEConnectionStateDisconnected: var pps []byte
if rtc.Stream != nil { sub.ID = rtc.RemoteAddr
rtc.Stream.Close() sub.Type = "WebRTC"
} nextHeader := func(ts uint32, marker bool) rtp.Header {
case ICEConnectionStateConnected: sequence++
var sequence uint16 return rtp.Header{
var sub Subscriber Version: 2,
sub.ID = rtc.RemoteAddr SSRC: ssrc,
sub.Type = "WebRTC" PayloadType: DefaultPayloadTypeH264,
nextHeader := func(ts uint32, marker bool) rtp.Header { SequenceNumber: sequence,
sequence++ Timestamp: ts,
return rtp.Header{ Marker: marker,
Version: 2, }
SSRC: ssrc, }
PayloadType: DefaultPayloadTypeH264, stapA := func(naul ...[]byte) []byte {
SequenceNumber: sequence, var buffer bytes.Buffer
Timestamp: ts, buffer.WriteByte(24)
Marker: marker, for _, n := range naul {
} l := len(n)
} buffer.WriteByte(byte(l >> 8))
stapA := func(naul ...[]byte) []byte { buffer.WriteByte(byte(l))
var buffer bytes.Buffer buffer.Write(n)
buffer.WriteByte(24) }
for _, n := range naul { return buffer.Bytes()
l := len(n) }
buffer.WriteByte(byte(l >> 8))
buffer.WriteByte(byte(l))
buffer.Write(n)
}
return buffer.Bytes()
}
// aud := []byte{0x09, 0x30} // aud := []byte{0x09, 0x30}
sub.OnData = func(packet *avformat.SendPacket) error { sub.OnData = func(packet *avformat.SendPacket) error {
if packet.Type == avformat.FLV_TAG_TYPE_AUDIO { if packet.Type == avformat.FLV_TAG_TYPE_AUDIO {
return nil return nil
}
if packet.IsSequence {
payload := packet.Payload[11:]
spsLen := int(payload[0])<<8 + int(payload[1])
sps = payload[2:spsLen]
payload = payload[3+spsLen:]
ppsLen := int(payload[0])<<8 + int(payload[1])
pps = payload[2:ppsLen]
} else {
if packet.IsKeyFrame {
if err := videoTrack.WriteRTP(&rtp.Packet{
Header: nextHeader(0, true),
Payload: stapA(sps, pps),
}); err != nil {
return err
} }
if packet.IsSequence { }
payload := packet.Payload[11:] payload := packet.Payload[5:]
spsLen := int(payload[0])<<8 + int(payload[1]) for {
sps := payload[2:spsLen] var naulLen = int(util.BigEndian.Uint32(payload))
payload = payload[3+spsLen:] payload = payload[4:]
ppsLen := int(payload[0])<<8 + int(payload[1]) _payload := payload[:naulLen]
pps := payload[2:ppsLen] if naulLen > 1000 {
if err := videoTrack.WriteRTP(&rtp.Packet{ part := _payload[:1000]
Header: nextHeader(0, false), indicator := ((part[0] >> 5) << 5) | 28
Payload: stapA(sps, pps), nalutype := part[0] & 31
}); err != nil { header := 128 | nalutype
return err part = part[1:]
} marker := false
} else {
payload := packet.Payload[5:]
for { for {
var naulLen = int(util.BigEndian.Uint32(payload)) if err := videoTrack.WriteRTP(&rtp.Packet{
payload = payload[4:] Header: nextHeader(packet.Timestamp*90, marker),
_payload := payload[:naulLen] Payload: append([]byte{indicator, header}, part...),
if naulLen > 1000 { }); err != nil {
part := _payload[:1000] return err
indicator := ((part[0] >> 5) << 5) | 28
nalutype := part[0] & 31
header := 128 | nalutype
part = part[1:]
marker := false
for {
if err := videoTrack.WriteRTP(&rtp.Packet{
Header: nextHeader(packet.Timestamp*90, marker),
Payload: append([]byte{indicator, header}, part...),
}); err != nil {
return err
}
marker = true
if _payload == nil {
break
}
if len(_payload[1000:]) <= 1000 {
header = 64 | nalutype
part = _payload[1000:]
_payload = nil
} else {
header = nalutype
part = _payload[1000:]
_payload = part
}
}
} else {
if err := videoTrack.WriteRTP(&rtp.Packet{
Header: nextHeader(packet.Timestamp*90, false),
Payload: _payload,
}); err != nil {
return err
}
} }
if len(payload) < naulLen+4 { if _payload == nil {
break break
} }
payload = payload[naulLen:] if len(_payload[1000:]) <= 1000 {
header = 64 | nalutype
part = _payload[1000:]
_payload = nil
marker = true
} else {
header = nalutype
part = _payload[1000:]
_payload = part
}
}
} else {
if err := videoTrack.WriteRTP(&rtp.Packet{
Header: nextHeader(packet.Timestamp*90, true),
Payload: _payload,
}); err != nil {
return err
} }
// if err := videoTrack.WriteRTP(&rtp.Packet{
// Header: nextHeader(packet.Timestamp * 90),
// Payload: aud,
// }); err != nil {
// return err
// }
} }
return nil if len(payload) < naulLen+4 {
break
}
payload = payload[naulLen:]
} }
sub.Subscribe(streamPath) // if err := videoTrack.WriteRTP(&rtp.Packet{
// Header: nextHeader(packet.Timestamp * 90),
// Payload: aud,
// }); err != nil {
// return err
// }
} }
}) return nil
}
go sub.Subscribe(streamPath)
// peerConnection.OnICEConnectionStateChange(func(connectionState ICEConnectionState) {
// Printf("%s Connection State has changed %s ", streamPath, connectionState.String())
// switch connectionState {
// case ICEConnectionStateDisconnected:
// if rtc.Stream != nil {
// rtc.Stream.Close()
// }
// case ICEConnectionStateConnected:
// }
// })
return true return true
} }
func (rtc *WebRTC) Publish(streamPath string) bool { func (rtc *WebRTC) Publish(streamPath string) bool {
@ -289,24 +294,13 @@ func (rtc *WebRTC) Publish(streamPath string) bool {
} }
return true return true
} }
func (rtc *WebRTC) GetAnswer(offer SessionDescription) ([]byte, error) { func (rtc *WebRTC) GetAnswer(localSdp SessionDescription) ([]byte, error) {
if err := rtc.SetRemoteDescription(offer); err != nil {
Println(err)
return nil, err
}
// Create answer
answer, err := rtc.CreateAnswer(nil)
if err != nil {
Println(err)
return nil, err
}
// Sets the LocalDescription, and starts our UDP listeners // Sets the LocalDescription, and starts our UDP listeners
if err = rtc.SetLocalDescription(answer); err != nil { if err := rtc.SetLocalDescription(localSdp); err != nil {
Println(err) Println(err)
return nil, err return nil, err
} }
if bytes, err := json.Marshal(answer); err != nil { if bytes, err := json.Marshal(localSdp); err != nil {
Println(err) Println(err)
return bytes, err return bytes, err
} else { } else {
@ -316,17 +310,22 @@ func (rtc *WebRTC) GetAnswer(offer SessionDescription) ([]byte, error) {
func run() { func run() {
http.HandleFunc("/webrtc/play", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/webrtc/play", func(w http.ResponseWriter, r *http.Request) {
streamPath := r.URL.Query().Get("streamPath") streamPath := r.URL.Query().Get("streamPath")
offer := SessionDescription{} // offer := SessionDescription{}
bytes, err := ioutil.ReadAll(r.Body) // bytes, err := ioutil.ReadAll(r.Body)
err = json.Unmarshal(bytes, &offer) // err = json.Unmarshal(bytes, &offer)
if err != nil { // if err != nil {
Println(err) // Println(err)
return // return
} // }
rtc := new(WebRTC) rtc := new(WebRTC)
rtc.RemoteAddr = r.RemoteAddr rtc.RemoteAddr = r.RemoteAddr
if rtc.Play(streamPath) { if rtc.Play(streamPath) {
if bytes, err = rtc.GetAnswer(offer); err == nil { offer, err := rtc.CreateOffer(nil)
if err != nil {
Println(err)
return
}
if bytes, err := rtc.GetAnswer(offer); err == nil {
w.Write(bytes) w.Write(bytes)
} else { } else {
Println(err) Println(err)
@ -349,7 +348,16 @@ func run() {
rtc := new(WebRTC) rtc := new(WebRTC)
rtc.RemoteAddr = r.RemoteAddr rtc.RemoteAddr = r.RemoteAddr
if rtc.Publish(streamPath) { if rtc.Publish(streamPath) {
if bytes, err = rtc.GetAnswer(offer); err == nil { if err := rtc.SetRemoteDescription(offer); err != nil {
Println(err)
return
}
answer, err := rtc.CreateAnswer(nil)
if err != nil {
Println(err)
return
}
if bytes, err = rtc.GetAnswer(answer); err == nil {
w.Write(bytes) w.Write(bytes)
} else { } else {
Println(err) Println(err)

221
ui/dist/plugin-webrtc.common.js

@ -165,21 +165,21 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
/***/ }), /***/ }),
/***/ "8dc9": /***/ "8e55":
/***/ (function(module, exports, __webpack_require__) { /***/ (function(module, exports, __webpack_require__) {
// extracted by mini-css-extract-plugin // extracted by mini-css-extract-plugin
/***/ }), /***/ }),
/***/ "c857": /***/ "e91a":
/***/ (function(module, __webpack_exports__, __webpack_require__) { /***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict"; "use strict";
/* harmony import */ var _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_3d66f6b2_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("8dc9"); /* harmony import */ var _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_03ea1df8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("8e55");
/* harmony import */ var _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_3d66f6b2_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_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_3d66f6b2_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _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_03ea1df8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_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_03ea1df8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__);
/* unused harmony reexport * */ /* unused harmony reexport * */
/* unused harmony default export */ var _unused_webpack_default_export = (_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_3d66f6b2_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default.a); /* unused harmony default export */ var _unused_webpack_default_export = (_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_03ea1df8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default.a);
/***/ }), /***/ }),
@ -214,12 +214,12 @@ if (typeof window !== 'undefined') {
// Indicate to webpack that this file can be concatenated // Indicate to webpack that this file can be concatenated
/* harmony default export */ var setPublicPath = (null); /* harmony default export */ var setPublicPath = (null);
// 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/App.vue?vue&type=template&id=3d66f6b2&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/App.vue?vue&type=template&id=03ea1df8&scoped=true&
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(_vm.$parent.titleTabActive == 1)?_c('pre',[_vm._v(_vm._s(_vm.localSDP))]):(_vm.$parent.titleTabActive == 2)?_c('pre',[_vm._v(_vm._s(_vm.remoteSDP))]):_c('div',[_c('mu-text-field',{attrs:{"label":"streamPath"},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),(!_vm.localSDP || _vm.ask)?_c('span',{staticClass:"blink"},[_vm._v("Connecting")]):(_vm.iceConnectionState!='connected')?[_c('m-button',{on:{"click":function($event){return _vm.startSession('publish')}}},[_vm._v("Publish")]),_c('m-button',{on:{"click":function($event){return _vm.startSession('play')}}},[_vm._v("Play")])]:(_vm.iceConnectionState=='connected')?_c('m-button',{on:{"click":_vm.stopSession}},[_vm._v("Stop")]):_vm._e(),_c('br'),_c('video',{ref:"video1",attrs:{"width":"640","height":"480","autoplay":"","muted":""},domProps:{"srcObject":_vm.stream,"muted":true}})],2)])} var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(_vm.$parent.titleTabActive == 1)?_c('pre',[_vm._v(_vm._s(_vm.localSDP))]):(_vm.$parent.titleTabActive == 2)?_c('pre',[_vm._v(_vm._s(_vm.remoteSDP))]):_c('div',[_c('mu-text-field',{attrs:{"label":"streamPath"},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),(!_vm.localSDP || _vm.ask)?_c('span',{staticClass:"blink"},[_vm._v("Connecting")]):_vm._e(),[_c('m-button',{on:{"click":function($event){return _vm.startSession('publish')}}},[_vm._v("Publish")]),_c('m-button',{on:{"click":function($event){return _vm.startSession('play')}}},[_vm._v("Play")])],_c('m-button',{on:{"click":_vm.stopSession}},[_vm._v("Stop")]),_c('br'),_c('video',{ref:"video1",attrs:{"width":"640","height":"480","autoplay":"","muted":""},domProps:{"srcObject":_vm.stream,"muted":true}})],2)])}
var staticRenderFns = [] var staticRenderFns = []
// CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=3d66f6b2&scoped=true& // CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=03ea1df8&scoped=true&
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js& // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js&
// //
@ -242,112 +242,123 @@ var staticRenderFns = []
// //
const config = { const config = {
iceServers:[ iceServers: [
// { // {
// urls:[ // urls:[
// "stun:stun.ekiga.net", // "stun:stun.ekiga.net",
// "stun:stun.ideasip.com", // "stun:stun.ideasip.com",
// "stun:stun.schlund.de", // "stun:stun.schlund.de",
// "stun:stun.stunprotocol.org:3478", // "stun:stun.stunprotocol.org:3478",
// "stun:stun.voiparound.com", // "stun:stun.voiparound.com",
// "stun:stun.voipbuster.com", // "stun:stun.voipbuster.com",
// "stun:stun.voipstunt.com", // "stun:stun.voipstunt.com",
// "stun:stun.voxgratia.org", // "stun:stun.voxgratia.org",
// "stun:stun.services.mozilla.com", // "stun:stun.services.mozilla.com",
// "stun:stun.xten.com", // "stun:stun.xten.com",
// "stun:stun.softjoys.com", // "stun:stun.softjoys.com",
// "stun:stunserver.org", // "stun:stunserver.org",
// "stun:stun.schlund.de", // "stun:stun.schlund.de",
// "stun:stun.rixtelecom.se", // "stun:stun.rixtelecom.se",
// "stun:stun.iptel.org", // "stun:stun.iptel.org",
// "stun:stun.ideasip.com", // "stun:stun.ideasip.com",
// "stun:stun.fwdnet.net", // "stun:stun.fwdnet.net",
// "stun:stun.ekiga.net", // "stun:stun.ekiga.net",
// "stun:stun01.sipphone.com", // "stun:stun01.sipphone.com",
// ] // ]
// } // }
] ]
} };
let pc = new RTCPeerConnection(config); let pc = new RTCPeerConnection(config);
var stream = null var stream = null;
var streamPath = "live/rtc" var streamPath = "live/rtc";
/* harmony default export */ var Appvue_type_script_lang_js_ = ({ /* harmony default export */ var Appvue_type_script_lang_js_ = ({
data() { data() {
return { return {
localSDP: pc&&pc.localDescription&&pc.localDescription.sdp, localSDP: pc && pc.localDescription && pc.localDescription.sdp,
remoteSDP: pc&&pc.remoteDescription&&pc.remoteDescription.sdp, remoteSDP: pc && pc.remoteDescription && pc.remoteDescription.sdp,
streamPath, streamPath,
iceConnectionState:pc&&pc.iceConnectionState, iceConnectionState: pc && pc.iceConnectionState,
stream, stream,
type:"", type: "",
ask:false ask: false
}; };
},
methods: {
startSession(type) {
this.type = type
this.ask = true
this.ajax({type: 'POST',processData:false,data: JSON.stringify(pc.localDescription),url:"/webrtc/"+type+"?streamPath="+this.streamPath,dataType:"json"}).then(result => {
this.ask = false
if (result.errmsg){
this.$toast.error(result.errmsg)
}else{
streamPath = this.streamPath
this.remoteSDP = result.sdp;
this.$parent.titleTabs = ["摄像头", "localSDP","remoteSDP"];
pc.setRemoteDescription(new RTCSessionDescription(result));
}
});
},
stopSession(){
pc.close()
pc = new RTCPeerConnection(config)
this.remoteSDP = ""
this.localSDP = ""
this.connectICE().catch(err=> this.$toast.error(err.message))
}, },
async connectICE(){ methods: {
pc.addStream(stream); async startSession(type) {
await pc.setLocalDescription(await pc.createOffer()) this.type = type;
pc.oniceconnectionstatechange = e => { this.ask = true;
this.$toast.info(pc.iceConnectionState) const result = await this.ajax({
this.iceConnectionState = pc.iceConnectionState type: "POST",
}; processData: false,
pc.onicecandidate = event => { data: JSON.stringify(pc.localDescription),
if (event.candidate === null) { url: "/webrtc/" + type + "?streamPath=" + this.streamPath,
this.localSDP = pc.localDescription.sdp; dataType: "json"
this.$parent.titleTabs = ["摄像头", "localSDP"]; });
this.ask = false;
if (result.errmsg) {
this.$toast.error(result.errmsg);
} else {
streamPath = this.streamPath;
this.remoteSDP = result.sdp;
this.$parent.titleTabs = ["摄像头", "localSDP", "remoteSDP"];
pc.setRemoteDescription(new RTCSessionDescription(result));
}
if (type == "publish") {
pc.addStream(stream);
this.localSDP = (
await pc.setLocalDescription(await pc.createOffer())
).sdp;
} else {
pc.ontrack = event => {
if(event.streams[0].id=="monibuca")
this.stream = stream = event.streams[0];
};
}
},
stopSession() {
pc.close();
pc = new RTCPeerConnection(config);
this.remoteSDP = "";
this.localSDP = "";
this.type = "";
// this.connectICE().catch(err => this.$toast.error(err.message));
} }
}; },
pc.ontrack = event=>{ async mounted() {
if(this.type=="play" && event.streams[0]){ pc.onsignalingstatechange = e => {
this.stream = stream = event.streams[0] console.log(e);
};
pc.oniceconnectionstatechange = e => {
this.$toast.info(pc.iceConnectionState);
this.iceConnectionState = pc.iceConnectionState;
};
pc.onicecandidate = event => {
if (event.candidate === null) {
this.$parent.titleTabs = ["摄像头", "localSDP"];
}
};
if (this.localSDP) {
let tabs = ["摄像头"];
if (this.localSDP) tabs.push("localSDP");
if (this.remoteSDP) tabs.push("remoteSDP");
this.$parent.titleTabs = tabs;
} else {
try {
if (!this.stream)
this.stream = stream = await navigator.mediaDevices.getUserMedia(
{ video: true, audio: true }
);
} catch (err) {
this.$toast.error(err.message);
}
} }
}
} }
},
async mounted() {
if (this.localSDP){
let tabs = ["摄像头"]
if(this.localSDP)tabs.push("localSDP")
if(this.remoteSDP)tabs.push("remoteSDP")
this.$parent.titleTabs = tabs;
} else {
try{
if(!this.stream)
this.stream = stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })
await this.connectICE()
}catch(err){
this.$toast.error(err.message)
}
}
}
}); });
// CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js& // CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js&
/* harmony default export */ var src_Appvue_type_script_lang_js_ = (Appvue_type_script_lang_js_); /* harmony default export */ var src_Appvue_type_script_lang_js_ = (Appvue_type_script_lang_js_);
// EXTERNAL MODULE: ./src/App.vue?vue&type=style&index=0&id=3d66f6b2&scoped=true&lang=css& // EXTERNAL MODULE: ./src/App.vue?vue&type=style&index=0&id=03ea1df8&scoped=true&lang=css&
var Appvue_type_style_index_0_id_3d66f6b2_scoped_true_lang_css_ = __webpack_require__("c857"); var Appvue_type_style_index_0_id_03ea1df8_scoped_true_lang_css_ = __webpack_require__("e91a");
// CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js // CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js
/* globals __VUE_SSR_CONTEXT__ */ /* globals __VUE_SSR_CONTEXT__ */
@ -464,7 +475,7 @@ var component = normalizeComponent(
staticRenderFns, staticRenderFns,
false, false,
null, null,
"3d66f6b2", "03ea1df8",
null null
) )

2
ui/dist/plugin-webrtc.common.js.map

File diff suppressed because one or more lines are too long

2
ui/dist/plugin-webrtc.css

@ -1 +1 @@
@-webkit-keyframes blink-data-v-3d66f6b2{0%{opacity:.2}50%{opacity:1}to{opacity:.2}}@keyframes blink-data-v-3d66f6b2{0%{opacity:.2}50%{opacity:1}to{opacity:.2}}.blink[data-v-3d66f6b2]{-webkit-animation:blink-data-v-3d66f6b2 1s infinite;animation:blink-data-v-3d66f6b2 1s infinite} @-webkit-keyframes blink-data-v-03ea1df8{0%{opacity:.2}50%{opacity:1}to{opacity:.2}}@keyframes blink-data-v-03ea1df8{0%{opacity:.2}50%{opacity:1}to{opacity:.2}}.blink[data-v-03ea1df8]{-webkit-animation:blink-data-v-03ea1df8 1s infinite;animation:blink-data-v-03ea1df8 1s infinite}

221
ui/dist/plugin-webrtc.umd.js

@ -174,21 +174,21 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
/***/ }), /***/ }),
/***/ "8dc9": /***/ "8e55":
/***/ (function(module, exports, __webpack_require__) { /***/ (function(module, exports, __webpack_require__) {
// extracted by mini-css-extract-plugin // extracted by mini-css-extract-plugin
/***/ }), /***/ }),
/***/ "c857": /***/ "e91a":
/***/ (function(module, __webpack_exports__, __webpack_require__) { /***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict"; "use strict";
/* harmony import */ var _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_3d66f6b2_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("8dc9"); /* harmony import */ var _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_03ea1df8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("8e55");
/* harmony import */ var _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_3d66f6b2_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_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_3d66f6b2_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _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_03ea1df8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_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_03ea1df8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__);
/* unused harmony reexport * */ /* unused harmony reexport * */
/* unused harmony default export */ var _unused_webpack_default_export = (_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_3d66f6b2_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default.a); /* unused harmony default export */ var _unused_webpack_default_export = (_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_03ea1df8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default.a);
/***/ }), /***/ }),
@ -223,12 +223,12 @@ if (typeof window !== 'undefined') {
// Indicate to webpack that this file can be concatenated // Indicate to webpack that this file can be concatenated
/* harmony default export */ var setPublicPath = (null); /* harmony default export */ var setPublicPath = (null);
// 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/App.vue?vue&type=template&id=3d66f6b2&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/App.vue?vue&type=template&id=03ea1df8&scoped=true&
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(_vm.$parent.titleTabActive == 1)?_c('pre',[_vm._v(_vm._s(_vm.localSDP))]):(_vm.$parent.titleTabActive == 2)?_c('pre',[_vm._v(_vm._s(_vm.remoteSDP))]):_c('div',[_c('mu-text-field',{attrs:{"label":"streamPath"},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),(!_vm.localSDP || _vm.ask)?_c('span',{staticClass:"blink"},[_vm._v("Connecting")]):(_vm.iceConnectionState!='connected')?[_c('m-button',{on:{"click":function($event){return _vm.startSession('publish')}}},[_vm._v("Publish")]),_c('m-button',{on:{"click":function($event){return _vm.startSession('play')}}},[_vm._v("Play")])]:(_vm.iceConnectionState=='connected')?_c('m-button',{on:{"click":_vm.stopSession}},[_vm._v("Stop")]):_vm._e(),_c('br'),_c('video',{ref:"video1",attrs:{"width":"640","height":"480","autoplay":"","muted":""},domProps:{"srcObject":_vm.stream,"muted":true}})],2)])} var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(_vm.$parent.titleTabActive == 1)?_c('pre',[_vm._v(_vm._s(_vm.localSDP))]):(_vm.$parent.titleTabActive == 2)?_c('pre',[_vm._v(_vm._s(_vm.remoteSDP))]):_c('div',[_c('mu-text-field',{attrs:{"label":"streamPath"},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),(!_vm.localSDP || _vm.ask)?_c('span',{staticClass:"blink"},[_vm._v("Connecting")]):_vm._e(),[_c('m-button',{on:{"click":function($event){return _vm.startSession('publish')}}},[_vm._v("Publish")]),_c('m-button',{on:{"click":function($event){return _vm.startSession('play')}}},[_vm._v("Play")])],_c('m-button',{on:{"click":_vm.stopSession}},[_vm._v("Stop")]),_c('br'),_c('video',{ref:"video1",attrs:{"width":"640","height":"480","autoplay":"","muted":""},domProps:{"srcObject":_vm.stream,"muted":true}})],2)])}
var staticRenderFns = [] var staticRenderFns = []
// CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=3d66f6b2&scoped=true& // CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=03ea1df8&scoped=true&
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js& // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js&
// //
@ -251,112 +251,123 @@ var staticRenderFns = []
// //
const config = { const config = {
iceServers:[ iceServers: [
// { // {
// urls:[ // urls:[
// "stun:stun.ekiga.net", // "stun:stun.ekiga.net",
// "stun:stun.ideasip.com", // "stun:stun.ideasip.com",
// "stun:stun.schlund.de", // "stun:stun.schlund.de",
// "stun:stun.stunprotocol.org:3478", // "stun:stun.stunprotocol.org:3478",
// "stun:stun.voiparound.com", // "stun:stun.voiparound.com",
// "stun:stun.voipbuster.com", // "stun:stun.voipbuster.com",
// "stun:stun.voipstunt.com", // "stun:stun.voipstunt.com",
// "stun:stun.voxgratia.org", // "stun:stun.voxgratia.org",
// "stun:stun.services.mozilla.com", // "stun:stun.services.mozilla.com",
// "stun:stun.xten.com", // "stun:stun.xten.com",
// "stun:stun.softjoys.com", // "stun:stun.softjoys.com",
// "stun:stunserver.org", // "stun:stunserver.org",
// "stun:stun.schlund.de", // "stun:stun.schlund.de",
// "stun:stun.rixtelecom.se", // "stun:stun.rixtelecom.se",
// "stun:stun.iptel.org", // "stun:stun.iptel.org",
// "stun:stun.ideasip.com", // "stun:stun.ideasip.com",
// "stun:stun.fwdnet.net", // "stun:stun.fwdnet.net",
// "stun:stun.ekiga.net", // "stun:stun.ekiga.net",
// "stun:stun01.sipphone.com", // "stun:stun01.sipphone.com",
// ] // ]
// } // }
] ]
} };
let pc = new RTCPeerConnection(config); let pc = new RTCPeerConnection(config);
var stream = null var stream = null;
var streamPath = "live/rtc" var streamPath = "live/rtc";
/* harmony default export */ var Appvue_type_script_lang_js_ = ({ /* harmony default export */ var Appvue_type_script_lang_js_ = ({
data() { data() {
return { return {
localSDP: pc&&pc.localDescription&&pc.localDescription.sdp, localSDP: pc && pc.localDescription && pc.localDescription.sdp,
remoteSDP: pc&&pc.remoteDescription&&pc.remoteDescription.sdp, remoteSDP: pc && pc.remoteDescription && pc.remoteDescription.sdp,
streamPath, streamPath,
iceConnectionState:pc&&pc.iceConnectionState, iceConnectionState: pc && pc.iceConnectionState,
stream, stream,
type:"", type: "",
ask:false ask: false
}; };
},
methods: {
startSession(type) {
this.type = type
this.ask = true
this.ajax({type: 'POST',processData:false,data: JSON.stringify(pc.localDescription),url:"/webrtc/"+type+"?streamPath="+this.streamPath,dataType:"json"}).then(result => {
this.ask = false
if (result.errmsg){
this.$toast.error(result.errmsg)
}else{
streamPath = this.streamPath
this.remoteSDP = result.sdp;
this.$parent.titleTabs = ["摄像头", "localSDP","remoteSDP"];
pc.setRemoteDescription(new RTCSessionDescription(result));
}
});
},
stopSession(){
pc.close()
pc = new RTCPeerConnection(config)
this.remoteSDP = ""
this.localSDP = ""
this.connectICE().catch(err=> this.$toast.error(err.message))
}, },
async connectICE(){ methods: {
pc.addStream(stream); async startSession(type) {
await pc.setLocalDescription(await pc.createOffer()) this.type = type;
pc.oniceconnectionstatechange = e => { this.ask = true;
this.$toast.info(pc.iceConnectionState) const result = await this.ajax({
this.iceConnectionState = pc.iceConnectionState type: "POST",
}; processData: false,
pc.onicecandidate = event => { data: JSON.stringify(pc.localDescription),
if (event.candidate === null) { url: "/webrtc/" + type + "?streamPath=" + this.streamPath,
this.localSDP = pc.localDescription.sdp; dataType: "json"
this.$parent.titleTabs = ["摄像头", "localSDP"]; });
this.ask = false;
if (result.errmsg) {
this.$toast.error(result.errmsg);
} else {
streamPath = this.streamPath;
this.remoteSDP = result.sdp;
this.$parent.titleTabs = ["摄像头", "localSDP", "remoteSDP"];
pc.setRemoteDescription(new RTCSessionDescription(result));
}
if (type == "publish") {
pc.addStream(stream);
this.localSDP = (
await pc.setLocalDescription(await pc.createOffer())
).sdp;
} else {
pc.ontrack = event => {
if(event.streams[0].id=="monibuca")
this.stream = stream = event.streams[0];
};
}
},
stopSession() {
pc.close();
pc = new RTCPeerConnection(config);
this.remoteSDP = "";
this.localSDP = "";
this.type = "";
// this.connectICE().catch(err => this.$toast.error(err.message));
} }
}; },
pc.ontrack = event=>{ async mounted() {
if(this.type=="play" && event.streams[0]){ pc.onsignalingstatechange = e => {
this.stream = stream = event.streams[0] console.log(e);
};
pc.oniceconnectionstatechange = e => {
this.$toast.info(pc.iceConnectionState);
this.iceConnectionState = pc.iceConnectionState;
};
pc.onicecandidate = event => {
if (event.candidate === null) {
this.$parent.titleTabs = ["摄像头", "localSDP"];
}
};
if (this.localSDP) {
let tabs = ["摄像头"];
if (this.localSDP) tabs.push("localSDP");
if (this.remoteSDP) tabs.push("remoteSDP");
this.$parent.titleTabs = tabs;
} else {
try {
if (!this.stream)
this.stream = stream = await navigator.mediaDevices.getUserMedia(
{ video: true, audio: true }
);
} catch (err) {
this.$toast.error(err.message);
}
} }
}
} }
},
async mounted() {
if (this.localSDP){
let tabs = ["摄像头"]
if(this.localSDP)tabs.push("localSDP")
if(this.remoteSDP)tabs.push("remoteSDP")
this.$parent.titleTabs = tabs;
} else {
try{
if(!this.stream)
this.stream = stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })
await this.connectICE()
}catch(err){
this.$toast.error(err.message)
}
}
}
}); });
// CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js& // CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js&
/* harmony default export */ var src_Appvue_type_script_lang_js_ = (Appvue_type_script_lang_js_); /* harmony default export */ var src_Appvue_type_script_lang_js_ = (Appvue_type_script_lang_js_);
// EXTERNAL MODULE: ./src/App.vue?vue&type=style&index=0&id=3d66f6b2&scoped=true&lang=css& // EXTERNAL MODULE: ./src/App.vue?vue&type=style&index=0&id=03ea1df8&scoped=true&lang=css&
var Appvue_type_style_index_0_id_3d66f6b2_scoped_true_lang_css_ = __webpack_require__("c857"); var Appvue_type_style_index_0_id_03ea1df8_scoped_true_lang_css_ = __webpack_require__("e91a");
// CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js // CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js
/* globals __VUE_SSR_CONTEXT__ */ /* globals __VUE_SSR_CONTEXT__ */
@ -473,7 +484,7 @@ var component = normalizeComponent(
staticRenderFns, staticRenderFns,
false, false,
null, null,
"3d66f6b2", "03ea1df8",
null null
) )

2
ui/dist/plugin-webrtc.umd.js.map

File diff suppressed because one or more lines are too long

2
ui/dist/plugin-webrtc.umd.min.js

File diff suppressed because one or more lines are too long

2
ui/dist/plugin-webrtc.umd.min.js.map

File diff suppressed because one or more lines are too long

242
ui/src/App.vue

@ -1,140 +1,150 @@
<template> <template>
<div> <div>
<pre v-if="$parent.titleTabActive == 1">{{localSDP}}</pre> <pre v-if="$parent.titleTabActive == 1">{{localSDP}}</pre>
<pre v-else-if="$parent.titleTabActive == 2">{{remoteSDP}}</pre> <pre v-else-if="$parent.titleTabActive == 2">{{remoteSDP}}</pre>
<div v-else> <div v-else>
<mu-text-field v-model="streamPath" label="streamPath"></mu-text-field> <mu-text-field v-model="streamPath" label="streamPath"></mu-text-field>
<span class="blink" v-if="!localSDP || ask">Connecting</span> <span class="blink" v-if="!localSDP || ask">Connecting</span>
<template v-else-if="iceConnectionState!='connected'"> <template>
<m-button @click="startSession('publish')">Publish</m-button> <m-button @click="startSession('publish')">Publish</m-button>
<m-button @click="startSession('play')">Play</m-button> <m-button @click="startSession('play')">Play</m-button>
</template> </template>
<m-button @click="stopSession" v-else-if="iceConnectionState=='connected'">Stop</m-button> <m-button @click="stopSession">Stop</m-button>
<br /> <br />
<video ref="video1" :srcObject.prop="stream" width="640" height="480" autoplay muted></video> <video ref="video1" :srcObject.prop="stream" width="640" height="480" autoplay muted></video>
</div>
</div> </div>
</div>
</template> </template>
<script> <script>
const config = { const config = {
iceServers:[ iceServers: [
// { // {
// urls:[ // urls:[
// "stun:stun.ekiga.net", // "stun:stun.ekiga.net",
// "stun:stun.ideasip.com", // "stun:stun.ideasip.com",
// "stun:stun.schlund.de", // "stun:stun.schlund.de",
// "stun:stun.stunprotocol.org:3478", // "stun:stun.stunprotocol.org:3478",
// "stun:stun.voiparound.com", // "stun:stun.voiparound.com",
// "stun:stun.voipbuster.com", // "stun:stun.voipbuster.com",
// "stun:stun.voipstunt.com", // "stun:stun.voipstunt.com",
// "stun:stun.voxgratia.org", // "stun:stun.voxgratia.org",
// "stun:stun.services.mozilla.com", // "stun:stun.services.mozilla.com",
// "stun:stun.xten.com", // "stun:stun.xten.com",
// "stun:stun.softjoys.com", // "stun:stun.softjoys.com",
// "stun:stunserver.org", // "stun:stunserver.org",
// "stun:stun.schlund.de", // "stun:stun.schlund.de",
// "stun:stun.rixtelecom.se", // "stun:stun.rixtelecom.se",
// "stun:stun.iptel.org", // "stun:stun.iptel.org",
// "stun:stun.ideasip.com", // "stun:stun.ideasip.com",
// "stun:stun.fwdnet.net", // "stun:stun.fwdnet.net",
// "stun:stun.ekiga.net", // "stun:stun.ekiga.net",
// "stun:stun01.sipphone.com", // "stun:stun01.sipphone.com",
// ] // ]
// } // }
] ]
} };
let pc = new RTCPeerConnection(config); let pc = new RTCPeerConnection(config);
var stream = null var stream = null;
var streamPath = "live/rtc" var streamPath = "live/rtc";
export default { export default {
data() { data() {
return { return {
localSDP: pc&&pc.localDescription&&pc.localDescription.sdp, localSDP: pc && pc.localDescription && pc.localDescription.sdp,
remoteSDP: pc&&pc.remoteDescription&&pc.remoteDescription.sdp, remoteSDP: pc && pc.remoteDescription && pc.remoteDescription.sdp,
streamPath, streamPath,
iceConnectionState:pc&&pc.iceConnectionState, iceConnectionState: pc && pc.iceConnectionState,
stream, stream,
type:"", type: "",
ask:false ask: false
}; };
},
methods: {
startSession(type) {
this.type = type
this.ask = true
this.ajax({type: 'POST',processData:false,data: JSON.stringify(pc.localDescription),url:"/webrtc/"+type+"?streamPath="+this.streamPath,dataType:"json"}).then(result => {
this.ask = false
if (result.errmsg){
this.$toast.error(result.errmsg)
}else{
streamPath = this.streamPath
this.remoteSDP = result.sdp;
this.$parent.titleTabs = ["摄像头", "localSDP","remoteSDP"];
pc.setRemoteDescription(new RTCSessionDescription(result));
}
});
}, },
stopSession(){ methods: {
pc.close() async startSession(type) {
pc = new RTCPeerConnection(config) this.type = type;
this.remoteSDP = "" this.ask = true;
this.localSDP = "" const result = await this.ajax({
this.connectICE().catch(err=> this.$toast.error(err.message)) type: "POST",
}, processData: false,
async connectICE(){ data: JSON.stringify(pc.localDescription),
pc.addStream(stream); url: "/webrtc/" + type + "?streamPath=" + this.streamPath,
await pc.setLocalDescription(await pc.createOffer()) dataType: "json"
pc.oniceconnectionstatechange = e => { });
this.$toast.info(pc.iceConnectionState) this.ask = false;
this.iceConnectionState = pc.iceConnectionState if (result.errmsg) {
}; this.$toast.error(result.errmsg);
pc.onicecandidate = event => { } else {
if (event.candidate === null) { streamPath = this.streamPath;
this.localSDP = pc.localDescription.sdp; this.remoteSDP = result.sdp;
this.$parent.titleTabs = ["摄像头", "localSDP"]; this.$parent.titleTabs = ["摄像头", "localSDP", "remoteSDP"];
pc.setRemoteDescription(new RTCSessionDescription(result));
}
if (type == "publish") {
pc.addStream(stream);
this.localSDP = (
await pc.setLocalDescription(await pc.createOffer())
).sdp;
} else {
pc.ontrack = event => {
if(event.streams[0].id=="monibuca")
this.stream = stream = event.streams[0];
};
}
},
stopSession() {
pc.close();
pc = new RTCPeerConnection(config);
this.remoteSDP = "";
this.localSDP = "";
this.type = "";
// this.connectICE().catch(err => this.$toast.error(err.message));
} }
}; },
pc.ontrack = event=>{ async mounted() {
if(this.type=="play" && event.streams[0]){ pc.onsignalingstatechange = e => {
this.stream = stream = event.streams[0] console.log(e);
};
pc.oniceconnectionstatechange = e => {
this.$toast.info(pc.iceConnectionState);
this.iceConnectionState = pc.iceConnectionState;
};
pc.onicecandidate = event => {
if (event.candidate === null) {
this.$parent.titleTabs = ["摄像头", "localSDP"];
}
};
if (this.localSDP) {
let tabs = ["摄像头"];
if (this.localSDP) tabs.push("localSDP");
if (this.remoteSDP) tabs.push("remoteSDP");
this.$parent.titleTabs = tabs;
} else {
try {
if (!this.stream)
this.stream = stream = await navigator.mediaDevices.getUserMedia(
{ video: true, audio: true }
);
} catch (err) {
this.$toast.error(err.message);
}
} }
}
} }
},
async mounted() {
if (this.localSDP){
let tabs = ["摄像头"]
if(this.localSDP)tabs.push("localSDP")
if(this.remoteSDP)tabs.push("remoteSDP")
this.$parent.titleTabs = tabs;
} else {
try{
if(!this.stream)
this.stream = stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })
await this.connectICE()
}catch(err){
this.$toast.error(err.message)
}
}
}
}; };
</script> </script>
<style scoped> <style scoped>
@keyframes blink { @keyframes blink {
0% { 0% {
opacity: 0.2; opacity: 0.2;
} }
50% { 50% {
opacity: 1; opacity: 1;
} }
100% { 100% {
opacity: 0.2; opacity: 0.2;
} }
} }
.blink { .blink {
animation: blink 1s infinite; animation: blink 1s infinite;
} }
</style> </style>
Loading…
Cancel
Save