Browse Source

update 直播

warrior 3 months ago
parent
commit
e04c48a08c

+ 1 - 1
projects/live-app/src/app/components/live/live.component.html

@@ -8,7 +8,7 @@
       height="100%"
       (click)="onChangeScreen('big',$event)"
     >
-      等待连接
+    等待对方接受邀请...
     </div>
     <!-- 副屏 -->
     <div

+ 1 - 1
projects/live-app/src/app/components/live/live.component.scss

@@ -1,5 +1,5 @@
 .video_box {
-  background-color: #000;
+  background-color: #9d9d9d;
   width: 100%;
   height: 100vh;
   // border-radius: 2px;

+ 5 - 3
projects/live-app/src/app/components/live/live.component.ts

@@ -24,6 +24,7 @@ export class LiveComponent implements OnInit {
   rid?: string;
   room?: Parse.Object;
   changeScreen: boolean = false; //大小屏切换
+  timer: any;//轮询获取频道token的定时
   constructor(
     public toastController: ToastController,
     private loadingCtrl: LoadingController,
@@ -31,10 +32,11 @@ export class LiveComponent implements OnInit {
     private alertController: AlertController,
     private http: HttpService,
     private liveService: LiveService
-  ) {}
+  ) {
+    this.liveService.initAgora()
+  }
 
   ngOnInit() {
-    this.liveService.initAgora();
     this.liveService.getDevices();
     this.activateRoute.paramMap.subscribe(async (params) => {
       let rid: any = params.get('rid');
@@ -58,7 +60,7 @@ export class LiveComponent implements OnInit {
     // this.profile = await queryProfile.first();
     if (this.room?.id) {
       await this.liveService.getToken(this.room);
-      this.liveService.join();
+      // this.liveService.join();
     } else {
       const alert = await this.alertController.create({
         header: '提示',

+ 3 - 0
projects/live-app/src/moduls/live/link-page/link-page.component.scss

@@ -104,6 +104,9 @@
           img{
             width: 50px;
             height: 50px;
+            background: white;
+            border-radius: 50%;
+            overflow: hidden;
           }
         }
         .action-icon{

+ 1 - 2
projects/live-app/src/moduls/live/link-page/link-page.component.ts

@@ -26,8 +26,6 @@ export class LinkPageComponent implements OnInit {
   room?: Parse.Object;
   isFollow: boolean = false;
   showTool: boolean = true; // 是否显示工具栏
-  // camera: boolean = false; //是否切换摄像头
-  // mute: boolean = false; //是否静音
   constructor(
     public toastController: ToastController,
     private loadingCtrl: LoadingController,
@@ -111,6 +109,7 @@ export class LinkPageComponent implements OnInit {
       case 'camera':
         break;
       case 'mute':
+        this.liveService.muteAudio();
         break;
     }
     // if (type == 'audio' || type == 'camera' || type == 'mute') {

+ 135 - 45
projects/live-app/src/services/live.service.ts

@@ -1,4 +1,5 @@
 import { Injectable } from '@angular/core';
+import { AlertController } from '@ionic/angular';
 import * as Parse from 'parse';
 import { AiChatService } from './aichart.service';
 import { HttpService } from './http.service';
@@ -22,31 +23,55 @@ export class LiveService {
     videoTrack: null,
   };
   rid?: string; //房间id(channel)
-  profile?:any = localStorage.getItem('profile');
+  profile?: any = localStorage.getItem('profile');
   client: any; //客户端
   company: string = '';
-  UID:any
+  UID: any;
   tools: any = {
-    audio:false, //是否关闭音频
+    audio: false, //是否关闭音频
     camera: false, //是否切换摄像头
     mute: false, //是否静音
   };
-  constructor(private http: HttpService, private aiServ: AiChatService) {
+  user_published_list = new Set(); //已发布列表
+  timer: any; //轮询获取频道token的定时
+  alert: any; //提示框
+  media_devices: {
+    //音视频设备列表
+    audioDevices: Array<any>;
+    videoDevices: Array<any>;
+  } = {
+    audioDevices: [],
+    videoDevices: [],
+  };
+  currentUsedDevice: { audioDevice: string; videoDevice: string } = {
+    //当前使用的设备
+    audioDevice: '',
+    videoDevice: '',
+  };
+  constructor(
+    private http: HttpService,
+    private aiServ: AiChatService,
+    private alertController: AlertController
+  ) {
     this.client?.leave();
     this.company = this.aiServ.company;
     this.getProfile();
   }
   async getProfile() {
-    if(this.profile) return
+    if (this.profile) return;
     let queryProfile = new Parse.Query('Profile');
     queryProfile.equalTo('user', Parse.User.current()?.id);
     queryProfile.notEqualTo('isDeleted', true);
     queryProfile.equalTo('isCross', true);
     let r = await queryProfile.first();
-    this.profile = r?.id
+    this.profile = r?.id;
   }
   /* 初始化Agora */
   initAgora() {
+    this.timer && clearTimeout(this.timer);
+    this.options['token'] = '';
+    this.options['channel'] = '';
+    this.client?.leave();
     this.client = AgoraRTC.createClient({ mode: 'rtc', codec: 'h264' });
     AgoraRTC.enableLogUpload();
   }
@@ -54,34 +79,45 @@ export class LiveService {
   getDevices() {
     AgoraRTC.getDevices()
       .then((devices: any) => {
-        const audioDevices = devices.filter(function (device: any) {
+        this.media_devices.audioDevices = devices.filter(function (
+          device: any
+        ) {
           return device.kind === 'audioinput';
         });
-        const videoDevices = devices.filter(function (device: any) {
+        this.media_devices.videoDevices = devices.filter(function (
+          device: any
+        ) {
           return device.kind === 'videoinput';
         });
-        let selectedMicrophoneId = audioDevices[0].deviceId;
-        let selectedCameraId = videoDevices[0].deviceId;
+        console.log(this.media_devices);
+        this.currentUsedDevice = {
+          audioDevice: this.media_devices.audioDevices[0].deviceId,
+          videoDevice: this.media_devices.videoDevices[0].deviceId,
+        };
         return Promise.all([
-          AgoraRTC.createCameraVideoTrack({ cameraId: selectedCameraId }),
-          AgoraRTC.createMicrophoneAudioTrack({
-            microphoneId: selectedMicrophoneId,
-          }),
+          AgoraRTC.createCameraVideoTrack(),
+          AgoraRTC.createMicrophoneAudioTrack(),
         ]);
       })
       .then((tracks: any) => {
-        console.log('createCameraVideoTrack', tracks);
+        console.log(tracks);
       })
       .catch((err: any) => {
-        console.log(err);
+        console.warn('获取媒体权限失败', err);
+        this.alertTips('获取媒体权限失败');
       });
   }
+
   async getToken(room: Parse.Object) {
+    this.timer && clearTimeout(this.timer);
     //获取频道token记录
     if (room?.get('profile').id == this.profile) {
-      this.UID = 111111
+      this.UID = 111111;
       let uid = Parse.User.current()?.id;
       if (!uid) {
+        this.timer = setTimeout(() => {
+          this.getToken(room);
+        }, 2000);
         return;
       }
       let baseurl = 'https://server.fmode.cn/api/webrtc/build_token';
@@ -95,14 +131,21 @@ export class LiveService {
       if (data.code == 200) {
         this.options.token = data.data.token;
         this.options.appid = data.data.appid;
-        this.options.channel = room?.get('profile').id
+        this.options.channel = room?.get('profile').id;
       }
     } else {
       let data = await this.updateToken(room?.get('profile').id);
+      console.log(data);
+      if (!data?.token) {
+        this.timer = setTimeout(() => {
+          this.getToken(room);
+        }, 2000);
+        return;
+      }
       this.options.token = data.token;
       this.options.channel = data.channel;
-      console.log(data);
     }
+    this.join();
   }
   /* 获取token */
   async updateToken(pid: string) {
@@ -121,9 +164,16 @@ export class LiveService {
   }
   // 进入频道
   async join() {
-    console.log('频道:',this.options.channel);
+    let path = location.pathname;
+    if (path.indexOf('/live/link-room/') == -1) return;
+    console.log('频道:', this.options.channel);
     let data = await Promise.all([
-      this.client.join(this.options.appid, this.options.channel, this.options.token, this.UID),
+      this.client.join(
+        this.options.appid,
+        this.options.channel,
+        this.options.token,
+        this.UID
+      ),
       /* 创建音频和视频轨道 */
       AgoraRTC.createMicrophoneAudioTrack(),
       AgoraRTC.createCameraVideoTrack(),
@@ -131,14 +181,15 @@ export class LiveService {
     // await this.client.setClientRole('host');
     this.localTracks.audioTrack = data[1];
     this.localTracks.videoTrack = data[2];
+    console.log(this.localTracks);
     let remoteEle = document.getElementById('vice-video');
     if (remoteEle) {
       remoteEle.textContent = '';
     }
     this.localTracks.videoTrack.play('vice-video'); //播放自己视频渲染
-    if(this.tools['audio']){
+    if (this.tools['audio']) {
       this.localTracks.audioTrack.setEnabled(false);
-    }else{
+    } else {
       this.localTracks.audioTrack.setEnabled(true);
     }
     await this.client.publish(Object.values(this.localTracks));
@@ -146,18 +197,19 @@ export class LiveService {
   }
   /* 订阅远程视频 */
   async joinReady() {
-    console.log(this.client.remoteUsers);
-    let wxRemoteUsers = this.client.remoteUsers.find((item: any) => {
-      if (item.uid && item._video_added_) {
-        return item;
-      }
-    });
-    console.log(wxRemoteUsers);
+    await Promise.all(
+      this.client.remoteUsers.map((item: any) => {
+        if (item.uid && item._video_added_ && item._videoTrack) {
+          console.log('已存在用户:', item);
+          this.client.subscribe(item);
+        }
+      })
+    );
     this.client.on('user-joined', (user: any) => {
       console.log(user, `${user.uid} 加入频道`);
     });
-    this.client.on('user-published', async (user: any, mediaType: any) => {
-      console.log('用户推流成功');
+    this.client.on('user-published', async (user: any, mediaType: string) => {
+      console.log('用户推流成功', user);
       // if (user.uid == 333333) {
       await this.client.subscribe(user, mediaType);
       // }
@@ -166,34 +218,72 @@ export class LiveService {
         remoteEle.textContent = '';
       }
       if (mediaType === 'video') {
-        user.videoTrack.play(`video`);
+        user.videoTrack.play('video');
+        this.alert?.dismiss();
       }
       if (mediaType === 'audio') {
         user.audioTrack.play();
+        this.user_published_list.add(user);
       }
     });
-    this.client.on('user-unpublished', (user: any) => {
-      let remoteEle = document.getElementById('video');
-      if (remoteEle) {
-        remoteEle.textContent = '对方离开直播间';
+    this.client.on('user-unpublished', async (user: any, mediaType: string) => {
+      if (mediaType === 'audio') {
+        console.log('对方已静音');
+        this.user_published_list.delete(user);
+      }
+      if (mediaType === 'video') {
+        console.log('用户取消推流');
+        let remoteEle = document.getElementById('video');
+        if (remoteEle) {
+          remoteEle.textContent = '对方离开直播间';
+        }
+        this.alertTips('对方已离开直播间');
       }
-      // if (user.uid == 333333) {
-      console.log('用户取消推流');
-      // }
     });
   }
   /* 停止音频推流 */
-  async updatePublishedAudioTrack(){
+  async updatePublishedAudioTrack() {
     this.tools['audio'] = !this.tools['audio'];
-    if(this.tools['audio'] && this.localTracks.audioTrack){
+    if (this.tools['audio'] && this.localTracks.audioTrack) {
       await this.localTracks.audioTrack.setEnabled(false);
       console.log('停止推送音频');
-    }else{
-      await this.localTracks.audioTrack.setEnabled(true)
+    } else {
+      await this.localTracks.audioTrack.setEnabled(true);
       console.log('恢复推送音频');
     }
     // await this.client.unpublish(this.localTracks.audioTrack);
-    return true
+    return true;
+  }
+  /* 静音 */
+  async muteAudio() {
+    this.tools['mute'] = !this.tools['mute'];
+    let list = Array.from(this.user_published_list);
+    for (let index = 0; index < list.length; index++) {
+      const user = list[index];
+      if (this.tools['mute']) {
+        console.log('静音');
+        await this.client.unsubscribe(user, 'audio');
+      } else {
+        await this.client.subscribe(user, 'audio');
+        console.log('恢复');
+      }
+    }
   }
 
+  async alertTips(message: string, title?: string, callBack?: Function) {
+    this.alert = await this.alertController.create({
+      header: title || '提示',
+      message: message,
+      buttons: [
+        {
+          text: '确认',
+          handler: () => {
+            console.log('Confirm Cancel: blah');
+            callBack && callBack();
+          },
+        },
+      ],
+    });
+    await this.alert.present();
+  }
 }