Przeglądaj źródła

新增美颜功能

warrior 2 tygodni temu
rodzic
commit
4bb4cb8bfc

+ 6 - 0
package-lock.json

@@ -30,6 +30,7 @@
         "@ionic/angular-toolkit": "^11.0.1",
         "@ionic/cordova-builders": "^12.1.2",
         "@ionic/core": "^8.4.0",
+        "agora-extension-beauty-effect": "^1.0.2-beta",
         "cordova-android": "13.0.0",
         "ionicons": "^7.4.0",
         "ngx-build-plus": "^18.0.0",
@@ -5169,6 +5170,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/agora-extension-beauty-effect": {
+      "version": "1.0.2-beta",
+      "resolved": "https://registry.npmmirror.com/agora-extension-beauty-effect/-/agora-extension-beauty-effect-1.0.2-beta.tgz",
+      "integrity": "sha512-nCEznllqgZiLmyzvUF4RxWdHXuFrVUWYlKhyl3ianvfF/9DY2551QQBuiRv6uPVsy4TEEWMwBX91EwxPX7v4Ig=="
+    },
     "node_modules/ajv": {
       "version": "8.17.1",
       "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",

+ 1 - 0
package.json

@@ -33,6 +33,7 @@
     "@ionic/angular-toolkit": "^11.0.1",
     "@ionic/cordova-builders": "^12.1.2",
     "@ionic/core": "^8.4.0",
+    "agora-extension-beauty-effect": "^1.0.2-beta",
     "cordova-android": "13.0.0",
     "ionicons": "^7.4.0",
     "ngx-build-plus": "^18.0.0",

+ 16 - 2
projects/live-app/src/modules/live/link-page/link-page.component.html

@@ -63,16 +63,30 @@
             </div>
             }
           </div>
-          @if (!liveService.isAnchor) {
+
           <div class="row">
+            <div class="row-li" (click)="onChangeLiveStatus($event, 'glorify')">
+              <div
+                [ngClass]="{
+                  'action-icon': liveService.tools['glorify'],
+                  'icon-box': true
+                }"
+              >
+                <ion-icon name="sparkles"></ion-icon>
+              </div>
+              <div class="label">
+                {{ liveService.tools["glorify"] ? "美颜已开启" : "美颜已关闭" }}
+              </div>
+            </div>
+            @if (!liveService.isAnchor) {
             <div class="row-li" (click)="onChangeLiveStatus($event, 'gift')">
               <div class="icon-box">
                 <ion-icon class="icon" name="gift"></ion-icon>
               </div>
               <div class="label">礼物</div>
             </div>
+            }
           </div>
-          }
           <div class="row">
             <div class="row-li" (click)="onChangeLiveStatus($event, 'camera')">
               <div

+ 14 - 11
projects/live-app/src/modules/live/link-page/link-page.component.ts

