Pano开发者中心
  • 文档中心
  • 下载中心

›音视频

新手入门

  • 简介
  • 名词解释
  • 账号注册指南
  • 创建第一个应用

规则说明

  • Channel ID命名规则
  • 权限控制
  • 计费说明
  • 最长通话时长说明
  • 每月一万分钟免费说明
  • 布局参数说明

场景方案

    教育行业

    • 1vN互动小班课
    • 互动直播大班课

快速接入

  • 简介
  • 音视频

    • Windows (C++)
    • Android (Java)
    • iOS (Objective-C)
    • Web
    • Electron

    白板

    • Android (Java)
    • iOS (Objective-C)
    • Web

高级功能

  • 简介
  • 音视频

    • 屏幕共享
    • 状态回调
    • 音量指示
    • 混音/伴音
    • 混响
    • 耳返
    • 美颜
    • 音视频数据回调
    • 音视频外部采集
    • 收发多路视频
    • 设备诊断
    • 反馈

    白板

    • Android (Java)
    • iOS (Objective-C)
    • Web

操作实践

  • 切换大小屏

RESTful API

  • 基本格式
  • 获取Token
  • 频道管理
  • 云端录制
  • CDN推流
  • 文档转码
  • 服务端消息通知API

SDK API

  • SDK接口说明
  • Windows (C++)
  • Android (Java)
  • iOS/macOS (Objective-C)
  • Web SDK(IE)
  • Web SDK

    • PanoRtc 参考
    • RtcEngine
    • RtcWhiteboard
    • Constants

更新记录

  • 简介
  • SDK

    • Windows
    • macOS
    • iOS
    • Android
    • Electron
    • Flutter
    • React Native
    • Web
    • Web SDK(IE)
    • Web Whiteboard

    Demo-PanoVideoCall

    • Windows、Mac和Web
    • iOS
    • Android

    Demo-PanoAudioChat

    • iOS
    • Android

帮助

  • FAQ
  • 更多帮助

Android (Java)

本文以实现视频通话为例,结合 SDK API 和示例代码,介绍如何快速接入。

如需查看完整 SDK API 列表,请点击左侧导航 SDK API 部分。

导入SDK

  • 请到 下载中心 下载 Android SDK压缩包。
  • 将其解压,获取 Android 目录下的 panortc.aar,将 panortc.aar 放到你的项目中。
  • 在 Module 的 build.gradle - dependencies 中,添加:
    implementation fileTree(dir: 'sdk_path', include: ['*.aar'])

请将其中 sdk_path 替换为可以定位到 panortc.aar 的实际路径。

配置权限

请在 AndroidManifest.xml 文件的 manifest 标签内添加必要的权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

防止混淆

如果你的项目需要混淆,请在 proguard-rules.pro 文件中配置以下内容防止混淆 Pano SDK。

-keep class com.pano.**{*;}
-keep class video.pano.**{*;}

如果将 Pano SDK 混淆,可能会出现报错,例如:
java.lang.ClassNotFoundException: Didn't find class"video.pano..." on path: DexPathList[[zip file "..."] ...

注册通知

通过实现 RtcEngineCallback 接口的回调方法来处理 Pano SDK 返回的通知。

public class MyPanoEngineCallback implements RtcEngineCallback {
    public void onChannelJoinConfirm(Constants.QResult result) {
        // 处理 加入频道 的结果
    }

    public void onChannelLeaveIndication(Constants.QResult result) {
        // 处理 离开频道 的结果
    }
    ......
}
  • 完整的回调方法列表与介绍,请查看 RtcEngineCallback接口。
  • 为结合介绍 SDK 接口,本文会提供部分 示例代码 中的片段,请开发者注意根据实际情况调整。

初始化

通过 RtcEngine 的 create 方法初始化实例。

public static final String APPID = ""; // 替换为你的应用ID
public static final String PANO_SERVER = "api.pano.video";
private RtcEngine mRtcEngine;
 // PanoEngineCallback 为"注册通知"章节中创建的 RtcEngineCallback 接口的子类
