一个让我欲罢不能的 GitHub 开源项目!
自 2015 年的千播大战至今,社交直播已经衍生出很多不同的玩法了。传统的简单 “你说我听”,已经再基础不过,又很难给观众带来 “刺激” 的形式了。你要是看过现在的直播,什么多人连麦、主播 PK、虚拟主播,玩法越来越多。现如今,如果能了解怎么开发其中一个直播场景,绝对能给自己的简历加分。
但问题是,实时音视频技术背后有非常多的坑,很难有一个人能从后端到前端自研出来一套直播系统。而通过调用不同的 API 来搭建是最佳的实践途径。
最近在 GitHub 上就有这样一个新的开源项目,它实现了单主播直播、多人连麦直播、PK 直播、虚拟主播,四种现在社交直播领域最成熟的场景。
Github URL:https://github.com/AgoraIO-usecase/agoralive
这个项目原本是声网 Agora 开发的「Agora Live」,是作为一个 Demo 提供给用户来体验不同互动直播场景而开发的。近期这个应用不仅升级了,重新设计了 UI,而且开源了出来。
大家完全可以参考这个应用做个自己的社交直播应用。(他们每个月都给每个开发者提供 10000 分钟免费用量)。
图:新版 Aogra Live(iOS)截图
当然了,你在苹果 App Store 也能搜到这个应用,Android 用户也可以在声网官网找到下载链接,或者自己用 GitHub 的源码编译一份也行,只是需要替换其中的 AppID 为自己的。
它实现的那些热门场景
新版 Agora Live 目前已经支持四种时下最热门的实时互动场景,包括:
- 单主播直播场景:这是 Agora Live 最初就支持的功能,支持美颜、文字消息、添加背景音乐等功能。
- 多人连麦直播场景:在直播的基础上,还可邀请另外 6 名观众进行连麦。
- PK 直播场景:就像大家在陌陌、抖音等应用中看到的 PK 直播一样,主播可以向另一个主播发起 PK 邀请。两个直播间的观众会同时看到两个主播在线互动。
- 虚拟主播场景:与单主播直播场景类似,只不过 App 会为主播生成一个实时的虚拟形象,虚拟形象的表情会与主播同步。在直播过程中,还可以邀请观众上麦。
App 中所有音视频实时互动与文字消息、控制指令(如邀请上麦),都是基于声网 Agora Native SDK 、声网 Agora 实时消息 RTM SDK 实现的。
核心功能的实现
下面以 Swift 代码为例。
这个示例中,直播间、房主与观众连麦,都是基于声网 Agora Native SDK 实现的。我们通过以下代码可以让用户加入 RTC 频道,实现音视频的互通。
func join(channel: String, token: String? = nil, streamId: Int, success: Completion = nil) {
agoraKit.join(channel: channel, token: token, streamId: streamId) { [unowned self] in
self.channelStatus = .ing
if let success = success {
success()
}
}
}
在直播间中的文字消息、控制指令(比如邀请观众上麦)等,都是基于 Agora 实时消息 RTM SDK 实现的。在这里我们集成 RTM SDK 后,通过以下代码让用户加入 RTM 频道。
func joinChannel(_ id: String, delegate: AgoraRtmChannelDelegate, success: Completion, fail: ErrorCompletion) {
do {
let channel = try createChannel(id: id, delegate: delegate)
channel.join { (errorCode) in
switch errorCode {
case .channelErrorOk:
self.log(info: "rtm join channel success", extra: "channel id: (id)")
if let success = success {
success()
}
default:
let error = AGEError.rtm("join channel fail",
code: errorCode.rawValue,
extra: "channel: (id)")
self.log(error: error)
if let fail = fail {
fail(error)
}
}
}
} catch {
log(error: error, extra: "create channel fail")
if let fail = fail {
fail(error)
}
}
}
美颜与虚拟形象是通过接入 FaceUnity 的服务来实现的。可以结合 FUClient 这个类的实现与 FaceUnity 的文档来集成美颜模块。
typedef void (^FUCompletion)(void);
typedef void (^FUErrorCompletion)(NSError *error);
typedef NS_ENUM(NSUInteger, FUFilterItemType) {
FUFilterItemTypeSmooth = 1,
FUFilterItemTypeBrighten = 2,
FUFilterItemTypeThinning = 3,
FUFilterItemTypeEye = 4
};
@interface FUFilterItem : NSObject
@property (nonatomic, assign) FUFilterItemType type;
@property (nonatomic, assign) float defaultValue;
@property (nonatomic, assign) float minValue;
@property (nonatomic, assign) float maxValue;
@property (nonatomic, assign) float value;
@property (nonatomic, copy) NSString *funcName;
@end
@interface FUClient : NSObject
- (void)loadFilterWithSuccess:(FUCompletion)success fail:(FUErrorCompletion)fail;
- (void)setFilterValue:(float)value withType:(FUFilterItemType)type;
- (FUFilterItem *)getFilterItemWithType:(FUFilterItemType)type;
- (void)loadBackgroudWithSuccess:(FUCompletion)success fail:(FUErrorCompletion)fail;
- (void)loadAnimoji:(NSString *)name success:(FUCompletion)success fail:(FUErrorCompletion)fail;
- (void)renderItemsToPixelBuffer:(CVPixelBufferRef)pixelBuffer;
- (void)destoryAllItems;
@end
视频流从 AVCaptureSession 流出,流入 FaceUnity 进行前处理,然后进入 Agora RTC SDK 发送到远端。
func camera(_ camera: AGESingleCamera, position: AGECamera.Position, didOutput sampleBuffer: CMSampleBuffer) { cameraStreamQueue.async { [unowned self] in guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } CVPixelBufferLockBaseAddress(pixelBuffer, .init(rawValue: 0)) let timeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) if self.enhancement.beauty == .on || self.enhancement.appearance != .none { self.enhancement.renderItems(to: pixelBuffer) } self.consumer?.consumePixelBuffer(pixelBuffer, withTimestamp: timeStamp, rotation: .rotationNone) CVPixelBufferUnlockBaseAddress(pixelBuffer, .init(rawValue: 0)) } }
大家可以使用 GitHub 中的源码,在声网官网注册一个账号,在后台获取 AppID 后,替换掉源码中的 AppID 就可以了。
官方表示还将在接下来几个月对 repo 中的代码进一步梳理、优化,提升源码的易用性、可读性。而且,未来还会增加新的场景。
不论是想体验一下社交直播应用开发,还是想基于此做个自己的直播应用的童鞋,都可以去试试:
GitHub 地址:
https://github.com/AgoraIO-usecase/agoralive
- 网站每日PV/IP统计/总带宽/URL统计脚本分享(依据网站访问日志)
- 查看服务器系统资源(cpu,内容)利用率前几位的进程的方法
- 腾讯云平台部总经理陈磊:大数据背后的技术支撑
- DataSet与Xml相互转化
- SqlTransaction事务使用示例
- nginx的web缓存服务环境部署记录
- nginx反向代理+缓存开启+url重写+负载均衡(带健康探测)的部署记录
- [转自blueidea]像table一样布局div Ⅰ
- 如何对动态创建控件进行验证以及在Ajax环境中的使用
- 升级个人网站框架组件IBatisNet+Castle
- 如何在多线程中调用winform窗体控件
- gerrit代码简单备份方案分享
- svn代码发版的脚本分享
- 正则表达式提取指定内容
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 奇技淫巧:在 ssh 里面把服务器的文本复制到本地电脑
- 【计算机网络】学习笔记,第一篇:概述(谢希仁版)
- 【Objective-C】Objective-C语言的动态性
- Python解构与封装
- 关于内网穿透:NPS神器
- 【填坑系列】Python习题集
- Facebook 新一代 React 状态管理库 Recoil
- Adminer 简单的利用
- Xserver免脱壳解密APP
- Flask 入门系列教程(三)
- 数据分析入门系列教程-微博热点
- 数据分析入门系列教程-常用图表
- PyTorch中的model.zero_grad() vs optimizer.zero_grad()
- Flask 入门系列教程(四)
- 代码审计