@@ -173,6 +173,9 @@ export class LinkPageComponent implements OnInit {
       case 'mute':
         this.liveService.muteAudio();
         break;
+      case 'glorify':
+        this.liveService.changeBeauty();
+        break;
       case 'gift':
         this.gift.openModal();
         break;
@@ -211,7 +214,7 @@ export class LinkPageComponent implements OnInit {
             console.log('Confirm Cancel: blah');
             this.onExit();
             if (!this.liveService.isAnchor) {
-              this.liveService.isOpenEvaluate = true
+              this.liveService.isOpenEvaluate = true;
               return;
             }
             // this.onComment();
@@ -313,7 +316,7 @@ export class LinkPageComponent implements OnInit {
           name: 'comment',
           placeholder: '评价',
           attributes: {
-            maxlength:20,
+            maxlength: 20,
           },
         },
         {
@@ -335,18 +338,18 @@ export class LinkPageComponent implements OnInit {
         {
           text: '评价',
           cssClass: 'secondary',
-          handler:async (data) => {
-            let {comment, star} = data;
+          handler: async (data) => {
+            let { comment, star } = data;
             const loading = await this.loadingCtrl.create({
               message: '加载中',
             });
             loading.present();
-            star = Math.round(star)
-            if(star < 1) star = 1;
-            if(star > 5) star = 5;
+            star = Math.round(star);
+            if (star < 1) star = 1;
+            if (star > 5) star = 5;
             console.log(comment, star);
             let obj = Parse.Object.extend('DramaPostLog');
-            let postLog = new obj()
+            let postLog = new obj();
             postLog.set('room', {
               __type: 'Pointer',
               className: 'Room',
@@ -362,9 +365,9 @@ export class LinkPageComponent implements OnInit {
               className: '_User',
               objectId: this.currentUser?.id,
             });
-            postLog.set('type', 'comment')
-            postLog.set('credit', star)
-            postLog.set('comment',comment)
+            postLog.set('type', 'comment');
+            postLog.set('credit', star);
+            postLog.set('comment', comment);
             await postLog.save();
             loading.dismiss();
             this.onExit();

+ 102 - 28
projects/live-app/src/services/live.service.ts

@@ -6,7 +6,7 @@ import { AiChatService } from './aichart.service';
 import { HttpService } from './http.service';
 import { MessageService } from './message.service';
 declare const AgoraRTC: any;
-
+import BeautyExtension from 'agora-extension-beauty-effect'; // 引入美颜扩展
 @Injectable({
   providedIn: 'root',
 })
@@ -33,9 +33,10 @@ export class LiveService {
   tools: any = {
     audio: false, //是否关闭音频
     camera: false, //是否切换摄像头
+    glorify: false, //是否开启美颜
     mute: false, //是否静音
   };
-  user_published_list = new Set(); //已发布列表
+  user_published_list: Array<any> = []; //已发布列表
   timer: any; //轮询获取频道token的定时
   alert: any; //提示框
   media_devices: {
@@ -59,7 +60,8 @@ export class LiveService {
   liveLog?: Parse.Object; //直播记录
 
   isOpenEvaluate: boolean = false; //是否开启评价
-
+  isBeautyExtensionRegistered: boolean = false; //是否注册美颜扩展
+  processor: any; //音视频处理
   constructor(
     private http: HttpService,
     private router: Router,
@@ -83,13 +85,30 @@ export class LiveService {
   }
   /* 初始化Agora */
   initAgora() {
+    this.tools = {
+      audio: false, //是否关闭音频
+      camera: false, //是否切换摄像头
+      glorify: false, //是否开启美颜
+      mute: false, //是否静音
+    };
     this.timer && clearTimeout(this.timer);
     this.timer_countdown && clearInterval(this.timer_countdown);
     this.options['token'] = '';
     this.options['channel'] = '';
+    this.user_published_list = [];
     this.client?.leave();
     this.client = AgoraRTC.createClient({ mode: 'rtc', codec: 'h264' });
     AgoraRTC.enableLogUpload();
+
+    if (!this.isBeautyExtensionRegistered) {
+      // 创建 BeautyExtension 实例
+      const extension: any = new BeautyExtension();
+      // 注册插件
+      AgoraRTC.registerExtensions([extension]);
+      // 创建 BeautyProcessor 实例
+      this.processor = extension.createProcessor();
+    }
+    this.setBeautyOptions();
   }
   // 获取所有音视频设备
   getDevices() {
@@ -226,6 +245,15 @@ export class LiveService {
       } else {
         this.localTracks.audioTrack.setEnabled(true);
       }
+
+      if (this.processor && this.localTracks.videoTrack) {
+        // 将插件注入 SDK 内的视频处理管道
+        this.localTracks.videoTrack
+          .pipe(this.processor)
+          .pipe(this.localTracks.videoTrack.processorDestination);
+        // 开启美颜
+        await this.processor.enable();
+      }
       await this.client.publish(Object.values(this.localTracks));
     } catch (err) {
       console.log('发布本地视频失败:', err);
@@ -234,12 +262,27 @@ export class LiveService {
       this.client.leave();
     }
   }
+  /* 设置各项美颜参数 */
+  async setBeautyOptions() {
+    this.processor.setOptions({
+      lighteningContrastLevel: 2, // 对比度
+      lighteningLevel: 0.8, // 亮度
+      smoothnessLevel: 0.8, // 平滑度
+      sharpnessLevel: 0.5, // 锐化程度
+      rednessLevel: 0.5, // 红润度
+    });
+    this.tools['glorify'] = true;
+  }
+
   /* 订阅远程视频 */
   async joinReady() {
     this.client.remoteUsers.forEach((user: any) => {
       console.log('remoteUsers', user.uid);
       this.client.subscribe(user, 'audio').then((audioTrack: any) => {
-        this.user_published_list.add(user);
+        // this.user_published_list.add(user);
+        if (!this.user_published_list.find((item) => item.uid === user.uid)) {
+          this.user_published_list.push(user);
+        }
         audioTrack.setVolume(100);
         audioTrack.play();
       });
@@ -267,28 +310,40 @@ export class LiveService {
       }
       if (mediaType === 'audio') {
         user.audioTrack.play();
-        this.user_published_list.add(user);
+        // this.user_published_list.add(user);
+        if (!this.user_published_list.find((item) => item.uid === user.uid)) {
+          this.user_published_list.push(user);
+        }
       }
     });
     this.client.on('user-unpublished', async (user: any, mediaType: string) => {
       if (mediaType === 'audio') {
         console.log('对方已静音');
-        this.user_published_list.delete(user);
+        // this.user_published_list.delete(user);
+        let idx = this.user_published_list.findIndex(
+          (item) => item.uid === user.uid
+        );
+        if (idx >= 0) {
+          this.user_published_list.splice(idx, 1);
+        }
       }
       if (mediaType === 'video') {
         console.log('用户取消推流');
-        let remoteEle = document.getElementById('video');
-        if (remoteEle) {
-          remoteEle.textContent = '对方离开直播间';
-        }
-        //主播离开,停止计时计费
-        // if (!this.isAnchor) {
-        this.client.leave();
+        // let remoteEle = document.getElementById('video');
+        // if (remoteEle) {
+        //   remoteEle.textContent = '对方已离开直播间';
         // }
-        // history.back()
-        this.alertTips('对方已离开直播间');
+        // // this.client.leave();
+        // this.alertTips('对方已离开直播间');
       }
     });
+    // 注册用户离开事件处理函数
+    this.client.on('user-left', (user: any) => {
+      console.log(`用户 ${user.uid} 离开了频道`);
+      //主播离开,停止计时计费
+      if (user.uid !== 100001) this.client.leave();
+      this.alertTips('对方已离开直播间');
+    });
     this.client.on(
       'connection-state-change',
       (curState: any, prevState: any) => {
@@ -306,8 +361,8 @@ export class LiveService {
             this.isOpenEvaluate = true;
           }
           console.log(this.router.url);
-          if(this.router.url.indexOf('/live/link-room/') == 0)
-          curState == 'DISCONNECTED' && history.back();
+          if (this.router.url.indexOf('/live/link-room/') == 0)
+            curState == 'DISCONNECTED' && history.back();
         }
         console.log('live状态变更:', this.connection_state);
       }
@@ -532,24 +587,43 @@ export class LiveService {
   /* 切换摄像头 */
   async changeCamera() {
     const oldCameras = await AgoraRTC.getCameras(true);
+    console.log('oldCameras:', oldCameras);
     let newCamers = oldCameras.find(
       (item: any) => item.deviceId !== this.currentUsedDevice.videoDevice
     );
     console.log(newCamers);
     newCamers &&
-      this.localTracks.videoTrack
-        .setDevice(newCamers.deviceId)
-        .then(() => {
-          this.tools['camera'] = !this.tools['camera'];
-          this.currentUsedDevice.videoDevice = newCamers.deviceId;
-        })
-        .catch((err: any) => {
-          console.log('set device error', err);
-          this.alertTips('切换摄像头失败');
-        });
+      (await this.localTracks.videoTrack.setDevice(newCamers.deviceId));
+    // .then(() => {
+    //   this.tools['camera'] = !this.tools['camera'];
+    //   this.currentUsedDevice.videoDevice = newCamers.deviceId;
+    // })
+    // .catch((err: any) => {
+    //   console.log('set device error', err);
+    //   this.tools['camera'] = !this.tools['camera'];
+    //   this.currentUsedDevice.videoDevice = newCamers.deviceId;
+    //   this.alertTips('切换摄像头失败');
+    // });
+    this.tools['camera'] = !this.tools['camera'];
+    this.currentUsedDevice.videoDevice = newCamers.deviceId;
     return true;
   }
-
+  /* 切换美颜 */
+  changeBeauty() {
+    if (!this.tools['glorify']) {
+      this.setBeautyOptions();
+    } else {
+      // 关闭美颜
+      this.processor.setOptions({
+        lighteningContrastLevel: 0,
+        lighteningLevel: 0,
+        smoothnessLevel: 0,
+        sharpnessLevel: 0,
+        rednessLevel: 0,
+      });
+      this.tools['glorify'] = false;
+    }
+  }
   /* 提示 */
   async alertTips(message: string, title?: string, callBack?: Function) {
     this.alert = await this.alertController.create({