├── .eslintignore ├── qrcode.png ├── src ├── assets │ ├── image │ │ ├── bg.jpg │ │ ├── call.png │ │ ├── close.png │ │ ├── copy.png │ │ ├── guide.png │ │ ├── like.png │ │ ├── like1.png │ │ ├── like3.png │ │ ├── logo.png │ │ ├── logo1.png │ │ ├── mute.png │ │ ├── play.png │ │ ├── quit.png │ │ ├── send.png │ │ ├── send1.png │ │ ├── share.png │ │ ├── tips.png │ │ ├── tips1.png │ │ ├── video.png │ │ ├── avatar.png │ │ ├── back-img.png │ │ ├── cdn-logo.png │ │ ├── copy-1.png │ │ ├── default.png │ │ ├── guide-1.png │ │ ├── guzhang.png │ │ ├── like-0.png │ │ ├── login_bg.png │ │ ├── logo-1.png │ │ ├── message.png │ │ ├── no-video.png │ │ ├── open-mic.png │ │ ├── picture.png │ │ ├── player.png │ │ ├── pushing.png │ │ ├── qr-code.png │ │ ├── qrcode.png │ │ ├── share1.png │ │ ├── share2.png │ │ ├── system.png │ │ ├── txc-logo.png │ │ ├── unmute.png │ │ ├── unmute1.png │ │ ├── unplay.png │ │ ├── video-bg.jpg │ │ ├── video-bg.png │ │ ├── video-gb.png │ │ ├── volume.png │ │ ├── big-mic-on.png │ │ ├── camera-max.png │ │ ├── chat_close.png │ │ ├── chat_open.png │ │ ├── close-mcp.png │ │ ├── close-mic.png │ │ ├── live-empty.png │ │ ├── live-share.png │ │ ├── login-log.png │ │ ├── logo-list.png │ │ ├── mobile-bg.png │ │ ├── room-icon.png │ │ ├── tab_video.png │ │ ├── time-icon.png │ │ ├── big-camera-on.png │ │ ├── big-mic-off.png │ │ ├── camera-close.png │ │ ├── camera-open.png │ │ ├── close-camera.png │ │ ├── close-login.png │ │ ├── live-banner.jpg │ │ ├── mobile-player.png │ │ ├── mobile-start.png │ │ ├── open-camera.png │ │ ├── pusher-guide.png │ │ ├── pusher-more.png │ │ ├── pusher-start.png │ │ ├── pusher-stop.png │ │ ├── room-mobile.png │ │ ├── small-start.png │ │ ├── start_preview.png │ │ ├── stop-player.png │ │ ├── stop_preview.png │ │ ├── time-mobile.png │ │ ├── webrtc_push.png │ │ ├── big-camera-off.png │ │ ├── live-img │ │ │ ├── img-1.png │ │ │ ├── img-2.png │ │ │ ├── img-3.png │ │ │ ├── img-4.png │ │ │ ├── img-5.png │ │ │ └── img-6.png │ │ ├── mobile-list-bg.jpg │ │ ├── mobile-list-bg.png │ │ ├── open-microphone.png │ │ ├── video_selected.png │ │ ├── web-pusher-stop.png │ │ ├── web-pusher-start.png │ │ ├── webrtc_pusher_stop.png │ │ └── webrtc_tab_more@2x.png │ ├── css │ │ ├── base.styl │ │ └── reset.css │ └── icon │ │ ├── tim.css │ │ ├── tim.ttf │ │ ├── tim.woff │ │ ├── tim.eot │ │ ├── iconfont.woff2 │ │ ├── iconfont.woff │ │ ├── tim.svg │ │ ├── iconfont.ttf │ │ ├── iconfont.eot │ │ └── iconfont.css ├── components │ ├── test │ │ ├── img │ │ │ ├── mic.png │ │ │ ├── camera.png │ │ │ ├── code.jpg │ │ │ ├── fail.png │ │ │ ├── logo.png │ │ │ ├── logout.png │ │ │ ├── mic-on.png │ │ │ ├── shot.png │ │ │ ├── loading.png │ │ │ ├── mic-off.png │ │ │ ├── success.png │ │ │ ├── success1.png │ │ │ ├── big-mic-off.png │ │ │ ├── big-mic-on.png │ │ │ ├── camera-max.png │ │ │ ├── camera-off.png │ │ │ ├── camera-on.png │ │ │ ├── screen-off.png │ │ │ ├── screen-on.png │ │ │ ├── big-camera-on.png │ │ │ ├── big-camera-off.png │ │ │ └── right-top-arrow.png │ │ └── presetting.js │ ├── liveLike │ │ └── images │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ ├── 8.png │ │ │ ├── 123.png │ │ │ ├── 124.png │ │ │ ├── 125.png │ │ │ ├── 13.png │ │ │ ├── bg1.png │ │ │ ├── bg2.png │ │ │ ├── bg3.png │ │ │ ├── bg4.png │ │ │ ├── bg5.png │ │ │ └── bg6.png │ ├── qrcode.vue │ ├── base │ │ └── tips.vue │ ├── chatroom │ │ └── message-status-icon.vue │ └── pusher │ │ └── components │ │ └── pusherSetting.vue ├── utils │ ├── development.js │ ├── mobile.js │ ├── vconsole.js │ ├── mta.js │ ├── trtcCustomMessageMap.js │ ├── formatDuration.js │ ├── index.js │ ├── date.js │ ├── decodeText.js │ ├── browser.js │ ├── emojiMap.js │ ├── common.js │ └── rtc-client.js ├── tim.js ├── router.js ├── pages │ ├── player │ │ ├── player.vue │ │ ├── IndexMobile.vue │ │ └── IndexPc.vue │ ├── pusher │ │ ├── pusher.vue │ │ ├── IndexMobile.vue │ │ └── IndexPc.vue │ └── live │ │ └── live.vue ├── App.vue ├── main.js └── store │ ├── index.js │ └── modules │ ├── user.js │ └── conversation.js ├── dist ├── img │ ├── logo.1dd6e6d4.png │ ├── guide.dfbfcbc1.png │ ├── img-1.2fcf8049.png │ ├── img-2.5dd346dc.png │ ├── img-3.ab9a0c2e.png │ ├── img-4.02a3b15f.png │ ├── img-5.76607c0e.png │ ├── img-6.11f1c584.png │ ├── logo-list.cd0456bc.png │ ├── mobile-bg.a687c495.png │ ├── no-video.f64769eb.png │ ├── txc-logo.576f62f4.png │ ├── video-gb.005bcdf6.png │ ├── live-banner.4c634841.jpg │ ├── live-empty.2acb9f92.png │ ├── mobile-list-bg.53eab997.png │ ├── right-top-arrow.9761ff85.png │ └── tim.df3f8550.svg ├── fonts │ ├── element-icons.535877f5.woff │ ├── element-icons.732389de.ttf │ ├── iconfont.5cc3f0e2.woff │ ├── iconfont.6f1fd06b.ttf │ └── iconfont.908bc2a8.eot ├── index.html └── debug │ └── GenerateTestUserSig.js ├── babel.config.js ├── .gitignore ├── .eslintrc ├── public ├── index.html └── debug │ └── GenerateTestUserSig.js ├── postcss.config.js ├── CHANGELOG.md ├── check-tweblive-version.js ├── vue.config.js ├── package.json ├── archive.js └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | src/assets/* 2 | node_modules/* 3 | sdk/* -------------------------------------------------------------------------------- /qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/qrcode.png -------------------------------------------------------------------------------- /src/assets/image/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/bg.jpg -------------------------------------------------------------------------------- /dist/img/logo.1dd6e6d4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/logo.1dd6e6d4.png -------------------------------------------------------------------------------- /src/assets/image/call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/call.png -------------------------------------------------------------------------------- /src/assets/image/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/close.png -------------------------------------------------------------------------------- /src/assets/image/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/copy.png -------------------------------------------------------------------------------- /src/assets/image/guide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/guide.png -------------------------------------------------------------------------------- /src/assets/image/like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/like.png -------------------------------------------------------------------------------- /src/assets/image/like1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/like1.png -------------------------------------------------------------------------------- /src/assets/image/like3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/like3.png -------------------------------------------------------------------------------- /src/assets/image/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/logo.png -------------------------------------------------------------------------------- /src/assets/image/logo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/logo1.png -------------------------------------------------------------------------------- /src/assets/image/mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/mute.png -------------------------------------------------------------------------------- /src/assets/image/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/play.png -------------------------------------------------------------------------------- /src/assets/image/quit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/quit.png -------------------------------------------------------------------------------- /src/assets/image/send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/send.png -------------------------------------------------------------------------------- /src/assets/image/send1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/send1.png -------------------------------------------------------------------------------- /src/assets/image/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/share.png -------------------------------------------------------------------------------- /src/assets/image/tips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/tips.png -------------------------------------------------------------------------------- /src/assets/image/tips1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/tips1.png -------------------------------------------------------------------------------- /src/assets/image/video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/video.png -------------------------------------------------------------------------------- /dist/img/guide.dfbfcbc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/guide.dfbfcbc1.png -------------------------------------------------------------------------------- /dist/img/img-1.2fcf8049.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/img-1.2fcf8049.png -------------------------------------------------------------------------------- /dist/img/img-2.5dd346dc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/img-2.5dd346dc.png -------------------------------------------------------------------------------- /dist/img/img-3.ab9a0c2e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/img-3.ab9a0c2e.png -------------------------------------------------------------------------------- /dist/img/img-4.02a3b15f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/img-4.02a3b15f.png -------------------------------------------------------------------------------- /dist/img/img-5.76607c0e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/img-5.76607c0e.png -------------------------------------------------------------------------------- /dist/img/img-6.11f1c584.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/img-6.11f1c584.png -------------------------------------------------------------------------------- /src/assets/image/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/avatar.png -------------------------------------------------------------------------------- /src/assets/image/back-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/back-img.png -------------------------------------------------------------------------------- /src/assets/image/cdn-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/cdn-logo.png -------------------------------------------------------------------------------- /src/assets/image/copy-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/copy-1.png -------------------------------------------------------------------------------- /src/assets/image/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/default.png -------------------------------------------------------------------------------- /src/assets/image/guide-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/guide-1.png -------------------------------------------------------------------------------- /src/assets/image/guzhang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/guzhang.png -------------------------------------------------------------------------------- /src/assets/image/like-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/like-0.png -------------------------------------------------------------------------------- /src/assets/image/login_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/login_bg.png -------------------------------------------------------------------------------- /src/assets/image/logo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/logo-1.png -------------------------------------------------------------------------------- /src/assets/image/message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/message.png -------------------------------------------------------------------------------- /src/assets/image/no-video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/no-video.png -------------------------------------------------------------------------------- /src/assets/image/open-mic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/open-mic.png -------------------------------------------------------------------------------- /src/assets/image/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/picture.png -------------------------------------------------------------------------------- /src/assets/image/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/player.png -------------------------------------------------------------------------------- /src/assets/image/pushing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/pushing.png -------------------------------------------------------------------------------- /src/assets/image/qr-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/qr-code.png -------------------------------------------------------------------------------- /src/assets/image/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/qrcode.png -------------------------------------------------------------------------------- /src/assets/image/share1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/share1.png -------------------------------------------------------------------------------- /src/assets/image/share2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/share2.png -------------------------------------------------------------------------------- /src/assets/image/system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/system.png -------------------------------------------------------------------------------- /src/assets/image/txc-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/txc-logo.png -------------------------------------------------------------------------------- /src/assets/image/unmute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/unmute.png -------------------------------------------------------------------------------- /src/assets/image/unmute1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/unmute1.png -------------------------------------------------------------------------------- /src/assets/image/unplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/unplay.png -------------------------------------------------------------------------------- /src/assets/image/video-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/video-bg.jpg -------------------------------------------------------------------------------- /src/assets/image/video-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/video-bg.png -------------------------------------------------------------------------------- /src/assets/image/video-gb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/video-gb.png -------------------------------------------------------------------------------- /src/assets/image/volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/volume.png -------------------------------------------------------------------------------- /dist/img/logo-list.cd0456bc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/logo-list.cd0456bc.png -------------------------------------------------------------------------------- /dist/img/mobile-bg.a687c495.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/mobile-bg.a687c495.png -------------------------------------------------------------------------------- /dist/img/no-video.f64769eb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/no-video.f64769eb.png -------------------------------------------------------------------------------- /dist/img/txc-logo.576f62f4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/txc-logo.576f62f4.png -------------------------------------------------------------------------------- /dist/img/video-gb.005bcdf6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/video-gb.005bcdf6.png -------------------------------------------------------------------------------- /src/assets/image/big-mic-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/big-mic-on.png -------------------------------------------------------------------------------- /src/assets/image/camera-max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/camera-max.png -------------------------------------------------------------------------------- /src/assets/image/chat_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/chat_close.png -------------------------------------------------------------------------------- /src/assets/image/chat_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/chat_open.png -------------------------------------------------------------------------------- /src/assets/image/close-mcp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/close-mcp.png -------------------------------------------------------------------------------- /src/assets/image/close-mic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/close-mic.png -------------------------------------------------------------------------------- /src/assets/image/live-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-empty.png -------------------------------------------------------------------------------- /src/assets/image/live-share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-share.png -------------------------------------------------------------------------------- /src/assets/image/login-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/login-log.png -------------------------------------------------------------------------------- /src/assets/image/logo-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/logo-list.png -------------------------------------------------------------------------------- /src/assets/image/mobile-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/mobile-bg.png -------------------------------------------------------------------------------- /src/assets/image/room-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/room-icon.png -------------------------------------------------------------------------------- /src/assets/image/tab_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/tab_video.png -------------------------------------------------------------------------------- /src/assets/image/time-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/time-icon.png -------------------------------------------------------------------------------- /src/components/test/img/mic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/mic.png -------------------------------------------------------------------------------- /dist/img/live-banner.4c634841.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/live-banner.4c634841.jpg -------------------------------------------------------------------------------- /dist/img/live-empty.2acb9f92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/live-empty.2acb9f92.png -------------------------------------------------------------------------------- /src/assets/image/big-camera-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/big-camera-on.png -------------------------------------------------------------------------------- /src/assets/image/big-mic-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/big-mic-off.png -------------------------------------------------------------------------------- /src/assets/image/camera-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/camera-close.png -------------------------------------------------------------------------------- /src/assets/image/camera-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/camera-open.png -------------------------------------------------------------------------------- /src/assets/image/close-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/close-camera.png -------------------------------------------------------------------------------- /src/assets/image/close-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/close-login.png -------------------------------------------------------------------------------- /src/assets/image/live-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-banner.jpg -------------------------------------------------------------------------------- /src/assets/image/mobile-player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/mobile-player.png -------------------------------------------------------------------------------- /src/assets/image/mobile-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/mobile-start.png -------------------------------------------------------------------------------- /src/assets/image/open-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/open-camera.png -------------------------------------------------------------------------------- /src/assets/image/pusher-guide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/pusher-guide.png -------------------------------------------------------------------------------- /src/assets/image/pusher-more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/pusher-more.png -------------------------------------------------------------------------------- /src/assets/image/pusher-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/pusher-start.png -------------------------------------------------------------------------------- /src/assets/image/pusher-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/pusher-stop.png -------------------------------------------------------------------------------- /src/assets/image/room-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/room-mobile.png -------------------------------------------------------------------------------- /src/assets/image/small-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/small-start.png -------------------------------------------------------------------------------- /src/assets/image/start_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/start_preview.png -------------------------------------------------------------------------------- /src/assets/image/stop-player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/stop-player.png -------------------------------------------------------------------------------- /src/assets/image/stop_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/stop_preview.png -------------------------------------------------------------------------------- /src/assets/image/time-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/time-mobile.png -------------------------------------------------------------------------------- /src/assets/image/webrtc_push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/webrtc_push.png -------------------------------------------------------------------------------- /src/components/test/img/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/camera.png -------------------------------------------------------------------------------- /src/components/test/img/code.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/code.jpg -------------------------------------------------------------------------------- /src/components/test/img/fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/fail.png -------------------------------------------------------------------------------- /src/components/test/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/logo.png -------------------------------------------------------------------------------- /src/components/test/img/logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/logout.png -------------------------------------------------------------------------------- /src/components/test/img/mic-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/mic-on.png -------------------------------------------------------------------------------- /src/components/test/img/shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/shot.png -------------------------------------------------------------------------------- /src/utils/development.js: -------------------------------------------------------------------------------- 1 | export const isDevelopment = () => { 2 | return process.env.NODE_ENV === 'development' 3 | } 4 | -------------------------------------------------------------------------------- /dist/img/mobile-list-bg.53eab997.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/mobile-list-bg.53eab997.png -------------------------------------------------------------------------------- /src/assets/image/big-camera-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/big-camera-off.png -------------------------------------------------------------------------------- /src/assets/image/live-img/img-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-img/img-1.png -------------------------------------------------------------------------------- /src/assets/image/live-img/img-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-img/img-2.png -------------------------------------------------------------------------------- /src/assets/image/live-img/img-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-img/img-3.png -------------------------------------------------------------------------------- /src/assets/image/live-img/img-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-img/img-4.png -------------------------------------------------------------------------------- /src/assets/image/live-img/img-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-img/img-5.png -------------------------------------------------------------------------------- /src/assets/image/live-img/img-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/live-img/img-6.png -------------------------------------------------------------------------------- /src/assets/image/mobile-list-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/mobile-list-bg.jpg -------------------------------------------------------------------------------- /src/assets/image/mobile-list-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/mobile-list-bg.png -------------------------------------------------------------------------------- /src/assets/image/open-microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/open-microphone.png -------------------------------------------------------------------------------- /src/assets/image/video_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/video_selected.png -------------------------------------------------------------------------------- /src/assets/image/web-pusher-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/web-pusher-stop.png -------------------------------------------------------------------------------- /src/components/liveLike/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/1.png -------------------------------------------------------------------------------- /src/components/liveLike/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/2.png -------------------------------------------------------------------------------- /src/components/liveLike/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/3.png -------------------------------------------------------------------------------- /src/components/liveLike/images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/4.png -------------------------------------------------------------------------------- /src/components/liveLike/images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/5.png -------------------------------------------------------------------------------- /src/components/liveLike/images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/6.png -------------------------------------------------------------------------------- /src/components/liveLike/images/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/7.png -------------------------------------------------------------------------------- /src/components/liveLike/images/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/8.png -------------------------------------------------------------------------------- /src/components/test/img/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/loading.png -------------------------------------------------------------------------------- /src/components/test/img/mic-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/mic-off.png -------------------------------------------------------------------------------- /src/components/test/img/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/success.png -------------------------------------------------------------------------------- /src/components/test/img/success1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/success1.png -------------------------------------------------------------------------------- /dist/fonts/element-icons.535877f5.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/fonts/element-icons.535877f5.woff -------------------------------------------------------------------------------- /dist/fonts/element-icons.732389de.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/fonts/element-icons.732389de.ttf -------------------------------------------------------------------------------- /dist/img/right-top-arrow.9761ff85.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/dist/img/right-top-arrow.9761ff85.png -------------------------------------------------------------------------------- /src/assets/image/web-pusher-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/web-pusher-start.png -------------------------------------------------------------------------------- /src/assets/image/webrtc_pusher_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/webrtc_pusher_stop.png -------------------------------------------------------------------------------- /src/assets/image/webrtc_tab_more@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/assets/image/webrtc_tab_more@2x.png -------------------------------------------------------------------------------- /src/components/liveLike/images/123.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/123.png -------------------------------------------------------------------------------- /src/components/liveLike/images/124.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/124.png -------------------------------------------------------------------------------- /src/components/liveLike/images/125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/125.png -------------------------------------------------------------------------------- /src/components/liveLike/images/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/13.png -------------------------------------------------------------------------------- /src/components/liveLike/images/bg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/bg1.png -------------------------------------------------------------------------------- /src/components/liveLike/images/bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/bg2.png -------------------------------------------------------------------------------- /src/components/liveLike/images/bg3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/bg3.png -------------------------------------------------------------------------------- /src/components/liveLike/images/bg4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/bg4.png -------------------------------------------------------------------------------- /src/components/liveLike/images/bg5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/bg5.png -------------------------------------------------------------------------------- /src/components/liveLike/images/bg6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/liveLike/images/bg6.png -------------------------------------------------------------------------------- /src/components/test/img/big-mic-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/big-mic-off.png -------------------------------------------------------------------------------- /src/components/test/img/big-mic-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/big-mic-on.png -------------------------------------------------------------------------------- /src/components/test/img/camera-max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/camera-max.png -------------------------------------------------------------------------------- /src/components/test/img/camera-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/camera-off.png -------------------------------------------------------------------------------- /src/components/test/img/camera-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/camera-on.png -------------------------------------------------------------------------------- /src/components/test/img/screen-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/screen-off.png -------------------------------------------------------------------------------- /src/components/test/img/screen-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/screen-on.png -------------------------------------------------------------------------------- /src/components/test/img/big-camera-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/big-camera-on.png -------------------------------------------------------------------------------- /src/components/test/img/big-camera-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/big-camera-off.png -------------------------------------------------------------------------------- /src/components/test/img/right-top-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TWebLive/HEAD/src/components/test/img/right-top-arrow.png -------------------------------------------------------------------------------- /src/utils/mobile.js: -------------------------------------------------------------------------------- 1 | export const isMobile = () => { 2 | return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) 3 | } 4 | -------------------------------------------------------------------------------- /src/utils/vconsole.js: -------------------------------------------------------------------------------- 1 | import { isMobile } from './mobile' 2 | import { isDevelopment } from './development' 3 | import Vconsole from 'vconsole' 4 | export function showVconsole(show) { 5 | if (isMobile() && isDevelopment() && show) { 6 | return new Vconsole() 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/app'], 3 | ignore: ['sdk/**', '../TIMSDK-WEB/dist/tim-js-sdk'], 4 | plugins: [ 5 | [ 6 | 'component', 7 | { 8 | libraryName: 'element-ui', 9 | styleLibraryName: 'theme-chalk' 10 | } 11 | ] 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/mta.js: -------------------------------------------------------------------------------- 1 | import MTA from 'mta-h5-analysis' 2 | 3 | MTA.init({ 4 | 'sid': '500732014', //必填,统计用的appid 5 | 'cid': '500732014', //如果开启自定义事件,此项目为必填,否则不填 6 | 'autoReport': 1, //是否开启自动上报(1:init完成则上报一次,0:使用pgv方法才上报) 7 | 'senseHash': 0, //hash锚点是否进入url统计 8 | 'senseQuery': 0, //url参数是否进入url统计 9 | 'performanceMonitor': 0, //是否开启性能监控 10 | 'ignoreParams': [] //开启url参数上报时,可忽略部分参数拼接上报 11 | }) 12 | 13 | export default MTA 14 | -------------------------------------------------------------------------------- /src/tim.js: -------------------------------------------------------------------------------- 1 | import TWebLive from 'tweblive' 2 | const SDKAppID = window.genTestUserSig('').SDKAppID 3 | import store from './store/index' 4 | let im = null 5 | // 初始化 SDK 实例 6 | 7 | try { 8 | im = TWebLive.createIM({ SDKAppID }) 9 | window.setLogLevel = im.setLogLevel 10 | 11 | // 无日志级别 12 | im.setLogLevel(0) 13 | } catch (e) { 14 | console.log(e) 15 | store.commit('showMessage', { message: e, type: 'error' }) 16 | } 17 | 18 | 19 | 20 | export default im 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/files/* 3 | build/temp 4 | build/temp/* 5 | docs/api/* 6 | dev.html 7 | projects 8 | .zenflow-log 9 | test/*.map 10 | .bunyipconfig.js 11 | .s3config.json 12 | package-lock.json 13 | 14 | node_modules 15 | npm-debug.log* 16 | 17 | sandbox/* 18 | !sandbox/*.example 19 | 20 | timsdk-mini-demo/dist 21 | 22 | *.swp 23 | *.swo 24 | 25 | *.orig 26 | 27 | *results.xml 28 | *.log 29 | 30 | test/coverage/* 31 | .coveralls.yml 32 | .sass-cache 33 | 34 | es5/* 35 | 36 | .idea/ 37 | package-lock.json 38 | coverage 39 | _tmp 40 | 41 | _doc/API 42 | 43 | 44 | TWebLive-demo.zip 45 | -------------------------------------------------------------------------------- /src/utils/trtcCustomMessageMap.js: -------------------------------------------------------------------------------- 1 | export const ACTION = { 2 | VIDEO_CALL_ACTION_ERROR: -2, 3 | VIDEO_CALL_ACTION_UNKNOWN: -1, 4 | VIDEO_CALL_ACTION_DIALING: 0, // 正在呼叫 5 | VIDEO_CALL_ACTION_SPONSOR_CANCEL: 1, // 发起人取消 6 | VIDEO_CALL_ACTION_REJECT: 2, // 拒接电话 7 | VIDEO_CALL_ACTION_SPONSOR_TIMEOUT: 3, // 无人接听 8 | VIDEO_CALL_ACTION_ACCEPTED: 4, // 连接进入通话 9 | VIDEO_CALL_ACTION_HANGUP: 5, // 挂断 10 | VIDEO_CALL_ACTION_LINE_BUSY: 6 // 电话占线 11 | } 12 | /** 13 | * 1: 仅仅是一个带链接的文本消息 14 | * 2: iOS支持的视频通话版本,后续已经不兼容 15 | * 3: Android/iOS/Web互通的视频通话版本 16 | */ 17 | export const VERSION = 3 -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "node": true 5 | }, 6 | "extends": [ 7 | "plugin:vue/essential", 8 | "eslint:recommended" 9 | ], 10 | "rules": { 11 | "no-console": 0, 12 | "no-undefined": 0, 13 | "no-unused-vars": "off", 14 | "quotes": ["error", "single"], 15 | "semi": ["error","never"], 16 | "space-before-blocks": [2, "always"], 17 | "comma-spacing": ["error", { "before": false, "after": true }], 18 | "space-unary-ops": "error", 19 | "object-curly-spacing": ["error", "always"], 20 | "space-infix-ops": "error", 21 | "keyword-spacing": ["error", {"after": true}] 22 | }, 23 | "parserOptions": { 24 | "parser": "babel-eslint" 25 | } 26 | } -------------------------------------------------------------------------------- /src/utils/formatDuration.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 格式化video通话时间 3 | * @export 4 | * @param {number} int 5 | * @returns 6 | */ 7 | function formatInt(int) { 8 | return int < 10 ? `0${int}` : int 9 | } 10 | export function formatDuration(duration) { 11 | if (duration < 60) { 12 | return `00:00:${formatInt(duration)}` 13 | } 14 | if (duration < 60 * 60) { 15 | const min = parseInt(duration / 60) 16 | const sec = duration - min * 60 17 | return `00:${formatInt(min)}:${formatInt(sec)}` 18 | } 19 | const hour = parseInt(duration / (60 * 60)) 20 | const remainder = duration - hour * (60 * 60) 21 | const min = parseInt(remainder / 60) 22 | const sec = remainder - min * 60 23 | return `${formatInt(hour)}:${formatInt(min)}:${formatInt(sec)}` 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | 2 | export function throttle(func, wait) { 3 | let timeout 4 | return function () { 5 | let that = this 6 | let args = arguments 7 | 8 | if (!timeout) { 9 | timeout = setTimeout(() => { 10 | timeout = null 11 | func.apply(that, args) 12 | }, wait) 13 | } 14 | } 15 | } 16 | 17 | /** 18 | * 利用 document.title 做新消息提示 19 | * @export 20 | * @param {Number} count 21 | */ 22 | export function titleNotify(count) { 23 | const hasNewMessage = count > 0 24 | if (hasNewMessage) { 25 | if (document.title.search(/\((.*?)\)/) >= 0) { 26 | document.title = document.title.replace(/\((.*?)\)/, `(${count > 99 ? '99+' : count})`) 27 | } else { 28 | document.title = `(${count})${document.title}` 29 | } 30 | } else { 31 | document.title = document.title.replace(/\((.*?)\)/, '') 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 腾讯云 Web 直播互动组件
-------------------------------------------------------------------------------- /src/assets/css/base.styl: -------------------------------------------------------------------------------- 1 | $bg = #4a5a6c 2 | 3 | $black = #000000 4 | $white = #ffffff 5 | 6 | // font-related 7 | $base = #1c2438 8 | $regular = #495060 9 | // $first = #99a8b4 10 | $first = #a5b5c1 11 | $secondary = #a5b5c1 12 | $font-light = #f7f7f8 13 | $font-dark = #76828c 14 | 15 | // border-related 16 | $border-base = #e7e7e7 17 | $border-light = #e9eaec 18 | $border-highlight = #55d48b 19 | 20 | // theme-related 21 | $dark-primary = #2b85e4 22 | $primary = #2d8cf0 23 | $light-primary = #5cadff 24 | // $light-primary = #55d48b 25 | $success = #0ac160 26 | $warning = #fa9d3b 27 | $danger = #f35f5f 28 | 29 | // background-related 30 | $light-background = #f2f7f7 31 | $background = #404953 32 | $dark-background = #363e47 33 | $deep-background = #303841 34 | 35 | $background = #404953 36 | $background-light = #f5f5f5 37 | $background-dark = #363e47 38 | $background-deep-dark = #303841 39 | 40 | 41 | $height = 80vh 42 | $width = 80vw -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 腾讯云 Web 直播互动组件 14 | 15 | 16 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/components/qrcode.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 29 | 46 | -------------------------------------------------------------------------------- /src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import store from './store' 4 | import live from './pages/live/live' 5 | 6 | Vue.use(Router) 7 | const router = new Router({ 8 | routes: [ 9 | { 10 | path: '/', 11 | name: 'live', 12 | component:live, 13 | children: [ 14 | { 15 | path: 'pusher', 16 | name: 'pusher', 17 | component: () => import(/* webpackChunkName: "group-tweblive" */ './pages/pusher/pusher') 18 | }, 19 | { 20 | path: 'player', 21 | name: 'player', 22 | component: () => import(/* webpackChunkName: "group-tweblive" */'./pages/player/player') 23 | }, 24 | ] 25 | }, 26 | ] 27 | }) 28 | router.beforeEach((to, from, next) => { 29 | // 判断是否登录 30 | if (to.fullPath === '/') { 31 | store.state.conversation.fullPath = '/' 32 | } else { 33 | store.state.conversation.fullPath = '' 34 | } 35 | next() 36 | 37 | }) 38 | 39 | export default router 40 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | //postcss.config.js文件 2 | module.exports = { 3 | plugins: { 4 | 'postcss-px-to-viewport': { 5 | unitToConvert: 'px', //需要转换的单位,默认为"px" 6 | viewportWidth: 375, // 视窗的宽度,对应的是我们设计稿的宽度 7 | // viewportHeight: 1334,//视窗的高度,根据375设备的宽度来指定,一般指定667,也可以不配置 8 | unitPrecision: 13, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除) 9 | propList: ['*'], // 能转化为vw的属性列表 10 | viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw 11 | fontViewportUnit: 'vw', //字体使用的视口单位 12 | selectorBlackList: ['.ignore-', '.hairlines'], //指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名 13 | minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值 14 | mediaQuery: false, // 允许在媒体查询中转换`px` 15 | replace: true, //是否直接更换属性值,而不添加备用属性 16 | exclude: [ 17 | /node_modules/, 18 | ], //忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件 19 | landscape: false, //是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape) 20 | landscapeUnit: 'vw', //横屏时使用的单位 21 | // landscapeWidth: 1134 //横屏时使用的视口宽度 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/pages/player/player.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 27 | 28 | 45 | -------------------------------------------------------------------------------- /src/pages/pusher/pusher.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 27 | 28 | 45 | -------------------------------------------------------------------------------- /src/utils/date.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 返回年月日 3 | * @export 4 | * @param {Date} date 5 | * @param {string} [splitor='-'] 6 | * @returns 7 | */ 8 | export function getDate(date, splitor = '-') { 9 | const year = date.getFullYear() 10 | const month = date.getMonth() + 1 11 | const day = date.getDate() 12 | return `${year}${splitor}${addZeroPrefix(month)}${splitor}${addZeroPrefix(day)}` 13 | } 14 | 15 | /** 16 | * 返回时分秒/时分 17 | * @export 18 | * @param {*} date 19 | * @param {boolean} [withSecond=false] 20 | * @returns 21 | */ 22 | export function getTime(date, withSecond = false) { 23 | const hour = date.getHours() 24 | const minute = date.getMinutes() 25 | const second = date.getSeconds() 26 | return withSecond ? `${addZeroPrefix(hour)}:${addZeroPrefix(minute)}:${addZeroPrefix(second)}` : `${hour}:${addZeroPrefix(minute)}` 27 | } 28 | 29 | export function getFullDate(date) { 30 | return `${getDate(date)} ${getTime(date)}` 31 | } 32 | 33 | export function isToday(date) { 34 | return date.toDateString() === new Date().toDateString() 35 | } 36 | 37 | 38 | /** 39 | * 个位数,加0前缀 40 | * @param {*} number 41 | * @returns 42 | */ 43 | function addZeroPrefix(number) { 44 | return number < 10 ? `0${number}` : number 45 | } 46 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 13 | 14 | 67 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #### 2020/10/23 2 | 3 | **Features** 4 | 5 | -1、根据最新的设计稿完成直播端和观众端的组件 6 | -2、增加直播间列表页面 7 | -3、适配移动端 8 | 9 | 10 | #### 2020/9/11 11 | 12 | **Features** 13 | 14 | - 更新直播端和观众端的组件UI 15 | - 区分cdn推流和webrtc低延时播放,统一观众端UI界面(手机端统一全屏) 16 | - 在主播端和观众端增加二维码分享和链接分享 17 | - 直播开始推流和停止推流下发自定义消息通知 18 | - 解决了手机webrtc推流旁路画面旋转问题 19 | 20 | **Changes** 21 | 22 | - 优化项目代码,分离逻辑层和UI层,便于用户修改UI界面,减少代码重复 23 | - 全新SDK 版本更新 1.0.3 24 | 25 | 26 | #### 2020/8/27 27 | 28 | **Features** 29 | 30 | - TWebLive demo 新加一分钟推流组件 31 | - TWebLive demo 新增低延时播放组件 32 | - TWebLive demo 支持PC端和移动端 33 | 34 | **Changes** 35 | 36 | - TWebLive demo 移动端播放器体验优化 37 | - 全新SDK 版本更新 1.0.1 38 | 39 | #### 2020/7/17 40 | 41 | **Features** 42 | 43 | - TWebLive demo 消息增加时间 44 | - TWebLive demo 增加二维码动态生成组件 45 | - TWebLive demo 引流,补充QQ技术交流群、github地址 46 | 47 | **Changes** 48 | 49 | - TWebLive demo 移动端播放器体验优化 50 | - SDK 版本更新至 0.3.2 51 | 52 | #### 2020/7/7 53 | 54 | **Features** 55 | 56 | - TWebLive demo canvas实现点赞动画 57 | 58 | **Changes** 59 | 60 | - TWebLive demo 播放器添加默认背景图片 61 | - SDK 版本更新至 0.3.1 62 | 63 | #### 2020/6/19 64 | 65 | **Features** 66 | 67 | - TWebLive demo Web端聊天区支持头像 68 | 69 | **Changes** 70 | 71 | - SDK 版本更新至 0.3.0 72 | 73 | #### 2020/6/24 74 | 75 | **Features** 76 | 77 | - TWebLive demo 移动端聊天区支持头像 78 | 79 | **Changes** 80 | 81 | - 优化发消息体验,输入完立即上屏 82 | - 关闭页面时尝试主动退群 83 | 84 | -------------------------------------------------------------------------------- /src/assets/icon/tim.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'tim'; 3 | src: url('tim.eot?gollaf'); 4 | src: url('tim.eot?gollaf#iefix') format('embedded-opentype'), 5 | url('tim.ttf?gollaf') format('truetype'), 6 | url('tim.woff?gollaf') format('woff'), 7 | url('tim.svg?gollaf#tim') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | font-display: block; 11 | } 12 | 13 | [class^="tim-icon-"], [class*=" tim-icon-"] { 14 | /* use !important to prevent issues with browser extensions that change fonts */ 15 | font-family: 'tim' !important; 16 | speak: none; 17 | font-style: normal; 18 | font-weight: normal; 19 | font-variant: normal; 20 | text-transform: none; 21 | line-height: 1; 22 | 23 | /* Better Font Rendering =========== */ 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | } 27 | 28 | .tim-icon-friend-add:before { 29 | content: "\e907"; 30 | } 31 | .tim-icon-close:before { 32 | content: "\e901"; 33 | } 34 | .tim-icon-right:before { 35 | content: "\e903"; 36 | } 37 | .tim-icon-add:before { 38 | content: "\e904"; 39 | } 40 | .tim-icon-refresh:before { 41 | content: "\e905"; 42 | } 43 | .tim-icon-send:before { 44 | content: "\e902"; 45 | } 46 | .tim-icon-angle:before { 47 | content: "\e900"; 48 | } 49 | .tim-icon-angle-middle:before { 50 | content: "\e906"; 51 | } 52 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { 3 | MessageBox, 4 | Button, 5 | Input, 6 | Dialog, 7 | Dropdown, 8 | DropdownMenu, 9 | DropdownItem, 10 | Form, 11 | FormItem, 12 | Popover, 13 | Tooltip, 14 | Divider, 15 | Select, 16 | Option, 17 | Slider, 18 | Message, 19 | } from 'element-ui' 20 | import App from './App.vue' 21 | import store from './store/index' 22 | import router from './router' 23 | import TWebLive from 'tweblive' 24 | import im from 'tim' 25 | // import { showVconsole } from './utils/vconsole' 26 | import './assets/icon/iconfont.css' 27 | import './assets/icon/tim.css' 28 | import './assets/css/reset.css' 29 | import './assets/css/animate.css' 30 | import VueClipboard from 'vue-clipboard2' 31 | 32 | 33 | window.im = im 34 | window.TWebLive = TWebLive 35 | window.store = store 36 | Vue.prototype.$bus = new Vue() // event Bus 用于无关系组件间的通信。 37 | Vue.prototype.im = im 38 | Vue.prototype.TWebLive = TWebLive 39 | Vue.prototype.$store = store 40 | Vue.prototype.$confirm = MessageBox.confirm 41 | 42 | 43 | Vue.use(Button) 44 | Vue.use(Input) 45 | Vue.use(Dialog) 46 | Vue.use(Dropdown) 47 | Vue.use(DropdownMenu) 48 | Vue.use(DropdownItem) 49 | Vue.use(Form) 50 | Vue.use(FormItem) 51 | Vue.use(Popover) 52 | Vue.use(Tooltip) 53 | Vue.use(Divider) 54 | Vue.use(Select) 55 | Vue.use(Option) 56 | Vue.use(Slider) 57 | Vue.use(VueClipboard) 58 | 59 | // 在移动端开发环境下是否开启 vconsole,默认关闭 60 | // showVconsole(false) 61 | 62 | new Vue({ 63 | router, 64 | store, 65 | render: h => h(App) 66 | }).$mount('#app') 67 | -------------------------------------------------------------------------------- /check-tweblive-version.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | const fs = require('fs') 3 | const path = require('path') 4 | const { promisify } = require('util') 5 | const exec = require('child_process').exec 6 | 7 | const target = './sdk' 8 | 9 | const readFileAsync = promisify(fs.readFile) 10 | const readdirAsync = promisify(fs.readdir) 11 | const execAsync = promisify(exec) 12 | 13 | const check = async function (targetPath) { // 检验sdk/tim-js.js是否更新到最新版本 14 | try { 15 | let files = await readdirAsync(targetPath) 16 | files.forEach(async (filename) => { 17 | let filedir = path.join(targetPath, filename) 18 | if (filename === 'sdk') { 19 | check(filedir) 20 | } 21 | if (filename === 'tweblive.js') { 22 | let subFiles = await readFileAsync(filedir, { encoding: 'utf-8' }) 23 | let execResult = await execAsync('npm show tweblive version') 24 | if (execResult.error) { 25 | console.log(execResult.error.stack); 26 | console.log('Error code: ' + execResult.error.code) 27 | } 28 | console.log('The latest version of [tweblive] is ' + execResult.stdout) 29 | if (subFiles.match(execResult.stdout.replace(/\n/g, ''))) { // 去掉换行符 30 | console.log('\033[32m successfully: [sdk/tweblive.js] is the latest! \033[0m') 31 | } else { 32 | console.log('\033[33m WARNING: Please update [sdk/tweblive.js] to the latest version! \033[0m') 33 | } 34 | } 35 | }) 36 | } catch (e) { 37 | console.log(e) 38 | } 39 | } 40 | check(target) 41 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import conversation from './modules/conversation' 4 | import user from './modules/user' 5 | import { Message } from 'element-ui' 6 | 7 | Vue.use(Vuex) 8 | 9 | export default new Vuex.Store({ 10 | state: { 11 | current: Date.now(), // 当前时间 12 | intervalID: 0, 13 | message: undefined, 14 | tips:{ 15 | status:false, 16 | content:'', 17 | title:'' 18 | } 19 | }, 20 | getters: { 21 | hidden(state) { 22 | // eslint-disable-next-line no-unused-vars 23 | const temp = state.current 24 | if (typeof document.hasFocus !== 'function') { 25 | return document.hidden 26 | } 27 | return !document.hasFocus() 28 | } 29 | }, 30 | mutations: { 31 | startComputeCurrent(state) { 32 | state.intervalID = setInterval(() => { 33 | state.current = Date.now() 34 | }, 500) 35 | }, 36 | stopComputeCurrent(state) { 37 | clearInterval(state.intervalID) 38 | state.intervalID = 0 39 | }, 40 | showMessage(state, options) { 41 | if (state.message) { 42 | state.message.close() 43 | } 44 | state.message = Message({ 45 | message: options.message, 46 | type: options.type || 'success', 47 | duration: options.duration || 2000, //2000 48 | offset: 40 49 | }) 50 | }, 51 | showTips(state, data) { 52 | state.tips.status = data.status 53 | state.tips.content = data.content 54 | state.tips.title = data.title || '提示' 55 | } 56 | }, 57 | modules: { 58 | conversation, 59 | user 60 | } 61 | }) 62 | -------------------------------------------------------------------------------- /src/utils/decodeText.js: -------------------------------------------------------------------------------- 1 | import { emojiMap, emojiUrl } from './emojiMap' 2 | /** 传入messageBody(群系统消息SystemMessage,群提示消息GroupTip除外) 3 | * payload = { 4 | * msgType: 'TIMTextElem', 5 | * msgContent: { 6 | * text: 'AAA[龇牙]AAA[龇牙]AAA[龇牙AAA]' 7 | * } 8 | *} 9 | **/ 10 | export function decodeText (text) { 11 | let renderDom = [] 12 | // 文本消息 13 | let temp = text 14 | 15 | let left = -1 16 | let right = -1 17 | while (temp !== '' && typeof temp !== 'undefined') { 18 | left = temp.indexOf('[') 19 | right = temp.indexOf(']') 20 | switch (left) { 21 | case 0: 22 | if (right === -1) { 23 | renderDom.push({ 24 | name: 'text', 25 | text: temp 26 | }) 27 | temp = '' 28 | } else { 29 | let _emoji = temp.slice(0, right + 1) 30 | if (emojiMap[_emoji]) { 31 | renderDom.push({ 32 | name: 'img', 33 | src: emojiUrl + emojiMap[_emoji] 34 | }) 35 | temp = temp.substring(right + 1) 36 | } else { 37 | renderDom.push({ 38 | name: 'text', 39 | text: '[' 40 | }) 41 | temp = temp.slice(1) 42 | } 43 | } 44 | break 45 | case -1: 46 | renderDom.push({ 47 | name: 'text', 48 | text: temp 49 | }) 50 | temp = '' 51 | break 52 | default: 53 | renderDom.push({ 54 | name: 'text', 55 | text: temp.slice(0, left) 56 | }) 57 | temp = temp.substring(left) 58 | break 59 | } 60 | } 61 | return renderDom 62 | } 63 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | import defaultImg from '../../assets/image/default.png' 2 | 3 | const user = { 4 | state: { 5 | currentUserProfile: {}, 6 | isLogin: false, // 是否在登录状态 目前是token为主 7 | isSDKReady: false, // TIM SDK 是否 ready 8 | userID: 0, 9 | userSig: '', 10 | sdkAppID: 0, 11 | errorImg: 'this.src="' + require('../../assets/image/default.png') + '"', //加载图片报错时处理方法 12 | userInfo: { 13 | nickName: '', 14 | avatar: '', 15 | defaultImg: defaultImg 16 | }, 17 | }, 18 | mutations: { 19 | updateCurrentUserProfile(state, userProfile) { 20 | state.currentUserProfile = userProfile 21 | }, 22 | toggleIsLogin(state, isLogin) { 23 | state.isLogin = typeof isLogin === 'undefined' ? !state.isLogin : isLogin 24 | }, 25 | toggleIsSDKReady(state, isSDKReady) { 26 | state.isSDKReady = typeof isSDKReady === 'undefined' ? !state.isSDKReady : isSDKReady 27 | }, 28 | // reset(state) { 29 | // Object.assign(state, { 30 | // currentUserProfile: {}, 31 | // isLogin: false, // 是否显示登录 32 | // isSDKReady: false // TIM SDK 是否 ready 33 | // }) 34 | // }, 35 | GET_USER_INFO(state, payload) { 36 | state.userID = payload.userID 37 | state.userSig = payload.userSig 38 | state.sdkAppID = payload.sdkAppID 39 | }, 40 | }, 41 | actions: { 42 | // logout(context) { 43 | // // 若有当前会话,在退出登录时已读上报 44 | // if (context.rootState.conversation.currentConversation.conversationID) { 45 | // tim.setMessageRead({ conversationID: context.rootState.conversation.currentConversation.conversationID }) 46 | // } 47 | // tim.logout().then(() => { 48 | // context.commit('toggleIsLogin') 49 | // context.commit('stopComputeCurrent') 50 | // context.commit('reset') 51 | // }) 52 | // } 53 | } 54 | } 55 | 56 | export default user 57 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | function resolve(dir) { 4 | return path.join(__dirname, dir) 5 | } 6 | module.exports = { 7 | publicPath: './', 8 | assetsDir: './', 9 | productionSourceMap: false, 10 | devServer:{ 11 | https:true 12 | }, 13 | chainWebpack: config => { 14 | config.resolve.alias 15 | .set('@', resolve('src')) 16 | .set('tim', resolve('src/tim.js')) 17 | // 删除预加载 18 | config.plugins.delete('preload') 19 | config.plugins.delete('prefetch') 20 | // 压缩代码 21 | config.optimization.minimize(true) 22 | // 分割代码 23 | config.optimization.splitChunks({ 24 | chunks: 'all' 25 | }) 26 | }, 27 | css: { 28 | loaderOptions: { 29 | stylus: { 30 | 'resolve url': true, 31 | // 自定义主题场景 32 | import: [path.resolve(__dirname, './src/assets/css/base.styl')] 33 | } 34 | } 35 | } 36 | // lintOnSave: true, 37 | // css: { 38 | // loaderOptions: { 39 | // postcss: { 40 | // plugins: [ 41 | // require('postcss-plugin-px2rem')({ 42 | // // rootValue: 100, //换算基数, 默认100 ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。 43 | // // unitPrecision: 5, //允许REM单位增长到的十进制数字。 44 | // //propWhiteList: [], //默认值是一个空数组,这意味着禁用白名单并启用所有属性。 45 | // // propBlackList: [], //黑名单 46 | // exclude: /(node_module)/, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值 47 | // // selectorBlackList: [], //要忽略并保留为px的选择器 48 | // // ignoreIdentifier: false, //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。 49 | // // replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。 50 | // mediaQuery: false, //(布尔值)允许在媒体查询中转换px。 51 | // minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0 52 | // }), 53 | // ] 54 | // } 55 | // } 56 | // }, 57 | } 58 | -------------------------------------------------------------------------------- /src/components/base/tips.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 40 | 41 | 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tweblive-demo", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node --max_old_space_size=4096 node_modules/@vue/cli-service/bin/vue-cli-service.js serve --open", 7 | "serve": "node node_modules/@vue/cli-service/bin/vue-cli-service.js serve", 8 | "build": "node node_modules/@vue/cli-service/bin/vue-cli-service.js build", 9 | "lint": "node node_modules/@vue/cli-service/bin/vue-cli-service.js lint src --ext .vue,.js --fix" 10 | }, 11 | "dependencies": { 12 | "animate.css": "^4.1.0", 13 | "archiver": "^4.0.1", 14 | "axios": "^0.19.0", 15 | "core-js": "^2.6.11", 16 | "element-ui": "^2.13.0", 17 | "jquery": "^3.5.1", 18 | "jsdom": "^16.4.0", 19 | "location": "0.0.1", 20 | "md5": "^2.2.1", 21 | "navigator": "^1.0.1", 22 | "postcss-plugin-px2rem": "^0.8.1", 23 | "postcss-px-to-viewport": "^1.1.1", 24 | "postcss-pxtorem": "^5.1.1", 25 | "qrcode": "^1.4.4", 26 | "tim-js-sdk": "^2.9.0", 27 | "trtc-js-sdk": "^4.6.6", 28 | "tweblive": "^1.3.1", 29 | "vconsole": "^3.3.4", 30 | "vue": "^2.6.11", 31 | "vue-clipboard2": "^0.3.1", 32 | "vue-router": "^3.4.3", 33 | "vuex": "^3.1.2", 34 | "xmlhttprequest": "^1.8.0" 35 | }, 36 | "devDependencies": { 37 | "@vue/cli-plugin-babel": "^3.12.1", 38 | "@vue/cli-plugin-eslint": "^3.12.1", 39 | "@vue/cli-service": "^3.12.1", 40 | "babel-eslint": "^10.0.3", 41 | "babel-plugin-component": "^1.1.1", 42 | "cp": "^0.2.0", 43 | "eslint": "^5.16.0", 44 | "eslint-plugin-vue": "^5.0.0", 45 | "stylus": "^0.54.7", 46 | "mta-h5-analysis": "^2.0.15", 47 | "stylus-loader": "^3.0.2", 48 | "vue-template-compiler": "^2.6.11" 49 | }, 50 | "postcss": { 51 | "plugins": { 52 | "autoprefixer": {} 53 | } 54 | }, 55 | "browserslist": [ 56 | "> 1%", 57 | "last 2 versions", 58 | "not ie <= 8" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /src/assets/icon/tim.ttf: -------------------------------------------------------------------------------- 1 |  �0OS/2��`cmapVҎTgasppglyf���x�headL�P6hhea���$hmtx#���0loca�*�maxpn� name@��xVpostp ��������3 @����@�@ 8 2 |  ����� ���������797979����)67>76767>767>75>54&'#.#0"#1!062(  3 | ��3B@@|;<9 @44Y(((  &������(��7& 64'&" &" 3267 326764'- 4 | 5 |  6 | ����  7 | 8 | �� 9 |        ��� 10 |  11 | �� 12 |  ����  ��   3;��%%7_�����}Z���o�d���v�H҂��8�$.#"1'.#"1131267164'6  ���  �  w 13 | ��^�  �� 14 |  ��@ $%2651!2654!4&#"1!"31!3   � �   �    � � �]`=N"1#"'.'&547>7632#"313265154&#"1.#1"327>7654&#@ O44<<44OO44<2\'U  �  -s@I@@``@@II@@` � <45NN54<;54N!  �  Q&+_@@II@@``@@I 4����)67>76767>767>75>54&'1.#0"#1!0j2(  ��3B@@|;<9 @43Z(((  &������(�6hc.Kk4'.'&#"326767>767327>765!47>7632#&'.'&#54&#"#";326=32654&I128911JK?+%%;    15 | N216711H�9&',,&'99%&+ +%&7< =  = < T911JJ119J"E**/  6,-BI217,'&99&',+%&99%%��<< << ��_�o_<� ٷsٷs�������� ��3���4� 16 | \���*��l l�<*Q 3 17 | Z  C - T  6 18 | 4ttimtimVersion 1.1Version 1.1timtimtimtimRegularRegulartimtimFont generated by IcoMoon.Font generated by IcoMoon. -------------------------------------------------------------------------------- /src/components/chatroom/message-status-icon.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 61 | 62 | 79 | -------------------------------------------------------------------------------- /src/assets/icon/tim.woff: -------------------------------------------------------------------------------- 1 | wOFF� �OS/2``�cmaphTTVҎgasp�glyf��؂��head�66L�hhea�$$��hmtx�00#��loca(�*maxpD nnamedVV@��xpost� ��������3 @����@�@ 8 2 |  ����� ���������797979����)67>76767>767>75>54&'#.#0"#1!062(  3 | ��3B@@|;<9 @44Y(((  &������(��7& 64'&" &" 3267 326764'- 4 | 5 |  6 | ����  7 | 8 | �� 9 |        ��� 10 |  11 | �� 12 |  ����  ��   3;��%%7_�����}Z���o�d���v�H҂��8�$.#"1'.#"1131267164'6  ���  �  w 13 | ��^�  �� 14 |  ��@ $%2651!2654!4&#"1!"31!3   � �   �    � � �]`=N"1#"'.'&547>7632#"313265154&#"1.#1"327>7654&#@ O44<<44OO44<2\'U  �  -s@I@@``@@II@@` � <45NN54<;54N!  �  Q&+_@@II@@``@@I 4����)67>76767>767>75>54&'1.#0"#1!0j2(  ��3B@@|;<9 @43Z(((  &������(�6hc.Kk4'.'&#"326767>767327>765!47>7632#&'.'&#54&#"#";326=32654&I128911JK?+%%;    15 | N216711H�9&',,&'99%&+ +%&7< =  = < T911JJ119J"E**/  6,-BI217,'&99&',+%&99%%��<< << ��_�o_<� ٷsٷs�������� ��3���4� 16 | \���*��l l�<*Q 3 17 | Z  C - T  6 18 | 4ttimtimVersion 1.1Version 1.1timtimtimtimRegularRegulartimtimFont generated by IcoMoon.Font generated by IcoMoon. -------------------------------------------------------------------------------- /src/assets/icon/tim.eot: -------------------------------------------------------------------------------- 1 | $ ��LPo�_�timRegularVersion 1.1tim �0OS/2��`cmapVҎTgasppglyf���x�headL�P6hhea���$hmtx#���0loca�*�maxpn� name@��xVpostp ��������3 @����@�@ 8 2 |  ����� ���������797979����)67>76767>767>75>54&'#.#0"#1!062(  3 | ��3B@@|;<9 @44Y(((  &������(��7& 64'&" &" 3267 326764'- 4 | 5 |  6 | ����  7 | 8 | �� 9 |        ��� 10 |  11 | �� 12 |  ����  ��   3;��%%7_�����}Z���o�d���v�H҂��8�$.#"1'.#"1131267164'6  ���  �  w 13 | ��^�  �� 14 |  ��@ $%2651!2654!4&#"1!"31!3   � �   �    � � �]`=N"1#"'.'&547>7632#"313265154&#"1.#1"327>7654&#@ O44<<44OO44<2\'U  �  -s@I@@``@@II@@` � <45NN54<;54N!  �  Q&+_@@II@@``@@I 4����)67>76767>767>75>54&'1.#0"#1!0j2(  ��3B@@|;<9 @43Z(((  &������(�6hc.Kk4'.'&#"326767>767327>765!47>7632#&'.'&#54&#"#";326=32654&I128911JK?+%%;    15 | N216711H�9&',,&'99%&+ +%&7< =  = < T911JJ119J"E**/  6,-BI217,'&99&',+%&99%%��<< << ��_�o_<� ٷsٷs�������� ��3���4� 16 | \���*��l l�<*Q 3 17 | Z  C - T  6 18 | 4ttimtimVersion 1.1Version 1.1timtimtimtimRegularRegulartimtimFont generated by IcoMoon.Font generated by IcoMoon. -------------------------------------------------------------------------------- /src/components/test/presetting.js: -------------------------------------------------------------------------------- 1 | /* global $ setBtnClickFuc */ 2 | 3 | // preset before starting RTC 4 | import $ from 'jquery' 5 | 6 | class Presetting { 7 | constructor() { 8 | this.options = { 9 | fetchUrl: 'https://service.trtc.qcloud.com/release/UserSigService', 10 | defaultSdkAppId: 1400188366, // unified sdkAppId for Demos on all platforms. 11 | accountType: 14418 12 | 13 | } 14 | 15 | } 16 | 17 | 18 | init() { 19 | // populate userId/roomId 20 | $('#userId').val('user_' + parseInt(Math.random() * 100000000)) 21 | $('#roomId').val(parseInt(Math.random() * 100000)) 22 | const roomId = this.query('roomId') 23 | const userId = this.query('userId') 24 | const privMap = this.query('privMap') 25 | if (roomId) { 26 | $('#roomId').val(roomId) 27 | } 28 | if (userId) { 29 | $('#userId').val(userId) 30 | } 31 | if (privMap) { 32 | $('#privMap').val(privMap) 33 | } 34 | $('#main-video-btns').hide() 35 | $('.mask').hide() 36 | setBtnClickFuc() 37 | } 38 | 39 | query(name) { 40 | const match = window.location.search.match(new RegExp('(\\?|&)' + name + '=([^&]*)(&|$)')) 41 | return !match ? '' : decodeURIComponent(match[2]) 42 | } 43 | 44 | login(share, callback) { 45 | let userId = 'linda'//$('#userId').val(); 46 | if (share) { 47 | userId = 'share_' + userId 48 | } 49 | const sdkAppId = this.query('sdkAppId') || this.options.defaultSdkAppId 50 | const roomId = '3456'//$('#roomId').val() 51 | const privMap = $('#privMap').val() 52 | $.ajax({ 53 | type: 'POST', 54 | url: this.options.fetchUrl, 55 | dataType: 'json', 56 | data: JSON.stringify({ 57 | pwd: '12345678', 58 | appid: parseInt(sdkAppId), 59 | roomnum: parseInt(roomId), 60 | privMap: parseInt(privMap), 61 | identifier: userId, 62 | accounttype: this.options.accountType 63 | }), 64 | success: function (json) { 65 | if (json && json.errorCode === 0) { 66 | const userSig = json.data.userSig 67 | const privateMapKey = json.data.privMapEncrypt 68 | callback({ 69 | sdkAppId, 70 | userId, 71 | userSig, 72 | roomId, 73 | privateMapKey 74 | }) 75 | } else { 76 | console.error('got invalid json:' + json) 77 | } 78 | }, 79 | error: function (err) { 80 | console.error('failed to retreive userSig') 81 | } 82 | }) 83 | } 84 | } 85 | 86 | export default Presetting 87 | -------------------------------------------------------------------------------- /dist/debug/GenerateTestUserSig.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | const _SDKAPPID = 0; 3 | const _SECRETKEY = ''; 4 | const _PLAYDOMAIN = ''; // 播放域名配置 5 | /* 6 | * Module: GenerateTestUserSig 7 | * 8 | * Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。 9 | * 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。 10 | * 11 | * Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下: 12 | * 13 | * 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品, 14 | * 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。 15 | * 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。 16 | * 17 | * 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。 18 | * 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。 19 | * 20 | * Reference:https://cloud.tencent.com/document/product/647/17275#Server 21 | */ 22 | function genTestUserSig(userID) { 23 | /** 24 | * 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。 25 | * 26 | * 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId, 27 | * 它是腾讯云用于区分客户的唯一标识。 28 | */ 29 | var SDKAPPID = _SDKAPPID; 30 | 31 | /** 32 | * 签名过期时间,建议不要设置的过短 33 | *

34 | * 时间单位:秒 35 | * 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天 36 | */ 37 | var EXPIRETIME = 604800; 38 | 39 | /** 40 | * 计算签名用的加密密钥,获取步骤如下: 41 | * 42 | * step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个, 43 | * step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。 44 | * step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中 45 | * 46 | * 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。 47 | * 文档:https://cloud.tencent.com/document/product/647/17275#Server 48 | */ 49 | var SECRETKEY = _SECRETKEY; 50 | /** 51 | * 配置播放域名并完成 CNAME,获取步骤如下: 52 | * step1. 登录云直播[控制台](https://console.cloud.tencent.com/live/)。 53 | * step2. 在左侧导航栏选择【域名管理】,您会看到在您的域名列表新增了一个推流域名,格式为 xxxxx.livepush.myqcloud.com,其中 xxxxx 是一个数字, 54 | 叫做 bizid,您可以在实时音视频控制台 >【应用管理】>【应用信息】中查找到 bizid 信息。 55 | * step3. 单击【添加域名】,输入您已经备案过的播放域名,选择域名类型为【播放域名】,选择加速区域(默认为【中国大陆】),单击【确定】即可。 56 | * step4. 域名添加成功后,系统会为您自动分配一个 CNAME 域名(以.liveplay.myqcloud.com为后缀)。CNAME 域名不能直接访问, 57 | 您需要在域名服务提供商处完成 CNAME 配置,配置生效后,即可享受云直播服务。具体操作请参见 CNAME 配置。 58 | 59 | * 注意:如果不需要 CDN 直播观看,此步骤可略过 60 | * 文档:https://cloud.tencent.com/document/product/647/16826 61 | */ 62 | var PLAYDOMAIN = _PLAYDOMAIN; 63 | 64 | var generator = new window.LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME); 65 | var userSig = generator.genTestUserSig(userID); 66 | return { 67 | SDKAppID: SDKAPPID, 68 | userSig: userSig, 69 | playDomain: PLAYDOMAIN 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /public/debug/GenerateTestUserSig.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | const _SDKAPPID = 0; 3 | const _SECRETKEY = ''; 4 | const _PLAYDOMAIN = ''; // 播放域名配置 5 | /* 6 | * Module: GenerateTestUserSig 7 | * 8 | * Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。 9 | * 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。 10 | * 11 | * Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下: 12 | * 13 | * 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品, 14 | * 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。 15 | * 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。 16 | * 17 | * 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。 18 | * 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。 19 | * 20 | * Reference:https://cloud.tencent.com/document/product/647/17275#Server 21 | */ 22 | function genTestUserSig(userID) { 23 | /** 24 | * 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。 25 | * 26 | * 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId, 27 | * 它是腾讯云用于区分客户的唯一标识。 28 | */ 29 | var SDKAPPID = _SDKAPPID; 30 | 31 | /** 32 | * 签名过期时间,建议不要设置的过短 33 | *

34 | * 时间单位:秒 35 | * 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天 36 | */ 37 | var EXPIRETIME = 604800; 38 | 39 | /** 40 | * 计算签名用的加密密钥,获取步骤如下: 41 | * 42 | * step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个, 43 | * step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。 44 | * step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中 45 | * 46 | * 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。 47 | * 文档:https://cloud.tencent.com/document/product/647/17275#Server 48 | */ 49 | var SECRETKEY = _SECRETKEY; 50 | /** 51 | * 配置播放域名并完成 CNAME,获取步骤如下: 52 | * step1. 登录云直播[控制台](https://console.cloud.tencent.com/live/)。 53 | * step2. 在左侧导航栏选择【域名管理】,您会看到在您的域名列表新增了一个推流域名,格式为 xxxxx.livepush.myqcloud.com,其中 xxxxx 是一个数字, 54 | 叫做 bizid,您可以在实时音视频控制台 >【应用管理】>【应用信息】中查找到 bizid 信息。 55 | * step3. 单击【添加域名】,输入您已经备案过的播放域名,选择域名类型为【播放域名】,选择加速区域(默认为【中国大陆】),单击【确定】即可。 56 | * step4. 域名添加成功后,系统会为您自动分配一个 CNAME 域名(以.liveplay.myqcloud.com为后缀)。CNAME 域名不能直接访问, 57 | 您需要在域名服务提供商处完成 CNAME 配置,配置生效后,即可享受云直播服务。具体操作请参见 CNAME 配置。 58 | 59 | * 注意:如果不需要 CDN 直播观看,此步骤可略过 60 | * 文档:https://cloud.tencent.com/document/product/647/16826 61 | */ 62 | var PLAYDOMAIN = _PLAYDOMAIN; 63 | 64 | var generator = new window.LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME); 65 | var userSig = generator.genTestUserSig(userID); 66 | return { 67 | SDKAppID: SDKAPPID, 68 | userSig: userSig, 69 | playDomain: PLAYDOMAIN 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /src/assets/icon/iconfont.woff2: -------------------------------------------------------------------------------- 1 | wOF2 T h BV�p 2 | �4�46$8  �m�%#�V���9`��hl�������=��Jz">�}"�[ҟ�m�H������ �::�;�f 3 | LG%<�ш������Ӧ������"�F}.*J�R��F�i��$��R �c5�@Z��5��Ҟ������o��ZFD�.y�/?=����� ��&�9@07�~��h]�<$�l��� �f����v��}�7.^B�Ј�J,�0�~�N��|h���(ML����`�]�*Q&.��%���X��<|�����0 B%���� ���=` <�ǰqF�)��i�}�N��rj썁>�/ Wl�ƚi��_L���ŌY � x��N,SnΊT�T�V��x)��Z|O�4|a��OT !TA ��0�6�XP���*s��KX*���B ��� Y��(� 4 | �o�%#̘Ot����Np���Xl��ȍ�����F'�x ��B!/&���&������QH�@�a�G� T|��ǫ����?�H�(���Jh�  2�@� � ����j|���Q�/���M�������>����1���ئ[���i�e�=A��gB�;�8�T⶞X���b�� o�kn�Gz3��OH���Zju�1&���<�َ�dGC�E\��k_��c�v�]�m/�z�Mk���1��=�H8�֓,jh¸fo 5 | F�tEstα[���d�Q���a���F�S��=��h���6.��s��K3�GA���z�I���Q>+�#`;.a�kF��1�h'������� �=�X�-��綑-C���,c��H������tv��r���6�ˍ�l;(qU٥F��d�4a�S.6BF-����C$Q �$#�2j���E�d��r��rʝ�}��>W��s4-�aH��iмnX�>6Xʯw����n:��mԝ��}E����T��:[�~�z� �t��<�����eV/�^K� 6 | *�"~z����>�I_<�gA���� ��}aaS�������@�8=�9�B�zߧk�Y��P��pS�̑r�j���}��ޑ�bh|��ǣ�����BE�Moؐ���ё'�� �_L��e���B�_�m갉|@�<=�È2r4�$�ܘhn� �� p�����1т��v��o��U�C.]�M=�||%h�%K�����]�Q�X���i|���-H����ijԵ�ߪ_ :�v�1O5-�_s��iޫU]�W�%���_���2u�g����_Nj�����*�LE����3s��Wo�J�*f]�^Q;��~���V���;:XJOh=�V#�1�{�DK���n�#���G2���ڄ(�I&y�∅���,�]�w�jߤ�N�o�������wԀ���Gj�B[x 7 | ����P3\S�/6݂e�ԥ�EM�a�[���/b*���a�G�-?�mS�0�cj���Y;�v�<�٫� 6�����j��T(]uiK��ہR�z���AqW�1����� 8 | �m�O�DJFJ|���:�6���e�h,.5������� 9 | S�8����͙�� �l"� 7�Z��j��8�8J,�;��Vs�Z])a���'�G�G�DUuٴ���Xe%�o�X���������]�E��3�ح�2@9�K�!3�iHbHr������7 .w�x._ ��5 ��/77^#T�FT� JÃQ�pV�,���Zt�8R�f�����ZHJ�$� 10 | ɜ��?��Qn�����b�.rd,���#I�Hz��������y|3�֖��Y��Y�kъg�_~��M:vL1D���O��Hv]����?~��eWy��l��-���o�O� �cE������a��ZK�TMx�\�o{�tŦ�j�Ԕs"_Y�(���e[�����Z�0u�yϛoj�G��ʥ1�R�{N�~�ҥ e��~H{cy �����nݐ��������4��b�a��tlI�yIѮc�0�q|��U~�.�6�0R�GK^K��b��c P�Z���VS?%�)� CoI+��<�텳�"����<[�<.��9��"|\s$�#u�r���"�9� �pӅ�f=�D�C��-�����ّ}��i4�dc���.��c ?���M�?q`v��0�F�X��1�N8Z�h�.]n�iANI����68p��۱�s��!]3���f:�" ��=�FGs~N����9��W�EX@O�0��dʐC�wf�B���@tj���CCL�?W[2H@��� lP�/6�hl�?Z���vw��঱h$x�K����5���h88�@��zpH 6�m���?����� �gRN �-��۲����6B�6���+� pR�ט�A}��o5�\�9��F��^ B��o���������o�(���7%ʢdށh�L�I���d.��G��T2�0�j$�`d�f$c 11 | g�q�5����p�ߛ�9|��!C�ИD" )���2*��'��hD�����hg�2Ѭ���\�#�Us��ˆ��3��v"L���)�=C�<��jDo�ֵٝYi����Jt���¤9�����o��W�d�S�̅�Z����k-y+���v�0rv�> Cϻ$�Aj��-:�UM�2u�j|1��y/�e��� J��j�aZ��zaw�Ay<�^i��N�D*�u6�QmoL�6���6Y����T�mZ99�h�h�t)!�%�J�����y[y\, -------------------------------------------------------------------------------- /archive.js: -------------------------------------------------------------------------------- 1 | // require modules 2 | var fs = require('fs'); 3 | var archiver = require('archiver'); 4 | 5 | // create a file to stream archive data to. 6 | var output = fs.createWriteStream(__dirname + '/TWebLive-demo.zip'); 7 | var archive = archiver('zip', { 8 | zlib: { level: 9 } // Sets the compression level. 9 | }); 10 | 11 | // listen for all archive data to be written 12 | // 'close' event is fired only when a file descriptor is involved 13 | output.on('close', function() { 14 | console.log(archive.pointer() + ' total bytes'); 15 | console.log('archiver has been finalized and the output file descriptor has closed.'); 16 | }); 17 | 18 | // This event is fired when the data source is drained no matter what was the data source. 19 | // It is not part of this library but rather from the NodeJS Stream API. 20 | // @see: https://nodejs.org/api/stream.html#stream_event_end 21 | output.on('end', function() { 22 | console.log('Data has been drained'); 23 | }); 24 | 25 | // good practice to catch warnings (ie stat failures and other non-blocking errors) 26 | archive.on('warning', function(err) { 27 | if (err.code === 'ENOENT') { 28 | // log warning 29 | } else { 30 | // throw error 31 | throw err; 32 | } 33 | }); 34 | 35 | // good practice to catch this error explicitly 36 | archive.on('error', function(err) { 37 | throw err; 38 | }); 39 | 40 | // pipe archive data to the file 41 | archive.pipe(output); 42 | 43 | // append a file 44 | archive.file('vue.config.js', { name: 'vue.config.js' }); 45 | 46 | archive.file('package.json', { name: 'package.json' }); 47 | 48 | archive.file('postcss.config.js', { name: 'postcss.config.js' }); 49 | 50 | archive.file('vue.config.js', { name: 'vue.config.js' }); 51 | 52 | archive.file('.eslintignore', { name: '.eslintignore' }); 53 | 54 | archive.file('.eslintrc', { name: '.eslintrc' }); 55 | 56 | archive.file('.gitignore', { name: '.gitignore' }); 57 | 58 | archive.file('archive.js', { name: 'archive.js' }); 59 | 60 | archive.file('babel.config.js', { name: 'babel.config.js' }); 61 | 62 | archive.file('check-tweblive-version.js', { name: 'check-tweblive-version.js' }); 63 | 64 | archive.file('README.md', { name: 'README.md' }); 65 | 66 | archive.file('腾讯云Web直播互动组件.md', { name: '腾讯云Web直播互动组件.md' }); 67 | 68 | archive.file('CHANGELOG.md', { name: 'CHANGELOG.md' }); 69 | 70 | // append files from a sub-directory, putting its contents at the root of archive 71 | archive.directory('sdk/', 'sdk'); 72 | 73 | archive.directory('src/', 'src'); 74 | 75 | archive.directory('dist/', 'dist'); 76 | 77 | archive.directory('public/', 'public'); 78 | 79 | // finalize the archive (ie we are done appending files but streams have to finish yet) 80 | // 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand 81 | archive.finalize(); -------------------------------------------------------------------------------- /src/assets/icon/iconfont.woff: -------------------------------------------------------------------------------- 1 | wOFF � hGSUB3B����OS/2<DV�glyfD� �Y�c�head 4/6��thhea d $��hmtx �88loca ���maxp �  �name �Em>T�}post |�ȑ�ex�c`d``�b�c�a`tq� a�``a�� cNfz"P �ʱ�i f���#Ox�c`da`��������t����B3�f0b�```b`ef� 2 | �\S�1�0bn�������f��Z x��� �@��ʏ��x6&4� ���*8�P���O�@ ���51� 3 | �ɷ��fg'�-�@ \�p8hܥ�|=���C\e�Q+t���d͖{�f.���U�g+��;�_ ������̻݃A� )��v��H�z{�2�����Po��&X�-+C�fm�`k��`g�ao��`�'�h� Sc�tsa y��F�x�mVkl\�>s�}���ݽ��f�w�{�H�zw��zm��Ƅ����Dq� %��!�T���橢��}�T *5���4} �$��� UA��"�?��?�]:w7 �Ծ;g�9s�̙o�J�g���Y���4! ���A��b�,�E=X�b�.0��AP���!�J�/���#���x�!��W�E��MY�=wO�Vc|�0�p|���� �s��y������һGFv�c��c��戛DI�����E�bo������bI�l�R@��rM����%A����!���K����zNp�H��fJ����zi�V��(/�:��ا Gt\�@3cfD��W�F�,�U��zp�n�.�e�Ck��/��!�z1�����[�ť3f g�Bc\Zd��:�;|�r�dK�5���� ���3. ~)r��Řp.��p�d��)��m���e�{}�����h�vs�<����UWJ��t@T8Ѻ,��x/�u�T K�W9J�368��$����-n ��5Z,�Zs~4�7�z?{�=B�$K�b��}\M� a�a� 4 | �<�ľW� ݀��ơhaD��cP�U �QI�T���P��jѨF'l�mH���6y�3};&�����s�I(m.��}�:�P�N�h�E=��B��Z_G VK�S���z]�b�E���(�: �����f7� 5 | 񒰍"ކ 6 | �� �V;Y��a��Stn�� 6��r'�����\9�9T��X{{���wp���X7�郅�?���^Y�5v��o�\}�1h�m��*~�c�4�g5����"R�0�`A� ^㛚Ԧ�,6��WXZ= �ѩ�G)�X~�5 7 | &�Ӈ�f���|�,��A��gv���Ύ+���� 8 | �i�.J����0�54�c�L �~VU_<�q�_T��k�*�7塷������� �X����;F6�tdž�M��b�X?1��Fv�=W���lx��/��cP�����Z�L'|iD5�iЮ��f�r��E�uA�����_;e CB 9 | ����-ڏ30�t�v*��J�0�Ǚ���iڏKpA?���V��i���鴕N3{�? �|�״m�}�p ����tST߇֚�����ڲ���m�J7����2 �v��chd�1iR�S�Z1 vE�%�z��+�ʟ�#�Տ��\�[H��Y� P�b{�]zV�8�O �.= 10 | +,�'+����Wܮ�1zW��l�.���[��T�{ߕ�ZQ������*�ݟ~�α*�Lv���V �X�z;�+��T�B�/�]�Žs��-^RTU�~�+�>���Ç�r��ŔṪ0�w�m1R�:8{�ֹa���v{�_��><���� 11 | ���� r?�G_ ��� Bʆ�>��H� 12 | �sO����� 8W 13 | ���c���f/G���v��)���s�樐r��n����(Β��z�}��O�4�XrҬ"W�0�*K%�*8~p�3*�D&��/k�vDQ�qA�A|U������f�� 14 | l �8K<�^�w�| xa�sJt~� ��9�G�{)q̮��V:a�kg���{nG�qԻasm��%/����3v�� ֽ1r ��L�iB��`1X�� 15 | `�1�l�B�f�%��X�l<۽�`�e�j4\�#�iQI�1h�ߐ�O��]( ����{��X%�n����菿�M��ͯ[7?6~r|��`4�$E,��f��:��ɭ��v�?�������E�x���e�2|�AAC�{n�׻�r 16 | ��rxy�%�9����x�fFo\;P�X^_��3R)cnt�Ȯ�`�n�߫yfO��`d�c��l�#�����?�j�f+�nl�F�7�O��P�O�z0���Ck2�\x}�7��ޑ���;S.�{pc϶α�#�/�Ll��v�[�ӭ�>��j�a�A��X�њ!&~P�g�@ص�����T@6h��]����vM.�?���؅ ������w�h���\|�t��5k6�ی�.n�-������/Fc�kˏ^�=,L��.H��p��gd�$􂽴�4G�����Ax�c`d``b��x~�� �, p��v������ ��``�� �x�c`d``n��������� P�rEyx�ca```�af$6 I<B�8��V�P�^j�x�c`d``�chf�`& �B��`>G�x�e�MN�0�_����`��b(��nXTj�]tߦN�*�#ǭ�p�� 8܀;�H'�6��߼ycO����-��=\2;r ��Sn�_��h�U�E�M��3��mtay�׸b��wa|�p�O�:�/��[��;� 17 | �����>�^W��G/��V/�^��Aš�"�9���^���k[�&S��_IS�i[�S��C�"Y�� �:I�ʭ�����Q���&�Xc����q�%�1Bd����;Uf���C�^{V=��t[��s���\S���y:O�=_Rut+n˞�4�^�I�B^ֶTB�6eW�z\щ?(gH� Zn�x�m��� 9&�f��7$������G�k�z���ďN�g@�jH(h4h�� ��ٕ�m����qL*���)����X9�!o���$���^���l�<��_ܗ��{���� 18 | �%˸��B|�%\ -------------------------------------------------------------------------------- /dist/fonts/iconfont.5cc3f0e2.woff: -------------------------------------------------------------------------------- 1 | wOFF � hGSUB3B����OS/2<DV�glyfD� �Y�c�head 4/6��thhea d $��hmtx �88loca ���maxp �  �name �Em>T�}post |�ȑ�ex�c`d``�b�c�a`tq� a�``a�� cNfz"P �ʱ�i f���#Ox�c`da`��������t����B3�f0b�```b`ef� 2 | �\S�1�0bn�������f��Z x��� �@��ʏ��x6&4� ���*8�P���O�@ ���51� 3 | �ɷ��fg'�-�@ \�p8hܥ�|=���C\e�Q+t���d͖{�f.���U�g+��;�_ ������̻݃A� )��v��H�z{�2�����Po��&X�-+C�fm�`k��`g�ao��`�'�h� Sc�tsa y��F�x�mVkl\�>s�}���ݽ��f�w�{�H�zw��zm��Ƅ����Dq� %��!�T���橢��}�T *5���4} �$��� UA��"�?��?�]:w7 �Ծ;g�9s�̙o�J�g���Y���4! ���A��b�,�E=X�b�.0��AP���!�J�/���#���x�!��W�E��MY�=wO�Vc|�0�p|���� �s��y������һGFv�c��c��戛DI�����E�bo������bI�l�R@��rM����%A����!���K����zNp�H��fJ����zi�V��(/�:��ا Gt\�@3cfD��W�F�,�U��zp�n�.�e�Ck��/��!�z1�����[�ť3f g�Bc\Zd��:�;|�r�dK�5���� ���3. ~)r��Řp.��p�d��)��m���e�{}�����h�vs�<����UWJ��t@T8Ѻ,��x/�u�T K�W9J�368��$����-n ��5Z,�Zs~4�7�z?{�=B�$K�b��}\M� a�a� 4 | �<�ľW� ݀��ơhaD��cP�U �QI�T���P��jѨF'l�mH���6y�3};&�����s�I(m.��}�:�P�N�h�E=��B��Z_G VK�S���z]�b�E���(�: �����f7� 5 | 񒰍"ކ 6 | �� �V;Y��a��Stn�� 6��r'�����\9�9T��X{{���wp���X7�郅�?���^Y�5v��o�\}�1h�m��*~�c�4�g5����"R�0�`A� ^㛚Ԧ�,6��WXZ= �ѩ�G)�X~�5 7 | &�Ӈ�f���|�,��A��gv���Ύ+���� 8 | �i�.J����0�54�c�L �~VU_<�q�_T��k�*�7塷������� �X����;F6�tdž�M��b�X?1��Fv�=W���lx��/��cP�����Z�L'|iD5�iЮ��f�r��E�uA�����_;e CB 9 | ����-ڏ30�t�v*��J�0�Ǚ���iڏKpA?���V��i���鴕N3{�? �|�״m�}�p ����tST߇֚�����ڲ���m�J7����2 �v��chd�1iR�S�Z1 vE�%�z��+�ʟ�#�Տ��\�[H��Y� P�b{�]zV�8�O �.= 10 | +,�'+����Wܮ�1zW��l�.���[��T�{ߕ�ZQ������*�ݟ~�α*�Lv���V �X�z;�+��T�B�/�]�Žs��-^RTU�~�+�>���Ç�r��ŔṪ0�w�m1R�:8{�ֹa���v{�_��><���� 11 | ���� r?�G_ ��� Bʆ�>��H� 12 | �sO����� 8W 13 | ���c���f/G���v��)���s�樐r��n����(Β��z�}��O�4�XrҬ"W�0�*K%�*8~p�3*�D&��/k�vDQ�qA�A|U������f�� 14 | l �8K<�^�w�| xa�sJt~� ��9�G�{)q̮��V:a�kg���{nG�qԻasm��%/����3v�� ֽ1r ��L�iB��`1X�� 15 | `�1�l�B�f�%��X�l<۽�`�e�j4\�#�iQI�1h�ߐ�O��]( ����{��X%�n����菿�M��ͯ[7?6~r|��`4�$E,��f��:��ɭ��v�?�������E�x���e�2|�AAC�{n�׻�r 16 | ��rxy�%�9����x�fFo\;P�X^_��3R)cnt�Ȯ�`�n�߫yfO��`d�c��l�#�����?�j�f+�nl�F�7�O��P�O�z0���Ck2�\x}�7��ޑ���;S.�{pc϶α�#�/�Ll��v�[�ӭ�>��j�a�A��X�њ!&~P�g�@ص�����T@6h��]����vM.�?���؅ ������w�h���\|�t��5k6�ی�.n�-������/Fc�kˏ^�=,L��.H��p��gd�$􂽴�4G�����Ax�c`d``b��x~�� �, p��v������ ��``�� �x�c`d``n��������� P�rEyx�ca```�af$6 I<B�8��V�P�^j�x�c`d``�chf�`& �B��`>G�x�e�MN�0�_����`��b(��nXTj�]tߦN�*�#ǭ�p�� 8܀;�H'�6��߼ycO����-��=\2;r ��Sn�_��h�U�E�M��3��mtay�׸b��wa|�p�O�:�/��[��;� 17 | �����>�^W��G/��V/�^��Aš�"�9���^���k[�&S��_IS�i[�S��C�"Y�� �:I�ʭ�����Q���&�Xc����q�%�1Bd����;Uf���C�^{V=��t[��s���\S���y:O�=_Rut+n˞�4�^�I�B^ֶTB�6eW�z\щ?(gH� Zn�x�m��� 9&�f��7$������G�k�z���ďN�g@�jH(h4h�� ��ٕ�m����qL*���)����X9�!o���$���^���l�<��_ܗ��{���� 18 | �%˸��B|�%\ -------------------------------------------------------------------------------- /src/components/pusher/components/pusherSetting.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 75 | 76 | 131 | -------------------------------------------------------------------------------- /dist/img/tim.df3f8550.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/icon/tim.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/store/modules/conversation.js: -------------------------------------------------------------------------------- 1 | // JSON.parse(localStorage.getItem('userInfo')) || 2 | const SDKAPPID = window.genTestUserSig('').SDKAppID 3 | const playDomain = window.genTestUserSig('').playDomain 4 | let defaultGroupId = '' 5 | let defaultTitle = '' 6 | let defaultUserInfo = { 7 | userId:'', 8 | userSig:'' 9 | } 10 | try { 11 | if (localStorage.groupId) { 12 | defaultGroupId = localStorage.groupId 13 | } 14 | } catch (e) { 15 | console.log(e) 16 | } 17 | try { 18 | if (localStorage.title) { 19 | defaultTitle = localStorage.title 20 | } 21 | } catch (e) { 22 | console.log(e) 23 | } 24 | try { 25 | if (localStorage.userInfo || localStorage.userSig) { 26 | defaultUserInfo.userId = localStorage.userId, 27 | defaultUserInfo.userSig = localStorage.userSig 28 | 29 | } 30 | } catch (e) { 31 | console.log(e) 32 | } 33 | 34 | const conversationModules = { 35 | state: { 36 | currentMessageList: [], 37 | currentLiveTips: [], 38 | liveDomain:'', 39 | playType: 'WebRTC', //默认webRTC 播放,cdn 40 | showLogin: false, //是否展示登录 41 | fullPath:'', 42 | pushInfo:{ 43 | playUrl:'', 44 | isPushing:false, 45 | title: defaultTitle, 46 | resolution:'720p' 47 | }, 48 | chatInfo: { 49 | groupId: defaultGroupId, 50 | userId: defaultUserInfo.userId, 51 | userSig: defaultUserInfo.userSig, 52 | sdkAppID: SDKAPPID, 53 | liveDomainName: playDomain, 54 | streamId: '', 55 | role: '', 56 | resolution: '' 57 | }, 58 | likeCount: 0 //点赞人数 59 | }, 60 | getters: {}, 61 | mutations: { 62 | setRole(state, data) { 63 | state.chatInfo.role = data 64 | }, 65 | setLiveDomain(state, data) { 66 | state.liveDomain = data 67 | }, 68 | setPlayInfo(state, data) { 69 | state.pushInfo.playUrl = data 70 | }, 71 | setIsPushing(state, data) { 72 | state.pushInfo.isPushing = data 73 | }, 74 | setPusherInfo(state, data) { 75 | state.pushInfo.title = data.title 76 | state.pushInfo.resolution = data.resolution 77 | try { 78 | localStorage.title = data.title 79 | } catch (e) { 80 | console.log(e) 81 | } 82 | }, 83 | setGroupId(state, data) { 84 | state.chatInfo.groupId = data 85 | 86 | try { 87 | localStorage.groupId = data 88 | } catch (e) { 89 | console.log(e) 90 | } 91 | // localStorage.setItem('userInfo', JSON.stringify(data)) 92 | // 之后才是修改state中的状态 93 | }, 94 | setPlayType(state, data) { 95 | state.playType = data 96 | }, 97 | showLogin(state, data) { 98 | state.showLogin = data 99 | }, 100 | setChatInfo(state, data) { 101 | // state.chatInfo.groupId = data.roomID 102 | 103 | state.chatInfo.userId = data.userID 104 | state.chatInfo.userSig = data.userSig 105 | state.chatInfo.resolution = data.resolution 106 | try { 107 | localStorage.userId = data.userID 108 | localStorage.userSig = data.userSig 109 | 110 | } catch (e) { 111 | console.log(e) 112 | } 113 | }, 114 | showLike(state, data) { 115 | state.likeCount += data 116 | }, 117 | /** 118 | * 将消息插入当前会话列表 119 | * 调用时机:收/发消息事件触发时 120 | * @param {Object} state 121 | * @param {Message[]|Message} data 122 | * @returns 123 | */ 124 | pushCurrentMessageList(state, data) { 125 | if (Array.isArray(data)) { 126 | state.currentMessageList = [...state.currentMessageList, ...data] 127 | } else { 128 | state.currentMessageList = [...state.currentMessageList, data] 129 | } 130 | }, 131 | pushCurrentTipsList(state, data) { 132 | let timer = null 133 | if (Array.isArray(data)) { 134 | state.currentLiveTips = [...state.currentLiveTips, ...data] 135 | } else { 136 | state.currentLiveTips = [...state.currentLiveTips, data] 137 | } 138 | timer = setTimeout(() => { 139 | state.currentLiveTips.shift() 140 | }, 2000) 141 | if (state.currentLiveTips.length === 0) { 142 | clearTimeout(timer) 143 | } 144 | }, 145 | /** 146 | * 从当前消息列表中删除某条消息 147 | * @param {Object} state 148 | * @param {Message} message 149 | */ 150 | reset(state) { 151 | Object.assign(state, { 152 | currentMessageList: [], 153 | currentLiveTips: [], 154 | }) 155 | } 156 | }, 157 | actions: {} 158 | } 159 | 160 | export default conversationModules 161 | -------------------------------------------------------------------------------- /src/assets/icon/iconfont.ttf: -------------------------------------------------------------------------------- 1 |  �0GSUB����8BOS/2� pglyfY�c�� �head��t�6hhea���$hmtx8�8loca��|maxp � name>T�}Pmpostȑ�e�����\��D \3_<� ��C���C����� 2 | 3 | � 4 | ,DFLTliga�������2PfEd@��2���\��,��, 5 | �� 6 | ����3�J�c�g�j����M�2������3�I�c�g�j����M�2�� 7 |    � �������3�3 8 | �I�I�J�J�c�c �g�g�j�j������ �M�M �2�2 B�8��V�P�^j����$'77'7>7..'>7zr�# W�4��4��4�\?Pq��qRmmRQmm�n2X"W�5��5��5�[(�on��DjOOiiOOj���| 467&.'467!7'.'>5.''>3�������ع�61�#>M�r9��{E1 $R>)C�:�P��6|���������W��Q�9�"8lGr16�{2K?(=R("�16��Q����5,NW`!!>7.!.'.1'&'&>!"&'5?6766?>732>4&"72"&46���'33'5'33��5 %Q*",�!%2�?�� 9 | �  � "y'�p)66R66) 43'�L'33'�'3A 10 | �9u�%$ �� 11 | � \� " � %�73!>54&'53"/&462762!"&4673>23`�@+99+2\2+99��(�'j�(V��29V92q9*�+9e��\e9+�?*9;�'g�'+*99*+��J> $'>74&'7%'>54&'7'.462|GR]VKGYem��I3<2+G9AJ�))<))=FF�tn�EGS����lIb>8[H,�LR��(=((=(���$;G.'>7"'.'"'>7"'>7.'>77>7.'�;I``H<��'ʙ��'���&�o1<tWF\\F�OggOOgitmG`~~`Fm"Ӑ��ʘ��(��z�!_7.!.'53264&+53264&+53264&+5>7!3>73.'2>4.#72"&46@��6I    I6@6II 12 | $��$    $@$��Rl@I66I@lR#:##:#6II6$$6$$@I6@��@6II6�6I�$$@��@$$��lR6II6RlB"7.%!3!2!5>!"&'!��� & 5 ��-=<.&-==��8 13 | & 4!F��5��k� 14 | D"=-�|.==.�.=R 15 | D"=��7d�����R (.'>7";.#>74&'76=�{��{|���f�0v?��̙��+'�#" �{|��|{�Y"#�(*̙��̙Bt/�f����,ET\u�"'#"'.?6?'&6?627>32;?6'76?6376?'&/7/2#7'&+76?6%"764/& ��� 16 | 17 | "���9��'-!9 ����  8 ���=9 ��#� o# o t�y  9 `���l9 2RsR9x�)1� ��6���:!X!���6�] 9���A 8 ` �*o pt- 18 | 8 f���s 9� Ns 19 | N(9 ���cEFGTU^_l&'&?6&'.>?327>4.'&""'&'&567>7627#2>4."#264&"#2>4."� :   ��_WT�EE�TW�WS�F49 ('�[_�_[�')('��f��6?-   .''.   b Y  <, r���r r�QHDA5 762>54&'&'.?> a�GC&* 3K/  O.>v���v>/O   20 | .K3 +%�W\���K�GCAUc�^2S  7T+]1P�r<7..'&>>7>.462.462�������ٲ�겲��hr 21 | ' PCCP ' 22 | r�**}���������겲�겲��}_ 23 | &AA& 24 | _=****�$, 4? 25 | +G r *� � � � � �  26 | V &i 27 | Created by iconfont 28 | iconfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com 29 | Created by iconfont 30 | iconfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com 31 |   32 |    female blacklisttupiandiaochavoicegroupcontactwenjianmalezidingyi conversationtuichusmile -------------------------------------------------------------------------------- /dist/fonts/iconfont.6f1fd06b.ttf: -------------------------------------------------------------------------------- 1 |  �0GSUB����8BOS/2� pglyfY�c�� �head��t�6hhea���$hmtx8�8loca��|maxp � name>T�}Pmpostȑ�e�����\��D \3_<� ��C���C����� 2 | 3 | � 4 | ,DFLTliga�������2PfEd@��2���\��,��, 5 | �� 6 | ����3�J�c�g�j����M�2������3�I�c�g�j����M�2�� 7 |    � �������3�3 8 | �I�I�J�J�c�c �g�g�j�j������ �M�M �2�2 B�8��V�P�^j����$'77'7>7..'>7zr�# W�4��4��4�\?Pq��qRmmRQmm�n2X"W�5��5��5�[(�on��DjOOiiOOj���| 467&.'467!7'.'>5.''>3�������ع�61�#>M�r9��{E1 $R>)C�:�P��6|���������W��Q�9�"8lGr16�{2K?(=R("�16��Q����5,NW`!!>7.!.'.1'&'&>!"&'5?6766?>732>4&"72"&46���'33'5'33��5 %Q*",�!%2�?�� 9 | �  � "y'�p)66R66) 43'�L'33'�'3A 10 | �9u�%$ �� 11 | � \� " � %�73!>54&'53"/&462762!"&4673>23`�@+99+2\2+99��(�'j�(V��29V92q9*�+9e��\e9+�?*9;�'g�'+*99*+��J> $'>74&'7%'>54&'7'.462|GR]VKGYem��I3<2+G9AJ�))<))=FF�tn�EGS����lIb>8[H,�LR��(=((=(���$;G.'>7"'.'"'>7"'>7.'>77>7.'�;I``H<��'ʙ��'���&�o1<tWF\\F�OggOOgitmG`~~`Fm"Ӑ��ʘ��(��z�!_7.!.'53264&+53264&+53264&+5>7!3>73.'2>4.#72"&46@��6I    I6@6II 12 | $��$    $@$��Rl@I66I@lR#:##:#6II6$$6$$@I6@��@6II6�6I�$$@��@$$��lR6II6RlB"7.%!3!2!5>!"&'!��� & 5 ��-=<.&-==��8 13 | & 4!F��5��k� 14 | D"=-�|.==.�.=R 15 | D"=��7d�����R (.'>7";.#>74&'76=�{��{|���f�0v?��̙��+'�#" �{|��|{�Y"#�(*̙��̙Bt/�f����,ET\u�"'#"'.?6?'&6?627>32;?6'76?6376?'&/7/2#7'&+76?6%"764/& ��� 16 | 17 | "���9��'-!9 ����  8 ���=9 ��#� o# o t�y  9 `���l9 2RsR9x�)1� ��6���:!X!���6�] 9���A 8 ` �*o pt- 18 | 8 f���s 9� Ns 19 | N(9 ���cEFGTU^_l&'&?6&'.>?327>4.'&""'&'&567>7627#2>4."#264&"#2>4."� :   ��_WT�EE�TW�WS�F49 ('�[_�_[�')('��f��6?-   .''.   b Y  <, r���r r�QHDA5 762>54&'&'.?> a�GC&* 3K/  O.>v���v>/O   20 | .K3 +%�W\���K�GCAUc�^2S  7T+]1P�r<7..'&>>7>.462.462�������ٲ�겲��hr 21 | ' PCCP ' 22 | r�**}���������겲�겲��}_ 23 | &AA& 24 | _=****�$, 4? 25 | +G r *� � � � � �  26 | V &i 27 | Created by iconfont 28 | iconfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com 29 | Created by iconfont 30 | iconfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com 31 |   32 |    female blacklisttupiandiaochavoicegroupcontactwenjianmalezidingyi conversationtuichusmile -------------------------------------------------------------------------------- /src/pages/pusher/IndexMobile.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 86 | 87 | 199 | -------------------------------------------------------------------------------- /dist/fonts/iconfont.908bc2a8.eot: -------------------------------------------------------------------------------- 1 | h�LP�� DiconfontRegularVersion 1.0iconfont �0GSUB����8BOS/2� pglyfY�c�� �head��t�6hhea���$hmtx8�8loca��|maxp � name>T�}Pmpostȑ�e�����\��D ��_<� ��C���C����� 2 | 3 | � 4 | ,DFLTliga�������2PfEd@��2���\��,��, 5 | �� 6 | ����3�J�c�g�j����M�2������3�I�c�g�j����M�2�� 7 |    � �������3�3 8 | �I�I�J�J�c�c �g�g�j�j������ �M�M �2�2 B�8��V�P�^j����$'77'7>7..'>7zr�# W�4��4��4�\?Pq��qRmmRQmm�n2X"W�5��5��5�[(�on��DjOOiiOOj���| 467&.'467!7'.'>5.''>3�������ع�61�#>M�r9��{E1 $R>)C�:�P��6|���������W��Q�9�"8lGr16�{2K?(=R("�16��Q����5,NW`!!>7.!.'.1'&'&>!"&'5?6766?>732>4&"72"&46���'33'5'33��5 %Q*",�!%2�?�� 9 | �  � "y'�p)66R66) 43'�L'33'�'3A 10 | �9u�%$ �� 11 | � \� " � %�73!>54&'53"/&462762!"&4673>23`�@+99+2\2+99��(�'j�(V��29V92q9*�+9e��\e9+�?*9;�'g�'+*99*+��J> $'>74&'7%'>54&'7'.462|GR]VKGYem��I3<2+G9AJ�))<))=FF�tn�EGS����lIb>8[H,�LR��(=((=(���$;G.'>7"'.'"'>7"'>7.'>77>7.'�;I``H<��'ʙ��'���&�o1<tWF\\F�OggOOgitmG`~~`Fm"Ӑ��ʘ��(��z�!_7.!.'53264&+53264&+53264&+5>7!3>73.'2>4.#72"&46@��6I    I6@6II 12 | $��$    $@$��Rl@I66I@lR#:##:#6II6$$6$$@I6@��@6II6�6I�$$@��@$$��lR6II6RlB"7.%!3!2!5>!"&'!��� & 5 ��-=<.&-==��8 13 | & 4!F��5��k� 14 | D"=-�|.==.�.=R 15 | D"=��7d�����R (.'>7";.#>74&'76=�{��{|���f�0v?��̙��+'�#" �{|��|{�Y"#�(*̙��̙Bt/�f����,ET\u�"'#"'.?6?'&6?627>32;?6'76?6376?'&/7/2#7'&+76?6%"764/& ��� 16 | 17 | "���9��'-!9 ����  8 ���=9 ��#� o# o t�y  9 `���l9 2RsR9x�)1� ��6���:!X!���6�] 9���A 8 ` �*o pt- 18 | 8 f���s 9� Ns 19 | N(9 ���cEFGTU^_l&'&?6&'.>?327>4.'&""'&'&567>7627#2>4."#264&"#2>4."� :   ��_WT�EE�TW�WS�F49 ('�[_�_[�')('��f��6?-   .''.   b Y  <, r���r r�QHDA5 762>54&'&'.?> a�GC&* 3K/  O.>v���v>/O   20 | .K3 +%�W\���K�GCAUc�^2S  7T+]1P�r<7..'&>>7>.462.462�������ٲ�겲��hr 21 | ' PCCP ' 22 | r�**}���������겲�겲��}_ 23 | &AA& 24 | _=****�$, 4? 25 | +G r *� � � � � �  26 | V &i 27 | Created by iconfont 28 | iconfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com 29 | Created by iconfont 30 | iconfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com 31 |   32 |    female blacklisttupiandiaochavoicegroupcontactwenjianmalezidingyi conversationtuichusmile -------------------------------------------------------------------------------- /src/assets/icon/iconfont.eot: -------------------------------------------------------------------------------- 1 | h�LP�� DiconfontRegularVersion 1.0iconfont �0GSUB����8BOS/2� pglyfY�c�� �head��t�6hhea���$hmtx8�8loca��|maxp � name>T�}Pmpostȑ�e�����\��D ��_<� ��C���C����� 2 | 3 | � 4 | ,DFLTliga�������2PfEd@��2���\��,��, 5 | �� 6 | ����3�J�c�g�j����M�2������3�I�c�g�j����M�2�� 7 |    � �������3�3 8 | �I�I�J�J�c�c �g�g�j�j������ �M�M �2�2 B�8��V�P�^j����$'77'7>7..'>7zr�# W�4��4��4�\?Pq��qRmmRQmm�n2X"W�5��5��5�[(�on��DjOOiiOOj���| 467&.'467!7'.'>5.''>3�������ع�61�#>M�r9��{E1 $R>)C�:�P��6|���������W��Q�9�"8lGr16�{2K?(=R("�16��Q����5,NW`!!>7.!.'.1'&'&>!"&'5?6766?>732>4&"72"&46���'33'5'33��5 %Q*",�!%2�?�� 9 | �  � "y'�p)66R66) 43'�L'33'�'3A 10 | �9u�%$ �� 11 | � \� " � %�73!>54&'53"/&462762!"&4673>23`�@+99+2\2+99��(�'j�(V��29V92q9*�+9e��\e9+�?*9;�'g�'+*99*+��J> $'>74&'7%'>54&'7'.462|GR]VKGYem��I3<2+G9AJ�))<))=FF�tn�EGS����lIb>8[H,�LR��(=((=(���$;G.'>7"'.'"'>7"'>7.'>77>7.'�;I``H<��'ʙ��'���&�o1<tWF\\F�OggOOgitmG`~~`Fm"Ӑ��ʘ��(��z�!_7.!.'53264&+53264&+53264&+5>7!3>73.'2>4.#72"&46@��6I    I6@6II 12 | $��$    $@$��Rl@I66I@lR#:##:#6II6$$6$$@I6@��@6II6�6I�$$@��@$$��lR6II6RlB"7.%!3!2!5>!"&'!��� & 5 ��-=<.&-==��8 13 | & 4!F��5��k� 14 | D"=-�|.==.�.=R 15 | D"=��7d�����R (.'>7";.#>74&'76=�{��{|���f�0v?��̙��+'�#" �{|��|{�Y"#�(*̙��̙Bt/�f����,ET\u�"'#"'.?6?'&6?627>32;?6'76?6376?'&/7/2#7'&+76?6%"764/& ��� 16 | 17 | "���9��'-!9 ����  8 ���=9 ��#� o# o t�y  9 `���l9 2RsR9x�)1� ��6���:!X!���6�] 9���A 8 ` �*o pt- 18 | 8 f���s 9� Ns 19 | N(9 ���cEFGTU^_l&'&?6&'.>?327>4.'&""'&'&567>7627#2>4."#264&"#2>4."� :   ��_WT�EE�TW�WS�F49 ('�[_�_[�')('��f��6?-   .''.   b Y  <, r���r r�QHDA5 762>54&'&'.?> a�GC&* 3K/  O.>v���v>/O   20 | .K3 +%�W\���K�GCAUc�^2S  7T+]1P�r<7..'&>>7>.462.462�������ٲ�겲��hr 21 | ' PCCP ' 22 | r�**}���������겲�겲��}_ 23 | &AA& 24 | _=****�$, 4? 25 | +G r *� � � � � �  26 | V &i 27 | Created by iconfont 28 | iconfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com 29 | Created by iconfont 30 | iconfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com 31 |   32 |    female blacklisttupiandiaochavoicegroupcontactwenjianmalezidingyi conversationtuichusmile -------------------------------------------------------------------------------- /src/assets/icon/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face {font-family: "iconfont"; 2 | src: url('iconfont.eot?t=1571037879389'); /* IE9 */ 3 | src: url('iconfont.eot?t=1571037879389#iefix') format('embedded-opentype'), /* IE6-IE8 */ 4 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAtUAAsAAAAAE2gAAAsGAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEcAqXNJM0ATYCJAM4Cx4ABCAFhG0HgSUbfxAjkg9WkOyvD7g5YB2zHKxobKzh+qoa2/WqPbHCSnoiPo59IsJbFdKfyG2qSMv5HA/A/fL9DL4COjrgO8sFZgpMRyU84NGIu80RgNAHwN/Tpr3dD72wi4QikUZ9LhAqSoxSB8LuRqhp0tQkvetSCwetYzWJQFqP1jWC1NKemKcHzMz/7W/a31pGRKguefYvPz2lgaaM8CC9xQAOJvc5QDA3736timhdwDwkHrVsp9sX3g3fHWaeqJAImXaimH38Ny5eBEKy0IjUSiz4MLx+r06Igxt8aPvCwwQoTUwF88/lvsQYF2DMA12fKlEmLokO5CWp4dJY8AKJPHzCHwPP3vcH/zALQgglEfaorYsLC7sCto89YAs89sewcUaEKeKN+GnUfYAPTrGRcmrsjYE+86IvDFdsysaaaa4FnAJfTLjizcWMWQmrDwx40RHPTixTbs6KVBKhVKNWrP94KcbXWnxP9DR8YZLKTwIXVAwhFlQGQQmqhDAGnDbCWFARhJmgKghzwelLWAAqhOAElUIIIIuG7wlZ1Pwo9AqMb/UlI8yYT3QWgJsCEKu8ThwQcKWIoFhsEqLdyI3g8/uHhUYn8HgJ4v5CIS8mhp+WJhTwwvsT/OjsCFFIhECDYQKMR+ULVHy+nMer8fmMrD/bSOsoo56hSmjmCRUMMoFAqSC0fwu/n/L5anyfGv2fUcEvmMDnq00SzcES6uCN9Ps+o4Dq9DH0scDYpluYnqFp9mXRPUGygWdCmzujOAe7VOK2nljuoe7VYocD8JuBDG+rFGtulxpHejOuFtlPSI3I5VoTanXKMSbMxR3KPOnZjrpkR0MY45LvjrRFXPHnA2tf2tZj7rZ2sl2MbS/rtnrNTWuErd0x3MM9g0g40Qgc1pMsamjCuGZvCka2dEVzDnTOsVvltNPcZJNRjMvmYaXl/EauU8nDPbauaLLOwzYuvMMac4C+Sxcz6EdBzBwYyjxJfISuv2q+ZrvCXp770A5Eq5nbGmkBZDXkjwkGY8GdtG9kHgYSdGkdm0G1DHURjCV5Ov71NcLbvjggrI2shyS9X3zUXyy6F0zkHgtMdl9OEtZfjcRIW5PZSxDOpP3XUkV1VyJm9TiJPB4cfccfT/af3vbslvnmU0J/1M/cMrHe+gdr+NZ6Ob3vKcGfCy90i7UCR52M2vuEFNg8AKGYq8n+RrxyJMbZxunLPtN68hRJGq8GiIdRPiuZIxlgOy5h2BprRrmxMcloJ6zy+vMDmP2ZDO09rliTLd3a57aRLUP0p9gsY5nnSJqxsdz6k3R2qZRykOTMNsrLjdRsOyhxVdmlRpmDZKI0YbRTLh82QkYtk9PT6p5DJFEM7SQII7AyaoATtMgaRclkk8xyg5Nyyp0d4X3a6T5Xg8xzNC2LYUibxWnQvG4IWI0+NhhYyq93sK+Erm46gAXngwVt1J2U+n1F2MjuwlQQ7N46W8N+87566wn3dIL1POed1sbpps5lVi+GXkvUAxYKKrUifnqQuRAc5qrzuKU+40lfPOtnQbagE8wcyAnQzn1hYVPq7PDn+v3DQNE4PfA5/R5C76R636drrVkdCJjoULnzcFOLzJFyFeZq8xyU2n3l9d6R0GJofKmpx6OX4I7d+EJFAvMTTW/YkLfB3NGRJxTB0A0V5V9MgsVl1dX4Qs0WX9J/beqwiXxA1Tw9psOIMnI0H+Ik6wLcmGhukAyIiQlwghyClIeCMdGCjZ529OtvtetV20MuXcpNPft8fCVo2CVL2O2qf/auXftR0Vj8l5FpfL2+iy1Ijd/r3mlq1LWj36pfCTrVdhiyMU81LaFfc7+Ead6rVV3PVx3pJb7T6pZfoQ7/CP8yde8SZ83jwuhfx4vt6//n9Sp//kxF9BKmq/Uzc/XnV39v7UqcKmZdrx9eUQ47i4l+lK72VpaRvTs6WEpPG2g9lVYj+DGCe4FEGAhLrh+x8G4QliOK2epHMpP8kdqEKLlJJnm24oiFuMGzLBn6Xdp322rfpL5O/W/+nLPeBPTf2HfUgBzZ48xHagXPQlt4CvWjzMdQM1xTrC823YJl1dSlsUUaTalh1lvYAJaqL2IqtdrMYdNHDs4tP6UZbVOzMA70Y2r/39hZO6J2uDwF/tmrrQINNvX996biHGqJ2FQoHl11aUu8pxvbgVIR7nrwwI0AQXFX3DG209P1xwrFbcBPnkRKRkp/fI2tuTqOGDaFxOhly2gsLjWuGKuowJyoogpT3ji8k5yIzZmL4QmkbCIW4Qnuj5o3F/KQWq3TarnqOKE4SiyMO7LuVnO1Wl0pYQPL8f4nlEfUR5REVXXZtKnr9VhlJaZvqlido8b0lZX6/MRdmUWZuxIzyNitujJAOZBLhCEzjmlIYkhy4ZP8uMHXH/M3CS53pnguBF8LHqveNQzeGZkvNzdeI1SKRlQGhQlKw4MUUaJwVuUskRKc5Fp0/DhSuGadtBavwRHwWkgSSsokuQrJnN7eP+b0UW706BHu5hCIYhz/LnIXZCyr7u2dI0mUSHrh3c7V0crf33l8M77WlrabCFnS2lkRv2vRime3X36VxE06dkwxRPn2u0+ff7dIdl34wY+lP3715qdlHld57LjBbOKLwy2rjdNvHahP4CDxsWNFmp+w857h6mGy4lpL9lRNeMIeXNZve/p0xabqaqXUlHMiX1m9KLKv7WVbsvjx4R/UWvgwdfZ5z5tvExBqqEechMqlGDHXUpt7TvKtfsLSpQlljvt+SHtjeQ37pp+dt27dkNIF2sYV8dfEy/c0EY/qYqxhnKl0bEmMeUnRrmMCujCEcXyVEsNVfvEuvTaqMFKdR0teS+bYYrSxYw1QkVqSottWUx4/JeEpoAtDGG9JK4G2PLnthbPBIn+RpqoeuTxb0DwuvKI5orkifFxzJJkjdadyr73OIqU5ggumcNOFiGY9oRlEm0ONoS2SxMGtotmRfdPPaTQFBepkY/qMkC7F5KNjDT/c96VNuD9xYHbJ2jAT6EbsWLHEMaxOOFqxaMQuXW6YaUFOSYH8tsk2OHD7+duxhnOKySFdGTOSjLVmOrEiCfrWPedGR3MVfk4RtNEEwR7XOfTVVwj4HEVYQE/dMJe7ZMqQQ8V3Zp9Ck9QFHA7pQHRq9p3iQ0NM3T8PV1sySBVAwNb/C2xQ3y82o2gPbPI/Wgce+BWpwHZ30PvgprFoJHjpS5Sku44SNcCH4Wg4OK0bGUCtf9B6cEgfDTb7GW3p3eg/9N7/kcMgj2dSThUN/y2E/Nuy58XDwjZC+zb2h+orf6MJcFL915jHQQB9/4dvNaxcyDmq5EYUrQbKXgxC2PhviYexCMG3Afy3qO8Pb4goq636NyXKomQc3oFogkz+SYQD/6xkLpCQR/rBf1QyAZkw+moSJLAUEGAcHgBkwGYkYxAKZ5JxEMI1guD/hHDg35vMBTl8h/shHEPJBNCYRCIJKe0Bnd4yKsEB+ieQ5mhEpZz8sd9oZ68y0ayO+8dciCO0VXPt+8KIuY8zys12IgZM5gCfzinoPUPKPKGWakRvuta12Z1ZaQ6Lk7eMSnT6AfTPwqQ5mt3llPn6b7SzV7lkyVPhf8yF9g9alaaG9xcfay15K5PLzXaEMANyduYAPglDz7sZJPNBE2qpjC0601VNtjJ1+Wp8MbzUeS++ZZnH2iBKsqJqumFatuN6YXeFQXk89l5p56nITuZEKu4HdTbrUW1vTBq3NvOc9vM2WZSW/R3jVM5tWjk5vGigaJ90KSG3JaZKtqgHl6THeVsCeVwsAAA=') format('woff2'), 5 | url('iconfont.woff?t=1571037879389') format('woff'), 6 | url('iconfont.ttf?t=1571037879389') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ 7 | url('iconfont.svg?t=1571037879389#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family: "iconfont" !important; 12 | font-size: 16px; 13 | font-style: normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-female:before { 19 | content: "\e649"; 20 | } 21 | 22 | .icon-blacklist:before { 23 | content: "\e66a"; 24 | } 25 | 26 | .icon-tupian:before { 27 | content: "\e64a"; 28 | } 29 | 30 | .icon-diaocha:before { 31 | content: "\e605"; 32 | } 33 | 34 | .icon-voice:before { 35 | content: "\e667"; 36 | } 37 | 38 | .icon-group:before { 39 | content: "\e696"; 40 | } 41 | 42 | .icon-contact:before { 43 | content: "\e61f"; 44 | } 45 | 46 | .icon-wenjian:before { 47 | content: "\e601"; 48 | } 49 | 50 | .icon-male:before { 51 | content: "\e832"; 52 | } 53 | 54 | .icon-zidingyi:before { 55 | content: "\e633"; 56 | } 57 | 58 | .icon-conversation:before { 59 | content: "\e663"; 60 | } 61 | 62 | .icon-tuichu:before { 63 | content: "\e74d"; 64 | } 65 | 66 | .icon-smile:before { 67 | content: "\e6d6"; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/pages/player/IndexMobile.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 94 | 95 | 221 | -------------------------------------------------------------------------------- /src/assets/css/reset.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8";html{color:#000;} 2 | body,ul,ol,dl,dd,h1,h2,h3,h4,h5,h6,figure,form,fieldset,legend,input,textarea,button,p,blockquote,th,td,pre,xmp{margin:0;padding:0} 3 | /*body,input,textarea,button,select,pre,xmp,tt,code,kbd,samp{line-height:1.5;}*/ 4 | /*h1,h2,h3,h4,h5,h6,small,big,input,textarea,button,select{font-size:100%}*/ 5 | /*h1,h2,h3,h4,h5,h6{font-family:tahoma,arial,"Hiragino Sans GB","微软雅黑",simsun,sans-serif}*/ 6 | /*h1,h2,h3,h4,h5,h6,b,strong{font-weight:normal}*/ 7 | /*address,cite,dfn,em,i,optgroup,var{font-style:normal}*/ 8 | table{border-collapse:collapse;border-spacing:0;text-align:left} 9 | caption,th{text-align:inherit} 10 | ul,ol,menu{list-style:none} 11 | fieldset,img{border:0} 12 | img,object,input,textarea,button,select{vertical-align:middle} 13 | article,aside,footer,header,section,nav,figure,figcaption,hgroup,details,menu{display:block} 14 | audio,canvas,video{display:inline-block;*display:inline;*zoom:1} 15 | blockquote:before,blockquote:after,q:before,q:after{content:"\0020"} 16 | textarea{overflow:auto;resize:vertical} 17 | input,textarea,button,select,a{outline:0 none;border: none;} 18 | button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0} 19 | mark{background-color:transparent} 20 | a,ins,s,del{text-decoration:none} 21 | sup,sub{vertical-align:baseline} 22 | html {overflow-x: hidden;height: 100%;-webkit-tap-highlight-color: transparent;} 23 | body {color: #333;line-height: 1;-webkit-text-size-adjust: none;} 24 | hr {height: .02rem;margin: .1rem 0;border: medium none;border-top: .02rem solid #cacaca;} 25 | a {color: #25a4bb;text-decoration: none;} 26 | .el-message { 27 | top: 80px !important; 28 | min-width: 0; 29 | width: auto; 30 | padding: 13px 13px 13px 18px 31 | } 32 | 33 | @media screen and (max-width: 767px){ 34 | .el-message { 35 | top: 60px !important; 36 | min-width: 0; 37 | width: auto; 38 | background: rgba(0,0,0,0.46); 39 | border-color: rgba(0,0,0,0); 40 | padding: 13px 13px 13px 18px 41 | } 42 | .el-message--success .el-message__content, .el-message .el-icon-success, 43 | .el-message__icon .el-icon-error, .el-message__icon .el-icon-error ,.el-message .el-icon-error, 44 | .el-message--error .el-message__content, .el-message--info .el-message__content, .el-message .el-icon-info, 45 | .el-message--warning .el-message__content, .el-message .el-icon-warning 46 | { 47 | color: #ffffff; 48 | } 49 | .el-message-box { 50 | width: 300px; 51 | border-radius:0; 52 | } 53 | 54 | } 55 | .el-popover .play-url { 56 | border: none; 57 | color: #2d8cf0; 58 | line-height: 25px; 59 | text-align: justify; 60 | font-size: 14px 61 | } 62 | .el-popover { 63 | width:auto !important; 64 | padding: 20px 15px; 65 | max-width: 400px; 66 | 67 | } 68 | /*分割线*/ 69 | .el-divider--horizontal { 70 | margin: 6px auto 0; 71 | width: 90% 72 | } 73 | 74 | .cursor { 75 | cursor: pointer; 76 | } 77 | /*主题颜色*/ 78 | .el-button--primary, .el-radio__input.is-checked .el-radio__inner{ 79 | background-color: #1162F9; 80 | /*border-color: #1162F9;*/ 81 | border: none; 82 | border-radius: 20px 83 | } 84 | .el-radio__input.is-checked+.el-radio__label { 85 | color: #1162F9; 86 | } 87 | .active .el-input { 88 | border-bottom: 1px solid #1162F9 89 | } 90 | el-button--primary:focus, .el-button--primary:hover { 91 | background: #1162F9; 92 | border: none; 93 | color: #FFF; 94 | } 95 | .el-button:focus, .el-button:hover { 96 | color: #1162F9; 97 | border: 1px solid #1162F9; 98 | background: none; 99 | } 100 | .el-button--primary:focus, .el-button--primary:hover { 101 | background: #1162F9; 102 | border-color: #1162F9; 103 | color: #FFF; 104 | } 105 | .el-input__inner{ 106 | border-radius: 0; 107 | border:none; 108 | border-bottom: 1px solid #eaeaea 109 | } 110 | /*.el-input__inner:focus{*/ 111 | /* border-radius: 0;*/ 112 | /* border:none;*/ 113 | /* border-bottom: 1px solid #1162F9*/ 114 | /*}*/ 115 | .el-select .el-input__inner:focus { 116 | border-color: #1162F9; 117 | } 118 | .el-select{ 119 | width: 100%; 120 | } 121 | .el-select .el-input.is-focus .el-input__inner { 122 | border-color: #1162F9; 123 | } 124 | .el-select-dropdown__item.selected { 125 | color: #ffffff; 126 | font-weight: 700; 127 | font-family: PingFangSC-Regular; 128 | } 129 | .el-input--suffix .el-input__inner{ 130 | padding-left: 70px; 131 | } 132 | .el-button:focus, .el-button:hover{ 133 | border-color: #1162F9; 134 | } 135 | .el-button { 136 | box-sizing: border-box; 137 | border: 1px solid #1162F9; 138 | border-radius:25px; 139 | } 140 | .el-button--mini, .el-button--small { 141 | border-radius:15px; 142 | } 143 | .el-button--small, .el-button--small.is-round { 144 | padding: 8px 14px; 145 | } 146 | button { 147 | font-family: PingFangSC-Regular , Microsoft YaHei, Arial, Helvetica, sans-serif, SimSun !important; 148 | } 149 | 150 | .el-select-dropdown { 151 | position: absolute; 152 | z-index: 1001; 153 | border: none; 154 | border-radius: 4px; 155 | background-color: rgba(0,0,0,0.3); 156 | box-shadow: 0 2px 12px 0 rgba(0,0,0,0); 157 | box-sizing: border-box; 158 | margin: 5px 0; 159 | color: #ffffff; 160 | } 161 | .el-select-dropdown__item{ 162 | color: #ffffff; 163 | font-family: PingFangSC-Regular; 164 | font-size: 14px; 165 | } 166 | .el-select-dropdown__item.hover, .el-select-dropdown__item:hover { 167 | background-color: rgba(0,0,0,0.5); 168 | } 169 | .el-popper[x-placement^=bottom] .popper__arrow { 170 | display: none; 171 | } 172 | .v-modal{ 173 | display: none; 174 | } 175 | -------------------------------------------------------------------------------- /src/utils/browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file browser.js 3 | * @module browser 4 | */ 5 | 6 | const USER_AGENT = window.navigator && window.navigator.userAgent || '' 7 | const webkitVersionMap = (/AppleWebKit\/([\d.]+)/i).exec(USER_AGENT) 8 | const appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null 9 | 10 | /* 11 | * Device is an iPhone 12 | * 13 | * @type {Boolean} 14 | * @constant 15 | * @private 16 | */ 17 | export const IS_IPAD = (/iPad/i).test(USER_AGENT) 18 | 19 | // The Facebook app's UIWebView identifies as both an iPhone and iPad, so 20 | // to identify iPhones, we need to exclude iPads. 21 | // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/ 22 | export const IS_IPHONE = (/iPhone/i).test(USER_AGENT) && !IS_IPAD 23 | export const IS_IPOD = (/iPod/i).test(USER_AGENT) 24 | export const IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD 25 | 26 | export const IOS_VERSION = (function () { 27 | const match = USER_AGENT.match(/OS (\d+)_/i) 28 | 29 | if (match && match[1]) { 30 | return match[1] 31 | } 32 | return null 33 | }()) 34 | 35 | export const IS_ANDROID = (/Android/i).test(USER_AGENT) 36 | export const ANDROID_VERSION = (function () { 37 | // This matches Android Major.Minor.Patch versions 38 | // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned 39 | const match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i) 40 | 41 | if (!match) { 42 | return null 43 | } 44 | 45 | const major = match[1] && parseFloat(match[1]) 46 | const minor = match[2] && parseFloat(match[2]) 47 | 48 | if (major && minor) { 49 | return parseFloat(match[1] + '.' + match[2]) 50 | } else if (major) { 51 | return major 52 | } 53 | return null 54 | }()) 55 | 56 | export const IS_TBS = (/TBS\/\d+/i).test(USER_AGENT) // 仅X5内核,QQ浏览器默认x5内核,但是agent没有TBS 57 | export const TBS_VERSION = (function () { 58 | var match = USER_AGENT.match(/TBS\/(\d+)/i) 59 | if (match && match[1]) { 60 | return match[1] 61 | } 62 | })()// X5内核版本 63 | 64 | export const IS_MQQB = !IS_TBS && (/MQQBrowser\/\d+/i).test(USER_AGENT) // 移动端QQ浏览器 android QQ也为true 65 | export const IS_QQB = !IS_TBS && (/ QQBrowser\/\d+/i).test(USER_AGENT) // pc端QQ浏览器 66 | export const IS_WECHAT = (/(micromessenger|webbrowser)/i).test(USER_AGENT) // 微信浏览器 67 | // export const IS_MQQ = !IS_TBS &&(/(QBWebViewType)/i).test(USER_AGENT); // 手机QQ内置浏览器 不是很可靠 需要搭配 IS_IOS 来用 68 | export const IS_MQQ = (/ QQ\/\d+/i).test(USER_AGENT) // 手机QQ内置浏览器 69 | 70 | // Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser 71 | export const IS_OLD_ANDROID = IS_ANDROID && (/webkit/i).test(USER_AGENT) && ANDROID_VERSION < 2.3 72 | export const IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537 73 | 74 | export const IS_FIREFOX = (/Firefox/i).test(USER_AGENT) 75 | export const IS_EDGE = (/Edge/i).test(USER_AGENT) 76 | // export const IS_CHROME = !IS_EDGE && (/Chrome/i).test(USER_AGENT); 77 | export const IS_CHROME = (function () { 78 | if (!IS_EDGE && (/Chrome/i).test(USER_AGENT)) { 79 | return true 80 | } else if ((/Safari/i).test(USER_AGENT) && (/CriOS/i).test(USER_AGENT)) { 81 | // ios chrome 82 | return true 83 | } 84 | return false 85 | }()) && !IS_WECHAT && !IS_MQQB && !IS_QQB 86 | export const CHROME_VERSION = (function () { 87 | const match = USER_AGENT.match(/Chrome\/(\d+)/) 88 | const matchIOS = USER_AGENT.match(/CriOS\/(\d+)/) 89 | if (match && match[1]) { 90 | return parseFloat(match[1]) 91 | } else if (matchIOS && matchIOS[1]) { 92 | return parseFloat(matchIOS[1]) 93 | } 94 | return null 95 | }()) 96 | export const IS_IE9 = (/MSIE\s9\.0/).test(USER_AGENT) 97 | //export const IS_IE = (/MSIE\s([\d.]+)/).test(USER_AGENT); 98 | export const IS_IE = (/(msie\s|trident.*rv:)([\w.]+)/i).test(USER_AGENT) // { // window版本 128 | /Windows NT ([.\w]+)/.test(USER_AGENT) 129 | return 'win' + RegExp.$1 130 | })() 131 | 132 | export const MAC_VER = (() => { // mac版本(暂时忽略iMac) 133 | /Mac OS X (\w+)/.test(USER_AGENT) 134 | return 'mac' + RegExp.$1 135 | })() 136 | 137 | export const QQ_VER = (() => { // qq浏览器版本 138 | /QQBrowser\/([.\d]+)/.test(USER_AGENT) 139 | return 'qq' + RegExp.$1 140 | })() 141 | 142 | export const EDGE_VER = (() => { // Edge版本 143 | /Edge\/([.\d]+)/.test(USER_AGENT) 144 | return 'edge' + RegExp.$1 145 | })() 146 | 147 | export const SAFARI_VER = (() => { // Edge版本 148 | /Version\/([.\d]+)/.test(USER_AGENT) 149 | return 'safari' + RegExp.$1 150 | })() 151 | 152 | export const FIREFOX_VER = (() => { // firefox版本 153 | /Firefox\/([.\d]+)/.test(USER_AGENT) 154 | return 'firefox' + RegExp.$1 155 | })() 156 | -------------------------------------------------------------------------------- /src/pages/player/IndexPc.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 87 | 88 | 264 | -------------------------------------------------------------------------------- /src/utils/emojiMap.js: -------------------------------------------------------------------------------- 1 | export const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/' 2 | export const emojiMap = { 3 | '[NO]': 'emoji_0@2x.png', 4 | '[OK]': 'emoji_1@2x.png', 5 | '[下雨]': 'emoji_2@2x.png', 6 | '[么么哒]': 'emoji_3@2x.png', 7 | '[乒乓]': 'emoji_4@2x.png', 8 | '[便便]': 'emoji_5@2x.png', 9 | '[信封]': 'emoji_6@2x.png', 10 | '[偷笑]': 'emoji_7@2x.png', 11 | '[傲慢]': 'emoji_8@2x.png', 12 | '[再见]': 'emoji_9@2x.png', 13 | '[冷汗]': 'emoji_10@2x.png', 14 | '[凋谢]': 'emoji_11@2x.png', 15 | '[刀]': 'emoji_12@2x.png', 16 | '[删除]': 'emoji_13@2x.png', 17 | '[勾引]': 'emoji_14@2x.png', 18 | '[发呆]': 'emoji_15@2x.png', 19 | '[发抖]': 'emoji_16@2x.png', 20 | '[可怜]': 'emoji_17@2x.png', 21 | '[可爱]': 'emoji_18@2x.png', 22 | '[右哼哼]': 'emoji_19@2x.png', 23 | '[右太极]': 'emoji_20@2x.png', 24 | '[右车头]': 'emoji_21@2x.png', 25 | '[吐]': 'emoji_22@2x.png', 26 | '[吓]': 'emoji_23@2x.png', 27 | '[咒骂]': 'emoji_24@2x.png', 28 | '[咖啡]': 'emoji_25@2x.png', 29 | '[啤酒]': 'emoji_26@2x.png', 30 | '[嘘]': 'emoji_27@2x.png', 31 | '[回头]': 'emoji_28@2x.png', 32 | '[困]': 'emoji_29@2x.png', 33 | '[坏笑]': 'emoji_30@2x.png', 34 | '[多云]': 'emoji_31@2x.png', 35 | '[大兵]': 'emoji_32@2x.png', 36 | '[大哭]': 'emoji_33@2x.png', 37 | '[太阳]': 'emoji_34@2x.png', 38 | '[奋斗]': 'emoji_35@2x.png', 39 | '[奶瓶]': 'emoji_36@2x.png', 40 | '[委屈]': 'emoji_37@2x.png', 41 | '[害羞]': 'emoji_38@2x.png', 42 | '[尴尬]': 'emoji_39@2x.png', 43 | '[左哼哼]': 'emoji_40@2x.png', 44 | '[左太极]': 'emoji_41@2x.png', 45 | '[左车头]': 'emoji_42@2x.png', 46 | '[差劲]': 'emoji_43@2x.png', 47 | '[弱]': 'emoji_44@2x.png', 48 | '[强]': 'emoji_45@2x.png', 49 | '[彩带]': 'emoji_46@2x.png', 50 | '[彩球]': 'emoji_47@2x.png', 51 | '[得意]': 'emoji_48@2x.png', 52 | '[微笑]': 'emoji_49@2x.png', 53 | '[心碎了]': 'emoji_50@2x.png', 54 | '[快哭了]': 'emoji_51@2x.png', 55 | '[怄火]': 'emoji_52@2x.png', 56 | '[怒]': 'emoji_53@2x.png', 57 | '[惊恐]': 'emoji_54@2x.png', 58 | '[惊讶]': 'emoji_55@2x.png', 59 | '[憨笑]': 'emoji_56@2x.png', 60 | '[手枪]': 'emoji_57@2x.png', 61 | '[打哈欠]': 'emoji_58@2x.png', 62 | '[抓狂]': 'emoji_59@2x.png', 63 | '[折磨]': 'emoji_60@2x.png', 64 | '[抠鼻]': 'emoji_61@2x.png', 65 | '[抱抱]': 'emoji_62@2x.png', 66 | '[抱拳]': 'emoji_63@2x.png', 67 | '[拳头]': 'emoji_64@2x.png', 68 | '[挥手]': 'emoji_65@2x.png', 69 | '[握手]': 'emoji_66@2x.png', 70 | '[撇嘴]': 'emoji_67@2x.png', 71 | '[擦汗]': 'emoji_68@2x.png', 72 | '[敲打]': 'emoji_69@2x.png', 73 | '[晕]': 'emoji_70@2x.png', 74 | '[月亮]': 'emoji_71@2x.png', 75 | '[棒棒糖]': 'emoji_72@2x.png', 76 | '[汽车]': 'emoji_73@2x.png', 77 | '[沙发]': 'emoji_74@2x.png', 78 | '[流汗]': 'emoji_75@2x.png', 79 | '[流泪]': 'emoji_76@2x.png', 80 | '[激动]': 'emoji_77@2x.png', 81 | '[灯泡]': 'emoji_78@2x.png', 82 | '[炸弹]': 'emoji_79@2x.png', 83 | '[熊猫]': 'emoji_80@2x.png', 84 | '[爆筋]': 'emoji_81@2x.png', 85 | '[爱你]': 'emoji_82@2x.png', 86 | '[爱心]': 'emoji_83@2x.png', 87 | '[爱情]': 'emoji_84@2x.png', 88 | '[猪头]': 'emoji_85@2x.png', 89 | '[猫咪]': 'emoji_86@2x.png', 90 | '[献吻]': 'emoji_87@2x.png', 91 | '[玫瑰]': 'emoji_88@2x.png', 92 | '[瓢虫]': 'emoji_89@2x.png', 93 | '[疑问]': 'emoji_90@2x.png', 94 | '[白眼]': 'emoji_91@2x.png', 95 | '[皮球]': 'emoji_92@2x.png', 96 | '[睡觉]': 'emoji_93@2x.png', 97 | '[磕头]': 'emoji_94@2x.png', 98 | '[示爱]': 'emoji_95@2x.png', 99 | '[礼品袋]': 'emoji_96@2x.png', 100 | '[礼物]': 'emoji_97@2x.png', 101 | '[篮球]': 'emoji_98@2x.png', 102 | '[米饭]': 'emoji_99@2x.png', 103 | '[糗大了]': 'emoji_100@2x.png', 104 | '[红双喜]': 'emoji_101@2x.png', 105 | '[红灯笼]': 'emoji_102@2x.png', 106 | '[纸巾]': 'emoji_103@2x.png', 107 | '[胜利]': 'emoji_104@2x.png', 108 | '[色]': 'emoji_105@2x.png', 109 | '[药]': 'emoji_106@2x.png', 110 | '[菜刀]': 'emoji_107@2x.png', 111 | '[蛋糕]': 'emoji_108@2x.png', 112 | '[蜡烛]': 'emoji_109@2x.png', 113 | '[街舞]': 'emoji_110@2x.png', 114 | '[衰]': 'emoji_111@2x.png', 115 | '[西瓜]': 'emoji_112@2x.png', 116 | '[调皮]': 'emoji_113@2x.png', 117 | '[象棋]': 'emoji_114@2x.png', 118 | '[跳绳]': 'emoji_115@2x.png', 119 | '[跳跳]': 'emoji_116@2x.png', 120 | '[车厢]': 'emoji_117@2x.png', 121 | '[转圈]': 'emoji_118@2x.png', 122 | '[鄙视]': 'emoji_119@2x.png', 123 | '[酷]': 'emoji_120@2x.png', 124 | '[钞票]': 'emoji_121@2x.png', 125 | '[钻戒]': 'emoji_122@2x.png', 126 | '[闪电]': 'emoji_123@2x.png', 127 | '[闭嘴]': 'emoji_124@2x.png', 128 | '[闹钟]': 'emoji_125@2x.png', 129 | '[阴险]': 'emoji_126@2x.png', 130 | '[难过]': 'emoji_127@2x.png', 131 | '[雨伞]': 'emoji_128@2x.png', 132 | '[青蛙]': 'emoji_129@2x.png', 133 | '[面条]': 'emoji_130@2x.png', 134 | '[鞭炮]': 'emoji_131@2x.png', 135 | '[风车]': 'emoji_132@2x.png', 136 | '[飞吻]': 'emoji_133@2x.png', 137 | '[飞机]': 'emoji_134@2x.png', 138 | '[饥饿]': 'emoji_135@2x.png', 139 | '[香蕉]': 'emoji_136@2x.png', 140 | '[骷髅]': 'emoji_137@2x.png', 141 | '[麦克风]': 'emoji_138@2x.png', 142 | '[麻将]': 'emoji_139@2x.png', 143 | '[鼓掌]': 'emoji_140@2x.png', 144 | '[龇牙]': 'emoji_141@2x.png' 145 | } 146 | export const emojiName = [ 147 | '[龇牙]', 148 | '[调皮]', 149 | '[流汗]', 150 | '[偷笑]', 151 | '[再见]', 152 | '[敲打]', 153 | '[擦汗]', 154 | '[猪头]', 155 | '[玫瑰]', 156 | '[流泪]', 157 | '[大哭]', 158 | '[嘘]', 159 | '[酷]', 160 | '[抓狂]', 161 | '[委屈]', 162 | '[便便]', 163 | '[炸弹]', 164 | '[菜刀]', 165 | '[可爱]', 166 | '[色]', 167 | '[害羞]', 168 | '[得意]', 169 | '[吐]', 170 | '[微笑]', 171 | '[怒]', 172 | '[尴尬]', 173 | '[惊恐]', 174 | '[冷汗]', 175 | '[爱心]', 176 | '[示爱]', 177 | '[白眼]', 178 | '[傲慢]', 179 | '[难过]', 180 | '[惊讶]', 181 | '[疑问]', 182 | '[困]', 183 | '[么么哒]', 184 | '[憨笑]', 185 | '[爱情]', 186 | '[衰]', 187 | '[撇嘴]', 188 | '[阴险]', 189 | '[奋斗]', 190 | '[发呆]', 191 | '[右哼哼]', 192 | '[抱抱]', 193 | '[坏笑]', 194 | '[飞吻]', 195 | '[鄙视]', 196 | '[晕]', 197 | '[大兵]', 198 | '[可怜]', 199 | '[强]', 200 | '[弱]', 201 | '[握手]', 202 | '[胜利]', 203 | '[抱拳]', 204 | '[凋谢]', 205 | '[米饭]', 206 | '[蛋糕]', 207 | '[西瓜]', 208 | '[啤酒]', 209 | '[瓢虫]', 210 | '[勾引]', 211 | '[OK]', 212 | '[爱你]', 213 | '[咖啡]', 214 | '[月亮]', 215 | '[刀]', 216 | '[发抖]', 217 | '[差劲]', 218 | '[拳头]', 219 | '[心碎了]', 220 | '[太阳]', 221 | '[礼物]', 222 | '[皮球]', 223 | '[骷髅]', 224 | '[挥手]', 225 | '[闪电]', 226 | '[饥饿]', 227 | '[咒骂]', 228 | '[折磨]', 229 | '[抠鼻]', 230 | '[鼓掌]', 231 | '[糗大了]', 232 | '[左哼哼]', 233 | '[打哈欠]', 234 | '[快哭了]', 235 | '[吓]', 236 | '[篮球]', 237 | '[乒乓]', 238 | '[NO]', 239 | '[跳跳]', 240 | '[怄火]', 241 | '[转圈]', 242 | '[磕头]', 243 | '[回头]', 244 | '[跳绳]', 245 | '[激动]', 246 | '[街舞]', 247 | '[献吻]', 248 | '[左太极]', 249 | '[右太极]', 250 | '[闭嘴]', 251 | '[猫咪]', 252 | '[红双喜]', 253 | '[鞭炮]', 254 | '[红灯笼]', 255 | '[麻将]', 256 | '[麦克风]', 257 | '[礼品袋]', 258 | '[信封]', 259 | '[象棋]', 260 | '[彩带]', 261 | '[蜡烛]', 262 | '[爆筋]', 263 | '[棒棒糖]', 264 | '[奶瓶]', 265 | '[面条]', 266 | '[香蕉]', 267 | '[飞机]', 268 | '[左车头]', 269 | '[车厢]', 270 | '[右车头]', 271 | '[多云]', 272 | '[下雨]', 273 | '[钞票]', 274 | '[熊猫]', 275 | '[灯泡]', 276 | '[风车]', 277 | '[闹钟]', 278 | '[雨伞]', 279 | '[彩球]', 280 | '[钻戒]', 281 | '[沙发]', 282 | '[纸巾]', 283 | '[手枪]', 284 | '[青蛙]' 285 | ] 286 | -------------------------------------------------------------------------------- /src/pages/pusher/IndexPc.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 79 | 80 | 296 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 注意 2 | 3 | 此项目已经**废弃**,以后不再维护。我们推出新的视频直播互动组件 [TUIPusher&TUIPlayer](https://cloud.tencent.com/document/product/647/63830) 4 | 5 | 体验地址: 6 | 7 | - [TUIPusher 体验链接](https://web.sdk.qcloud.com/component/tuiliveroom/tuipusher/login.html) 8 | - [TUIPlayer 体验链接](https://web.sdk.qcloud.com/component/tuiliveroom/tuiplayer/login.html) 9 | 10 | 如果您想要了解更多关于 TUIPusher & TUIPlayer,请阅读官网文档 [TUIPusher&TUIPlayer](https://cloud.tencent.com/document/product/647/63830) 11 | 12 | - 欢迎加入 QQ 群:**592465424**,进行技术交流和反馈~ 13 | 14 |

15 | 以下为原 README 内容 16 | 17 | ## 简介 18 | [TWebLive](https://www.npmjs.com/package/tweblive),腾讯云 Web 直播互动组件,是腾讯云终端研发团队推出的一个新的 SDK,集成了[腾讯云实时音视频 TRTC](https://cloud.tencent.com/product/trtc/)、[腾讯云即时通信 TIM](https://cloud.tencent.com/product/im)、[腾讯云超级播放器 TCPlayer](https://cloud.tencent.com/document/product/454/7503),覆盖了 Web 直播互动场景常见的功能(推流、开/关麦,开/关摄像头,微信分享观看、聊天点赞等等),并封装了简单易用的 [API](https://web.sdk.qcloud.com/component/tweblive/doc/zh-cn/TWebLive.html),接入后可快速实现 Web 端推流、拉流以及实时聊天互动功能。 19 | 20 | ## 效果展示 21 | 22 | ![](https://web.sdk.qcloud.com/component/tweblive/assets/doc/demo.gif) 23 | 24 | ## 架构设计 25 | 26 | ![](https://web.sdk.qcloud.com/component/tweblive/assets/doc/demo-framework.png) 27 | 28 | ## TWebLive 的优点 29 | 开发者接入此 SDK,可**彻底替代 flash 推流方案**,**大大降低** Web 推流、Web 低延时观看、CDN 观看以及实时聊天互动(或弹幕)的**实现复杂度和时间成本**,举例说明: 30 | 1. 当需要推流时,创建 Pusher(推流)对象,最简单的推流仅需3步。 31 | 32 | ```javascript 33 |
34 | 54 | ``` 55 | 56 | 2. 当需要拉流播放时,创建 Player(播放器)对象,最简单的拉流仅需3步。 57 | ```javascript 58 |
59 | 79 | ``` 80 | 81 | 3. 当主播和观众需要聊天互动时,创建 IM(即时通信)对象,最简单的消息收发仅需3步。 82 | ```javascript 83 | // 1、创建 IM(即时通信)对象并监听事件 84 | let im = TWebLive.createIM({ 85 | SDKAppID: 0 // 接入时需要将0替换为您的云通信应用的 SDKAppID 86 | }); 87 | // 监听 IM_READY IM_TEXT_MESSAGE_RECEIVED 等事件 88 | let onIMReady = function(event) { 89 | im.sendTextMessage({ roomID: 'your roomID', text: 'hello from TWebLive' }); 90 | }; 91 | let onTextMessageReceived = function(event) { 92 | event.data.forEach(function(message) { 93 | console.log((message.from || message.nick) + ' : ', message.payload.text); 94 | }); 95 | }; 96 | // 接入侧监听此事件,然后可调用 SDK 发送消息等 97 | im.on(TWebLive.EVENT.IM_READY, onIMReady); 98 | // 收到文本消息,上屏 99 | im.on(TWebLive.EVENT.IM_TEXT_MESSAGE_RECEIVED, onTextMessageReceived); 100 | 101 | // 2、登录 102 | im.login({userID: 'your userID', userSig: 'your userSig'}).then((imResponse) => { 103 | console.log(imResponse.data); // 登录成功 104 | if (imResponse.data.repeatLogin === true) { 105 | // 标识账号已登录,本次登录操作为重复登录 106 | console.log(imResponse.data.errorInfo); 107 | } 108 | }).catch((imError) => { 109 | console.warn('im | login | failed', imError); // 登录失败的相关信息 110 | }); 111 | 112 | // 3、加入直播间 113 | im.enterRoom('your roomID').then((imResponse) => { 114 | switch (imResponse.data.status) { 115 | case TWebLive.TYPES.ENTER_ROOM_SUCCESS: // 加入直播间成功 116 | break; 117 | case TWebLive.TYPES.ALREADY_IN_ROOM: // 已经在直播间内 118 | break; 119 | default: 120 | break; 121 | } 122 | }).catch((imError) => { 123 | console.warn('im | enterRoom | failed', imError); // 加入直播间失败的相关信息 124 | }); 125 | 126 | ``` 127 | 128 | 为了进一步降低开发者的开发和人力成本,我们在 TWebLive SDK 的基础上,提供了同时适配 PC 和移动端浏览器的 [Demo](https://github.com/tencentyun/TWebLive),并开源到了 github。开发者 fork&clone 项目到本地(顺手来个star,谢谢~),稍作修改即可把 Demo 跑起来,或者集成到自己的项目部署上线。 129 | 130 | ## 运行体验 131 | 132 | - [在线 Demo](https://web.sdk.qcloud.com/component/tweblive/demo/latest/index.html#/) 133 | - [本地一分钟跑通体验](https://cloud.tencent.com/document/product/269/47959) 134 | 135 | ## 接入使用 136 | 接入前,您需要: 137 | - 在 [腾讯云实时音视频 TRTC 控制台](https://console.cloud.tencent.com/trtc/app) 中创建一个实时音视频应用(*此时会自动创建一个 `SDKAppID` 相同的 IM 应用*),取得 `SDKAPPID`。然后应用管理 -> 功能配置 -> 开启自动旁路推流。开启旁路推流功能后, TRTC 房间里的每一路画面都配备一路对应的播放地址(*如果不需要 CDN 直播观看,可略过开启旁路推流的步骤*)。 138 | ![](https://web.sdk.qcloud.com/component/tweblive/assets/doc/2.png) 139 | - 在 [腾讯云直播控制台](https://console.cloud.tencent.com/live/) 配置播放域名并完成 CNAME 配置,详细操作指引请参见[《CDN 直播观看》](https://cloud.tencent.com/document/product/647/16826)(*如果不需要 CDN 直播观看,此步骤可略过*)。 140 | - 通过 npm 下载 TWebLive 141 | ```javascript 142 | npm i tweblive --save 143 | ``` 144 | 145 | ## 支持的平台 146 | 147 | Web 推流和 Web 低延时观看用到了 WebRTC 技术。目前主要在桌面版 Chrome 浏览器、桌面版 Safari 浏览器以及移动版 Safari 浏览器上有较为完整的支持,其他平台(例如 Android 平台的浏览器)支持情况均比较差,具体如下: 148 | 149 | | 操作系统 | 浏览器类型 | 浏览器最低版本要求 | 接收(播放)| 发送(上麦)| 屏幕分享 | 150 | |:-------:|:-------:|:-------:|:-------:|:-------:| :-------:| 151 | | Mac OS | 桌面版 Safari 浏览器 | 11+ | 支持 | 支持 | 不支持 | 152 | | Mac OS | 桌面版 Chrome 浏览器 | 56+ | 支持 | 支持 | 支持(需要 chrome72+ 版本) | 153 | | Windows | 桌面版 Chrome 浏览器| 56+ | 支持 | 支持 | 支持(需要 chrome72+ 版本) | 154 | | Windows | 桌面版 QQ 浏览器 | 10.4 | 支持 | 支持 | 不支持 | 155 | | iOS | 移动版 Safari 浏览器 | 11.1.2 | 支持 | 支持 | 不支持 | 156 | | iOS | 微信内嵌网页| 12.1.4 | 支持 | 不支持 | 不支持 | 157 | | Android | 移动版 QQ 浏览器| - | 不支持 | 不支持 | 不支持 | 158 | | Android | 移动版 UC 浏览器| - | 不支持 | 不支持 | 不支持 | 159 | | Android | 微信内嵌网页(TBS内核)| - | 支持 | 支持 | 不支持 | 160 | 161 | 在移动端推荐使用 [小程序](https://cloud.tencent.com/document/product/647/17018) 解决方案,微信和手机 QQ 小程序均已支持,都是由各平台的 Native 技术实现,音视频性能更好,且针对主流手机品牌进行了定向适配。如果您的应用场景主要为教育场景,那么教师端推荐使用稳定性更好的 [Electron](https://cloud.tencent.com/document/product/647/38549) 解决方案,支持大小双路画面,更灵活的屏幕分享方案以及更强大的弱网络恢复能力。 162 | 163 | ## 注意事项 164 | 165 | - 实时音视频应用与 IM 应用的 `SDKAppID` 一致,才能复用账号与鉴权。 166 | - IM 应用针对文本消息,提供基础版本的安全打击能力,如果您希望使用自定义不雅词功能,您可以点击升级或在购买页购买安全打击-专业版服务。 167 | - 本地计算 UserSig 的方式仅用于本地开发调试,请勿直接发布到线上,一旦您的 `SECRETKEY` 泄露,攻击者就可以盗用您的腾讯云流量。正确的 UserSig 签发方式是将 UserSig 的计算代码集成到您的服务端,并提供面向 App 的接口,在需要 UserSig 时由您的 App 向业务服务器发起请求获取动态 UserSig。更多详情请参见 [服务端生成 UserSig](https://cloud.tencent.com/document/product/269/32688#GeneratingdynamicUserSig)。 168 | - 由于 H.264 版权限制,华为系统的 Chrome 浏览器和以 Chrome WebView 为内核的浏览器均不支持 TRTC 桌面浏览器端 SDK 的正常运行。 169 | 170 | ## 参考文档 171 | 172 | - [TWebLive 接口手册](https://web.sdk.qcloud.com/component/tweblive/doc/zh-cn/TWebLive.html) 173 | -------------------------------------------------------------------------------- /src/utils/common.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | export function translateGroupSystemNotice(message) { 3 | const groupName = message.payload.groupProfile.name || message.payload.groupProfile.groupID 4 | switch (message.payload.operationType) { 5 | case 1: 6 | return `${message.payload.operatorID} 申请加入群组:${groupName}` 7 | case 2: 8 | return `成功加入群组:${groupName}` 9 | case 3: 10 | return `申请加入群组:${groupName}被拒绝` 11 | case 4: 12 | return `你被管理员${message.payload.operatorID}踢出群组:${groupName}` 13 | case 5: 14 | return `群:${groupName} 已被${message.payload.operatorID}解散` 15 | case 6: 16 | return `${message.payload.operatorID}创建群:${groupName}` 17 | case 7: 18 | return `${message.payload.operatorID}邀请你加群:${groupName}` 19 | case 8: 20 | return `你退出群组:${groupName}` 21 | case 9: 22 | return `你被${message.payload.operatorID}设置为群:${groupName}的管理员` 23 | case 10: 24 | return `你被${message.payload.operatorID}撤销群:${groupName}的管理员身份` 25 | case 255: 26 | return '自定义群系统通知: ' + message.payload.userDefinedField 27 | } 28 | } 29 | 30 | export const errorMap = { 31 | 500: '服务器错误', 32 | 602: '用户名或密码不合法', 33 | 610: '用户名格式错误', 34 | 612: '用户已存在', 35 | 620: '用户不存在', 36 | 621: '密码错误' 37 | } 38 | 39 | export function getUrlKey(name) { 40 | let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i') 41 | let r = window.location.search.substr(1).match(reg) 42 | if (r != null) { 43 | return unescape(r[2]) 44 | } 45 | return null 46 | } 47 | 48 | export function isValidFlv(url) { 49 | let domian = url.replace(/^https?:\/\/(.*?)(:\d+)?\/.*$/, '$1').toString() 50 | return domian === '3891.liveplay.myqcloud.com' 51 | } 52 | export const isMobileType = { 53 | Android: function () { 54 | return navigator.userAgent.match(/Android/i) 55 | }, 56 | BlackBerry: function () { 57 | return navigator.userAgent.match(/BlackBerry|BB10/i) 58 | }, 59 | iOS: function () { 60 | return navigator.userAgent.match(/iPhone|iPad|iPod/i) 61 | }, 62 | Opera: function () { 63 | return navigator.userAgent.match(/Opera Mini/i) 64 | }, 65 | Windows: function () { 66 | return navigator.userAgent.match(/IEMobile/i) 67 | }, 68 | isSafari:function() { 69 | return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) 70 | }, 71 | any: function () { 72 | return (isMobileType.Android() || isMobileType.BlackBerry() || isMobileType.iOS() || isMobileType.Opera() || isMobileType.Windows()) 73 | }, 74 | getOsName: function () { 75 | var osName = 'Unknown OS' 76 | if (isMobileType.Android()) { 77 | osName = 'Android' 78 | } 79 | 80 | if (isMobileType.BlackBerry()) { 81 | osName = 'BlackBerry' 82 | } 83 | 84 | if (isMobileType.iOS()) { 85 | osName = 'iOS' 86 | } 87 | 88 | if (isMobileType.Opera()) { 89 | osName = 'Opera Mini' 90 | } 91 | 92 | if (isMobileType.Windows()) { 93 | osName = 'Windows' 94 | } 95 | return { 96 | osName, 97 | type: 'mobile' 98 | } 99 | } 100 | } 101 | 102 | 103 | export function detectDesktopOS() { 104 | var unknown = '-' 105 | 106 | var nVer = navigator.appVersion 107 | var nAgt = navigator.userAgent 108 | 109 | var os = unknown 110 | var clientStrings = [{ 111 | s: 'Chrome OS', 112 | r: /CrOS/ 113 | }, { 114 | s: 'Windows 10', 115 | r: /(Windows 10.0|Windows NT 10.0)/ 116 | }, { 117 | s: 'Windows 8.1', 118 | r: /(Windows 8.1|Windows NT 6.3)/ 119 | }, { 120 | s: 'Windows 8', 121 | r: /(Windows 8|Windows NT 6.2)/ 122 | }, { 123 | s: 'Windows 7', 124 | r: /(Windows 7|Windows NT 6.1)/ 125 | }, { 126 | s: 'Windows Vista', 127 | r: /Windows NT 6.0/ 128 | }, { 129 | s: 'Windows Server 2003', 130 | r: /Windows NT 5.2/ 131 | }, { 132 | s: 'Windows XP', 133 | r: /(Windows NT 5.1|Windows XP)/ 134 | }, { 135 | s: 'Windows 2000', 136 | r: /(Windows NT 5.0|Windows 2000)/ 137 | }, { 138 | s: 'Windows ME', 139 | r: /(Win 9x 4.90|Windows ME)/ 140 | }, { 141 | s: 'Windows 98', 142 | r: /(Windows 98|Win98)/ 143 | }, { 144 | s: 'Windows 95', 145 | r: /(Windows 95|Win95|Windows_95)/ 146 | }, { 147 | s: 'Windows NT 4.0', 148 | r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ 149 | }, { 150 | s: 'Windows CE', 151 | r: /Windows CE/ 152 | }, { 153 | s: 'Windows 3.11', 154 | r: /Win16/ 155 | }, { 156 | s: 'Android', 157 | r: /Android/ 158 | }, { 159 | s: 'Open BSD', 160 | r: /OpenBSD/ 161 | }, { 162 | s: 'Sun OS', 163 | r: /SunOS/ 164 | }, { 165 | s: 'Linux', 166 | r: /(Linux|X11)/ 167 | }, { 168 | s: 'iOS', 169 | r: /(iPhone|iPad|iPod)/ 170 | }, { 171 | s: 'Mac OS X', 172 | r: /Mac OS X/ 173 | }, { 174 | s: 'Mac OS', 175 | r: /(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ 176 | }, { 177 | s: 'QNX', 178 | r: /QNX/ 179 | }, { 180 | s: 'UNIX', 181 | r: /UNIX/ 182 | }, { 183 | s: 'BeOS', 184 | r: /BeOS/ 185 | }, { 186 | s: 'OS/2', 187 | r: /OS\/2/ 188 | }, { 189 | s: 'Search Bot', 190 | r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/ 191 | }] 192 | for (var i = 0, cs; cs = clientStrings[i]; i++) { 193 | if (cs.r.test(nAgt)) { 194 | os = cs.s 195 | break 196 | } 197 | } 198 | 199 | var osVersion = unknown 200 | 201 | if (/Windows/.test(os)) { 202 | if (/Windows (.*)/.test(os)) { 203 | osVersion = /Windows (.*)/.exec(os)[1] 204 | } 205 | os = 'Windows' 206 | } 207 | 208 | switch (os) { 209 | case 'Mac OS X': 210 | if (/Mac OS X (10[\.\_\d]+)/.test(nAgt)) { 211 | osVersion = /Mac OS X (10[\.\_\d]+)/.exec(nAgt)[1] 212 | } 213 | break 214 | case 'Android': 215 | if (/Android ([\.\_\d]+)/.test(nAgt)) { 216 | osVersion = /Android ([\.\_\d]+)/.exec(nAgt)[1] 217 | } 218 | break 219 | case 'iOS': 220 | if (/OS (\d+)_(\d+)_?(\d+)?/.test(nAgt)) { 221 | osVersion = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer) 222 | osVersion = osVersion[1] + '.' + osVersion[2] + '.' + (osVersion[3] | 0) 223 | } 224 | break 225 | } 226 | 227 | return { 228 | osName: os + osVersion, 229 | type: 'desktop' 230 | } 231 | } 232 | 233 | export function getOS() { 234 | if (isMobileType.any()) { 235 | return isMobileType.getOsName() 236 | } else { 237 | return detectDesktopOS() 238 | } 239 | } 240 | export function getBroswer() { 241 | var sys = {} 242 | var ua = navigator.userAgent.toLowerCase() 243 | var s; 244 | (s = ua.match(/edge\/([\d.]+)/)) 245 | ? (sys.edge = s[1]) 246 | : (s = ua.match(/rv:([\d.]+)\) like gecko/)) 247 | ? (sys.ie = s[1]) 248 | : (s = ua.match(/msie ([\d.]+)/)) 249 | ? (sys.ie = s[1]) 250 | : (s = ua.match(/firefox\/([\d.]+)/)) 251 | ? (sys.firefox = s[1]) 252 | : (s = ua.match(/chrome\/([\d.]+)/)) 253 | ? (sys.chrome = s[1]) 254 | : (s = ua.match(/opera.([\d.]+)/)) 255 | ? (sys.opera = s[1]) 256 | : (s = ua.match(/version\/([\d.]+).*safari/)) 257 | ? (sys.safari = s[1]) 258 | : 0 259 | 260 | if (sys.edge) return { broswer: 'Edge', version: sys.edge } 261 | if (sys.ie) return { broswer: 'IE', version: sys.ie } 262 | if (sys.firefox) return { broswer: 'Firefox', version: sys.firefox } 263 | if (sys.chrome) return { broswer: 'Chrome', version: sys.chrome } 264 | if (sys.opera) return { broswer: 'Opera', version: sys.opera } 265 | if (sys.safari) return { broswer: 'Safari', version: sys.safari } 266 | 267 | return { broswer: '', version: '0' } 268 | } 269 | -------------------------------------------------------------------------------- /src/pages/live/live.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 205 | 206 | 217 | -------------------------------------------------------------------------------- /src/utils/rtc-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import TRTC from 'trtc-js-sdk' 3 | 4 | class RtcClient { 5 | constructor(options) { 6 | this.sdkAppId_ = options.sdkAppId; 7 | this.userId_ = options.userId; 8 | this.userSig_ = options.userSig; 9 | this.roomId_ = options.roomId; 10 | 11 | this.isJoined_ = false; 12 | this.isPublished_ = false; 13 | this.localStream_ = null; 14 | this.remoteStreams_ = []; 15 | this.ready = false 16 | 17 | // check if browser is compatible with TRTC 18 | TRTC.checkSystemRequirements().then(result => { 19 | if (!result) { 20 | alert('Your browser is not compatible with TRTC! Please download Chrome M72+'); 21 | } 22 | }); 23 | } 24 | 25 | async join() { 26 | if (this.isJoined_) { 27 | console.warn('duplicate RtcClient.join() observed'); 28 | return; 29 | } 30 | 31 | // create a client for RtcClient 32 | this.client_ = TRTC.createClient({ 33 | mode: 'videoCall', // 实时通话模式 34 | sdkAppId: this.sdkAppId_, 35 | userId: this.userId_, 36 | userSig: this.userSig_ 37 | }); 38 | 39 | // 处理 client 事件 40 | this.handleEvents(); 41 | 42 | try { 43 | // join the room 44 | await this.client_.join({ roomId: this.roomId_ }); 45 | console.log('join room success'); 46 | this.isJoined_ = true; 47 | } catch (error) { 48 | window.dispatchEvent(new Event('leave')); 49 | alert( 50 | '进房失败原因:' + 51 | error 52 | ); 53 | return; 54 | } 55 | 56 | this.localStream_.on('player-state-changed', event => { 57 | console.log(`local stream ${event.type} player is ${event.state}`); 58 | if (event.type === 'video' && event.state === 'PLAYING') { 59 | // dismiss the remote user UI placeholder 60 | } else if (event.type === 'video' && event.state === 'STOPPPED') { 61 | // show the remote user UI placeholder 62 | } 63 | }); 64 | 65 | try { 66 | this.localStream_.play('local') // 在id为 local 的 div 容器上播放本地音视频 67 | } catch (e) { 68 | } 69 | 70 | // publish local stream by default after join the room 71 | await this.publish(); 72 | console.log('发布本地流成功!') 73 | } 74 | 75 | async leave() { 76 | if (!this.isJoined_) { 77 | console.warn('leave() - leave without join()d observed'); 78 | return; 79 | } 80 | 81 | if (this.isPublished_) { 82 | // ensure the local stream has been unpublished before leaving. 83 | await this.unpublish(true); 84 | } 85 | 86 | try { 87 | // leave the room 88 | await this.client_.leave(); 89 | this.isJoined_ = false; 90 | } catch (error) { 91 | location.reload(); 92 | } finally { 93 | // 停止本地流,关闭本地流内部的音视频播放器 94 | this.localStream_.stop(); 95 | this.localStream_.close(); 96 | this.localStream_ = null; 97 | // 关闭本地流,释放摄像头和麦克风访问权限 98 | } 99 | } 100 | 101 | async publish() { 102 | if (!this.isJoined_) { 103 | console.warn('publish() - please join() firstly'); 104 | return; 105 | } 106 | if (this.isPublished_) { 107 | console.warn('duplicate RtcClient.publish() observed'); 108 | return; 109 | } 110 | try { 111 | // 发布本地流 112 | await this.client_.publish(this.localStream_); 113 | this.isPublished_ = true; 114 | } catch (error) { 115 | this.isPublished_ = false; 116 | } 117 | } 118 | 119 | async unpublish(isLeaving) { 120 | if (!this.isJoined_) { 121 | console.warn('unpublish() - please join() firstly'); 122 | return; 123 | } 124 | if (!this.isPublished_) { 125 | console.warn('RtcClient.unpublish() called but not published yet'); 126 | return; 127 | } 128 | 129 | try { 130 | // 停止发布本地流 131 | await this.client_.unpublish(this.localStream_); 132 | this.isPublished_ = false; 133 | } catch (error) { 134 | if (!isLeaving) { 135 | console.warn('leaving the room because unpublish failure observed'); 136 | this.leave(); 137 | } 138 | } 139 | } 140 | 141 | muteLocalAudio() { 142 | this.localStream_.muteAudio(); 143 | } 144 | 145 | unmuteLocalAudio() { 146 | this.localStream_.unmuteAudio(); 147 | } 148 | 149 | muteLocalVideo() { 150 | this.localStream_.muteVideo(); 151 | } 152 | 153 | unmuteLocalVideo() { 154 | this.localStream_.unmuteVideo(); 155 | } 156 | 157 | async createLocalStream(options) { 158 | this.localStream_ = TRTC.createStream({ 159 | audio: options.audio, // 采集麦克风 160 | video: options.video, // 采集摄像头 161 | userId: this.userId_ 162 | // cameraId: getCameraId(), 163 | // microphoneId: getMicrophoneId() 164 | }); 165 | // 设置视频分辨率帧率和码率 166 | this.localStream_.setVideoProfile('480p'); 167 | 168 | await this.localStream_.initialize(); 169 | } 170 | 171 | handleEvents() { 172 | // 处理 client 错误事件,错误均为不可恢复错误,建议提示用户后刷新页面 173 | this.client_.on('error', () => { 174 | // alert(err); 175 | // location.reload(); 176 | }); 177 | 178 | // 处理用户被踢事件,通常是因为房间内有同名用户引起,这种问题一般是应用层逻辑错误引起的 179 | // 应用层请尽量使用不同用户ID进房 180 | this.client_.on('client-banned', () => { 181 | // location.reload(); 182 | }); 183 | 184 | // 远端用户进房通知 - 仅限主动推流用户 185 | this.client_.on('peer-join', evt => { 186 | const userId = evt.userId; 187 | console.log('peer-join ' + userId); 188 | }); 189 | // 远端用户退房通知 - 仅限主动推流用户 190 | this.client_.on('peer-leave', evt => { 191 | const userId = evt.userId; 192 | window.dispatchEvent(new Event('leave')); 193 | console.log('peer-leave ' + userId); 194 | }); 195 | 196 | // 处理远端流增加事件 197 | this.client_.on('stream-added', evt => { 198 | const remoteStream = evt.stream; 199 | const id = remoteStream.getId(); 200 | const userId = remoteStream.getUserId(); 201 | console.log(`remote stream added: [${userId}] ID: ${id} type: ${remoteStream.getType()}`); 202 | console.log('subscribe to this remote stream'); 203 | // 远端流默认已订阅所有音视频,此处可指定只订阅音频或者音视频,不能仅订阅视频。 204 | // 如果不想观看该路远端流,可调用 this.client_.unsubscribe(remoteStream) 取消订阅 205 | this.client_.subscribe(remoteStream); 206 | }); 207 | 208 | // 远端流订阅成功事件 209 | this.client_.on('stream-subscribed', evt => { 210 | const remoteStream = evt.stream; 211 | const id = remoteStream.getId(); 212 | this.remoteStreams_.push(remoteStream); 213 | try { 214 | document.getElementsByName('remote')[0].setAttribute('id', id); 215 | remoteStream.play(id); // 在指定的 div 容器上播放音视频 216 | } catch(e) { 217 | } 218 | console.log('stream-subscribed ID: ', id); 219 | }); 220 | 221 | // 处理远端流被删除事件 222 | this.client_.on('stream-removed', evt => { 223 | const remoteStream = evt.stream; 224 | const id = remoteStream.getId(); 225 | // 关闭远端流内部的音视频播放器 226 | remoteStream.stop(); 227 | this.remoteStreams_ = this.remoteStreams_.filter(stream => { 228 | return stream.getId() !== id; 229 | }); 230 | console.log(`stream-removed ID: ${id} type: ${remoteStream.getType()}`); 231 | }); 232 | 233 | // 处理远端流更新事件,在音视频通话过程中,远端流音频或视频可能会有更新 234 | this.client_.on('stream-updated', evt => { 235 | const remoteStream = evt.stream; 236 | console.log( 237 | 'type: ' + 238 | remoteStream.getType() + 239 | ' stream-updated hasAudio: ' + 240 | remoteStream.hasAudio() + 241 | ' hasVideo: ' + 242 | remoteStream.hasVideo() 243 | ); 244 | }); 245 | 246 | // 远端流音频或视频mute状态通知 247 | this.client_.on('mute-audio', evt => { 248 | console.log(evt.userId + ' mute audio'); 249 | }); 250 | this.client_.on('unmute-audio', evt => { 251 | console.log(evt.userId + ' unmute audio'); 252 | }); 253 | this.client_.on('mute-video', evt => { 254 | console.log(evt.userId + ' mute video'); 255 | }); 256 | this.client_.on('unmute-video', evt => { 257 | console.log(evt.userId + ' unmute video'); 258 | }); 259 | 260 | // 信令通道连接状态通知 261 | this.client_.on('connection-state-changed', evt => { 262 | console.log(`RtcClient state changed to ${evt.state} from ${evt.prevState}`); 263 | }); 264 | } 265 | } 266 | 267 | export default RtcClient --------------------------------------------------------------------------------