private PanoEngineCallback mRtcCallback = new PanoEngineCallback();
protected Constants.AudioAecType mAudioAecType = Constants.AudioAecType.Default;
protected boolean mHwAcceleration = false;

RtcEngineConfig engineConfig = new RtcEngineConfig();
engineConfig.appId = APPID; // 应用ID
engineConfig.server = PANO_SERVER; // PANO服务器地址
engineConfig.context = getApplicationContext();
engineConfig.callback = mRtcCallback; // RtcEngineCallback回调对象
engineConfig.audioAecType = mAudioAecType; // 回音消除算法
engineConfig.videoCodecHwAcceleration = mHwAcceleration; // 硬件加速

mRtcEngine = RtcEngine.create(engineConfig);
  • 请登录 Pano控制台,点击左侧导航 应用管理 ,查看应用ID(即 appId)。
  • 建议在 app 的 Application 的 onCreate 中进行初始化。只有当初始化完成后,才可以使用 RtcView 显示视频画面。如果尚未初始化就开始在 UI 中使用 RtcView 将出现报错。

本地预览

通过 RtcView 的 init 方法初始化视频画布。
通过 RtcEngine 实例的 setLocalVideoRender 方法设置显示自己画面的视频画布,startPreview 方法开启本地摄像头预览。

// 画布类型为 com.pano.rtc.api.RtcView,可以动态创建,也可以通过 XML 文件静态配置
/* [注意] RtcView 外面必须包裹一层 Layout (建议使用 ConstraintLayout),
   而且 RtcView 自身宽高需要设置为 wrap_content,请参考:
   https://github.com/PanoVideo/video-call-samples/blob/master/Android/BasicVideoCall/app/src/main/res/layout/content_call.xml#L11
*/
mLocalView = new RtcView(this); // 动态创建
/* 需要调用 init 方法来初始化画布;不需要再使用时,调用 release 方法释放画布
   如果创建过多的 RtcView 而未释放,可能出现报错:
   java.lang.RuntimeException: Failed to create EGL context: 0x3003
*/
/*mLocalView.init(new RendererCommon.RendererEvents() {
    @Override
    public void onFirstFrameRendered() {
        // 可以按需处理
    }
    @Override
    public void onFrameResolutionChanged(int i, int i1, int i2) {
        // 可以按需处理
    }
});*/
mLocalView.init(null); // 如果不需要处理 RendererEvents,可以在 init 时传入 null
// 除 setMirror 外,RtcView 还支持 setScalingType 设置视频缩放类型,等
mLocalView.setMirror(mFrontCamera); // 通常前置摄像头需要开启镜像
mRtcEngine.setLocalVideoRender(mLocalView);
mRtcEngine.startPreview(Constants.VideoProfileType.HD720P, true);
  • 如果设置的分辨率高于摄像头支持的最大分辨率,则自动降低为摄像头支持的最大分辨率。
  • 如需切换预览不同的摄像头,先通过 RtcEngine 实例的 stopPreview 方法停止当前预览,再通过 startPreview 方法开启新的预览,无需操作 View。
  • 如果不需要在 加入频道 前进行本地预览,可以不调用 startPreview 接口。

加入频道

加入频道

通过 RtcEngine 实例的 joinChannel 方法加入频道。

RtcChannelConfig config = new RtcChannelConfig();
config.userName = ""; // 用户名,可选参数,可为空,建议配置以区分不同用户
config.mode_1v1 = false; // 一对一模式/会议模式;如果有 Web 端参与,请设置为 false
// serviceFlags 频道标志:音视频 | 白板 (按位或)
// config.serviceFlags = Constants.kChannelServiceMedia | Constants.kChannelServiceWhiteboard;
config.serviceFlags = Constants.kChannelServiceMedia; // 只使用音视频
config.subscribeAudioAll = true; // 自动订阅音频,可以配置为 false 来主动订阅音频
Constants.QResult ret = mRtcEngine.joinChannel(mAppToken, mChannelId, mUserId, config);
if (ret != Constants.QResult.OK) {
    // 加入失败,请根据 QResult 进行处理
}
  • 另请参考 名词解释 了解 channelId、token、userId、userName 的作用。
  • 可以使用 临时token 来进行临时测试。

