# FAQ
# 登录失败(通用)
# 问题现象
登录接口调用失败
# 定位步骤
正常情况下,考虑到用户使用场景,应该从网络情况、是否有内外网限制、是否参数正确、是否多传参数或者少传参数等等方面进行排查。
# 问题排查
- 检查网络是否正常;
- 是否是外网直接访问内网地址,需要修改地址;
- 检查每个参数是否正确:中英文、大小写、参数内容、参数类型。
- 检查每个参数的含义,是否多传参数或者少传参数,如不支持国密传国密或导致失败。
- 实在排查不出请联系我们。
# 登出崩溃(通用)
# 问题现象
挂断后登出崩溃或者偶发登出崩溃。
# 定位步骤
登出功能正常运行一般不会出问题,排查方向可定为使用场景、环境。
# 问题排查
是否子线程,只能主线程登出,移动端建议在UI主线程,JavaSwing PC端建议在 UI 线程。
# SDK非主线程调用失败(通用)
# 问题现象
在非主线程中调用SDK方法失败或者导致其他问题。
# 定位步骤
一般情景SDK方法可以正常运行,在子线程中可能会导致出现不可知问题。
# 问题排查
是否子线程,只能主线程使用,,移动端建议在UI主线程,JavaSwing PC端建议在 UI 线程。
# 挂断后仍然无法正常结束通话(通用)
# 问题现象
成员1离开通话后,成员2仍然能看到成员1卡住的画面。此种情况大多数都是由于成员1异常离开导致的
# 定位步骤
正常情况下,成员1离开通话,服务端能立刻知道成员1离开。
异常离开通话后,成员1无法立刻通知服务端,这时服务端会等待成员1的心跳响应,1分钟(默认1分钟超时)后如果没有收到心跳回应,服务端会将成员1踢出通话。
# 问题排查
- 成员1没有调用term挂断
- 成员1先调用logout登出,然后调用term挂断
- 用户1直接杀进程离开会议(此种情况不可避免)
# 通话听不到声音或看不到画面,无法访问媒体设备(通用)
# 问题现象
双方通话过程中,自己说话对方听不到声音或看不到画面
# 定位步骤
一般移动端设备考虑被占用或者未授予权限,异常不能使用情况基本不考虑
# 问题排查
# 未开启麦克风/相机权限
- iOS
进入手机设置,查看对应的应用是否开启权限。
- Android
进入手机设置-应用-应用管理-权限,查看对应的应用是否开启权限。
- Windows
麦克风:设置->隐私->麦克风->打开麦克风权限,同时允许本应用访问麦克风。
摄像头:设置->隐私->相机->打开相机权限,同时允许本应用访问相机。
# 麦克风/相机被占用或设备异常
麦克风后打开的应用都会抢占之前打开的应用,一般系统都会提示麦克风占用
摄像头后打开的应用都会抢占之前打开的应用,一般系统都会提示摄像头占用
# 视频画面出现黑边(通用)
# 问题现象
视频预览有黑边
# 定位步骤
渲染视频接口是否全屏幕渲染还是全内容渲染。
# 问题排查
当实际视频尺寸和显示视图宽高比不同时,如果是全内容渲染,那么就会留有黑边,如果是全屏幕渲染,会将画面等比例放大缩小充满显示区域,超出部分被裁剪,首先确认本端实际采集视频大小(本地预览),对端实际发送视频(预览对方)的视频宽高比和显示区域宽高比是否相同。
通话中可以通过设置本地宽高比修改发送的视频宽高比, setRatio 方法。
# 视频旋转(通用)
# 问题现象
使用过程中竖屏横屏切换,会导致视频画面方向转动。
# 定位步骤
视频方向是有转动功能的,排查方向放在设置转动上。
# 问题排查
SDK 中 JRTCMediaDevice 模块的 setVideoAngle 接口是否设置为自动模式(默认自动,可设置0,90,180,270),可以通过设置该接口适时修改画面方向或者固定画面方向。
# 音频被打断导致访客无声音画面
# 问题现象
通话中被其他音视频软件打断通话,
# 定位步骤
之前正常抢占之后无声音无画面定位需要看上报的问题
# 问题排查
上层在JRTCMediaDeviceCallBack的onVideoError接口去打开摄像头,代码如下:
@Override
public void onVideoError(@VideoErrorType int errorType, String errorDetail) {
if (errorType == JRTCMediaDevice.VIDEO_ERROR_CAMERA) {
//摄像头异常,sdk内部会去自动关闭摄像头,如果有需要可以在这里重新打开,但是避免死循环打开
//可以重拾一次还是不行提示客户
mediaDevice.startCamera();
}
}
# iOS进入后台后音频暂停或回到前台后未继续播放
# 问题现象
iOS App 进入后台后,音频暂停;或再次回到前台时,音频没有继续播放。
# 定位步骤
优先检查 App 是否已开启 iOS 后台音频能力。
# 问题排查
在 Xcode 中打开 App Target,进入 Signing & Capabilities,检查 Background Modes 是否已勾选 Audio, AirPlay, and Picture in Picture。
如果未勾选,App 进入后台后系统可能会暂停音频会话,导致回到前台时音频无法按预期继续播放。开启后重新打包验证。
# 移动端坐席收到来电后无法接起
# 问题现象
集成方同时初始化坐席和访客模块,收到来电后,访客模块也收到了来电邀请,向排队机回了responseCancelInvite。
# 定位步骤
取消同时初始化进行定位
# 问题排查
只能初始化一个模块
# 播放音乐无声音(通用)
# 问题现象
使用SDK startRing播放等待铃声没有声音
# 定位步骤
需要确定使用的是本地播放还是通话内播放
# 问题排查
本地播放接口和通话内播放接口和逻辑不同,需要分别实现startRing本地播放、enableAudioInputFromFile通话内播放
# 小米9崩溃
# 问题现象
集成完毕但运行崩溃在小米9
# 定位步骤
集成完毕运行崩溃首先检查混淆,部分手机运行崩溃检查运行环境手机内核。
# 问题排查
使用v7a文件夹的so放armabi里去
# 虚拟背景墙崩溃(Windows&UOS)
# 问题现象
设置,使用虚拟背景墙崩溃。
# 定位步骤
从加载、资源、外界环境去定位
# 问题排查
- 选择虚拟背景墙后,界面提示5秒,首次加载慢,请耐心等待,首次时间较长。
- 图片分辨率超过3840*2160提示图片太大
# 访客看不到坐席画面(H5/WEB)
# 问题现象
H5界面自动播放失败
# 定位步骤
代码逻辑正常的情况下需要定位WebView、权限等限制问题。
# 问题排查
浏览器(WebView)安全性要求用户与界面有交互才允许自动播放(保护用户隐私,必须用户手动确认播放才允许播放视频/音频),有些浏览器会认为设备授权(摄像头、麦克风)行为是一次UI交互,WebView行为不确定。另外,目前H5端这方面的策略越来越严格,自动播放受限越来越严格。页面增加自动播放异常处理,弹窗交互确认,在确认按钮下增加play()接口调用
# 移动端坐席收到来电后无法接起(Android/IOS/Web)
# 问题现象
集成方同时初始化坐席和访客模块,收到来电后,访客模块也收到了来电邀请,向排队机回了responseCancelInvite。
# 定位步骤
取消同时初始化进行定位
# 问题排查
只能初始化一个模块
# PC插件的浏览器的要求及常见问题(Windows&UOS)
# 问题现象
IE11无法与坐席插件通讯
# 定位步骤
安全设置、浏览器是否能启动程序、是否能连接插件,多浏览器对比检测进行定位
# 问题排查
IE11无法与坐席插件通讯,远程地址加入IE白名单,IE安全级别设置为中/低
# 屏幕共享频繁闪现黑屏(Windwos&UOS)
# 问题现象
如题屏幕共享频繁闪现黑屏
# 定位步骤
在上层代码没问题的情况下检查集成和驱动。
# 问题排查
坐席显卡驱动未更新
# 屏幕共享闪退(IOS)
# 问题现象
ios使用屏幕共享功能应用闪退,screencapture start capture error: 录制因多任务和调整内容大小而中断
# 定位步骤
上层代码没问题的情况下,检查硬件条件、系统版本
# 问题排查
- 限制系统ios13以下不允许屏幕共享
- 使用应用外屏幕共享
参考链接: http://www.bubuko.com/infodetail-3801263.html
# 访客插件销毁后拉不起来(Windows&UOS)
# 问题现象
- java方式第一次拉起后 销毁 就再也拉不起来
- 如果不在他们业务里java同步骤1操作正常拉起。
- 网页版测试正常,若java拉不起,用网页同样拉不起,包检查失败,请重新检查
# 定位步骤
启动不了首先检查初始化相关功能
# 问题排查
- websocket 没有建立连接成功 初始化所以失败;
- websocket连接成功onOpen回调后再去初始化。
# 访客蓝牙接通时会被外放(IOS)
# 问题现象
蓝牙接通但是没有起到作用
# 定位步骤
查看应用界面逻辑
# 问题排查
- 视频建立前已经连接蓝牙,需要界面监听扬声器、蓝牙、耳机改变通知;然后再选择是否调用enableSpeak开启扬声器
- 视频建立后且已经开启扬声器,这时候连接蓝牙、耳机。系统会默认切换到蓝牙、耳机
# 多方通话加入失败(Windows&UOS)
# 问题现象
如题加入失败。
# 定位步骤
从代码集成,基础配置入手,没问题可以查看licence并发数是否超过上限。
# 问题排查
- 代码集成是否出问题,对照Sample;
- 配置是否出问题,对照文档;
- 增加licence并发数
# 录制CD异常问题(Windows&UOS)
# 问题现象
会议中停止录制服务,终端提示录制结束,视频会议也没有了,但是再次去加入会议,提示还在会议中
# 定位步骤
最后通话的录制异常回调里的isshutdown值为什么,发现无论isshutdown是否为ture,都是去关闭了通话窗口并弹出录制结束提示
# 问题排查
更新JMDS版本
# mvtm本地视频不显示(Windows&UOS)
# 问题现象
mvtm显示不出本地视频画面
# 定位步骤
上层代码没问题的情况下,检查运行条件
# 问题排查
内存不足
# 端口占用(Windows&UOS)
# 问题现象
启动应用提示端口占用
# 定位步骤
上次是否关闭,有无其他应用占用
# 问题排查
- 先关闭上次使用;
- 通过进程/任务管理器关闭相应端口应用。
- 重启计算机。
# 录制相关问题(Windows&UOS)
# 问题现象
- 本地录制视频失败。
- 录制文件被切割等配置问题。
# 定位步骤
需要明白服务器录制、本地录制中的会议内录制和会议外录制,还有相关的录制配置。
# 问题排查
- 本地录制生成录制文件失败,客户以看在传filePath时,确保路径已经生成,确保路径填写正确。
- 服务器录制是发起者的呼叫参数来控制开关:
访客呼叫参数JRTCallCenterCallParam.autoRecord;
座席回呼参数JRTCallCenterCallParam.autoRecord;
房间参数JRTCRoomJoinParam.enableRemoteRecord
视频客服中当发起者入会参数关闭了远程自动录制时,可通过调用enableRemoteRecord()接口控制远程录制开关和配置,多方中获取录制状态后即可通过该接口实现具体需要的配置,配置如下:
recordVideo 设置录制是否包含视频,false的时候服务器为录音文件aac
frameRate 设置录制帧率
mergeMode 媒体录制视频合并模式
intelligentMergeMode 设置 mergeMode 为智能分屏模式下的布局样式(无屏幕共享)
scsMergeMode 设置 mergeMode 为智能分屏模式下的布局样式(有屏幕共享)
videoWidth 设置录制视频的宽度
videoHeight 设置录制视频的高度
iBitrate 设置录制码率
extraInfo 设置录制自定义随路参数, json格式
watermarkTextMap 设置水印串
layoutType 设置录制样式,对应业务管理平台上配置的录制样式的名字, 不传则用默认
List<RecordLayout> 设置录制成员布局列表,自定义布局需要
protocol 设置录制文件存储环境 aws qiniu ftp等
uploadEndpoint 设置接入地址,ftp模式下例:ftp://127.0.0.1:21
accessKey 设置存储环境相关key, ftp模式传ftp服务器登录名
secretKey 设置存储环境相关key, ftp模式传ftp服务器登录密码
bucketName 设置桶名,存储环境相关key
fileName 存储文件名, ftp模式下可以带路径如:juphoon/1.mp4;视频文件录制后缀为mp4,如xx.mp4
音频文件录制后缀为aac,如xx.aac
splitFileSize 分割文件大小,单位为 kb
- 本地录制会议外录制JRTCMediaDevice.startVideoCaptureRecord(),会议外录制是指不加入会也可录制的本地录制,相应的又停止录制的方法stopVideoCaptureRecord,录制配置如下:
filePath 保存的文件路径,必须包含文件名(xxx.mp4或者xxx.avi)
streamId 视频流ID, (包括摄像头ID、文件视频源ID、屏幕ID等)
audioSource 录制文件音频源
fileType 录制文件编码封装类型
width 录制文件宽(传-1则默认屏幕共享采集属性的宽)
height 录制文件高(传-1则默认屏幕共享采集属性的高)
- 本地录制会议内录制JRTCRoom.enableLocalRecord();会议内录制是指加入会才也可录制的本地录制,JRTCRecordLocalParam录制配置如下:
frameRate 设置录制帧率, 默认18
mergeMode 设置媒体录制视频合并模式,默认智能分屏模式
intelligentMergeMode 设置 mergeMode 为智能分屏模式下的布局样式(无屏幕共享)
scsMergeMode 设置 mergeMode 为智能分屏模式下的布局样式(有屏幕共享)
videoWidth 设置录制视频的宽度
videoHeight 设置录制视频的高度
iBitrate 设置录制码率
filePath 设置保存的文件路径,必须包含文件名;音频文件录制后缀为mp4,如xx.mp4
音频文件录制后缀为aac,如xx.aac
recVideo 设置是否录制视频,默认true
recAudio 设置是否录制音频,默认true
includeSelf 设置录制是否包含自己,默认true
watermarkTextMap 设置录制视频水印串
configFilePath 设置录制配置文件路径 例如: xxx\record.cfg
List<RecordLayout> 设置录制成员布局列表,mergeMode 为自定义布局需要
- 如果配置出问题,检查无误后可咨询是否有新版本。
注:详细介绍请看相关接口的开发文档。
# 音频占用问题(iOS)
# 问题现象
- 收到部分三方App来电(微信来电),通话音频被中断,用户拒接或者结束通话导致音频无法恢复。
# 定位步骤
- app通话过程中,收到微信来电振铃声音较大,音频被中断然后拒绝微信电话,app声音无法恢复
- IOS 16.3系统,微信8.0.34版本
- 微信通知功能已经开启,且iPhone处于非静音模式
- 收到微信来电振铃时微信使用的是独占模式,会把app的声音采集中断,挂断后没有收到系统的中断结束通知,导致app语音无法恢复。
# 问题排查
- 收到音频被中断的通知后,判断是否收到系统来电,如果不是系统来电引发的中断,需要App层弹窗让用户选择是否恢复通话;
- 示例代码:
#import <JRTCSDK/JRTCSDK.h>
#import <JRTCSDK/JRTCSystemPhone.h>
@interface JRTCManager () <JRTCClientCallback, JRTCMediaDeviceCallback, JRTCSystemPhoneCallback> {
BOOL _systemCall; //记录是否系统来电
}
//实现接口
@end
@property (nonatomic, strong) JRTCClient* client;
@property (nonatomic, strong) JRTCMediaDevice* mediaDevice;
@implementation JRTCManager
-(void)init {
//初始化client
_client = [JRTCClient create:self initParam:nil];
//初始化_mediaDevice
_mediaDevice = [JRTCMediaDevice create:_client callback:self initParam:nil];
//设置系统通话监听,也可以上层自行使用系统api监听系统通话
[JRTCSystemPhone.shared addCallback: self];
}
//监听系统通话
- (void)onSystemPhoneStateChanged:(SystemPhoneState)newState oldState:(SystemPhoneState)oldState {
switch (newState) {
case SystemPhoneStateRing: //系统来电
case SystemPhoneStateOffhook: //系统通话建立/系统电话呼出
_systemCall = YES;
break;
case SystemPhoneStateIdle: //空闲
default:
_systemCall = NO;
break;
}
}
//监听音频中断恢复通知
- (void)onAudioInerruptAndResume:(bool)interrupt {
if (interrupt) { //音频中断
if (_systemCall) {
//收到系统来电,系统通话结束音频可自行恢复,不需要做处理
} else {
//收到三方App来电,部分通话软件通话结束后导致无法恢复音频
//可以在这里弹框通知用户是否恢复音频
//如果用户选择恢复,重新打开音频设备
[self restartAudio];
}
} else {
//音频恢复
}
}
//重新打开音频设备
- (void)restartAudio {
[_mediaDevice stopAudio]; //关闭音频设备
//设置全局音频模式
NSError *error = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error: &error];
[audioSession setActive:NO error: &error];
[_mediaDevice startAudio];//打开音频设备
}
@end
# 系统摄像头占用问题(Android)
# 问题现象
- 部分手机视频通话过程中被抢占摄像头,无法收到SDK的onVideoError通知。
# 定位步骤
- 部分手机摄像头被占用无法收到异常通知。
# 问题排查
- 渲染摄像头视图所在页面监听前后台切换,并记录当前前后台状态;
- 当页面在后台收到 onVideoError 通知,记录变量;
- 当页面回到前台判断是否有收到onVideoError 通知,如果有收到,则强行重启摄像头;如果没有,则判断当前摄像头是否已经开启,如果开启,则强行重启摄像头。
- 示例代码:
public CameraVideoActivity extends AppCompatActivity implements JRTCClientCallback, JRTCMediaDeviceCallback {
private JRTCClient mClient;
private JRTCMediaDevice mMediaDevice;
private boolean mToBack = false; //记录当前页面是否在后台
private boolean mVideoError = false; //记录是否收到视频异常通知
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_video);
mClient = JRTCClient.create(this, this, null);
mMediaDevice = JRTCMediaDevice.create(mClient, this, null);
}
//监听视频异常
@Override
public void onVideoError(String error) {
//大部分手机在摄像头被占用,能收到视频异常回调,需要通过变量记录下
if (mToBack) {
mVideoError = true;
} else {
//如果在前台出现视频异常,那就一般不是摄像头被占用,或者被系统停止导致的;
//可以在这里给予用户UI上提示;
//一般手机设备默认摄像头不会出现损坏,所以在前台收到视频异常,
//一般是其他视频错误导致,比如渲染异常等,需要提供日志反馈给开发定位。
}
}
@Override
protected void onStart() {
super.onStart();
//页面回到前台
mToBack = false;
if (mVideoError) {
//如果收到了视频异常的的回调,SDK内部已经关闭了摄像头,只要重新打开摄像头就行
mMediaDevice.startCamera();
mVideoError = false; //重置变量
} else if (mMediaDevice.isCameraOpen()) {
//如果没有收到视频异常的的回调,则强行重新打开摄像头
mMediaDevice.stopCamera();
mMediaDevice.startCamera();
}
}
@Override
protected void onStop() {
super.onStop();
//页面退到后台
mToBack = true;
}
}
# 部分手机退到后台导致无声或者摄像头画面静止问题(Android)
# 问题现象
- 部分手机在通话界面弹出申请悬浮窗权限;
- 用户点击去开启,跳转到系统应用设置界面开关权限;
- 麦克风无法采集到声音;
- 摄像头画面静止,无法采集到画面。
# 定位步骤
- Android 高版本对后台应用麦克风、摄像头等隐私权限加强了限制,当应用退到后台,一段时间后或者有应用权限变更,导致系统停止麦克风和摄像头采集。
# 问题排查
- 视频/音频通话建立时,需要增加前台服务通知来保活;
- 示例代码:
在 AndroidManifest. xml 里增加声明;
<!-- 前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 保活服务 --> <!-- targetVersion 30或者以上需要添加 android:foregroundServiceType 这个配置 --> <service android:name="com.xxx.XXXAliveService" android:foregroundServiceType="camera|microphone" android:enabled="true"/>XXXAliveService.java文件,添加前台服务通知;
public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { createNotificationChannel(); return super.onStartCommand(intent, flags, startId); } private void createNotificationChannel() { //Android 8.0 通知必须要有 channelId,可以随意字符串,只要和NotificationChannel中参数一致; NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "audioDevice") .setContentTitle("菊风") .setContentText("视频通话中") .setDefaults(Notification.DEFAULT_SOUND) .setWhen(System.currentTimeMillis()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); NotificationChannel channel = new NotificationChannel("audioDevice", "keepAlive", NotificationManager.IMPORTANCE_DEFAULT); notificationManager.createNotificationChannel(channel); } Notification notification = builder.build(); //targetVersion 30以下 startForeground(1000, notification); //targetVersion 30或者以上 startForeground(1000, notification, FOREGROUND_SERVICE_TYPE_CAMERA | FOREGROUND_SERVICE_TYPE_MICROPHONE); } @Override public void onDestroy() { stopForeground(true); super.onDestroy(); } }在音频/视频通话建立时开启前台服务通知
//context 可以是界面Activity对象也可以是,Application 对象 Intent service = new Intent(context, XXXAliveService.class); startForegroundService(service);在视频通话结束后停止前台服务通知
//context 可以是界面Activity对象也可以是,Application 对象 Intent service = new Intent(context, XXXAliveService.class); this.stopService(service);
# Android 工程 targetVersion 29导致屏幕共享失败
# 问题现象
使用屏幕共享过程中抛出 SecurityException 异常
java.lang.SecurityException: Media projections require a foreground service
of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
# 定位步骤
在 targetSdkVersion 大于等于29时,系统加强了对屏幕采集的限制,必须先启动相应的前台 Service,才能正常调用 getMediaProjection 方法,否则会抛异常;
# 问题排查
如果工程配置 targetSdkVersion 大于等于29(需要使用Android X),目前上架 google 应用市场和国内应用市场要求targetSdkVersion 大于等于30;
- 首先确保菊风提供的 sdk 中包含类 com.justalk.cloud.zmf.CaptureScreenService ,部分提供较早的 sdk 还没有兼容,所以没有该类,如果没有需要菊风侧 sdk 升级
- 需要在 AndroidManifest.xml 配置如下:
//如果Android tagetVersion 设置29及以上,则需要添加前台服务权限,屏幕共享需要
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
//注册activity,屏幕共享需要
<activity
android:name="com.justalk.cloud.zmf.ZmfActivity"
android:theme="@android:style/Theme.Dialog" />
//如果Android tagetVersion 设置29或以上,则还需要注册service,屏幕共享需要
<service
android:name="com.justalk.cloud.zmf.CaptureScreenService"
android:enabled="true"
android:foregroundServiceType="mediaProjection"/>
# Andorid 15 及以上手机屏幕共享黑屏或者蒙影
# 问题现象
如果客户端是Android 15 或者以上手机,服务器录制文件屏幕共享画面黑屏或者蒙影
# 定位步骤
Android 15以及以上手机默认针对银行类/支付类App开启屏幕共享保护,当打开屏幕共享的时候,一般系统会有提示。
# 问题排查
系统设置可以把该保护关闭。
# PC端程序崩溃(Java Swing ),赞同场景
# 问题现象
程序崩溃
# 定位步骤
- 需要提供jvm异常文件,类似如下:需要配置 jvm 运行参数 -XX:ErrorFile
暂时无法在飞书文档外展示此内容
- 需要提供core文件,需要配置 jvm 运行参数 -XX:+CreateMinidumpOnCrash
- 如果是 Windows 端,还可以提供下 Windows 下的系统崩溃日志
# 问题排查
如果jvm异常堆栈指向菊风库,可以提供崩溃堆栈和菊风的日志找菊风开发定位
# NoCandidate:JSM.JSMS 错误
# 问题现象
创建会议失败,报错 MtcMpcallCreateDidFailNotification mCookie:2 info={"MtcMpcallErrorKey":"NoCandidate:JSM.JSMS"}
# 定位步骤
该报错表示没有会场资源
# 问题排查
检查 RoomLicence 是否正常启动
# 小程序看远端视频画面卡住
# 问题现象
盛京银行小程序视频通话过程中收到微信消息,点击弹出的消息横幅打开微信聊天窗口,关闭聊天窗口后小程序看远端视频画面卡住。
# 定位步骤
打开聊天窗口类似于退后台,这时候推拉流都停止,但是关闭聊天窗口后并没有恢复拉流,只恢复了推流。
# 解决方案
将live-player拉流组件的auto-pause-if-open-native(当跳转到其它微信原生页面时,是否自动暂停本页面的实时音视频播放)和auto-pause-if-navigate(当跳转到本小程序的其他页面时,是否自动暂停本页面的实时音视频播放)两个属性值设置成 false 后解决
# H5摄像头权限失败
# 问题现象
调用 startCameraVideo 失败,或收到 onCameraError 回调。
常见错误码:
111013C21 / C21_OPEN_CAMERA_NOT_PERMISSION:开启摄像头未获得摄像头权限
# 定位步骤
正常情况下,考虑到用户使用场景,应该从浏览器权限、页面协议、系统权限、摄像头设备、设备占用、采集参数是否正确等方面进行排查。
# 问题排查
- 检查页面是否使用 HTTPS 或 localhost,普通 HTTP 页面通常无法调用摄像头;
- 检查浏览器地址栏中的摄像头权限是否被拒绝;
- 检查系统隐私设置是否允许当前浏览器访问摄像头;
- 检查摄像头是否被其他 App、会议软件、其他浏览器标签页占用;
- 检查设备是否真的存在摄像头,可通过
getCameras()或浏览器设备设置确认; - 检查是否在用户点击按钮后触发采集授权,移动端浏览器更依赖用户手势;
- 检查
setCameraProperty(width, height, frameRate)设置的分辨率和帧率是否被设备支持; - 移动端检查前后摄像头
facingMode是否可用; - 检查浏览器控制台中
getUserMedia的具体异常,如NotAllowedError、NotFoundError、NotReadableError;
# H5麦克风权限失败
# 问题现象
调用 startAudioInput 失败,或收到 onAudioInputError 回调。
常见错误码:
111005C21 / C21_START_AUDIO_INPUT_NOT_MIC_PERMISSION:打开音频输入设备未获得麦克风权限
# 定位步骤
正常情况下,考虑到用户使用场景,应该从浏览器权限、页面协议、系统权限、麦克风设备、设备占用、音频输入状态等方面进行排查。
# 问题排查
- 检查页面是否使用 HTTPS 或 localhost;
- 检查浏览器地址栏中的麦克风权限是否被拒绝;
- 检查系统隐私设置是否允许当前浏览器访问麦克风;
- 检查麦克风是否被其他 App、会议软件、其他浏览器标签页占用;
- 检查麦克风是否被系统禁用、静音或未插好;
- 检查调用
startAudioInput前媒体类型是否允许音频,MediaType.VIDEO下不支持打开音频输入; - 检查浏览器控制台中
getUserMedia的具体异常;
# H5本地视频预览黑屏或不显示
# 问题现象
摄像头已授权,但页面本地视频区域黑屏、无画面,或 startCameraVideo 成功但画面不出。
# 定位步骤
H5 工程通过动态创建 video 标签并设置 srcObject 渲染本地流。排查重点包括 DOM 容器、视频流、播放状态、浏览器渲染和页面样式。
# 问题排查
- 检查传入
startCameraVideo的videoBox是否真实存在; - 检查
videoBox及父容器是否有有效宽高,避免宽高为 0; - 检查页面 CSS 是否隐藏了视频容器;
- 检查
startCameraVideo是否返回了有效的 canvas 对象; - 检查本地
MediaStream是否包含 video track; - 检查 video 标签是否触发
oncanplay、onplaying; - 检查浏览器是否阻止自动播放,可尝试在用户点击事件中调用
canvas.resume(); - 检查是否调用过
stopVideo或stopAllMedia导致媒体流被停止; - 检查 iOS Safari、微信内置浏览器是否需要用户手势恢复播放;
# H5远端视频播放失败
# 问题现象
订阅远端视频后,对端画面不显示,或调用 startVideo 返回空、画面黑屏。
常见错误码:
111027C21 / C21_START_VIDEO_FAIL:开启预览视频失败112024C22 / C22_REQUEST_OTHER_VIDEO_FAIL:请求房间中其他用户的视频流失败
# 定位步骤
远端视频流程通常是先调用 requestVideo 获取远端 mediaStream,再调用 startVideo(streamUrl, renderType, mediaStream, videoBox) 渲染。
# 问题排查
- 检查远端成员是否真的开启了视频;
- 检查
requestVideo是否成功; - 检查房间或通话是否已加入,未入会时请求远端视频会失败;
- 检查是否请求了自己的视频流,SDK 会拒绝 request self video;
- 检查
participant.streamUrl是否为空,streamUrl为空会导致startVideo失败; - 检查
mediaStream是否存在 video track; - 检查传入的远端视频容器
videoBox是否存在且有尺寸; - 检查远端是否中途关闭视频或取消发送视频流;
- 检查 iOS Safari、微信内置浏览器是否需要用户手势恢复播放;
# H5远端音频无声
# 问题现象
远端视频能看到,但听不到对方声音;或调用 startAudioOutput 后没有声音。
常见错误码:
112022C22 / C22_ENABLE_REMOTE_AUDIO_OUTPUT_FAIL:开关远端音频输出失败111058C21 / C21_AUDIO_ERROR_CALLBACK:音频异常回调
# 定位步骤
H5 工程远端音频通过 JRTCMediaDeviceAudioContainer 播放,并且实际创建的是隐藏的 media 标签。排查重点包括远端音频流、浏览器自动播放策略、音频容器、输出设备和系统音量。
# 问题排查
- 检查远端成员是否开启了音频;
- 检查
mediaStream.getAudioTracks()是否有音频轨道; - 检查
startAudioOutput(result.mediaStream, userId, audioBox)入参是否正确; - 建议传入有效的
audioBox,不传可能无法播放音频; - 检查浏览器是否限制自动播放,移动端建议在用户点击后触发入会、订阅或播放;
- 检查是否调用过
stopAudioOutput或enableAudio(false); - 检查系统音量、浏览器标签页是否静音;
- 检查 iOS Safari、微信内置浏览器是否需要用户手势恢复播放;
# H5切换摄像头失败
# 问题现象
调用 switchCamera 失败,无法切换前后摄像头或指定摄像头。
常见错误码:
111018C21 / C21_SWITCH_CAMERA_FAIL:切换摄像头失败
# 定位步骤
H5 工程要求摄像头已经打开,并且设备列表中存在可切换摄像头。切换时会先停止当前 track,再重新调用 getUserMedia。
# 问题排查
- 检查调用
switchCamera前是否已经成功打开摄像头; - 检查
getCameras()是否有两个以上摄像头; - 检查旧摄像头资源是否已释放;
- 检查摄像头是否被其他应用占用;
# 角色值判断(通用)
# 问题现象
通话或会议场景中,需要根据角色值判断当前成员是访客、座席、主访客、主座席,还是普通成员。
# 定位步骤
角色值本质上是按位组合的结果,通常需要通过二进制位和按位与运算来判断角色类型,再结合基础成员值确定最终身份。
# 问题排查
基础值说明:
| 十进制 | 二进制 | 十六进制 | 含义 |
|---|---|---|---|
131072 | 100000000000000000 | 0x20000 | 主角色位 |
128 | 10000000 | 0x80 | 访客位 |
64 | 1000000 | 0x40 | 座席位 |
6 | 110 | 0x06 | 普通音视频成员基础值 |
常见角色值对照:
| 角色值 | 二进制 | 十六进制 | 组成 | 角色说明 |
|---|---|---|---|---|
131206 | 100000000011000110 | 0x20086 | 131072 + 128 + 6 | 主访客 |
131142 | 100000000010000110 | 0x20046 | 131072 + 64 + 6 | 主座席 |
134 | 10000110 | 0x86 | 128 + 6 | 普通访客 |
70 | 1000110 | 0x46 | 64 + 6 | 普通座席 |
6 | 110 | 0x06 | 6 | 普通成员 |
现场判断顺序:
- 先看角色值里有没有
131072。如果角色值 & 131072 = 131072,就说明带主角色位,是主角色。 - 再看角色值里有没有
128。如果角色值 & 128 = 128,就说明是访客。 - 再看角色值里有没有
64。如果角色值 & 64 = 64,就说明是座席。 - 如果只有基础值
6,没有主角色位、访客位、座席位,那就是普通成员。
现场可直接参考下面的判断结果:
- 带
131072且带128:主访客。 - 带
131072且带64:主座席。 - 不带
131072但带128:普通访客。 - 不带
131072但带64:普通座席。 - 只有
6:普通成员。
按位与运算示例:
131206 & 131072 = 131072,所以131206带主角色位。131142 & 131072 = 131072,所以131142带主角色位。134 & 131072 = 0,所以134不是主角色。134 & 128 = 128,所以134是访客。131206 & 128 = 128,所以131206是访客,也就是主访客。70 & 64 = 64,所以70是座席。131142 & 64 = 64,所以131142是座席,也就是主座席。
# 多方通话/多方通话2.0(Mpcall)中普通服务器录制
# 问题现象
通话中,如何开启普通服务器录制以及监听服务器录制状态变化
# 定位步骤
通过监听通话属性接口是否上报录制相关的属性变化
# 问题排查
以 Android 端举例
多方通话监听 JRTCRoomCallback 接口的 onRoomPropertyChanged 回调
//定义个全局变量记录当前服务器录制状态,默认初始化状态
@JRTCEnum.RemoteRecordState int mCurrentRemoteRecordState = JRTCEnum.RECORD_STATE_NONE;
/**
* 房间属性变化回调
* <p>
* 当房间的属性发生变化时,会收到此回调,例如房间中有成员发起屏幕共享、录制状态发生变化等。
*
* @param changeParam {@link PropChangeParam} 变化标识集合
* @param room 当前 JRTCRoom 对象
*/
void onRoomPropertyChanged(PropChangeParam changeParam, JRTCRoom room) {
if (changeParam.remoteRecordState) {
//表示远程录制状态变化
@JRTCEnum.RemoteRecordState int remoteRecordState = room.getRemoteRecordState();
if (this.mCurrentRemoteRecordState == JRTCEnum.RECORD_STATE_NONE && remoteRecordState == JRTCEnum.RECORD_STATE_READY) {
//录制准备就绪,此时可以开启录制
room.enableRemoteRecord(true, new JRTCRecordRemoteParam());
//同理可以通过 room.enableRemoteRecord(false, null);停止呀远程录制
} else if (remoteRecordState == JRTCEnum.RECORD_STATE_RUNNING) {
//表示录制进行中
} else if (
this.mCurrentRemoteRecordState == JRTCEnum.RECORD_STATE_RUNNING &&remoteRecordState == JRTCEnum.RECORD_STATE_READY) {
//表示录制停止,此时又可以调用,room.enableRemoteRecord(true, new JRTCRecordRemoteParam()); 开启一个新的录制
}
this.mCurrentRemoteRecordState = remoteRecordState;
}
}
多方2.0(Mpcall)监听 JRTCCallCallback 接口的 onCallPropertyChanged 回调
//定义个全局变量记录当前服务器录制状态,默认初始化状态
@JRTCEnum.RemoteRecordState int mCurrentRemoteRecordState = JRTCEnum.RECORD_STATE_NONE;
/**
* 通话属性改变,重点关注屏幕共享
* <p>
* @param propChangeParam 通话改变的属性
*/
void onCallPropertyChanged(PropChangeParam changeParam) {
if (changeParam.remoteRecordState) {
//表示远程录制状态变化
@JRTCEnum.RemoteRecordState int remoteRecordState = room.getRemoteRecordState();
if (this.mCurrentRemoteRecordState == JRTCEnum.RECORD_STATE_NONE && remoteRecordState == JRTCEnum.RECORD_STATE_READY) {
//录制准备就绪,此时可以开启录制
this.call.enableRemoteRecord(true, new JRTCRecordRemoteParam());
//同理可以通过 this.call.enableRemoteRecord(false, null);停止呀远程录制
} else if (remoteRecordState == JRTCEnum.RECORD_STATE_RUNNING) {
//表示录制进行中
} else if (this.mCurrentRemoteRecordState == JRTCEnum.RECORD_STATE_RUNNING && remoteRecordState == JRTCEnum.RECORD_STATE_READY) {
//表示录制停止,此时又可以调用,this.call.enableRemoteRecord(true, new JRTCRecordRemoteParam()); 开启一个新的录制
}
mthis.CurrentRemoteRecordState = remoteRecordState;
}
}
# 通话中如何监听屏幕共享状态变化
# 问题现象
通话中,成员开启屏幕共享,如何监听并渲染对方屏幕画面
# 定位步骤
通过监听通话属性接口是否上报屏幕共享相关的属性变化
# 问题排查
以 Android 端举例
多方通话监听 JRTCRoomCallback 接口的 onRoomPropertyChanged 回调
String mCurrentShareUserId = ""; //当前发起共享屏幕的用户ID
JRTCMediaDeviceVideoCanvas mShareVideoCanvas;//当前屏幕供选渲染视图对象
/**
* 房间属性变化回调
* <p>
* 当房间的属性发生变化时,会收到此回调,例如房间中有成员发起屏幕共享、录制状态发生变化等。
*
* @param changeParam {@link PropChangeParam} 变化标识集合
* @param room 当前 JRTCRoom 对象
*/
void onRoomPropertyChanged(PropChangeParam changeParam, JRTCRoom room) {
if (changeParam.screenShare) {
//表示通话中屏幕共享状态变化
String screenShareUserId = room.getShareUserId();
if (!TextUtils.isEmpty(screenShareUserId)) {
//表示有人发起了屏幕共享
if (TextUtils.isEmpty(mCurrentShareUserId)) {
//有人发起屏幕共享
} else {
//原先的屏幕共享被顶,一个通话只能有一路屏幕共享,比如,成员A发起了共享,成员B再去发起,成员A的屏幕共享就会被成员B顶替
//但是视频流ID还是同一个
}
if (TextUtils.equals(screenShareUserId, this.mClient.getUserId())) {
//表示自己发起了屏幕共享
} else{
//通话中其他成员开启了屏幕共享,此时可以取渲染对方的屏幕视频画面,先去订阅屏幕视频流
room.requestScreenVideo(new JRTCVideoSize(1280, 720));
mShareVideoCanvas = this.mMediaDevice.startVideo(room.getShareStreamId(), JRTCMediaDevice.RENDER_FULL_CONTENT);
}
} else if (!TextUtils.isEmpty(mCurrentShareUserId) && TextUtils.isEmpty(screenShareUserId)) {
//表示屏幕共享结束,此时可以取消订阅屏幕共享流,以及停止渲染
room.unRequestScreenVideo();
if (mShareVideoCanvas != null) {
this.mMediaDevice.stopVideo(mShareVideoCanvas);
}
}
}
}
同理,多方通话2.0(Mpcall)已经座席、访客模块,监听 onCallPropertyChanged 回调
