able99 4 жил өмнө
parent
commit
d6050d4ca1

+ 166 - 0
jhim/jhim.js

@@ -0,0 +1,166 @@
+import TIM from './tim-wx';
+import LibGenerateTestUserSig from "./lib-generate-test-usersig-es.min";
+
+const EXPIRETIME = 604800;
+
+export default class JhIm {
+  constructor(userId, sdkAppID, secretKey) {
+    this.userId = userId;
+    this.sdkAppID = sdkAppID;
+    this.secretKey = secretKey;
+    this.tim = TIM.create({ SDKAppID: this.sdkAppID });
+    const generator = new LibGenerateTestUserSig(this.sdkAppID, this.secretKey, EXPIRETIME);
+    this.userSig = generator.genTestUserSig(this.userId);
+    this.roomId = null;
+    this.logined = false;
+    this.groupReady = false;
+
+    // 0 普通级别,日志量较多,接入时建议使用
+    // 1 release级别,SDK 输出关键信息,生产环境时建议使用
+    // 2 告警级别,SDK 只输出告警和错误级别的日志
+    // 3 错误级别,SDK 只输出错误级别的日志
+    // 4 无日志级别,SDK 将不打印任何日志
+    this.tim.setLogLevel(1);
+    
+    this.tim.on(TIM.EVENT.MESSAGE_RECEIVED, event=>{
+      event = event.data.map(v=>v);
+      console.log(11111111111,event);
+      this.onIMMessageReceived&&this.onIMMessageReceived(event);
+    }, this);
+
+    this.tim.on(TIM.EVENT.SDK_READY, event=>this.onIMSDKReady&&this.onIMSDKReady(event), this);
+    this.tim.on(TIM.EVENT.SDK_NOT_READY, event=>{
+      this.logined = false;
+      this.onIMSDKNotReady&&this.onIMSDKNotReady();
+    }, this);
+	
+    // 收到被踢下线通知
+    // event.name - TIM.EVENT.KICKED_OUT
+    // event.data.type - 被踢下线的原因,例如 :
+    //    - TIM.TYPES.KICKED_OUT_MULT_ACCOUNT 多实例登录被踢
+    //    - TIM.TYPES.KICKED_OUT_MULT_DEVICE 多终端登录被踢
+    //    - TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED 签名过期被踢。使用前需要将SDK版本升级至v2.4.0或以上。
+    this.tim.on(TIM.EVENT.KICKED_OUT, event=>this.onIMKickedOut&&this.onIMKickedOut(event), this);
+
+    // 收到 SDK 发生错误通知,可以获取错误码和错误信息
+    // event.name - TIM.EVENT.ERROR
+    // event.data.code - 错误码
+    // event.data.message - 错误信息
+    this.tim.on(TIM.EVENT.ERROR, event=>this.onIMError&&this.onIMError(event), this);
+    return this;
+  }
+  on(name, cb) {
+    this[name] = cb;
+    return this;
+  }
+  off(name) {
+    this[name] = null;
+    return this;
+  }
+  login(name, avatar) {
+    this.name = name; 
+    this.avatar = avatar;
+    return new Promise(resolve=>{
+      let cb = event=>{
+        this.logined = true;
+        this.tim.updateMyProfile({
+          nick: name,
+          avatar: avatar,
+          allowType: TIM.TYPES.ALLOW_TYPE_ALLOW_ANY
+        });
+        this.onIMReady&&this.onIMReady(event);
+        resolve();
+        this.tim.off(TIM.EVENT.SDK_READY, cb, this);
+      }
+      this.tim.on(TIM.EVENT.SDK_READY, cb, this);
+      this.tim.login({
+        userID: this.userId,
+        userSig: this.userSig,
+      })
+    });
+  }
+  logout() {
+    return this.tim.logout().then(()=>{
+      this.logined = false;
+    });
+  }
+  createGroup(roomId) {
+    this.roomId = roomId;
+    return this.tim.searchGroupByID(this.roomId).then(()=>{
+      return this.joinGroup(roomId);
+    },()=>{
+      return this.tim.createGroup({
+        groupID: this.roomId,
+        name: this.roomId,
+        type: TIM.TYPES.GRP_AVCHATROOM,
+      }).then(() => { 
+        return this.joinGroup(roomId);
+      });
+    });
+  }
+  dismissGroup() {
+		return this.tim.dismissGroup(this._createGroup.roomId).then(() => {
+      this.groupReady = false;
+      this.roomId = null;
+    });
+  }
+  joinGroup(roomId) {
+    this.roomId = roomId;
+    return this.tim.joinGroup({ 
+      groupID: this.roomId, 
+      type: TIM.TYPES.GRP_AVCHATROOM 
+    }).then((imResponse) => {
+			switch (imResponse.data.status) {
+			  case TIM.TYPES.JOIN_STATUS_WAIT_APPROVAL: // 等待管理员同意
+				  break;
+			  case TIM.TYPES.JOIN_STATUS_SUCCESS: // 加群成功
+        case TIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP: // 已经在群中
+          this.groupReady = true;
+          this.sendGroupMessage({
+            data: this.userId,
+            description: 'userJoinin',
+            extension: '',
+          });
+				  break;
+			}
+		});
+  }
+  exitGroup() {
+    return this.sendGroupMessage({
+      data: this.userId,
+      description: 'userJoinin',
+      extension: '',
+    }).then(()=>{
+      return this.tim.quitGroup(this.roomId).then(()=>{
+        this.groupReady = false;
+        this.roomId = null;
+      });
+    })
+  }
+  sendGroupText(text) {
+    const message = this.tim.createTextMessage({
+      to: this.roomId,
+      conversationType: TIM.TYPES.CONV_GROUP,
+      payload: {text},  
+    })
+    return this.tim.sendMessage(message).then(()=>({
+      name: this.name,
+      avatar: this.avatar,
+      message: text,
+    }));
+  }
+  sendGroupMessage(payload) {
+    const message = this.tim.createCustomMessage({
+      to: this.roomId,
+      conversationType: TIM.TYPES.CONV_GROUP,
+      payload,
+    })
+    return this.tim.sendMessage(message);
+  }
+  getGroupProfile() {
+    return this.tim.getGroupProfile({ groupID: this.roomId }).then(res => imResponse.data.group);
+  }
+  getGroupNum() {
+    return this.getGroupProfile(res=>res.memberCount);
+  }
+}

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 1217 - 0
jhim/lib-generate-test-usersig-es.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
jhim/tim-wx.js