自己加入频道的通知

调用 joinChannel 方法后,将触发 onChannelJoinConfirm 通知。

public void onChannelJoinConfirm(Constants.QResult result) {
    // result 表示自己加入频道的结果
}

joinChannel (加入频道) 接口返回的 QResult 仅表示调用该接口的结果,而 onChannelJoinConfirm (自己加入频道的通知) 返回的 QResult 表示和服务器交互后的结果。
也就是说当 onChannelJoinConfirm 返回 OK 才表示加入频道成功。

其他用户加入频道的通知

其他用户加入频道后,将触发 onUserJoinIndication 通知。

public void onUserJoinIndication(long userId, String userName) {
    // 其他用户加入频道的通知。userId 和 userName 都是该用户在 joinChannel 时传入的
    // 此时可以将其加入到与会者列表中
}

倒计时通知

加入频道后,如果存在倒计时限制,将触发 onChannelCountDown 通知。

public void onChannelCountDown(long remain) {
    // 频道倒计时通知,单位:秒;请保存用于展示倒计时,此回调仅在加入频道后回调一次
}
  • 已实名认证,并且使用正式token,Pano不限制频道时长
  • 未实名认证,或者使用临时token,最大频道时长为 30 分钟

操作视频

发送本地视频

通过 RtcEngine 实例的 startVideo 方法发送本地视频。

// 调用此方法后,其他用户才能看到你的画面;请在 onChannelJoinConfirm 回调加入频道成功后再调用
mRtcEngine.startVideo(Constants.VideoProfileType.HD720P, true);
  • startPreview (开启本地摄像头预览) 和 startVideo (发送本地视频) 可以设置不同的摄像头(frontCamera 参数),但是通常都应设置相同的摄像头,因为一般都是预览发送出去的画面。
  • startVideo 设置的分辨率表示期望的发送分辨率,实际过程中可能会因硬件支持情况、网络情况和订阅情况触发 SDK 自动调整而降低(后文会介绍订阅)。

切换摄像头

在通话过程中,可以通过 RtcEngine 实例的 switchCamera 方法切换摄像头。

mRtcEngine.switchCamera(); // 此方法将切换发送出去的摄像头画面

停止发送本地视频

通过 RtcEngine 实例的 stopVideo 方法停止发送本地视频。

mRtcEngine.stopVideo(); // 调用此方法后,其他用户将看不到你的画面;本地预览不会被停止
  • 当 startPreview 和 startVideo 接口设置不同的 profileType 参数时,预览分辨率会自动调整为和和实际的发送分辨率一致。当 stopVideo 后,预览的分辨率会恢复为 startPreview 设置的分辨率。
  • 当然,前提条件仍然是摄像头支持相应的分辨率,否则会降低为摄像头支持的最大分辨率。
    后文同理不再重复介绍。

其他用户开启视频的通知

当其他用户发送视频时,将触发 onUserVideoStart 通知。

public void onUserVideoStart(long userId, Constants.VideoProfileType maxProfile) {
    // maxProfile 表示该用户的最大可发送分辨率
    // 取决于 摄像头支持的最大分辨率 和 设置的发送分辨率 这两个值中的较小值。
    // 即:maxProfile = min{摄像头支持的最大分辨率, 设置的发送分辨率}
    // 可以订阅低于 maxProfile 的 VideoProfileType ,以节省性能、带宽、流量和费用
    // 例如,当应用场景需要同时展示多个远端小画面时,可以向远端订阅一个较低的分辨率
}

订阅其他用户的视频

