首页 > 其他分享 >腾讯云实时音视频

腾讯云实时音视频

时间:2024-06-05 10:23:25浏览次数:24  
标签:console 腾讯 userId 实时 音视频 client error config TRTC

import { Injectable } from '@angular/core';
import { Observable, Subject, BehaviorSubject } from 'rxjs';
import { UserService } from './user.service';
declare var $: any;
declare var TRTC: any;

@Injectable({
    providedIn: 'root'
})
export class TrtcService {
    sdkAppId: number;
    userSig: string;
    cameras: Array<any> = [];
    microphones: Array<any> = [];
    cameraId: any;
    microphoneId: any;
    client: any = null;
    public isJoined: boolean = false;
    public IsInitDevice: boolean = false;
    public initDeviceMsg: string = "正在检测设备中,请稍后再试";
    config: TRTCConfig;

    constructor(private userService: UserService) {
        this.config = new TRTCConfig();
    }

    /*
     * 监听进房/退房的用户
     */
    socketSub: Subject<any> = new BehaviorSubject<any>(null);

    /*
     * 初始化配置
     */
    init() {
        this.initDevice();
    }

    /*
    * 生成用户签名
    */
    generateUserSig() {
        return new Promise((resolve, reject) => {
            var that = this;
            this.userService.getTrtcUserSig({ Id: this.config.userId, Remark: this.config.fkTb }).subscribe(result => {
                if (result.code == 100 && result.data) {
                    that.sdkAppId = result.data.SdkAppId;
                    that.userSig = result.data.UserSig;
                } else {
                    alert.bind('生成签名失败,请联系管理员');
                }
                resolve(true);
            });
        });

    }

    /*
     * 创建 Client 对象
     */
    async createClient() {
        if (this.client) {
            return;
        }
        try {
            this.client = TRTC.create();
            this.installEventHandlers();
            console.log(`Client [${this.config.userId}] created.`);
        } catch (e) {
            alert(`Failed to create Client [${this.config.userId}].`);
        }
    }


    /*
     * 进房
     */
    async join() {
        if (this.isJoined) {
            console.warn(`has been joined ${this.config.userId}`);
            return;
        }
        if (this.client == null) {
            await this.createClient();
        }
        if (!this.userSig) {
            await this.generateUserSig();
            if (!this.userSig) {
                alert.bind('生成签名失败,请联系管理员');
                return;
            }
        }
        try {
            await this.client.enterRoom({
                strRoomId: this.config.roomId,
                sdkAppId: this.sdkAppId,
                userId: this.config.userId,
                userSig: this.userSig
            });
            this.isJoined = true;
            if (this.config.video) this.setLocalVideo(true);
            if (this.config.audio) this.setLocalAudio(true);
        } catch (e) {
            console.error(`Join room ${this.config.roomId} failed, please check your params. Error: ${e.message}`);
            this.reportTrtcflow('Join room failed, please check your params. Error:', '2joinRoom', e);
        }
    }

    /*
     * 退房
     */
    async leave() {
        if (!this.isJoined) {
            console.warn('leave() - please join() firstly');
            return;
        }
        try {
            await this.client.exitRoom();
            this.isJoined = false;
            if (this.config.video) this.setLocalVideo(false);
            if (this.config.audio) this.setLocalAudio(false);
        } catch (error) {
            console.error(`Leave room failed. Error: ${error.message_}`);
            this.reportTrtcflow('leaveRoom:', '5leaveRoom', error);
        }
    }

    /*
    * 监听事件
    * https://web.sdk.qcloud.com/trtc/webrtc/v5/doc/zh-cn/module-EVENT.html
    */
    installEventHandlers() {
        this.client.on(TRTC.EVENT.KICKED_OUT, this.handleKickedOut.bind(this));
        this.client.on(TRTC.EVENT.REMOTE_USER_ENTER, this.handleRemoteUserEnter.bind(this));
        this.client.on(TRTC.EVENT.REMOTE_USER_EXIT, this.handleRemoteUserExit.bind(this));
        this.client.on(TRTC.EVENT.REMOTE_VIDEO_AVAILABLE, this.handleRemoteVideoAvailable.bind(this));
        this.client.on(TRTC.EVENT.REMOTE_VIDEO_UNAVAILABLE, this.handleRemoteVideoUnavailable.bind(this));
        this.client.on(TRTC.EVENT.REMOTE_AUDIO_AVAILABLE, this.handleRemoteAudioAvailable.bind(this));
        this.client.on(TRTC.EVENT.REMOTE_AUDIO_UNAVAILABLE, this.handleRemoteAudioUnavailable.bind(this));
        this.client.on(TRTC.EVENT.SCREEN_SHARE_STOPPED, this.handleScreenShareStopped.bind(this));
    }

