本文介绍如何建立一个简单的 Cocos2d-x 项目并集成声网音频 SDK,搭建一个具备基础音频直播功能的 iOS 应用。
安装了 iOS 9.0 或以上版本的设备。部分模拟机可能存在功能缺失或者性能问题,所以推荐使用真机。
有效的声网开发者账号。
本节介绍如何使用 Cocos2d-x 命令行工具创建一个新项目。
前往 Cocos2d-x 下载页面,选择任意版本的 Cocos2d-x 引擎,下载并解压。
解压后,运行根目录下的 setup.py
脚本文件,将 cocos
命令添加到环境变量。
你可以在终端运行 cocos -v
,检查 cocos
命令行工具是否已经成功添加到环境变量。若配置成功,会出现如下输出:
cocos2d-x-3.17.2
Cocos Console 2.3
使用 cocos new
命令创建新项目,命令格式如下:
cocos new <game name> -p <package identifier> -l <language> -d <location>
其中:
<game name>
:设置项目名称。
-p <package identifier>
:设置项目的包名,格式为 com.MyCompany.MyGame
,例如 io.agora.gaming.cocos2d
。
-l <language>
:设置项目使用的编程语言,可选值包括 cpp
,lua
和 js
。要集成声网 SDK,<language>
必须设为 cpp
。
-d <location>
:设置项目存放路径。
cocos
命令工具创建项目的更多信息,详见 cocos 命令。前往下载页面,下载最新版的声网音频 SDK 并解压。
在项目根目录下创建 sdk
文件夹,用于存放声网音频 SDK。你可以按照如下结构创建文件夹:
└─sdk
├─android
│ ├─agora
│ └─lib
└─ios
└─agora
./sdk/ios/agora
路径替换成你的声网 SDK 存放路径。将 audio/libs/ios
文件夹下的以下动态库复制到 ./sdk/ios/agora
文件夹下:
AgoraRtcKit.framework
Agorafdkaac.framework
Agoraffmpeg.framework
AgoraSoundTouch.framework
audio/libs/ios/ALL_ARCHITECTURE
文件夹下的上述动态库复制到 ./sdk/ios/agora
文件夹下。该路径下的动态库包含 x86-64 架构,会影响 app 在 App Store 的发布,你需要在将 app 发布至 App Store 前移除 x86-64 架构。根据场景需要,在 ./proj.ios_mac/ios/info.plist
文件中,添加如下内容,获取相应的设备权限:
<key>NSMicrophoneUsageDescription</key>
<string>Microphone</string>
现在,你可以在调用声网音频 SDK 提供的核心 API 实现基础的音频直播。
在 HelloWorldScene.h
文件中导入类,并添加变量与函数的声明。
导入 AgoraRtcKit
和 IAgoraRtcEngine
类。
#ifdef __APPLE__
#include <AgoraRtcKit/IAgoraRtcEngine.h>
#elif __ANDROID__
#include "IAgoraRtcEngine.h"
#endif
定义 App ID 和 Token。
在创建并初始化 IRtcEngine
对象时,你需要传入你的声网项目的 App ID。详见获取 App ID。
为提高项目的安全性,你需要使用 Token(动态密钥)对即将加入频道的用户进行鉴权。
// 将 <#YOUR APP ID#> 替换成你的声网项目的 App ID,并加引号,如 "xxxxx"。
#define AGORA_APP_ID <#YOUR APP ID#>
// 将 <#YOUR TOKEN#> 替换成你自己生成的 Token,并加引号,如 "xxxxx"。
#define AGORA_TOKEN <#YOUR TOKEN#>
添加函数声明。
class HelloWorld : public cocos2d::Scene {
public:
static cocos2d::Scene *createScene();
bool init() override;
// 进入 HelloWorld 场景的回调。
void onEnter() override;
// 离开 HelloWorld 场景的回调。
void onExit() override;
...
private:
// 点击加入频道按钮的回调。
void onJoinChannelClicked();
// 点击离开频道按钮的回调。
void onLeaveChannelClicked();
private:
cocos2d::ui::EditBox *editBox;
agora::rtc::IRtcEngine *engine;
agora::rtc::IRtcEngineEventHandler *eventHandler;
std::map<uid_t, bool> users;
};
根据场景需要,为你的项目创建音频直播的用户界面。
声网推荐你添加如下用户界面元素:
你可以参考声网示例项目 Cocos2d-x, 在 HelloWorldScene.cpp
中添加如下代码,创建用户界面元素并定义点击事件处理函数:
频道名输入框
// 创建一个输入框,用于获取用户输入的频道名,并在加入频道时调用。
// 你需要自行将 TextBox.png 图片添加到 ./Resources 文件夹中。
auto editBox = cocos2d::ui::EditBox::create(Size(120, 30), "TextBox.png");
if (editBox==nullptr) {
problemLoading("'TextBox.png'");
} else {
editBox->setPlaceHolder("Channel ID");
editBox->setPosition(Vec2(origin.x + leftPadding + editBox->getContentSize().width/2,
origin.y + visibleSize.height
- editBox->getContentSize().height*1.5f));
this->addChild(editBox, 0);
}
加入频道按钮
// 创建加入频道按钮。当按钮被点击时,会触发 onJoinChannelClicked() 函数。
// 你需要自行将 Button.png 和 ButtonPressed.png 图片添加到 ./Resources 文件夹中。
auto joinButton =
cocos2d::ui::Button::create("Button.png", "ButtonPressed.png", "ButtonPressed.png");
if (joinButton==nullptr) {
problemLoading("'Button.png' and 'ButtonPressed.png'");
} else {
joinButton->setTitleText("Join Channel");
joinButton->setPosition(Vec2(origin.x + leftPadding + joinButton->getContentSize().width/2,
origin.y + visibleSize.height
- 1*joinButton->getContentSize().height
- 2*editBox->getContentSize().height));
joinButton->addTouchEventListener([&](cocos2d::Ref *sender, ui::Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:break;
case ui::Widget::TouchEventType::ENDED:onJoinChannelClicked();
break;
default:break;
}
});
this->addChild(joinButton, 0);
}
离开频道按钮
// 创建离开频道按钮。当按钮被点击时,会触发 onLeaveChannelClicked() 函数。
auto leaveButton = ui::Button::create("Button.png", "ButtonPressed.png", "ButtonPressed.png");
if (leaveButton==nullptr) {
problemLoading("'Button.png' and 'ButtonPressed.png'");
} else {
leaveButton->setTitleText("Leave Channel");
leaveButton->setPosition(Vec2(origin.x + leftPadding + leaveButton->getContentSize().width/2,
origin.y + visibleSize.height
- 2*leaveButton->getContentSize().height
- 2*editBox->getContentSize().height));
leaveButton->addTouchEventListener([&](cocos2d::Ref *sender, ui::Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:break;
case ui::Widget::TouchEventType::ENDED:onLeaveChannelClicked();
break;
default:break;
}
});
this->addChild(leaveButton, 0);
}
在调用其他声网 API 前,需要创建并初始化 IRtcEngine
对象。调用 createAgoraRtcEngine
和 initialize
方法,传入获取到的 App ID,即可初始化 IRtcEngine
。
class MyIGamingRtcEngineEventHandler : public agora::rtc::IRtcEngineEventHandler {
private:
HelloWorld *mUi;
public:
explicit MyIGamingRtcEngineEventHandler(HelloWorld *ui) : mUi(ui) {}
// 注册 onJoinChannelSuccess 回调。
// 本地用户成功加入频道时,会触发该回调。
void onJoinChannelSuccess(const char *channel, uid_t uid, int elapsed) override {
}
// 注册 onLeaveChannel 回调。
// 本地用户成功离开频道时,会触发该回调。
void onLeaveChannel(const agora::rtc::RtcStats &stats) override {
}
};
...
void HelloWorld::onEnter() {
cocos2d::Scene::onEnter();
eventHandler = new MyIGamingRtcEngineEventHandler(this);
// 创建 IRtcEngine 对象。
engine = createAgoraRtcEngine();
// 定义 RtcEngineContext。
agora::rtc::RtcEngineContext context;
context.appId = AGORA_APP_ID;
context.eventHandler = eventHandler;
// 初始化 IRtcEngine 对象。
engine->initialize(context);
}
完成初始化后,调用 setChannelProfile
,将频道场景设为互动直播。
一个 IRtcEngine
只能使用一种频道场景。如果想切换为其他模式,需要先调用 release
方法释放当前的 IRtcEngine
实例,然后调用 createAgoraRtcEngine
和 initialize
方法创建一个新实例,再调用 setChannelProfile 设置新的频道场景。
void HelloWorld::onJoinChannelClicked() {
if (editBox == nullptr || strlen(editBox->getText()) == 0) {
return;
}
// 将频道场景设置为直播场景。
engine->setChannelProfile(agora::rtc::CHANNEL_PROFILE_LIVE_BROADCASTING);
...
}
互动直播频道有两种用户角色:主播和观众,其中默认的角色为观众。设置频道场景为互动直播后,你可以在 app 中参考如下步骤设置用户角色:
setClientRole
,然后使用用户选择的角色进行传参。注意,互动直播频道内的用户只能听到主播的声音。加入频道后,如果你想切换用户角色,也可以调用 setClientRole
。
void HelloWorld::onJoinChannelClicked() {
if (editBox == nullptr || strlen(editBox->getText()) == 0) {
return;
}
...
// 将用户角色设置为主播。
engine->setClientRole(agora::rtc::CLIENT_ROLE_BROADCASTER);
...
}
完成设置角色后,你可以调用 joinChannel
方法,填入 Token、频道名称和用户 ID,加入频道。
void HelloWorld::onJoinChannelClicked() {
if (editBox == nullptr || strlen(editBox->getText()) == 0) {
return;
}
...
// 传入 Token 和频道名,加入频道。
// 将 uid 设为 0 表示由 SDK 自动分配一个 uid。
engine->joinChannel(AGORA_TOKEN, editBox->getText(), "Cocos2d", 0);
}
mute
方法实现。根据场景需要,调用 leaveChannel
离开当前音频直播。
void HelloWorld::onLeaveChannelClicked() { engine->leaveChannel(); }
如果你想在退出 HelloWorld
场景时释放声网引擎的内存,需调用 release 方法销毁声网引擎。
void HelloWorld::onExit() {
Node::onExit();
agora::rtc::IRtcEngine::release(true);
engine = nullptr;
delete eventHandler;
eventHandler = nullptr;
}
Cocos2d-x/proj.ios_mac/Hello-Cocos2d-Agora.xcodeproj
文件。当成功开始音频互动直播时,观众可以听到主播的声音。
声网在 GitHub 上提供一个开源的音视频通话示例项目 Agora-Cocos-Quickstart/Cocos2d-x,你可以结合该示例项目与本文示例代码实现音频互动直播。