通过 RtcEngine 实例的 subscribeVideo 方法订阅其他用户的视频,通过 setRemoteVideoRender 方法设置显示其他用户画面的视频画布。

// 请在收到其他用户的 onUserVideoStart 通知后,再调用订阅;返回 OK 表示接口调用成功,否则表示失败
Constants.QResult ret = mRtcEngine.subscribeVideo(userId, profileType);
mRtcEngine.setRemoteVideoRender(userId, render);
  • Pano采用订阅模式来接收视频,参与者之间需要相互订阅,才可以看到彼此的视频画面。
  • 默认 正式token 最多可以订阅 6 路视频,临时token 最多可以订阅 3 路视频。
  • 使用 RtcVideoStreamManager 的开发者,请换用 RtcVideoStreamManager.subscribeVideo 方法来订阅其他用户的视频流。

订阅视频结果通知

当订阅其他用户的视频后,会触发 onUserVideoSubscribe 通知。

public void onUserVideoSubscribe(long userId, Constants.MediaSubscribeResult result) {
    // 处理订阅视频结果通知,Success 表示成功
}
  • subscribeVideo 接口返回的 QResult 仅表示调用该接口的结果,而 onUserVideoSubscribe 返回的 MediaSubscribeResult 表示和服务器交互后的结果。
    也就是说,onUserVideoSubscribe 返回 Success 才表示订阅成功。
  • 如果重复调用 订阅其他用户的视频 接口,只会在第一次调用时触发 订阅视频结果通知。如果取消订阅再重新订阅,视为第一次调用,可正常触发一次 订阅视频结果通知。

视频首帧的通知

当自己发送或收到其他用户第一个视频帧时,将触发 onFirstVideoFrameRendered 通知。

public void onFirstVideoFrameRendered(long userId) {
    // 第一个视频帧通知,可以开始显示视频画面
}

取消订阅其他用户的视频

通过 RtcEngine 实例的 unsubscribeVideo 方法取消订阅其他用户的视频。

mRtcEngine.unsubscribeVideo(userId); // 调用此方法后,你将看不到该用户的画面
  • 当其他用户停止视频或者离开频道的时候,将被自动取消订阅。
  • 取消订阅后重新订阅的情况,如果使用同一 render,无须重新调用 setRemoteVideoRender 方法。
  • 使用 RtcVideoStreamManager 的开发者,请换用 RtcVideoStreamManager.unsubscribeVideo 方法来取消订阅。

操作声音

发送本地声音

通过 RtcEngine 实例的 startAudio 方法发送本地声音。

mRtcEngine.startAudio(); // 调用此方法后,其他用户才能听到你的声音;请在加入频道成功后再调用

停止发送本地声音

通过 RtcEngine 实例的 stopAudio 方法停止发送本地声音。

// 调用此方法后,其他用户将听不到你的声音
// 不影响你接收其他用户的声音
// 可以调用 startAudio 重新发送
mRtcEngine.stopAudio();

有三种方式将自己静音(不让其他用户听到你的声音):1 停止发送本地声音,2 静音本地麦克风,3 静音本地麦克风(系统层操作)
它们的区别在于:
1 "停止发送本地声音"会断开音频通道连接(同时停止发送麦克风和伴音的声音,会取消其他用户订阅你的声音,如需重建连接需要消耗时间)
2 "静音本地麦克风"会发送静音包(不影响伴音发送,不影响订阅关系,临时静音建议使用此方式,取消静音能够迅速恢复发送声音)
3 "静音本地麦克风(系统层操作)"会调用系统接口设置底层硬件状态,一般情况不建议使用,因此本文不介绍该接口

静音

通过 RtcEngine 实例的 muteAudio 方法静音本地麦克风。

mRtcEngine.muteAudio(); // 调用此方法后,其他用户将听不到你的声音;可以调用 unmuteAudio 取消静音

取消静音

通过 RtcEngine 实例的 unmuteAudio 方法取消静音本地麦克风。

