首先声明本文是Agora SDK入门的小白文章


一.集成

1.注册账号创建项目

其中最重要的要数 App ID 了


2.下载Agora SDK

二、学会看示例代码(可跳过)

1.整体了解项目结构(1v1的视频通信示例)

以前看一个Android项目先看AndroidManifest.xml,我更喜欢先把文件夹内的结构树打印出来
打印文件夹内的结构树可详见:杂篇-从整理文件发起的杂谈[-File-]

|---app|---.gitignore|---build.gradle|---libs|---PLACEHOLDER|---proguard-rules.pro|---src|---main|---AndroidManifest.xml|---java|---io|---agora|---tutorials1v1vcall|---VideoChatViewActivity.java|---jniLibs|---arm64-v8a|---PLACEHOLDER|---armeabi-v7a|---PLACEHOLDER|---x86|---PLACEHOLDER|---res|---drawable-xxxhdpi|---btn_end_call.png|---btn_mute.png|---btn_switch_camera.png|---btn_video.png|---btn_voice.png|---ic_launcher.png|---layout|---activity_video_chat_view.xml|---values|---colors.xml|---dimens.xml|---strings.xml|---styles.xml
|---build.gradle
|---gradle|---wrapper|---gradle-wrapper.jar|---gradle-wrapper.properties
|---gradle.properties
|---gradlew
|---gradlew.bat
|---images|---ActivityViewChat.png
|---LICENSE.md
|---README.md
|---README.zh.md
|---settings.gradle
复制代码

2.查看最项目的settings.gradlebuild.gradle(最外层)

如果你想导入AS中查看,可以看一下com.android.tools.build:gradle的版本修改一下

---->[settings.gradle]----------------看一下项目包含的模块------------
include ':app'---->[build.gradle]----------------看一下项目的一些信息------------
buildscript {repositories {jcenter()google()}dependencies {classpath 'com.android.tools.build:gradle:3.1.4'}
}
allprojects {repositories {jcenter()google()}
}
task clean(type: Delete) {delete rootProject.buildDir
}
复制代码

