<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('liveEvent', {detail:{eventName: 'onRemoteUserEnterRoom', eventData: {userId: 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('liveEvent', {detail:{eventName: 'onRemoteUserLeaveRoom', eventData: {userId: 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>