mRtcEngine.unmuteAudio(); // 静音后,需要取消静音,其他用户才能听到你的声音

其他用户开启声音的通知

当其他用户发送声音时,将触发 onUserAudioStart 通知。

public void onUserAudioStart(long userId) {
    ...
}

订阅其他用户的声音

如果在 joinChannel (加入频道)时,配置了自动订阅音频(例如:config.subscribeAudioAll = true),则开发者无需再主动订阅其他用户的声音。否则,需要通过 RtcEngine 实例的 subscribeAudio 方法订阅其他用户的声音。

// 如果 加入频道 时配置了自动订阅音频,则无需调用此接口
// 请在收到其他用户的 onUserAudioStart 通知后,再调用订阅
mRtcEngine.subscribeAudio(userId);
  • 如果希望在通话过程中,不收听某位与会者,或者不收听所有其他与会者,请在加入频道时,设置不自动订阅音频;随后按需订阅或取消订阅某位或所有其他与会者。

订阅声音结果通知

当主动订阅其他用户的声音后,会触发 onUserAudioSubscribe 通知。

public void onUserAudioSubscribe(long userId, Constants.MediaSubscribeResult result) {
    // 处理订阅声音结果通知,Success 表示成功
}
  • subscribeAudio 接口返回的 QResult 仅表示调用该接口的结果,而 onUserAudioSubscribe 返回的 MediaSubscribeResult 表示和服务器交互后的结果。
    也就是说,onUserAudioSubscribe 返回 Success 才表示订阅成功。
  • 如果配置了自动订阅音频,则不会触发此通知。

收到其他用户声音的通知

当收到其他用户的声音时,将触发 onFirstAudioDataReceived 通知。

public void onFirstAudioDataReceived(long userId) {
    // 收到其他用户的首个声音数据包
}

取消订阅其他用户的声音

通过 RtcEngine 实例的 unsubscribeAudio 方法取消订阅其他用户的声音。

mRtcEngine.unsubscribeAudio(userId); // 调用此方法后,你将听不到该用户的声音

当其他用户停止声音或者离开频道的时候,将被自动取消订阅。

离开频道

离开频道

通过 RtcEngine 实例的 leaveChannel 方法离开频道。

mRtcEngine.leaveChannel();

其他用户离开频道的通知

其他用户离开频道后,将触发 onUserLeaveIndication 通知。

onUserLeaveIndication(long userId, Constants.UserLeaveReason reason) {
    // 可将其从与会者列表中移除
};

至此,Android 快速接入已介绍完毕。

SDK API 指南

本文仅介绍接入Pano Android SDK实现视频通话的基本流程和接口。
实际场景需要结合使用更多接口,请 点此查看 API 列表。

示例代码

为方便开发者了解丰富的接口使用方式,我们还提供示例代码,请 体验参考。

Last updated on 2/24/2021
← Windows (C++)iOS (Objective-C) →
  • 导入SDK
  • 配置权限
  • 防止混淆
  • 注册通知
  • 初始化
  • 本地预览
  • 加入频道
    • 加入频道
    • 自己加入频道的通知
    • 其他用户加入频道的通知
    • 倒计时通知
  • 操作视频
    • 发送本地视频
    • 停止发送本地视频
    • 其他用户开启视频的通知
    • 订阅其他用户的视频
    • 订阅视频结果通知
    • 视频首帧的通知
    • 取消订阅其他用户的视频
  • 操作声音
    • 发送本地声音
    • 停止发送本地声音
    • 静音
    • 取消静音
    • 其他用户开启声音的通知
    • 订阅其他用户的声音
    • 订阅声音结果通知
    • 收到其他用户声音的通知
    • 取消订阅其他用户的声音
  • 离开频道
    • 离开频道
    • 其他用户离开频道的通知
  • SDK API 指南
  • 示例代码
浙ICP备20002645号 Copyright ©2020 拍乐云. All Rights Reserved