3.查看模块下的build.gradle
---->[app/build.gradle]----------------看一下项目的具体信息------------
apply plugin: 'com.android.application'
android {compileSdkVersion 26defaultConfig {applicationId "io.agora.tutorials1v1vcall"minSdkVersion 16targetSdkVersion 26versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}sourceSets {//这里是jniLibs的目录main {jniLibs.srcDirs = ['../../../libs']}}
}dependencies {//这里是依赖implementation fileTree(dir: '../../../libs', include: ['*.jar']) // DO NOT CHANGE, CI may needs it when packagingimplementation 'com.android.support:appcompat-v7:26.1.0'
}
复制代码

4.查看AndroidManifest.xml,得到入口Activity

可见示例的入口是VideoChatViewActivity,并看一下权限

<activityandroid:name=".VideoChatViewActivity"android:screenOrientation="sensorPortrait"android:theme="@style/FullScreenVideoTheme"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>|--- 权限 ------------
<!--网络权限-->
<uses-permission android:name="android.permission.INTERNET"/>
<!--录音权限-->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!--更改录音设置-->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<!--网络状态权限-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--相机权限-->
<uses-permission android:name="android.permission.CAMERA"/>
<!--蓝牙权限-->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--SD卡写权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
复制代码

三、创建IChat项目


1、配置项目

项目的配置如图,将依赖包以及.so文件放在对应位置

为了方便些,将res文件夹的资源拷贝一下


2、配置APP ID

3.视频通话Activity的分析

一共也就200多行,还包括一大坨权限申请的代码,这里权限申请的代码单独拎出来,就当复习一下。

3.1:权限申请(非要点,可忽略)
---->[成员变量]----------------------------------
private static final int PERMISSION_REQ_ID = 22;
//WRITE_EXTERNAL_STORAGE 权限只是为了保存日志到SD卡
private static final String[] REQUESTED_PERMISSIONS = {Manifest.permission.RECORD_AUDIO,//录音权限Manifest.permission.CAMERA,//相机权限Manifest.permission.WRITE_EXTERNAL_STORAGE//SD卡写权限
};if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID) &&checkSelfPermission(REQUESTED_PERMISSIONS[2], PERMISSION_REQ_ID)) {//执行到此处说明已有权限成功     initAgoraEngineAndJoinChannel();
}/*** 检查权限的方法** @param permission  权限* @param requestCode 请求码* @return 是否拥有权限*/
public boolean checkSelfPermission(String permission, int requestCode) {Log.i(LOG_TAG, "checkSelfPermission " + permission + " " + requestCode);if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {//发送权限请求ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);return false;}return true;
}@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {Log.i(LOG_TAG, "onRequestPermissionsResult " + grantResults[0] + " " + requestCode);switch (requestCode) {case PERMISSION_REQ_ID: {//请求码if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||grantResults[1] != PackageManager.PERMISSION_GRANTED ||grantResults[2] != PackageManager.PERMISSION_GRANTED) {//三个权限有任意的未被允许,弹吐司,退出showLongToast("Need permissions " +Manifest.permission.RECORD_AUDIO + "/" +Manifest.permission.CAMERA + "/" +Manifest.permission.WRITE_EXTERNAL_STORAGE);finish();break;}//执行到此处说明用户已允许权限initAgoraEngineAndJoinChannel();break;}}
}
复制代码

4.初始化Agora引擎和连接频道
/*** 初始化Agora引擎和连接频道*/
private void initAgoraEngineAndJoinChannel() {initializeAgoraEngine();//初始化Agora引擎setupVideoProfile();//设置视频信息setupLocalVideo();//设置本地的视频窗joinChannel();//连接频道
}/*** 初始化Agora引擎*/
private void initializeAgoraEngine() {try {mRtcEngine = RtcEngine.create(//实例化Rtc引擎getBaseContext(),//传入Context getString(R.string.agora_app_id), //传入APP IDmRtcEventHandler);//RTC事件处理器} catch (Exception e) {//发生异常时捕获异常Log.e(LOG_TAG, Log.getStackTraceString(e));throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));}
}/*** 设置视频信息*/
private void setupVideoProfile() {mRtcEngine.enableVideo();//启用视屏mRtcEngine.setVideoEncoderConfiguration(//视频解码配置new VideoEncoderConfiguration(//实例化对象VideoEncoderConfiguration.VD_120x120,//尺寸VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,//帧率VideoEncoderConfiguration.STANDARD_BITRATE,//比特率VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));//旋转模式
}
|---关于VideoEncoderConfiguration对象---->[VideoEncoderConfiguration构造方法]------------------public VideoEncoderConfiguration(VideoEncoderConfiguration.VideoDimensions dimensions, //尺寸VideoEncoderConfiguration.FRAME_RATE frameRate,//帧率 int bitrate, //比特率VideoEncoderConfiguration.ORIENTATION_MODE orientationMode)//旋转模式/*** 设置本地视频窗*/
private void setupLocalVideo() {FrameLayout container = findViewById(R.id.local_video_view_container);//FrameLayout视图SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());//创建SurfaceViewsurfaceView.setZOrderMediaOverlay(true);container.addView(surfaceView);mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0));
}/*** 连接到频道*/private void joinChannel() {mRtcEngine.joinChannel(null, "demoChannel1", "Extra Optional Data", 0);// 如果你不指定 uid(第四参), 我们会为你生成一个 uid}
复制代码

5.RTC事件处理器:IRtcEngineEventHandler

IRtcEngineEventHandler是一个抽象类,定义了非常多的抽象方法还有一些静态内部类

private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {@Override//已完成远端视频首帧解码回调。public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {runOnUiThread(() -> setupRemoteVideo(uid));}@Override//远端用户(通信模式)/主播(直播模式)离开当前频道回调。public void onUserOffline(int uid, int reason) {runOnUiThread(() -> onRemoteUserLeft());}@Override//远端用户静音回调。public void onUserMuteVideo(final int uid, final boolean muted) {runOnUiThread(() -> onRemoteUserVideoMuted(uid, muted));}
};/*** 根据uid设置远端视频* @param uid 唯一标识符*/
private void setupRemoteVideo(int uid) {FrameLayout container = findViewById(R.id.remote_video_view_container);if (container.getChildCount() >= 1) {return;}SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());container.addView(surfaceView);mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, usurfaceView.setTag(uid); // 用uid为surfaceView打标签View tipMsg = findViewById(R.id.quick_tips_when_use_agora_sdk); // 隐藏文字UItipMsg.setVisibility(View.GONE);
}/*** 远端用户挂断*/
private void onRemoteUserLeft() {FrameLayout container = findViewById(R.id.remote_video_view_container);container.removeAllViews();View tipMsg = findViewById(R.id.quick_tips_when_use_agora_sdk); // 显示文字UItipMsg.setVisibility(View.VISIBLE);
}/*** 远端用户静音* @param uid 标识符* @param muted 是否静音*/
private void onRemoteUserVideoMuted(int uid, boolean muted) {FrameLayout container = findViewById(R.id.remote_video_view_container);SurfaceView surfaceView = (SurfaceView) container.getChildAt(0);Object tag = surfaceView.getTag();if (tag != null && (Integer) tag == uid) {surfaceView.setVisibility(muted ? View.GONE : View.VISIBLE);}
}
复制代码

6.几个点击事件
/*** 是否屏蔽视频* @param view*/
public void onLocalVideoMuteClicked(View view) {ImageView iv = (ImageView) view;if (iv.isSelected()) {iv.setSelected(false);iv.clearColorFilter();} else {iv.setSelected(true);iv.setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);}mRtcEngine.muteLocalVideoStream(iv.isSelected());//核心的一句API,FrameLayout container = findViewById(R.id.local_video_view_container);SurfaceView surfaceView = (SurfaceView) container.getChildAt(0);surfaceView.setZOrderMediaOverlay(!iv.isSelected());surfaceView.setVisibility(iv.isSelected() ? View.GONE : View.VISIBLE);
}/*** 是否静音* @param view*/
public void onLocalAudioMuteClicked(View view) {ImageView iv = (ImageView) view;if (iv.isSelected()) {iv.setSelected(false);iv.clearColorFilter();} else {iv.setSelected(true);iv.setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);}mRtcEngine.muteLocalAudioStream(iv.isSelected());//核心的一句API,
}/*** 切换摄像头* @param view*/
public void onSwitchCameraClicked(View view) {mRtcEngine.switchCamera();
}/*** 关闭* @param view*/
public void onEncCallClicked(View view) {finish();
}@Overrideprotected void onDestroy() {super.onDestroy();leaveChannel();//离开频道RtcEngine.destroy();//引擎销毁mRtcEngine = null;//引擎置空}/*** 离开频道*/
private void leaveChannel() {mRtcEngine.leaveChannel();
}
复制代码

[番外]:我与网络(个人感触,不想看,可略过,嘻嘻...)

1.我与网络的初遇

记得第一次接触网络是在高二的时候(2011年),那时候手机还是键盘式的,貌似每月有100M流量
印象很深,当时用手机上网查了"GPRS流量"是什么意思? 看得我一头雾水, 一直没弄明白。
那时好像超过1M收一元钱,所以流量对我来说很宝贵。通过不断测试(用网+短信查询):

1.它和网络有关
2.只要上网,GPRS流量就会减少
3.文字消耗的流量很少,图片消耗的流量较多
4.下载多大的文件就会消耗多大的GPRS流量
5.进制1M=1024KB ; 1KB = 1024B
复制代码

2.时代的变迁

那时主要的沟通方式就是短信,一个月500条免费的短信都不够发
当时觉得用手机可以打电话,发短信是一件多么神奇和美好的事
也曾幻想过用手机视频通话,但感觉就像在痴人说梦,然而技术的发展往往令人惊叹。

高考之后(2012年)的暑假,在一个好友家里建了一个QQ号,起名"张风杰特烈"(后更名"张风捷特烈")
从此之后我的手机基本和打电话,发短信无缘了。可以说是打开了新世界的大门吧。
之后手机换了一部又一部,屏幕越来越大,流量也从100M变成了200M,之后 500M, 2G, 流量无限量
有了自己的笔记本电脑,自己捯饬连上了路由器,自此WIFI成了相依为命的伙伴,流量也不是我
一年前还是个连流量都不知道是什么的人,却能在短时间内融入这个网络时代,也许就是年轻人的优势吧
复制代码

很快,QQ就支持视频通话了,那遥不可及的梦如梦般降临,而我就这么幸运的站在梦中
由于我的专业需要使用很多软件,所以电脑玩的还算比较6的。但看到很早就接触电脑的人用起来却非常生涩
我曾对一个人说过:我抓住了时代的尾巴,正一点点先前攀爬,而身处时代中的人已停止不前


3.我与游戏

说到网络就不得不说游戏,这也是网络的双刃之处,很多人沉迷其中无法自拔
可以说作为一个94年的小伙子,我接触网络算非常晚的,因此什么魔兽世界,星际争霸都与我无缘

英雄联盟,王者荣耀什么的,看到小人跑我头都晕,一点兴趣都没有
大二吧,比较喜欢玩QQ飞车,玩的挺6的。后来被几个班里的"后起之秀"虐了,也逐渐没什么兴趣了
从小我就喜欢《游戏王》,所以卡牌对我来说是很有诱惑力的,特别是集卡和策略
所以玩过不少策略卡牌类的手游,[圣火英雄传],[召唤师对决],[六界],[神之刃]等
我一般都是V3,一段时间后,基本都是V9以下无敌手,然后成区霸,最后游戏倒闭, 关门大吉。
经历几次后,感觉也看淡了,都是些数据而已,也没必要去较真,也就不玩游戏了
复制代码

4.真正踏入网络时代

作为一名使用者,我可以贪婪的享受着网络中的一切便利,但我越来越感到,只是这样是不够的
网络对我来说仅是一个黑盒,它为我提供服务,我却对它一无所知,这让我感到困惑和恐惧
并不仅为此,我决定踏上编程之路,想要更深入一点去看待这个时代,而不止于使用者

当我的网站连同之时,整个互联网中有了一个属于我节点。也许是我真正踏入网络时代大门的那一刻
从那时,世界网络中[二进制流]的输入与输出便成了我对网络时代的认知,眼中的一切似乎都有所不同
打开一个网址,浏览器和服务器通过Http协议用请求与响应传输数据,数据在流动中加工,反馈,展现
通过前端、后端、移动端的涉猎,基本明白了是怎么回事。这并非神迹,而是大概有三个要点:
接口(协议)、逻辑(代码)、数据(bit流)
复制代码

Agora SDK 使用体验征文大赛 | 掘金技术征文,征文活动正在进行中

Agora SDK 在Android中的使用(在线视频通话)| 掘金技术征文相关推荐

  1. iOS 开发中的得力鲁班尺 - SnapKit | 掘金技术征文

    SnapKit 先来谈谈何为 DSL DSL(Domain Specific Language),即领域特定语言,指的是一种针对特定问题的编程语言,与此相对便是 GPL(General Purpose ...

  2. Android 集成 Agora SDK 快速体验 RTC 版多人视频聊天|掘金技术征文

    RTC (Real-Time Communication) 作为实时通讯领域的"新贵",在互动直播.远程控制.多人视频会议.屏幕共享等领域广受好评,如果你还不了解 RTC ,Tak ...

  3. Agora 在线语音聊天室开发上手和源码解读 | 掘金技术征文

    使用声网的在线语音聊天室 SDK 能够实现开黑聊天室.娱乐房间.K 歌房.FM 超高音质房等各种语音聊天室所需要的音频功能. 场景描述 语音聊天室 是一种纯音频的使用场景.用户作为主播或者听众加入房间 ...

  4. 视频讲解Agora视频通话SDK| 掘金技术征文

    最近比较忙,发了一篇Agora SDK 安卓端的使用的视频,大家直接看视频就可以撸码了. 本视频手把手带大家认识声网Agora视频通话SDK,然后在Android手机上面运行一个Demo,演示一下如何 ...

  5. 火眼金睛识别公司招聘中给你埋下的那些“坑”| 掘金技术征文

    版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请标明出处: juejin.im/post/5a5249- 本文出自 AWeiLoveAndroid的博客 [前言]又到了年末,有一些公司在招 ...

  6. 我是如何在天猫、蚂蚁金服、百度等大厂面试中被拒的 | 掘金技术征文

    本人16年毕业于普通二本院校网络相关专业,工作经验两年半,目前就职业于一家普通民营企业. 由于非985.211学历硬伤,校招进大厂的门槛远高于同届985.211的毕业生.于是乎,从毕业到现在经历了三家 ...

  7. 基于 Agora SDK 实现 Android 端的多人视频互动

    本系列教程将分为三期,分享基于 Agora SDK 在各系统平台应用中实现一对一视频通话.多人互动直播,以及结合跨平台技术进行开发.本期推送在 Android.iOS.Windows.Web.macO ...

  8. Android 中的数据储存方案, 持久化技术

    为什么80%的码农都做不了架构师?>>>    Android 中储存数据的方法主要有三种: 1,文件储存. 2,SharedPreference储存. 3,数据库储存. 1. 文件 ...

  9. 记录我杭州 Android 面试的经历 | 掘金技术征文

    前言 2017年四月下旬来到杭州,这段经历是四月到五月的,现在过去两个月了,情况可能有变,仅供参考.面试之后回去的公交地铁上,偶尔会在便携本上简单的记录一下(真的是简单记录,以至于现在距离我那时的面试 ...

最新文章

  1. 学习全基因组测序数据分析2:FASTA和FASTQ
  2. Android调用WebService系列之对象构建传递
  3. JoshChen判断是否微信内置浏览器访问【转载】
  4. 如何学好C、C++------思维方式的转变
  5. Luogu T16048 会议选址
  6. Web前端面试题集锦
  7. psa name_Windows 10安全性PSA:启用自动商店更新
  8. Shell入门(一)之简介
  9. Angular2 - Starter - NgModule
  10. 马云:成功与情商有关 与读书多少关系不大
  11. jquery页面隐藏和展开之间切换
  12. Android Content Providers(二)——Contacts Provider
  13. 对称函数、半正定矩阵(核函数涉及)
  14. linux脚本判断奇数偶数,Bash Shell -- 奇数 偶数 之和计算
  15. Tilera 64核处理器快速上手
  16. 两部苹果手机同步照片_如何将旧苹果手机音乐里面的歌曲同步到新苹果手机上...
  17. java函数参数使用冒号_java8中:: 用法示例(JDK8双冒号用法)
  18. 一台计算机多个显示,一台计算机如何有两个显示器并显示不同的内容?
  19. 小德张-清朝最后一位首领太监
  20. (转载)书蕴——基于书评的人工智能推荐系统

热门文章

  1. blender 创建脸部骨骼
  2. fclose函数的作用
  3. html滚动条实现,超简单
  4. 每日思考第 74 期:幸福的汉堡模型
  5. C++:排列组合算法
  6. java 泛域名_Apache和Tomcat 实现泛域名解析的尝试
  7. Xcode下的DerivedData文件路径
  8. 悟空与佛祖的经典对话
  9. Android平台上获取文件的MIME
  10. 分红 10 亿,小游戏《羊了个羊》背后实控人拿走 3亿 !股价暴跌 38%