123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- <template>
- <view class="container" data-type="template" data-is="1v1" data-attr="pusher, streamList, debug">
- <view v-for="item in streams.slice(0,1)" :key="item.streamID" class="player-container" :style="'display:'+playerStyle">
- <template v-if="item.src && (item.hasVideo || item.hasAudio)">
- <live-player
- class="player"
- :data-userid="item.userID"
- :data-streamid="item.streamID"
- :data-streamtype="item.streamType"
- :src="item.src"
- :mode="item.mode"
- :autoplay="item.autoplay"
- :mute-audio="item.muteAudio"
- :mute-video="item.muteVideo"
- :orientation="item.orientation"
- :object-fit="item.objectFit"
- :background-mute="item.enableBackgroundMute"
- :min-cache="item.minCache"
- :max-cache="item.maxCache"
- :sound-mode="item.soundMode"
- :enable-recv-message="item.enableRecvMessage"
- :auto-pause-if-navigate="item.autoPauseIfNavigate"
- :auto-pause-if-open-native="item.autoPauseIfOpenNative"
- :debug="debug"
- @statechange="playerStateChangeFun"
- @fullscreenchange="playerFullscreenChangeFun"
- @netstatus="playerNetStatusFun"
- @audiovolumenotify="playerAudioVolumeNotifyFun"
- :idAttr="item.streamID" />
- </template>
- </view>
- <view v-if="pusher.url" class="pusher-container" :style="'display:'+pusherStyle">
- <live-pusher
- class="pusher"
- :url="pusher.url"
- :mode="pusher.mode"
- :autopush="pusher.autopush"
- :enable-camera="pusher.enableCamera"
- :enable-mic="pusher.enableMic"
- :enable-agc="pusher.enableAgc"
- :enable-ans="pusher.enableAns"
- :enable-ear-monitor="pusher.enableEarMonitor"
- :auto-focus="pusher.enableAutoFocus"
- :zoom="pusher.enableZoom"
- :min-bitrate="pusher.minBitrate"
- :max-bitrate="pusher.maxBitrate"
- :video-width="pusher.videoWidth"
- :video-height="pusher.videoHeight"
- :beauty="pusher.beautyLevel"
- :whiteness="pusher.whitenessLevel"
- :orientation="pusher.videoOrientation"
- :aspect="pusher.videoAspect"
- :device-position="pusher.frontCamera"
- :remote-mirror="pusher.enableRemoteMirror"
- :local-mirror="pusher.localMirror"
- :background-mute="pusher.enableBackgroundMute"
- :audio-quality="pusher.audioQuality"
- :audio-volume-type="pusher.audioVolumeType"
- :audio-reverb-type="pusher.audioReverbType"
- :waiting-image="pusher.waitingImage"
- :debug="debug"
- @statechange="pusherStateChangeHandlerFun"
- @netstatus="pusherNetStatusHandlerFun"
- @error="pusherErrorHandlerFun"
- @bgmstart="pusherBGMStartHandlerFun"
- @bgmprogress="pusherBGMProgressHandlerFun"
- @bgmcomplete="pusherBGMCompleteHandlerFun" />
- </view>
- </view>
- </template>
- <script>
- const LOGTAG = '--JHLIVE--:';
- const pusherStateCodeDic = {
- 1001: '已经连接推流服务器',
- 1002: '已经与服务器握手完毕,开始推流',
- 1003: '打开摄像头成功',
- 1004: '录屏启动成功',
- 1005: '推流动态调整分辨率',
- 1006: '推流动态调整码率',
- 1007: '首帧画面采集完成',
- 1008: '编码器启动',
- 1018: '进房成功',
- 1019: '退出房间',
- 2003: '渲染首帧视频',
- 1020: '远端用户全量列表更新',
- 1031: '远端用户进房通知',
- 1032: '远端用户退房通知',
- 1033: '用户视频状态变化,新增stream或者更新stream',
- 1034: '远端用户音频状态位变化通知',
- '-1301': '打开摄像头失败',
- '-1302': '打开麦克风失败',
- '-1303': '视频编码失败',
- '-1304': '音频编码失败',
- '-1307': '推流连接断开',
- '-100018': '进房失败',
- '5000': '小程序被挂起',
- '1021': '网络类型发生变化,需要重新进房',
- '2007': '本地视频播放loading',
- '2004': '本地视频播放开始',
- }
- const defaultStreamParams = {
- streamType: '',
- src: '',
- mode: 'RTC',
- autoplay: true, // 7.0.9 必须设置为true,否则 Android 有概率调用play()失败
- muteAudio: false, // 默认不拉取音频,需要手动订阅
- muteVideo: false, // 默认不拉取视频,需要手动订阅
- orientation: 'vertical', // 画面方向 vertical horizontal
- objectFit: 'fillCrop', // 填充模式,可选值有 contain,fillCrop
- enableBackgroundMute: false, // 进入后台时是否静音(已废弃,默认退台静音)
- minCache: 1, // 最小缓冲区,单位s(RTC 模式推荐 0.2s)
- maxCache: 2, // 最大缓冲区,单位s(RTC 模式推荐 0.8s)
- soundMode: 'speaker', // 声音输出方式 ear speaker
- enableRecvMessage: 'false', // 是否接收SEI消息
- autoPauseIfNavigate: true, // 当跳转到其它小程序页面时,是否自动暂停本页面的实时音视频播放
- autoPauseIfOpenNative: true // 当跳转到其它微信原生页面时,是否自动暂停本页面的实时音视频播放
- }
- export default {
- name: 'jhlive-wechat',
- data() {
- return {
- pusher: {
- url: '',
- mode: 'RTC', // RTC:实时通话(trtc sdk) live:直播模式(liteav sdk)
- autopush: false, // 自动推送
- enableCamera: false, // 是否开启摄像头
- enableMic: false, // 是否开启麦克风
- enableAgc: false, // 是否开启音频自动增益
- enableAns: false, // 是否开启音频噪声抑制
- enableEarMonitor: false, // 是否开启耳返(目前只在iOS平台有效)
- enableAutoFocus: true, // 是否自动对焦
- enableZoom: false, // 是否支持调整焦距
- minBitrate: 200, // 最小码率
- maxBitrate: 1000, // 最大码率
- videoWidth: 360, // 视频宽(若设置了视频宽高就会忽略aspect)
- videoHeight: 640, // 视频高(若设置了视频宽高就会忽略aspect)
- beautyLevel: 0, // 美颜,取值范围 0-9 ,0 表示关闭
- whitenessLevel: 0, // 美白,取值范围 0-9 ,0 表示关闭
- videoOrientation: 'vertical', // vertical horizontal
- videoAspect: '9:16', // 宽高比,可选值有 3:4,9:16
- frontCamera: 'front', // 前置或后置摄像头,可选值:front,back
- enableRemoteMirror: false, // 设置推流画面是否镜像,产生的效果会表现在 live-player
- localMirror: 'auto', // auto:前置摄像头镜像,后置摄像头不镜像(系统相机的表现)enable:前置摄像头和后置摄像头都镜像 disable: 前置摄像头和后置摄像头都不镜像
- enableBackgroundMute: false, // 进入后台时是否静音
- audioQuality: 'high', // 高音质(48KHz)或低音质(16KHz),可选值:high,low
- audioVolumeType: 'voicecall', // 声音类型 可选值: media: 媒体音量,voicecall: 通话音量
- audioReverbType: 0, // 音频混响类型 0: 关闭 1: KTV 2: 小房间 3:大会堂 4:低沉 5:洪亮 6:金属声 7:磁性
- waitingImage: '', // 当微信切到后台时的垫片图片 trtc暂不支持
- waitingImageHash: ''
- },
- users: [],
- };
- },
- props: {
- sdkAppID: Number,
- userSig: String,
- userid: String,
- roomid: String,
- isAuthor: Boolean,
- linkMic: Boolean
- },
- computed: {
- streams() {
- console.log(LOGTAG+'users', this.users);
- let streams = [];
- this.users.forEach(v=>{
- let userStreams = Object.entries(v.streams);
- streams = streams.concat(userStreams.map(([kk,vv])=>vv).filter(vv=>vv.hasVideo));
- });
- console.log(LOGTAG+'streams', streams);
- return streams;
- },
- playerStyle() {
- return (!this.isAuthor)?'block':'none';
- },
- pusherStyle() {
- return this.isAuthor?'block':'none';
- }
- },
- methods: {
- enterRoom() {
- this.pusher.url = `room://cloud.tencent.com/rtc?sdkappid=${this.sdkAppID}&roomid=${this.roomid}&userid=${this.userid}&usersig=${this.userSig}&appscene=live&encsmall=1&cloudenv=PRO`;
- this.pusher.autopush = this.isAuthor||this.linkMic;
- this.pusher.enableCamera = this.isAuthor;
- this.pusher.enableMic = this.isAuthor||this.linkMic;
- this.$nextTick(()=>{
- this.pusherContext = wx.createLivePusherContext();
- this.pusherContext.start();
- })
- console.log(LOGTAG+'pusher',this.pusher);
- },
- exitRoom: function() {
- if (this.pusherContext) {
- this.pusherContext.stop();
- this.pusherContext = null;
- }
- },
- switchCarema() {
- wx.createLivePusherContext().switchCamera();
- this.pusher.frontCamera = this.pusher.frontCamera=='front'?'back':'front';
- console.log(LOGTAG+'pusher',this.pusher);
- },
- setBeauty(blv, wlv) {
- this.pusher.beautyLevel = blv;
- this.pusher.whitenessLevel = wlv;
- console.log(LOGTAG+'pusher',this.pusher);
- },
- /** --- pusher event handler --- **/
- pusherStateChangeHandlerFun: function(event) {
- const code = event.detail.code;
- const message = event.detail.message;
- console.log(LOGTAG+'pusherState',code, pusherStateCodeDic[code]);
-
- // 远端用户进房通知
- if(code == 1031) {
- const data = JSON.parse(event.detail.message)||{};
- (data.userlist||[]).forEach( v=> {
- if(!this.users.find(vv => vv.userid == v.userid)) {
- this.users.push({
- userid: v.userid,
- streams: {},
- });
- this.$emit('onRemoteUserEnterRoom', {detail:v.userid});
- }
- })
- }
- // 远端用户退房通知
- if(code == 1032) {
- const data = JSON.parse(event.detail.message)||{};
- (data.userlist||[]).forEach( v=> {
- let user = this.users.find(v => v.userid == data.userid);
- if(!user) return;
- user.streams.forEach(vv=>{
- if(vv.playerContext) {
- vv.playerContext.stop;
- vv.playerContext = null;
- }
- });
- user.streams = [];
- this.$emit('onRemoteUserLeaveRoom', {detail:v.userid});
- })
- this.users = this.users.filter(v => (data.userlist||[]).find(vv=>vv.userid!=v.userid));
- }
- // 用户视频状态变化,新增stream或者更新stream 状态
- if(code == 1033) {
- const data = JSON.parse(event.detail.message)||{};
- (data.userlist||[]).forEach( v=> {
- let user = this.users.find(vv => v.userid == v.userid);
- if(!user) return;
- let stream = user.streams[v.streamtype] = user.streams[v.streamtype] || {...defaultStreamParams};
- stream.streamtype = v.streamtype;
- stream.userID = v.userid;
- stream.streamID = v.userid + '_' + stream.streamType;
- stream.hasVideo = v.hasvideo;
- stream[`has${stream.streamType}Video`] = stream.hasVideo;
- stream.src = v.playurl;
- if(stream.hasVideo) stream.playerContext = wx.createLivePlayerContext(stream.streamID, this);
- })
- this.users = [...this.users];
- }
-
- // 远端用户音频状态位变化通知
- if(code == 1034) {
- console.log('远端用户音频状态位变化通知', data);
- const data = JSON.parse(event.detail.message)||{};
- (data.userlist||[]).forEach( v=> {
- let user = this.users.find(vv => v.userid == vv.userid);
- if(!user) return;
- v.streamtype = 'main';
- let stream = user.streams[v.streamtype] = user.streams[v.streamtype] || {...defaultStreamParams}
- stream.streamtype = v.streamtype;
- stream.userID = v.userid;
- stream.streamID = v.userid + '_' + stream.streamType;
- stream.hasAudio = v.hasaudio;
- stream[`has${stream.streamType}Audio`] = stream.hasAudio;
- stream.src = v.playurl;
- if(stream.hasAudio) stream.playerContext = wx.createLivePlayerContext(stream.streamID, this);
- })
- this.users = [...this.users];
- }
- },
- pusherNetStatusHandlerFun: function(event) {
-
- },
- pusherErrorHandlerFun: function(event) {
- this.$emit('liveEvent', {detail:{eventName: 'onError', eventData: {msg: '推送错误'}}});
- console.error(LOGTAG+'pusher error: ',event.detail);
- },
- pusherBGMStartHandlerFun: function(event) {
-
- },
- pusherBGMProgressHandlerFun: function(event) {
-
- },
- pusherBGMCompleteHandlerFun: function(event) {
-
- },
-
- /** --- player event handler --- **/
- playerStateChangeFun: function(event) {
- console.log(LOGTAG+'playerStateChangeFun');
- },
- playerFullscreenChangeFun: function(event) {
- console.log(LOGTAG+'playerFullscreenChangeFun');
- },
- playerNetStatusFun: function(event) {
- console.log(LOGTAG+'playerNetStatusFun');
- let dataset = event.currentTarget.dataset;
- let info = event.detail.info;
- let user = this.users.find(v => v.userid == dataset.userid);
- if(!user) return;
- let stream = user.streams[dataset.streamtype];
- if(!stream) return;
- stream.videoWidth = info.videoWidth;
- stream.videoHeight = info.videoHeight;
- },
- playerAudioVolumeNotifyFun: function(event) {
- console.log(LOGTAG+'playerAudioVolumeNotifyFun');
- },
- }
- };
- </script>
- <style lang="less" scoped>
- .container {
- width: 100%;
- height: 100%;
- }
- .pusher-container {
- width: 100%;
- height: 100%;
- }
- .player-container{
- width: 100%;
- height: 100%;
- }
- .pusher {
- width: 100%;
- height: 100%;
- }
- .player {
- width: 100%;
- height: 100%;
- }
- </style>
|