+ 250 - 0
jhlive/jhlive.nvue

@@ -0,0 +1,250 @@
+<template>
+	<view class="container-jhlive" data-type="jhlive">
+    <liveView 
+      class="liveView"
+      ref="liveView"
+      :sdkAppID="sdkAppID"
+      :userSig="userSig"
+      :userid="userid" 
+      :roomid="roomid" 
+      :isAuthor="isAuthor"
+      :linkMic="linkMic" />
+    <view class="top_left_box">
+      <image class="top_left_box_img" :src="avtar"></image>
+      <view class="top_left_box_text">
+        <text class="top_left_box_text1">{{name}}</text>
+        <text class="top_left_box_text2" >{{num||1}}</text>
+      </view>
+    </view>
+    <view class="top-right-box">
+			<view class="top-right-box-btn" v-if="isAuthor" @click="btnChangeCamera">
+        <text class="top-right-box-btn-text">切换</text>
+      </view>
+    </view>
+
+    <view class="bottom-left-box" v-if="!imReady">
+      <view class="bottom-left-box-login"><text>登录中...</text></view>
+    </view>
+    <view class="bottom-left-box" v-if="imReady">
+			<view class="bottom-left-box-messages" v-for="(item, index) in imMsgs" :key="index">
+			  <view class="bottom-left-box-message">
+          <image :src="item.avatar" />
+          <text>{{item.name}}:{{item.text}}</text>
+        </view>
+		  </view>
+		  <view class="bottom-left-box-input-box">
+        <input 
+          class="bottom-left-box-input"
+          placeholder="说点什么..." placeholder-style="color:#fff" 
+          v-model="imMsgInput"
+          confirm-type="send" @confirm="btnImSend" />
+      </view>
+    </view>
+    <view class="bottom-right-box">
+			<view class="bottom-right-box-btn" @click="btnShop">
+        <text class="bottom-right-box-btn-text">商品</text>
+      </view>
+      <view class="bottom-right-box-btn" @click="btnLike">
+        <text class="bottom-right-box-btn-text">点赞</text>
+      </view>
+    </view>
+	</view>
+</template>
+
+<script>
+
+import LibGenerateTestUserSig from "./lib-generate-test-usersig-es.min";
+
+// #ifdef MP-WEIXIN
+import liveView from './live-wechat';
+//#endif
+// #ifdef H5
+import liveView from './live-wechat';
+//#endif
+// #ifdef APP-PLUS
+import liveView from './live-app';
+//#endif
+
+const EXPIRETIME = 604800;
+
+export default {
+  name: 'jhlive',
+  components: { liveView },
+
+	data() {
+		return {
+      userSig: '',
+      imMsgInput: '',
+		};
+	},
+
+	props: {
+    sdkAppID: Number,
+    secretKey: String,
+    userid: String,
+    roomid: String,
+    isAuthor: Boolean,
+    linkMic: Boolean,
+    name: String,
+    avtar: String,
+    num: Number,
+    likes: Number,
+    imReady: Boolean,
+    imMsgs: Array,
+	},
+	mounted: function() {
+    this.init();
+	},
+	destroyed: function() {
+		this.destroy();
+	},
+	methods: {
+    init() {
+      uni.setKeepScreenOn({
+        keepScreenOn: true
+      });
+    },
+    destroy() {
+      uni.setKeepScreenOn({
+        keepScreenOn: false
+      });
+      this.exitRoom()
+    },
+		enterRoom() {
+      const generator = new LibGenerateTestUserSig(this.sdkAppID, this.secretKey, EXPIRETIME);
+      this.userSig = generator.genTestUserSig(this.userid);
+      
+      setTimeout(()=>{
+				this.$refs.liveView.enterRoom();
+			}, 1000)
+		},
+		exitRoom() {
+			this.$refs.liveView.exitRoom();
+    },
+    btnChangeCamera() {
+      this.$refs.liveView.ChangeCamera();
+    },
+    btnImSend() {
+      this.$emit('imSend', this.imMsgInput);
+      this.imMsgInput = '';
+    },
+    btnLike() {
+      this.$emit('like');
+    },
+    btnShop() {
+      this.$emit('shop');
+    }
+	}
+};
+</script>
+
+<style scoped>
+
+.container-jhlive {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  background-color: black;
+  width: 100%;
+  height: 100%;
+}
+
+.liveView {
+  flex: 1;
+}
+
+.top_left_box {
+  left: 0;
+  top: 0;
+  margin-left: 10px;
+  margin-top: 10px;
+  position: absolute;
+  z-index: 100;
+  background-color:rgba(0, 0, 0, 0.4);
+  border-radius: 1000px;
+  display: flex;
+  flex-direction: row;
+  padding: 10px;
+}
+.top_left_box_img {
+  width: 80rpx;
+  height: 80rpx;
+  border-radius: 1000px;
+  background-color: white;
+}
+.top_left_box_text {
+  margin-left: 10px;
+  flex: 1;
+}
+.top_left_box_text1 {
+  font-size: 28rpx;
+  color: white;
+}
+.top_left_box_text2 {
+  font-size: 20rpx;
+  color: white;
+}
+
+
+.top-right-box {
+  right: 0;
+  top: 0;
+  margin-top: 10px;
+  margin-right: 10px;
+  position: absolute;
+  z-index: 100;
+}
+.top-right-box-btn {
+	color: white;
+}
+.top-right-box-btn {
+  color: white;
+}
+
+
+.bottom-left-box {
+  left: 0;
+  bottom: 0;
+  margin-left: 10px;
+  margin-bottom: 10px;
+  position: absolute;
+  z-index: 100;
+}
+.bottom-left-box-login {
+  color: white;
+}
+.bottom-left-box-messages {
+
+}
+.bottom-left-box-message {
+
+}
+.bottom-left-box-input-box {
+
+}
+.bottom-left-box-input {
+  color: #fff;
+  font-size: 30rpx;
+}
+
+
+.bottom-right-box {
+  right: 0;
+  bottom: 0;
+  margin-bottom: 10px;
+  margin-right: 10px;
+  position: absolute;
+  z-index: 100;
+  display: flex;
+  flex-direction: row;
+}
+.bottom-right-box-btn {
+	color: white;
+  margin-left: 5px;
+}
+.bottom-right-box-btn-color {
+	color: white;
+}
+
+</style>

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 1217 - 0
jhlive/lib-generate-test-usersig-es.min.js


