在现在的移动互联网时代,音视频相关应用已经深刻到咱们平常生活的方方面面。java
而在它背后的音视频技术也是很是成熟了,短视频编辑、带货直播、视频语音通话等应用形式无不体现着音视频技术给咱们生活带来的便利。android
而此次就去实际体验一下,接入声网的音频 SDK ,并打造一个音视频通话应用。git
首先要作的就是在声网(https://www.agora.io/cn)上注册帐号,并完成实名认证。github
登陆以后就进到管理界面了,在左侧有一系列选项能够操做,直接进到项目管理,建立咱们的 VideoChat 项目。后端
在项目建立的安全模式上,选择 APPID + Token 的方式。为了提升项目的安全性,Agora 后续会取消对 APP ID 鉴权方案的支持。安全
当项目建立完成后就有了对应的 APP ID ,这个在后续代码开发中会用到的。微信
除此以外,咱们还须要生成 Token ,在项目管理页去生成一个临时 Token 。网络
这个临时 Token 是有时效的,仅供测试使用,若是有本身的后端开发,到生产环境再去生成正式 Token。一样,这个 Token 字符串在后续开发中也会用到的。架构
建立项目并准备好 APP ID 和 Token 以后,就能够在官网上下载音频 SDK 了。app
下载解压后的内容如上所示。libs 文件夹内有对应不一样 CPU 架构的 so 动态库,还有动态库对应的头文件以及 Java 版本的 Jar 包,可分别进行 C++ 版本和 Java 版本的集成。
这里就只用到 Java 版原本演示了,其实 Java 版本里面不少方法都是走到 native 调用了,而 native 调用的就是 so 动态库里面的方法。用 C++ 版本集成的话,还须要本身写 JNI 代码将 Java 与 C++ 链接起来,不如直接用 Java 版原本的快。
SDK 集成有两种方式,一种是直接使用 JCenter 来集成,在 build.gradle 里面添加一行代码就行。
dependencies { implementation 'io.agora.rtc:full-sdk:3.1.3' }
版本号能够在官网上查询,目前最新版本就是 3.1.3 了。
固然还能够经过加载 jar 包和 so 动态库的方式进行集成,把 agora-rtc-sdk.jar 和各版本 so 拷贝到对应目录下,以下图所示:
另外别忘了在 app 目录下的 build.gradle 中添加以下代码:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) }
少了这行代码,可解析不到添加的 jar 包。
以上,就完成了整个 SDK 的工程接入,接下来就是代码开发环节了。
咱们要开发的是一款音视频通话应用,就像微信视频同样,想一想会有哪些内容。
首先要经过 Camera 采集咱们的画面,而后经过麦克风录制咱们的声音,再经过网络传输给到对方,而且可以听到对方的声音,在屏幕上显示画面。
想想这些内容要是纯 Android 开发的话,那涉及的东西可多了,四五我的都不必定能 hold 住,而使用专业的音视频 SDK ,一我的就能搞定大部分工做了。
接下来就要去完成这样的开发工做,具体代码能够在 Github 上获取:
https://github.com/glumes/ago...
首先是权限申请,涉及到 Camera、网络、存储、录制等等内容,在官网上也有给出具体权限列表,以下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.agora.tutorials1v1acall"> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> // 若是你的场景中涉及读取外部存储,需添加以下权限: <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> // 若是你使用的是 Android 10.0 及以上设备,还须要添加以下权限: <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> ... </manifest>
具体代码可见 Github :
接下来就是建立 RtcEngine ,SDK 的不少方法都是经过 RtcEngine 来调用的。
// 声明 RtcEngine private RtcEngine mRtcEngine; // 建立 RtcEngine private void initializeEngine() { try { mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler); } catch (Exception e) { Log.e(TAG, Log.getStackTraceString(e)); throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e)); } }
在建立 RtcEngine 的时候须要用到 APP ID ,前面已经提过,在建立项目时就已经有了。
最后一个参数是 mRtcEventHandler
,它是一个 IRtcEngineEventHandler
类型的抽象类,类里面定义了不少方法,去响应 RtcEngine 不一样状态的回调,好比链接成功,链接失败、加入频道、离开频道、网络状态改变等等。若是有须要对应用的性能作一些监视,那么就能够在 IRtcEngineEventHandler 的回调方法作相关统计和埋点。
RtcEngine 把 Camera 相关操做都封装在 SDK 内了,经过几行代码就能实现 Camera 画面预览。
首先要有一个控件去承接显示 Camera 的画面输出内容,能够用 SurfaceView 也能够用 TextureView ,但并不须要咱们去建立控件,而是用 Agora SDK 提供的方法。
// 使用 SurfaceView 的场景 SurfaceView mLocalView = RtcEngine.CreateRendererView(getBaseContext()); // 使用 TextureView 的场景 TextureView mLocalView = RtcEngine.CreateTextureView(getBaseContext());
TextureView 是 Agora SDK 在 3.1.0 版本才提供的,它与 SurfaceView 的区别在于 TextureView 能够对画面进行缩放、旋转和平移,而 SurfaceView 更适合在视频通话和直播场景使用。
有了显示的 View 以后,要把它添加到当前 Activity 的控件树上,后面 Camera 画面就会输出到这里。
接下来就是让 Camera 输出画面了,可实际上不用写一行关于 Camera 的代码,三行代码就能够搞定。
// 开启视频 mRtcEngine.enableVideo(); // 初始化本地视图 mRtcEngine.setupLocalVideo(new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN, 0)); // 开启预览 mRtcEngine.startPreview();
经过以上代码就能在屏幕上显示咱们的画面了,默认是前置摄像头的内容。
具体代码可见 Github :
在代码开发中,首先要启用视频模块,默认是关闭的,经过 disableVideo 也能够关闭。而音频模块默认就是开启的,也能够经过 enableAudio 和 disableAudio 来开启关闭音频模块。
以后就是经过 setupLocalVideo 方法来初始化本地视图,主要是设置本地用户视频信息的,也就是咱们的画面要在 SurfaceView 中如何显示,配置信息都是经过 VideoCanvas 类下发的,它有多种参数类型。
// VideoCanvas 构造函数类型 VideoCanvas (View view) VideoCanvas (View view, int renderMode, int uid) VideoCanvas (View view, int renderMode, String channelId, int uid) VideoCanvas (View view, int renderMode, int uid, int mirrorMode) VideoCanvas (View view, int renderMode, String channelId, int uid, int mirrorMode)
其中 renderMode 就是指定咱们的画面在 SurfaceView 如何显示,有以下类型:
RENDER_MODE_HIDDEN
RENDER_MODE_FIT
RENDER_MODE_FILL
默认状况下都是使用 RENDER_MODE_HIDDEN 模式的。另外还有 mirrorMode 这样的属性来设置是否要画面镜像。
完成了画面显示配置以后,直接调用 startPreview 就能在屏幕上看到画面啦,是否是很简单!
简单的背后实际上是 Agora SDK 作了不少封装工做,好比 Camera1 和 Camera2 的调用逻辑、Camera 输出的分辨率策略、先后摄像头选择等等。
咱们能够在开启预览前经过 setCameraCapturerConfiguration 方法来配置本身想要的 Camera 信息。
// 配置 Camera 信息 mRtcEngine.setCameraCapturerConfiguration(new CameraCapturerConfiguration(CAPTURER_OUTPUT_PREFERENCE_AUTO,CAMERA_FRONT));
Camera 参数信息主要是在 CameraCapturerConfiguration 类中,它的两个参数都是枚举类型,其中第二个参数指定了使用前置仍是后置摄像头。
第一个参数就是关于 Camera 输出分辨率的一些策略,Agora SDK 并无给出接口让咱们指定 Camera 输出宽是多少,长是多少,并且根据使用场景组合了三个策略,更方面咱们去调用了。
CAPTURER_OUTPUT_PREFERENCE_AUTO
CAPTURER_OUTPUT_PREFERENCE_PERFORMANCE
CAPTURER_OUTPUT_PREFERENCE_PREVIEW
经过以上操做,就完成了 Camera 画面预览显示。
接下来就要去加入一个频道,并和同一频道内的朋友进行通讯。
// 函数原型 joinChannel ( String token,String channelName,String optionalInfo,int optionalUid) // 具体调用 private void joinChannel() { // 获得 Token String token = getString(R.string.agora_access_token); // Token 和 频道名要匹配 mRtcEngine.joinChannel(token, "demoChannel1", "", 0); }
经过 joinChannel
方法加入,其中 token 就是咱们以前建立好的,而频道名称也是建立 token 时指定的,这二者要匹配起来。optionalInfo 是可选的字符串。optionalUid 是用户 ID,也是可选项,若是不指定(设为 0),SDK 会自动分配一个,并在 onJoinChannelSuccess 回调方法中返回。
当咱们加入频道成功后,会回调 IRtcEngineEventHandler 中的 onJoinChannelSuccess 方法。
经过 leaveChannel
方法,咱们能够离开当前频道,一样会回调 IRtcEngineEventHandler 中的 onLeaveChannel 方法。
加入频道后,咱们就要和频道内的朋友们通讯。要把咱们的画面和声音发送给对方,那确定要将数据进行编码,而后通过网络传输送给对方。
注意:音频和视频的参数都必定要在加入频道前设定好,也就是 joinChannel 方法调用以前,在其以后调用是不生效的。
这里咱们要指定视频编码的分辨率、帧率、码率、视频等信息,经过 setVideoEncoderConfiguration
方法。
mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration( // 视频分辨率 VideoEncoderConfiguration.VD_640x360, // 帧率 VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15, // 码率 VideoEncoderConfiguration.STANDARD_BITRATE, // 视频方向 VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
在更早的 Agora SDK 版本中是经过 setVideoProfile 来设定的,还能够指定具体的宽高、帧率数值。
最新版本换成了 VideoEncoderConfiguration 来配置,而且配置的参数是都已经定义好了相关的常量,不用本身写 720、1280 这样的 Magic Number 了。
参数的设置并非一成不变的,由于网络或者性能等因素会有一些波动,但仍是会取最接近咱们设定的值。
而音频相关的参数,则是经过 setAudioProfile
方法来设置。
mRtcEngine.setAudioProfile( // 设置音频采样率、码率、编码模式和声道数 Constants.AudioProfile.DEFAULT.ordinal(), // 设置音频的应用场景 Constants.AudioScenario.DEFAULT.ordinal());
音频咱们能够设置采样率、码率、编码模式以及声道数。和视频参数设置同样,咱们不用指定具体的数值,Agora SDK 都根据业务使用场景作了封装,根据须要来设置就好啦。
音频 AudioProfile 有以下的配置:
DEFAULT
SPEECH_STANDARD
MUSIC_STANDARD_STEREO
MUSIC_HIGH_QUALITY
MUSIC_HIGH_QUALITY_STEREO
音频的应用场景也有以下:
DEFAULT
CHATROOM_ENTERTAINMENT
EDUCATION
GAME_STREAMING
SHOWROOM
CHATROOM_GAMING
通常来讲,咱们使用默认的配置 DEFAULT 就行了。
当设置好了本身的数据编码参数,而且也成功加入了频道,接下来就是去接收频道内其余人的画面和信息了。
具体代码可见 Github:
当 IRtcEngineEventHandler 中的 onUserJoined 方法回调时,表明有人加入了当前频道,此时就能够创建并初始化远端用户视图了。
若是启用了视频录制功能,视频录制服务也会回调 onUserJoined 方法,至关于有个机器人加入该频道,此时要区分开来,不能为机器人创建远端视频,而后它不会发送视频流的,创建了也是黑屏的。
为了不机器人加入带来的误判,在 2.9.0 版本后更建议在 onRemoteVideoStateChanged 方法回调中去创建远端用户视图。
onRemoteVideoStateChanged 方法顾名思义就是当远端用户状态发生改变时就会调用,其中定义了以下几个状态:
REMOTE_VIDEO_STATE_STARTING
REMOTE_VIDEO_STATE_DECODING
REMOTE_VIDEO_STATE_STOPPED
REMOTE_VIDEO_STATE_FROZEN
REMOTE_VIDEO_STATE_FAILED
当状态是 REMOTE_VIDEO_STATE_STARTING 或者 REMOTE_VIDEO_STATE_DECODING 时,咱们认定有朋友加入频道了,此时创建远端用户视图。
@Override public void onRemoteVideoStateChanged(final int uid, int state, int reason, int elapsed) { if (state == Constants.REMOTE_VIDEO_STATE_STARTING){ runOnUiThread(new Runnable() { @Override public void run() { setupRemoteVideo(uid); } }); } }
其中 onRemoteVideoStateChanged 回调方法中 state 参数表明状态,uid 用来标识远端用户 id,若是有多个朋友加入了该频道,咱们就要用 uid 来区分一下用户,避免漏了或者重复创建远端用户视图。
接下来创建远端用户视图,和创建 Camera 预览视图方法基本一致。
// 由 Agora SDK 建立 SurfaceView mRemoteView = RtcEngine.CreateRendererView(getBaseContext()); // 把 SurfaceView 添加到当前 Activity 的布局控件树上 mRemoteContainer.addView(mRemoteView); // Camera 画面预览就用 setupLocalVideo 方法,远端用户就用 setupRemoteVideo 方法 mRtcEngine.setupRemoteVideo(new VideoCanvas(mRemoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
一样是由 Agora SDK 去建立 SurfaceView ,把它添加到控件容器上,最后经过 setupRemoteVideo 方法完成创建,整个逻辑和 Camera 视图创建是相似的,就是最后调用的方法不同了。
当创建好了远端用户视图,理论上如今就能够显示本身和对方的画面了,并互相听到声音了。
用两台手机分别运行程序,能够验证效果以下:
另外在官网上还能够查看当前项目的流量使用状况:
每月有 10000 分钟的流量赠送,能够放心使用
经过以上的 SDK 接入和代码示例就已经完成了一个简单的双人音视频通话。
而 Agora SDK 提供的功能远非如此。
咱们还能够对当前频道的音视频进行控制,选择是否静音、是否关闭画面等等;咱们还能够切换频道,参与频道的通话;咱们还能够将项目打形成多人的音视频通话,为每一个加入频道的用户创建远端视图。
更多的音视频相关功能均可以经过 Agora SDK 来实现了。
总结一下总体的接入流程也是很是方便的:
SDK 集成 -> 权限设置 -> Camera 预览 -> 加入频道 -> 显示画面 -> 在线通话
以上的每一个步骤在文章中都有讲解,但愿在你的使用过程当中会有一些帮助!!!