    uninstallEventHandlers(offAll: boolean = false) {
        if (offAll) {
            this.client.off('*');
        } else {
            this.client.off(TRTC.EVENT.KICKED_OUT, this.handleKickedOut.bind(this));
            this.client.off(TRTC.EVENT.REMOTE_USER_ENTER, this.handleRemoteUserEnter.bind(this));
            this.client.off(TRTC.EVENT.REMOTE_USER_EXIT, this.handleRemoteUserExit.bind(this));
            this.client.off(TRTC.EVENT.REMOTE_VIDEO_AVAILABLE, this.handleRemoteVideoAvailable.bind(this));
            this.client.off(TRTC.EVENT.REMOTE_VIDEO_UNAVAILABLE, this.handleRemoteVideoUnavailable.bind(this));
            this.client.off(TRTC.EVENT.REMOTE_AUDIO_AVAILABLE, this.handleRemoteAudioAvailable.bind(this));
            this.client.off(TRTC.EVENT.REMOTE_AUDIO_UNAVAILABLE, this.handleRemoteAudioUnavailable.bind(this));
            this.client.off(TRTC.EVENT.SCREEN_SHARE_STOPPED, this.handleScreenShareStopped.bind(this));
        }
    }

    handleKickedOut(event) {
        const { userId } = event;
        this.socketSub.next({ Id: this.config.userId, IsJoined: false });
        console.log('KickedOut ' + userId);
    }

    handleRemoteUserEnter(event) {
        const { userId } = event;
        this.socketSub.next({ Id: userId, IsJoined: true });
        console.log("handleRemoteUserEnter " + event);
    }

    handleRemoteUserExit(event) {
        const { userId } = event;
        this.socketSub.next({ Id: userId, IsJoined: false });
        console.log('UserExit ' + userId);
    }

    handleRemoteVideoAvailable(event) {
        var that = this;
        const { userId, streamType } = event;
        if (that.config.subscribeUser.length == 0 || that.config.subscribeUser.indexOf(userId) > -1) {
            setTimeout(function () {
                that.setRemoteVideo(userId, true, streamType);
                console.log('RemoteVideoAvailable ' + userId);
            }, 10);
        }
    }

    handleRemoteVideoUnavailable(event) {
        const { userId, streamType } = event;
        this.setRemoteVideo(userId, false, streamType);
        console.log('RemoteVideoUnavailable ' + userId);
    }

    handleRemoteAudioUnavailable(event) {
        
    }

    handleRemoteAudioAvailable(event) {
       
    }

    handleScreenShareStopped() {
       
    }

    /*
    * 设置本地音频(开/关)
    * https://web.sdk.qcloud.com/trtc/webrtc/v5/doc/zh-cn/tutorial-15-basic-dynamic-add-video.html
    */
    setLocalAudio(mute: boolean = true) {
        if (mute) {
            this.client.startLocalAudio();
        } else {
            this.client.stopLocalAudio();
        }
    }

    /*
     * 设置本地视频(开/关)
     */
    setLocalVideo(mute: boolean = true) {
        if (mute) {
            this.client.startLocalVideo({ view: `video-${this.config.userId}`});
        } else {
            this.client.stopLocalVideo();
        }
    }

    /*
     * 设置本地视频流编码,120p为小流
     * @param isSmall 表示是否拉取小流
     */
    setLocalVideoProfile(profile: number = 120) {
        if (profile == 120) {
            this.client.updateLocalVideo({ option: { small: `${profile}p` } });
        } else {
            this.client.updateLocalVideo({ option: { small: false, profile: `${profile}p` } });
        }
    }

    /*
     * 设置远端视频(开/关)
     */
    setRemoteVideo(userId: string, mute: boolean = true, streamType: string = "main") {
        if (mute) {
            this.client.startRemoteVideo({ userId, streamType, view: `video-${userId}`, option: { small: this.config.remoteVideoSmall } });
        } else {
            this.client.stopRemoteVideo({ userId, streamType });
        }
    }

    /*
     * 静音远端用户
     * @param userId 用户ID,*表示所有用户
     * @param mute 表示是否静音
     */
    muteRemoteAudio(userId: string, mute: boolean) {
        this.client.muteRemoteAudio(userId, mute);
    }

    /*
     * 设置远端用户音量
     * @param userId 用户ID,*表示所有用户
     * @param volume 音量大小,取值范围为0 - 100,默认值为 100
     */
    setRemoteAudioVolume(userId: string, volume: number) {
        this.client.setRemoteAudioVolume(userId, volume);
    }

    /*
     * 动态开关远端视频小流
     * @param userId 用户ID,*表示所有用户
     * @param isSmall 表示是否拉取小流
     */
    smallRemoteVideo(userId: string, isSmall: boolean = false) {
        this.client.updateRemoteVideo({ userId, streamType: "main", option: { small: isSmall } });
    }

    /*
     * 检查设备
     */
    async initDevice() {
        try {
            let that = this;
            await navigator.mediaDevices.getUserMedia({
                audio: this.config.audio,
                video: this.config.video
            }).then(function (stream) {
                stream.getTracks().forEach(track => track.stop());
                that.reportTrtcflow('', '0initDevice', null);
            });
            this.IsInitDevice = true;
            console.log("检查设备完成");

        } catch (err) {
            this.IsInitDevice = false;
            console.error(`${err.name}: ${err.message}`);
            switch (err.name) {
                case "NotFoundError":
                case "DevicesNotFoundError":
                    this.initDeviceMsg = "未找到麦克风或摄像头,无法开启视频会议。";
                    break;
                case "NotReadableError":
                case "TrackStartError":
                    this.initDeviceMsg = "麦克风和摄像头被使用,开启视频将会失败。";
                    break;
                case "OverconstrainedError":
                case "ConstraintNotSatisfiedErrror":
                    this.initDeviceMsg = "获取麦克风或摄像头失败,请联系系统管理员。";
                    break;
                case "NotAllowedError":
                case "PermissionDeniedError":
                    this.initDeviceMsg = "如果不允许当前页面访问麦克风和摄像头权限,您在发布本地流的时候可能会失败。";
                    break;
                default:
                    this.initDeviceMsg = "如果不允许当前页面访问麦克风和摄像头权限,您在发布本地流的时候可能会失败。";
                    break;
            }
            confirm.bind(this.initDeviceMsg);
            this.reportTrtcflow(`摄像头或麦克风权限出错. Error: `, '0initDevice', err);
        }
    }

    /*
     * 更新设备
     */
    async updateDevice() {
        try {
            const updateDevice = async () => {
                this.cameras = await TRTC.getCameraList();
                this.microphones = await TRTC.getMicrophoneList();
                console.log("cameras", this.cameras);
                console.log("microphones", this.microphones);
            }
            await updateDevice();
            // 设备更新
            navigator.mediaDevices.addEventListener('devicechange', async () => {
                await updateDevice();
            });
        } catch (e) {
            console.error('get device failed', e);
        }
    }

    /*
     * 切换视频设备
     */
    async switchDeviceVideo(videoId) {
        if (videoId) {
            try {
                await this.client.updateLocalVideo({ option: { cameraId: videoId } });
                console.log('Switch video device success');
            } catch (error) {
                console.error('switchDevice failed', error);
            }
        }
    }

    /*
     * 切换音频设备
     */
    async switchDeviceAudio(audioId) {
        if (audioId) {
            try {
                await this.client.updateLocalAudio({ option: { microphoneId: audioId } });
                console.log('Switch audio device success');
            } catch (error) {
                console.error('switchDevice failed', error);
            }
        }
    }

    /**
     * 上报事件到自己的日志平台,如果是正式发布
     * @param msg
     * @param mode 类型:初始化本地语音流、视频流等等
     */
    reportTrtcflow(msg: string, mode: string, error: any) {
        if (mode && mode.length) {
            let errmsg = '';
            if (error) {
                errmsg = error.message_ ? error.message_ : error.message;
            }
            let errcode = '';
            if (error) {
                if (error.getCode) {
                    errcode = error.getCode();
                }
            }
            let name = '';
            if (error) {
                if (error.name) {
                    name = error.name;
                }
            }
            let fixedRoom = '';
            if (this.config) {
                fixedRoom = `${this.config.roomId}::${this.config.userId}`;
            }
            let data = `${fixedRoom}::${mode}::${msg} ${errmsg} :: ${errcode} :: ${name}`;
            this.userService.addReportTrtc({ NotTitle: data });
        }
    }
}

@Injectable({
    providedIn: 'root'
})
export class TRTCConfig {
    userId: string;//用户id(必填)
    roomId: string;//房间号(必填)
    audio: boolean = true;// true 表示开启语音
    video: boolean = true;// true 表示开启视频
    isSubscribe: boolean = true;// true 表示订阅远端视频流
    subscribeUser: Array<any> = [];//为空表示订阅全部,有值表示订阅指定部分
    remoteVideoSmall: boolean = true;//拉流端选择拉大流或小流 true 表示拉小流,false 表示拉大流
    fkTb: string = "notice";//验证
}

 