+ 52 - 0
jhlive/live-app.vue

@@ -0,0 +1,52 @@
+<template>
+	<JhliveApp 
+    class="container"
+    ref="jhliveApp"
+    :sdkAppID="sdkAppID"
+    :userSig="userSig"
+    :userid="userid" 
+    :roomid="roomid" 
+    :isAuthor="isAuthor"
+    :linkMic="linkMic" />
+</template>
+
+<script>
+
+export default {
+	data() {
+		return {
+			
+		};
+	},
+	props: {
+		props: {
+      sdkAppID: Number,
+      userSig: String,
+      userid: String,
+      roomid: String, 
+      isAuthor: Boolean,
+      linkMic: Boolean
+    },
+	},
+	mounted: function() {
+
+	},
+	destroyed: function() {
+		
+	},
+	methods: {
+		enterRoom: function() {
+			this.$refs.jhliveApp.enterRoom();
+		},
+		exitRoom: function() {
+			this.$refs.jhliveApp.exitRoom();
+		}
+	}
+};
+</script>
+
+<style scoped>
+.container {
+  flex: 1;
+}
+</style>

+ 435 - 0
jhlive/live-wechat.vue

@@ -0,0 +1,435 @@
+<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="RTC"
+          :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 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>
+export default {
+  name: 'jhlive-wechat',
+	data() {
+		return {
+      pusher: null,
+      users: [],
+		};
+	},
+
+	props: {
+		sdkAppID: Number,
+    userSig: String,
+    userid: String,
+    roomid: String, 
+    isAuthor: Boolean,
+    linkMic: Boolean
+  },
+  computed: {
+    streams() {
+      console.log('--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('--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',
+        mode: 'RTC', // RTC:实时通话(trtc sdk) live:直播模式(liteav sdk)
+        autopush: this.isAuthor||this.linkMic, // 自动推送
+        enableCamera: this.isAuthor, // 是否开启摄像头
+        enableMic: this.isAuthor||this.linkMic, // 是否开启麦克风
+        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: ''
+      };
+
+      console.log('JHLIVE-PUSHER CONFIG', this.pusher);
+      setTimeout(()=>{
+        this.pusherContext = wx.createLivePusherContext();
+        this.pusherContext.start();
+        console.log('JHLIVE-PUSHER pusherContext', this.pusherContext);
+      },1000);
+		},
+		exitRoom: function() {
+			if (this.pusherContext) {
+        this.pusherContext.stop();
+        this.pusherContext = null;
+      }
+    },
+    /** --- pusher event handler --- **/
+		pusherStateChangeHandlerFun: function(event) {
+			const code = event.detail.code;
+      const message = event.detail.message;
+      
+			switch (code) {
+				case 0:
+					console.log(message, code);
+					break;
+
+				case 1001:
+					console.log('已经连接推流服务器', code);
+					break;
+
+				case 1002:
+					console.log('已经与服务器握手完毕,开始推流', code);
+					break;
+
+				case 1003:
+					console.log('打开摄像头成功', code);
+					break;
+
+				case 1004:
+					console.log('录屏启动成功', code);
+					break;
+
+				case 1005:
+					console.log('推流动态调整分辨率', code);
+					break;
+
+				case 1006:
+					console.log('推流动态调整码率', code);
+					break;
+
+				case 1007:
+					console.log('首帧画面采集完成', code);
+					break;
+
+				case 1008:
+					console.log('编码器启动', code);
+					break;
+
+				case 1018:
+					console.log('进房成功', code);
+					break;
+
+				case 1019:
+					console.log('退出房间', code);
+					break;
+
+				case 2003:
+					console.log('渲染首帧视频', code);
+					break;
+
+				case 1020: // 远端用户全量列表更新
+          break;
+        case 1031: {// 远端用户进房通知
+          const data = JSON.parse(event.detail.message)||{};
+          console.log('远端用户进房通知', data);
+          (data.userlist||[]).forEach( v=> {
+            if(!this.users.find(vv => vv.userid == v.userid)) {
+              this.users.push({
+                userid: v.userid,
+                streams: {},
+              });
+            }
+          })
+        }break;
+        case 1032: {// 远端用户退房通知
+          console.log('远端用户退房通知', data);
+          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.users = this.users.filter(v => (data.userlist||[]).find(vv=>vv.userid!=v.userid));
+        }break;
+        case 1033: {// 用户视频状态变化,新增stream或者更新stream 状态
+          console.log('用户视频状态变化,新增stream或者更新stream', data);
+          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] || {
+              streamType: v.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 // 当跳转到其它微信原生页面时,是否自动暂停本页面的实时音视频播放
+            }
+
+            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;
+            // stream.objectFit = stream.hasVideo && stream.streamType === 'aux' && 'contain';
+
+            if(stream.hasVideo) stream.playerContext = wx.createLivePlayerContext(stream.streamID, this);
+          })
+          this.users = [...this.users];
+        }break;
+        case 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] || {
+              streamType: v.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 // 当跳转到其它微信原生页面时,是否自动暂停本页面的实时音视频播放
+            }
+
+            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];
+        }break;
+				case -1301:
+					console.error('打开摄像头失败: ', code);
+					break;
+
+				case -1302:
+					console.error('打开麦克风失败: ', code);
+					break;
+
+				case -1303:
+					console.error('视频编码失败: ', code);
+					break;
+
+				case -1304:
+					console.error('音频编码失败: ', code);
+					break;
+
+				case -1307:
+					console.error('推流连接断开: ', code);
+					break;
+
+				case -100018:
+					console.error('进房失败: ', code, message);
+					break;
+
+				case 5000:
+					console.log('小程序被挂起: ', code); 
+          this.exitRoom()
+          this.enterRoom()
+					break;
+
+				case 1021:
+					console.log('网络类型发生变化,需要重新进房', code);
+					break;
+
+				case 2007:
+					console.log('本地视频播放loading: ', code);
+					break;
+
+				case 2004:
+					console.log('本地视频播放开始: ', code);
+					break;
+
+				default:
+					console.log(message, code);
+			}
+		},
+		pusherNetStatusHandlerFun: function(event) {
+			
+		},
+		pusherErrorHandlerFun: function(event) {
+			try {
+        console.error('pusher error: ');
+				const code = event.detail.errCode;
+				const message = event.detail.errMsg;
+        console.error(code, message);
+			} catch (exception) {}
+		},
+		pusherBGMStartHandlerFun: function(event) {
+			
+		},
+		pusherBGMProgressHandlerFun: function(event) {
+			
+		},
+		pusherBGMCompleteHandlerFun: function(event) {
+			
+    },
+    
+    /** --- player event handler --- **/
+		playerStateChangeFun: function(event) {
+      console.log('playerStateChangeFun');
+		},
+		playerFullscreenChangeFun: function(event) {
+      console.log('playerFullscreenChangeFun');
+		},
+		playerNetStatusFun: function(event) {
+      console.log('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('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>

+ 1 - 0
manifest.json

@@ -6,6 +6,7 @@
 	"versionCode": "100",
 	"transformPx": false,
 	"app-plus": {
+		"nvueCompiler":"uni-app",
 		"usingComponents": true,
 		"compilerVersion": 3,
 		/* 5+App特有相关 */

+ 6 - 2
pages/media/index.vue

@@ -81,8 +81,8 @@
 			}
 		},
 		onShow() {
-			this.userData = uni.getStorageSync("userData")||{}
-			this.getBaseData()
+			// this.userData = uni.getStorageSync("userData")||{}
+			// this.getBaseData()
 		},
 		onPullDownRefresh() {
 			this.getBaseData('refresh')
@@ -141,6 +141,10 @@
 			},
 			//  查看直播详情
 			goToLiveDetail() {
+				uni.navigateTo({
+									url: '/pagesMedia/liveDetail?liveId=' + 1
+								});
+								return;
 				if(!this.userData.roleInfos.some(v=>v.menuInfos.some(vv=>vv.label == '开始直播并可选择商品'))){
 					this.$refs.uTips.show({
 						title: '没有授权使用,请联系商户负责人',

+ 167 - 0
pagesMedia/liveDetail.nvue

@@ -0,0 +1,167 @@
+<template>
+	<view 
+		class="container" 
+		:style="'width: '+windowWidth+'px; height: '+windowHeight+'px;'">
+		<jhlive 
+			ref="jhlive" 
+			class="jhlive"
+			:sdkAppID="1400430241" 
+			secretKey="941e01ca06e94057de3013b235b67a784ea28b45c43decbd518e765f7d5fc140"
+			userid="123"
+			roomid="1"
+			:isAuthor="false"
+			:linkMic="false" 
+			:avtar="avtar"
+			:num="num"
+			:likes="likes"
+			:name="name" 
+			:imReady="imReady"
+			:imMsgs="imMsgs" 
+			@imSend="handleImSend"
+			@like="handleLike"
+			@shop="handleShop"/>
+	</view>
+</template>
+
+<script>
+	import jhlive from "@/jhlive/jhlive";
+	import Jhim from "@/jhim/jhim";
+	const NET = require('@/utils/request')
+	const API = require('@/config/api')
+	
+	export default {
+		components: { jhlive },
+		data() {
+			return {
+				windowWidth: 0,
+				windowHeight: 0,
+				userId: '123',
+				roomID: '1',
+				liveId: '',
+				num: 0,
+				likes: 0,
+				name:"",
+				avtar:"../static/images/loginLogo.png",
+				userData: {},
+				imReady: false,
+				imMsgs: [],
+			}
+		},
+		onLoad(options) {
+			this.liveId = options.liveId
+			this.userData = uni.getStorageSync("userData");
+			let info = uni.getSystemInfoSync();
+			this.windowWidth = info.windowWidth;
+      this.windowHeight = info.windowHeight;
+			return;
+
+			NET.request(API.getBindedLiveGoods, {
+				liveId: this.liveId
+			}, 'GET').then(res => {
+				let goodsIds = res.data.map(site => {
+					return site.productId
+				}).join(',')
+				this.getAllGoods(goodsIds)
+			}).catch(res => {
+				this.$refs.uTips.show({
+					title: '获取已绑定商品失败',
+					type: 'warning',
+				})
+			})
+			NET.request(API.creatLive, {
+				liveId: this.liveId,
+				liveStatus: 1
+			}, 'GET').then(res => {}).catch(res => {
+				this.$refs.uTips.show({
+					title: '开启直播失败',
+					type: 'warning',
+				})
+			})
+			NET.request(API.startLivePushMessage + options.liveId, {}, 'GET').then(res => {
+
+			}).catch(res => {
+				
+			})
+			NET.request(API.getLiveData + this.liveId, {}, 'POST').then(res => {
+				this.enterRoom({
+					roomID: Number(res.data.roomId),
+					userID: this.userData.userId,
+					template: "grid",
+				});
+				this.avtar = res.data.imgUrl;
+				this.name = res.data.liveName;
+				this.roomID = Number(res.data.roomId);
+				setTimeout(()=>{
+					this.$refs.jhlive&&this.$refs.jhlive.enterRoom();
+				}, 500)
+			}).catch(res => {
+				this.$refs.uTips.show({
+					title: '获取直播设置参数失败',
+					type: 'warning',
+				})
+			})
+		},
+		onReady() {
+			setTimeout(()=>{
+				this.jhim = new Jhim(this.userId, 1400430241, '941e01ca06e94057de3013b235b67a784ea28b45c43decbd518e765f7d5fc140');
+				this.jhim.on('onIMMessageReceived', event=>{
+					this.imMsgs = this.imMsgs.concat(event);
+				}).on('onIMSDKNotReady', event=>{
+					this.imReady = false;
+				}).on('onIMSDKReady', event=>{
+					this.imReady = true;
+				})
+				this.jhim
+					.login('name', 'avatar')
+					.then(()=>this.jhim.ready)
+					.then(()=>this.jhim.createGroup(this.roomID))
+				this.$refs.jhlive&&this.$refs.jhlive.enterRoom();
+			}, 500)		
+		},
+		onUnload() {
+			this.jhim.exitGroup();
+			if(this.isAuthor) this.jhim.dismissGroup();
+			this.jhim.logout();
+
+			// NET.request(API.creatLive, {
+			// 	liveId: this.liveId,
+			// 	liveStatus: 2
+			// }, 'GET').then(res => {}).catch(res => {
+			// 	this.$refs.uTips.show({
+			// 		title: '关闭直播失败',
+			// 		type: 'warning',
+			// 	})
+			// })
+		},
+		methods: {
+			handleImSend(msg) {				
+				let msgObj = {
+				  data: msg,
+				  description: this.userData.headImage,
+				  extension: this.userData.userName
+				};
+
+				this.jhim.sendGroupText(msg).then(msg=>{
+					this.imMsgs.push(msg);
+				});
+			},
+			handleLike(msg) {
+			},
+			handleShop(msg) {			
+			}
+		},
+	}
+</script>
+
+<style lang="less" scoped>
+	.container {
+		position: relative;
+		display: flex;
+		flex-direction: column;
+		align-items: stretch;
+	}
+
+	.jhlive {
+		flex: 1;
+	}
+</style>

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно