video.nvue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. <template>
  2. <view class="video_box" :style="'height:' + phoneHeight + 'px'">
  3. <!-- 本地预览视图 -->
  4. <view class="video_me" v-show="allUserViewObjectList.length > 0">
  5. <!-- <view class="video_me" v-if="videoShow"> -->
  6. <zego-local-view :viewMode="publisherViewModeIndex"
  7. style="width: 150px; height: 200px; flex: 1; position: fixed; right: 0; top: 65px;">
  8. </zego-local-view>
  9. </view>
  10. <!-- 服务器传来的预览图 -->
  11. <view class="video_you" v-for="(item, index) in allUserViewObjectList" :key="item.streamID">
  12. <!-- <view class="video_you"> -->
  13. <zego-remote-view v-if="item.streamID" :streamID="item.streamID" :viewMode="item.viewMode"
  14. style="width: 620px; height: 600px; flex: 1;">
  15. </zego-remote-view>
  16. </view>
  17. <view class="video_btn">
  18. <view class="video_imgList">
  19. <view class="video_imgList1">
  20. <view class="video_view" @click="turn">
  21. <image class="video_view_img" src="../../static/image/9.png" mode=""></image>
  22. </view>
  23. <text class="video_view_txt">翻转镜头</text>
  24. </view>
  25. <view class="video_imgList2" v-if="CameraShow">
  26. <view class="video_view" @click="closeCamera">
  27. <image class="video_view_img" src="../../static/image/11.png" mode=""></image>
  28. </view>
  29. <text class="video_view_txt" style="margin: 0 0 0 30rpx;">静音</text>
  30. </view>
  31. <view class="video_imgList2" v-else>
  32. <view class="video_view" @click="openCamera">
  33. <image class="video_view_img" src="../../static/image/12.png" mode=""></image>
  34. </view>
  35. <text class="video_view_txt" style="margin: 0 0 0 30rpx;">开启</text>
  36. </view>
  37. </view>
  38. <image @click="offVideo()" style="width: 50px; height: 50px; margin: 0 0 0 330rpx;"
  39. src="../../static/image/10.png" mode=""></image>
  40. </view>
  41. <!-- 消息提醒 -->
  42. <u-toast ref="uToast"></u-toast>
  43. </view>
  44. </template>
  45. <script>
  46. import store from '@/store/index.js'; //需要引入store
  47. let App = getApp();
  48. // var API = App.globalData.socketTask;
  49. var API = App.globalData;
  50. import permision from "@/zego-express-video-uniapp/permission.js";
  51. import ZegoExpressEngine from '@/zego-express-video-uniapp/lib/ZegoExpressEngine';
  52. import {
  53. ZegoScenario,
  54. ZegoRoomState,
  55. ZegoUpdateType,
  56. // ZegoViewMode,
  57. ZegoVideoCodecID
  58. } from '@/zego-express-video-uniapp/lib/ZegoExpressDefines'
  59. import {
  60. AppID,
  61. AppSign
  62. } from '@/zego-express-video-uniapp/KeyCenter.js'
  63. import ZegoLocalView from '@/zego-express-video-uniapp/zego-view/ZegoLocalView';
  64. import ZegoRemoteView from '@/zego-express-video-uniapp/zego-view/ZegoRemoteView';
  65. export default {
  66. data() {
  67. return {
  68. phoneHeight: '', // 获取当前的屏幕高度
  69. // 即构
  70. publisherViewModeIndex: 0, // 本地预览图
  71. viewModeA: 0, // 服务器预览图
  72. serveViewModeIndex: "", // 服务器拉流预览图
  73. engine: undefined,
  74. videoObj: null,
  75. userid: "Uni" + Math.floor(Math.random() * 1000000).toString(),
  76. isPublishingStream: false,
  77. shotShow: false, // 翻转镜头
  78. videoShow: false, // 切换视频显示
  79. allStreamList: [],
  80. allUserViewObjectList: [],
  81. CameraShow: true, // 镜头开启关闭
  82. }
  83. },
  84. components: {
  85. ZegoLocalView: ZegoLocalView,
  86. ZegoRemoteView: ZegoRemoteView
  87. },
  88. watch: {
  89. allUserViewObjectList(val) {
  90. var that = this
  91. if (val.length > 0) {
  92. val.forEach((item) => {
  93. if (item.streamID) {
  94. this.tensile(item)
  95. return true
  96. }
  97. })
  98. }
  99. }
  100. },
  101. methods: {
  102. // 即构 - 视频通话 初始化
  103. async setup() {
  104. var that = this
  105. // 创建引擎
  106. let profile = {
  107. appID: AppID,
  108. appSign: AppSign,
  109. scenario: ZegoScenario.General
  110. }
  111. this.engine = await ZegoExpressEngine.createEngineWithProfile(profile);
  112. this.engine.useFrontCamera(this.shotShow); // 设置前后摄像头
  113. // console.log(this.engine)
  114. this.addListeners();
  115. // console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' + that.videoObj.room_id)
  116. this.engine.loginRoom(that.videoObj.room_id, {
  117. userID: that.videoObj.room_id,
  118. userName: that.videoObj.room_id
  119. }, {
  120. isUserStatusNotify: true
  121. });
  122. },
  123. // 即构 - 翻转镜头
  124. turn() {
  125. this.shotShow = !this.shotShow
  126. this.engine.useFrontCamera(this.shotShow)
  127. },
  128. // 即构 - 关闭镜头 - 停止拉流 、推流
  129. closeCamera() {
  130. this.allStreamList.forEach((item) => {
  131. // this.notTensile(item.streamID); // 停止拉流
  132. item.muteAudio = !item.muteAudio;
  133. this.engine.mutePlayStreamAudio(item.streamID, item.muteAudio);
  134. })
  135. // // 停止推流
  136. this.CameraShow = false
  137. },
  138. // 即构 - 开启镜头 - 开启拉流、推流
  139. openCamera() {
  140. console.log('开启摄像头')
  141. this.allStreamList.forEach((item) => {
  142. // this.engine.startPlayingStream(item.streamID); // 开始拉流
  143. item.muteAudio = !item.muteAudio;
  144. this.engine.mutePlayStreamAudio(item.streamID, item.muteAudio);
  145. })
  146. // // 开始推流
  147. // this.engine.startPreview();
  148. // this.engine.startPublishingStream(this.videoObj.room_id);
  149. this.CameraShow = true
  150. },
  151. // 切换视频显示
  152. changeShow() {
  153. this.videoShow = !this.videoShow
  154. // this.onPublish()
  155. this.engine.startPreview();
  156. this.engine.startPublishingStream(this.videoObj.room_id);
  157. this.publishBtnName = "Stop Publishing";
  158. console.log(this.videoShow)
  159. },
  160. // 即构 - 视频通话 监听房间
  161. addListeners() {
  162. console.log('开始监听房间了啊')
  163. var that = this
  164. // console.log(this.allStreamList, '------------------')
  165. // 房间状态变化通知
  166. this.engine.on("roomStateUpdate", (roomID, state, errorCode, extendedData) => {
  167. // console.log('房间状态变化')
  168. if (state == "CONNECTED") {
  169. // 与房间连接成功,只有当房间状态是连接成功时,才能进行推流、拉流等操作。
  170. // 接下来的“预览并推流”的代码写在这里
  171. console.log("房间连接成功");
  172. }
  173. if (state == "DISCONNECTED") {
  174. // 与房间断开了连接
  175. console.log("与房间断开连接");
  176. }
  177. if (state == "CONNECTING") {
  178. // 与房间尝试连接中
  179. console.log("与房间尝试连接中");
  180. }
  181. });
  182. // 房间用户变化通知
  183. this.engine.on("roomUserUpdate", (roomID, updateType, userList) => {
  184. console.log(updateType)
  185. console.log(userList)
  186. console.log("有其他用户进出房间");
  187. if (updateType == ZegoUpdateType.Add) {
  188. console.log('进入了啊AAAAAAAAAA')
  189. for (let user of userList) {
  190. for (let stream of this.allStreamList) {
  191. if (user.userID == stream.user.userID) {
  192. user.streamID = stream.streamID;
  193. }
  194. }
  195. this.allUserViewObjectList.push(user);
  196. }
  197. } else if (updateType == ZegoUpdateType.Delete) {
  198. this.allUserViewObjectList = this.allUserViewObjectList.filter((object) => {
  199. for (let user of userList) {
  200. if (user.userID == object.userID) {
  201. return false;
  202. }
  203. }
  204. return true;
  205. });
  206. }
  207. if (updateType == "1") {
  208. // 有其他用户退出房间
  209. this.offVideo()
  210. }
  211. });
  212. // 房间内其他用户推的流变化通知
  213. this.engine.on("roomStreamUpdate", (roomID, updateType, streamList) => {
  214. // if (updateType == "0") {
  215. // // 流新增,开始拉流
  216. // this.tensile(streamList[0].streamID)
  217. // } else if (updateType == "1") {
  218. // // 流删除,停止拉流
  219. // this.notTensile(streamList[0].streamID);
  220. // }
  221. console.log('进入了啊BBBBBBBBBBBBBBBBBBBBBBB')
  222. console.log('---------updateType-----------', updateType)
  223. console.log('---------streamList-----------', streamList)
  224. console.log('---------ZegoUpdateType-----------', ZegoUpdateType)
  225. console.log('---------ZegoUpdateType.Add-----------', ZegoUpdateType.Add)
  226. console.log('---------ZegoUpdateType.Delete-----------', ZegoUpdateType.Delete)
  227. console.log('---------allUserViewObjectList-----------', this.allUserViewObjectList)
  228. if (updateType == ZegoUpdateType.Add) {
  229. for (let object of this.allUserViewObjectList) {
  230. for (let stream of streamList) {
  231. if (object.userID == stream.user.userID) {
  232. object.streamID = stream.streamID;
  233. }
  234. }
  235. }
  236. this.allStreamList = this.allStreamList.concat(streamList);
  237. console.log(this.allStreamList, '-------------')
  238. } else if (updateType == ZegoUpdateType.Delete) {
  239. for (let object of this.allUserViewObjectList) {
  240. for (let stream of streamList) {
  241. if (object.streamID == stream.streamID) {
  242. object.streamID = undefined;
  243. }
  244. }
  245. }
  246. this.allStreamList = this.allStreamList.filter((object) => {
  247. for (let stream of streamList) {
  248. if (object.streamID == stream.streamID) {
  249. return false;
  250. }
  251. }
  252. return true;
  253. });
  254. }
  255. });
  256. // 拉流质量回调
  257. this.engine.on("playerQualityUpdate", (streamID, quality) => {
  258. console.log('拉流质量回调');
  259. console.log(streamID, quality);
  260. // if (this.videoShow == false) {
  261. // setTimeout(() => {
  262. // that.videoShow = true
  263. // console.log(that.videoShow, '要打开推流的视频窗口了啊')
  264. // }, 3500)
  265. // }
  266. });
  267. // 拉流后的事件回调
  268. this.engine.on("playerStateUpdate", (streamID, state, errorCode, extendedData) => {
  269. console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' + '拉流后的事件触发了')
  270. })
  271. },
  272. tensile(item) {
  273. console.log(this.allStreamList)
  274. console.log(item)
  275. console.log(this.allUserViewObjectList)
  276. this.engine.startPlayingStream(item.streamID)
  277. },
  278. // 停止拉流
  279. notTensile(roomId) {
  280. this.serveViewModeIndex = roomId
  281. this.engine.stopPlayingStream(roomId)
  282. },
  283. // 推流 - 展示视图 - 本地视频流
  284. onPublish() {
  285. if (this.isPublishingStream) {
  286. // 停止推流
  287. this.engine.stopPreview();
  288. this.engine.stopPublishingStream();
  289. } else {
  290. console.log('开始推流了啊', this.isPublishingStream)
  291. // 开始推流
  292. this.engine.startPreview();
  293. // 设置编码格式
  294. // let videoConfig = {};
  295. // videoConfig.codecID = ZegoVideoCodecID.VP8;
  296. // this.engine.setVideoConfig(videoConfig);
  297. // 设置编码格式
  298. // this.engine.startPublishingStream(this.videoObj.room_id);
  299. console.log(this.userid)
  300. this.engine.startPublishingStream(this.userid);
  301. // this.videoShow = true
  302. }
  303. this.isPublishingStream = !this.isPublishingStream;
  304. },
  305. // 挂断退出
  306. async offVideo() {
  307. console.log('进入了啊')
  308. var that = this
  309. that.engine.logoutRoom(that.videoObj.room_id); // 退出房间
  310. that.$refs.uToast.show({
  311. type: 'default',
  312. message: '结束视频通话!',
  313. })
  314. setTimeout(() => {
  315. that.videoShow = true
  316. that.allStreamList = [];
  317. that.allUserViewObjectList = [];
  318. var obj = {}
  319. // obj = {
  320. // 'action': 'read', // 动作标识,必填
  321. // 'send_user_id': that.videoObj.user_id, // 接收人用户id, 非必填
  322. // 'data': {}
  323. // }
  324. console.log('-----------接收人用户id-------------', that.videoObj.user_id, API)
  325. obj = {
  326. 'action': 'list', // 动作标识,必填
  327. 'type': '当前为挂断',
  328. 'recv_user_id': that.videoObj.user_id, // 接收人用户id, 非必填
  329. 'data': {}
  330. }
  331. API.socketTask.send({
  332. data: JSON.stringify(obj),
  333. async success(res) {
  334. console.log("消息发送成功");
  335. },
  336. });
  337. uni.navigateBack({
  338. delta: 1
  339. })
  340. }, 1500)
  341. // uni.redirectTo({
  342. // url: "/pages/response/index"
  343. // })
  344. },
  345. // 删除this.engine对象, 删除即构
  346. async destroyEngine() {
  347. this.engine = undefined;
  348. ZegoExpressEngine.destroyEngine();
  349. },
  350. },
  351. async onLoad(optinos) {
  352. var that = this
  353. that.videoObj = JSON.parse(optinos.videoObj)
  354. // // console.log(that.videoObj)
  355. // // 即构 - 视频通话
  356. // // 获取系统信息同步接口
  357. if (uni.getSystemInfoSync().platform === 'android') {
  358. await permision.requestAndroidPermission('android.permission.RECORD_AUDIO');
  359. await permision.requestAndroidPermission('android.permission.CAMERA');
  360. }
  361. await this.setup()
  362. this.onPublish(); // 推流
  363. uni.getSystemInfo({ //异步获取。
  364. success(res) {
  365. // that.phoneHeight = res.windowHeight - 13; //窗口高度
  366. that.phoneHeight = res.windowHeight; //窗口高度
  367. }
  368. });
  369. },
  370. async onShow() {
  371. await this.setup();
  372. },
  373. // 监听页面返回
  374. onBackPress() {
  375. console.log('返回了!')
  376. this.offVideo(); // 挂断退出
  377. this.destroyEngine(); // 删除this.engine对象,删除即构
  378. },
  379. // 页面卸载 - 生命周期
  380. onUnload() {
  381. this.destroyEngine();
  382. console.log('onUnload');
  383. },
  384. }
  385. </script>
  386. <style lang="scss">
  387. .video_box {
  388. background: #000;
  389. width: 1200rpx;
  390. position: relative;
  391. // .video_you {
  392. .video_me {
  393. background: #000;
  394. width: 150px;
  395. height: 200px;
  396. position: fixed;
  397. right: 0;
  398. top: 65px;
  399. }
  400. .video_you {
  401. background: #000;
  402. width: 620px;
  403. height: 600px;
  404. position: absolute;
  405. right: 0;
  406. bottom: 0;
  407. }
  408. .video_btn {
  409. position: fixed;
  410. bottom: 35rpx;
  411. left: 0;
  412. width: 750rpx;
  413. .video_imgList {
  414. display: flex;
  415. flex-direction: row;
  416. justify-content: space-around;
  417. // 翻转
  418. .video_imgList1 {
  419. .video_view {
  420. background: rgba(0, 0, 0, .5);
  421. border-radius: 50px;
  422. width: 50px;
  423. height: 50px;
  424. margin: 0 auto;
  425. .video_view_img {
  426. height: 25px;
  427. width: 25px;
  428. margin: 24rpx 0 0 25rpx;
  429. }
  430. }
  431. .video_view_txt {
  432. color: #fff;
  433. font-size: 14px;
  434. line-height: 30px;
  435. text-align: center;
  436. }
  437. }
  438. // 语音通话
  439. .video_imgList2 {
  440. .video_view {
  441. background: rgba(0, 0, 0, .5);
  442. border-radius: 50px;
  443. width: 50px;
  444. height: 50px;
  445. margin: 0 0 0 30rpx;
  446. .video_view_img {
  447. height: 25px;
  448. width: 25px;
  449. margin: 24rpx 0 0 25rpx;
  450. }
  451. }
  452. .video_view_txt {
  453. color: #fff;
  454. font-size: 14px;
  455. line-height: 30px;
  456. text-align: center;
  457. }
  458. }
  459. }
  460. }
  461. }
  462. </style>