标签:console,腾讯,userId,实时,音视频,client,error,config,TRTC
From: https://www.cnblogs.com/xm123/p/18232434

相关文章

  • 低代码智能通信:腾讯云短信助力,快速构建高效消息应用
    前言​ 随着信息技术的飞速发展,现代社会对信息传达的及时性、准确性与便捷性要求越来越高。尤其在移动互联网时代,用户对于服务的体验要求不断提升,这促使各类网站、APP、小程序等服务平台必须持续优化其交互方式,以满足用户日益增长的需求。​ 在此背景下,短信作为一种成熟、稳定且......
  • 基于腾讯元器搭建前端小助手
    #前言在当今智能技术蓬勃发展的时代,开发一个属于自己的专属机器人已经变得非常容易。在本文中,我们将探讨如何通过腾讯元器来构建一个前端助手智能体,以帮助我们解决前端开发过程中的问题。通过一个简单的示例,我们将模拟我们在遇到问题时如何寻找解决方案的过程。前端助手前端助......
  • Mysql实时数据监听高可用
    一、需求:数据实时监听在项目中有着重要的意义,例如某些项目需要监听数据库的变化,生成对应的元数据块,这个数据块为前端接口提供数据支撑或者数据计算使用,监听到某些数据的变化,及时提醒上游或下游服务等等。如何保证数据监听的高可用?本文用自身项目结构简易阐述,不喜勿喷。二、......
  • 实时分析用户反馈:淘宝商品评论API助力电商创新
    淘宝商品评论API在助力电商创新,特别是在实时分析用户反馈方面,发挥着重要作用。以下是关于淘宝商品评论API如何支持电商创新的详细解析:一、淘宝商品评论API概述淘宝商品评论API是淘宝开放平台提供的一种数据接口服务,允许开发者通过编程方式获取淘宝平台上的商品评论信息。这些......
  • 梵几 x TapData:如何高效落地实时数据中台,助力家居企业优化数字营销
    使用TapData,化繁为简,摆脱手动搭建、维护数据管道的诸多烦扰,轻量代替OGG、DSG等同步工具,「CDC+流处理+数据集成」组合拳,加速数据流转,帮助企业将真正具有业务价值的数据作用到实处,将“实时数仓”等实时的中央化数据存储方法论落进现实。TapData持续迭代产品能力,优化用户体......
  • flink sql 实时同步及离线同步
    createdatabasetest;usetest;离线数据源接入CREATETABLEttab_source(idINT,namevarchar(100),PRIMARYKEY(id)NOTENFORCED)WITH('connector'='jdbc','url'='jdbc:sqlserver://xx.xx.40.186:1433;DatabaseName=test&......
  • 韩国指数实时API接口
    韩国指数实时API接口#RestfulAPIhttps://tsanghi.com/api/fin/index/KOR/realtime?token={token}&ticker={ticker}指定指数代码,获取该指数的实时行情(开、高、低、收、量)。更新周期:实时。请求方式:GET。#测试https://tsanghi.com/api/fin/index/KOR/realtime?......
  • 淘宝商品评论数据接口(Taobao.item_review)丨淘宝实时API接口指南
    淘宝商品评论数据接口(Taobao.item_review)是淘宝开放平台提供的一个API,用于获取商品的评论信息。该接口对于商家分析商品反馈、顾客满意度以及进行市场研究具有重要意义。下面将介绍如何高效利用这一接口:一、注册和获取权限注册开发者账号:在淘宝开放平台注册一个开发者账号,......
  • 印度指数实时API接口
    印度指数实时API接口#RestfulAPIhttps://tsanghi.com/api/fin/index/IND/realtime?token={token}&ticker={ticker}指定指数代码,获取该指数的实时行情(开、高、低、收、量)。更新周期:实时。请求方式:GET。#测试https://tsanghi.com/api/fin/index/IND/realtime?......
  • 天猫商品评论数据接口(Tmall.item_review)丨天猫实时API接口指南
    天猫商品评论数据接口(Tmall.item_review)是一个强大的工具,它允许开发者通过编程方式获取天猫平台上商品的评论数据。这些数据通常包括评论内容、评价时间、评价等级等信息,对于商家来说,这些信息是非常宝贵的,因为它们可以帮助商家更好地了解客户需求和市场趋势,为商品营销和品质改......