客户端实现
本文介绍如何使用声网灵隼纯呼叫版本的客户端示例项目在 Android 客户端实现呼叫和通话等功能。
纯呼叫版本的客户端示例项目提供呼叫、实时音视频等功能。你需要自行实现账号管理和设备管理相关逻辑。
如果你已有自研的设备管理等模块,声网建议你使用纯呼叫版本示例项目。
前提条件
开始前,请确保你已参考开通并配置声网灵隼物联网服务开通灵隼服务。
业务流程
在纯呼叫模式下,你需要自行实现账号系统与设备管理功能。基本流程如下:
环境准备
注册微信小程序账号并获取微信开发者工具
获取小程序组件权限
在微信公众平台的小程序开发选项中,切换到接口设置页签,打开实时播放音视频流和实时录制音视频流的开关。
配置服务器域名
你需要在 request 合法域名及 socket 合法域名中添加以下域名:
wss://a1g2ouvmztk85d.ats.iot.cn-north-1.amazonaws.com.cn;
wss://miniapp.agoraio.cn;
https://ap-web-1.agoraio.cn;
https://ap-web-2.agoraio.cn;
https://ap-web-3.agoraio.cn;
https://ap-web-4.agoraio.cn;
https://apaas-iot.sd-rtn.com;
https://iot-api-gateway.sh.agoralab.co;
https://iot.sh.agoralab.co;
https://miniapp.agoraio.cn;
https://report-ad.agoralab.co;
https://rest-argus-ad.agoralab.co;
https://uap-ap-web-1.agora.io;
https://uap-ap-web-2.agoraio.cn;
https://uap-ap-web-3.agora.io;
https://uap-ap-web-4.agoraio.cn;
https://un2nfllop5.execute-api.cn-north-1.amazonaws.com.cn;
https://uni-webcollector.agora.io;
跑通示例项目
-
下载示例项目并使用微信开发者工具打开项目。修改项目根目录下的
callkit.config.js
文件。参考开通并配置声网灵隼物联网服务从声网灵隼控制台的应用配置>>开发者选项页面获取所需参数。JavaScriptmodule.exports = {
DEBUG: true,
// 声网灵隼控制台的应用配置>>开发者选项中的 App ID
APPID: 'YOUR_APPID',
// 声网灵隼控制台的应用配置>>开发者选项中的 Product Key
PRODUCT_KEY: 'YOUR_PRODUCT_KEY',
// 声网灵隼控制台的应用配置>>开发者选项中的 Project ID
PROJECT_ID: 'YOUR_PROJECT_ID',
} -
在开发者工具中选择工具 >> 构建 npm。完成项目构建。
-
在登录页面输入你的账号名,进行登录。
-
登录完成后,输入需要呼叫的设备 ID 并点击呼叫设备。
实现客户端
创建小程序项目
参考如下步骤创建一个新的小程序。
- 打开微信开发者工具,然后按照屏幕提示扫码登录。
- 完成登录后,点击小程序界面的 +。
- 在弹出的新建项目界面中,依次填入小程序的项目名称、本地存储目录、小程序 AppID,然后点击新建。
成功创建小程序后,微信开发者工具的左侧会显示当前小程序的界面。你还可以点击真机调试,并扫描生成的二维码,在手机上进行体验。
引用 index.js 文件
-
下载示例项目。
-
使用
require
将main/callkit/index.js
集成到项目中:JavaScriptconst CallKitSDK = require('./callkit/index.js');
获取配置信息
通过灵隼控制台的应用配置页面中的开发者选项选项卡获取以下配置信息:
- App ID:声网的 App ID。
- Product Key:声网灵隼产品 ID。
本文将获取的配置定义为以下常量:
export const appid = 'Your App ID';
export const PRODUCT_KEY = 'Your product key';
添加微信小程序组件
音视频通话页面的 .wxml
文件中需要使用微信的 live-player
组件和 live-pusher
组件。
<view>
<view class="box flex-center-row">
<live-player src="{{playUrl}}" mode="RTC" autoplay bindstatechange="statechange" binderror="error" style="width: 225px; height: 225px;" />
</view>
<view class="box flex-center-row">
<live-pusher url="{{pushUrl}}" mode="RTC" autopush bindstatechange="statechange" style="width: 225px; height: 225px;" />
</view>
<view class="box flex-center-row">
<button type="default" size="mini" bindtap="onHangup">挂断</button>
</view>
</view>
初始化 SDK 并登录
// 引入 callkit config 文件,在 init 项目的时候传入config文件
const config = require('../../callkit.config.js');
const username = 'agorauser'
CallKitSDK.getAccountManager().initAndLogin(config, username)
.then(this.onUserLoginSuccess)
.catch(this.onLoginFail);
注册呼叫事件回调
onLoad() {
// peer 呼叫请求事件
this.peerRequestEventCallbackUnsubscribe = CallKitSDK.getCallkitManager().peerRequestEventCallback((event) => {
log.i('peerRequestEventCallback invoked');
const attachMsg = event.attachMsg || '';
// 调转到待接听界面
wx.navigateTo({
url: `/pages/answer/answer?attachMsg=${attachMsg}`,
});
});
// peer 正在忙事件
this.peerBusyEventCallbackUnsubscribe = CallKitSDK.getCallkitManager().peerBusyEventCallback((event) => {
log.i('peerBusyEventCallback invoked');
wx.showToast({
title: '对方正忙',
icon: 'error',
mask: true,
});
});
// peer 接听事件
this.peerAnswerEventCallbackUnsubscribe = CallKitSDK.getCallkitManager().peerAnswerEventCallback((event) => {
log.i('peerAnswerEventCallback invoked');
wx.hideLoading();
// peer 接听后跳转到 live 界面
wx.navigateTo({
url: '/pages/live/live',
});
});
// peer 挂断事件
this.peerHangupEventCallbackUnsubscribe = CallKitSDK.getCallkitManager().peerHangupEventCallback((event) => {
log.i('peerHangupEventCallback invoked');
wx.showToast({
title: '对方挂断',
icon: 'error',
mask: true,
});
});
},
当退出小程序或者页面卸载时,可以调用返回的 unsubscribe 函数来删除订阅事件,节省资源。
onUnload() {
// 退出界面时解除所有事件的绑定
this.peerRequestEventCallbackUnsubscribe();
this.peerBusyEventCallbackUnsubscribe();
this.peerAnswerEventCallbackUnsubscribe();
this.peerHangupEventCallbackUnsubscribe();
},
呼叫设备端
const deviceId = 'mydoorbell' // 设备端ID
const attachMsg = 'Hello, stranger.' // optional,携带给设备端的消息
CallKitSDK.getCallkitManager().callDevice(deviceId, attachMsg)
.then((res) => {
console.log('正在呼叫')
}).catch((err) => {
log.e(err);
wx.showToast({
title: '呼叫设备失败',
icon: 'error',
});
});
当对方接听时,触发 peerAnswerEventCallback
回调。如果对方挂断,会收到 peerHangupEventCallback
的事件。如果对方忙,会收到 peerBusyEventCallback
的事件。如果此时设备端呼叫请求,那么 peerRequestEventCallback
会触发回调事件。
开始视频通话
通过 peerStreamAddedEventCallback
的回调获取拉流地址。然后调用 userPublishStream
接口来推送本地的推流地址。同时监听 peerHangupEventCallback
事件。
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
wx.showLoading({
title: '正在拉取流',
mask: true,
});
// peer加入频道,获得播放地址
this.peerStreamAddedEventCallbackUnsubscribe = CallKitSDK.getCallkitManager().peerStreamAddedEventCallback((playUrl) => {
log.i('peerStreamAddedEventCallback invoked');
wx.hideLoading();
this.setData({
playUrl,
});
// 获得推流地址,开始推流
CallKitSDK.getCallkitManager().userPublishStream().then((pushUrl) => {
this.setData({
pushUrl,
});
}).catch((err) => {
log.e(err);
wx.switchTab({ url: '/pages/device/device' });
});
});
// 如果peer挂断呼叫,本地则返回主界面
this.peerHangupEventCallbackUnsubscribe = CallKitSDK.getCallkitManager().peerHangupEventCallback((event) => {
log.i('peerHangupEventCallback invoked');
wx.showToast({
title: '对方已挂断',
duration: 1500,
});
setTimeout(() => {
wx.switchTab({ url: '/pages/device/device' });
}, 1500);
});
},
挂断通话
调用 hangupDevice
接口来挂断当前通话。
onHangup() {
CallKitSDK.getCallkitManager().hangupDevice()
.then((res) => {
wx.switchTab({ url: '/pages/device/device' });
}).catch((err) => {
wx.switchTab({ url: '/pages/device/device' });
});
},
通过注册的回调处理设备端呼叫。
onLoad(options) {
this.setData({
name: options.name || '',
attachMsg: options.attachMsg || '',
});
// peer挂断事件,返回主界面
this.peerHangupEventCallbackUnsubscribe = CallKitSDK.getCallkitManager().peerHangupEventCallback((event) => {
log.i('peerHangupEventCallback invoked');
wx.showToast({
title: '对方已挂断',
icon: 'error',
duration: 2000,
});
setTimeout(() => {
wx.switchTab({ url: '/pages/device/device' });
}, 2000);
});
// 待接听时,可以显示peer的预览画面
this.peerStreamAddedEventCallbackUnsubscribe = CallKitSDK.getCallkitManager().peerStreamAddedEventCallback((playUrl) => {
log.i('peerStreamAddedEventCallback invoked');
this.setData({
playUrl,
});
});
},
onAccept() {
CallKitSDK.getCallkitManager().answerDevice()
.then((res) => {
wx.navigateTo({
url: '/pages/live/live',
});
}).catch((err) => {
wx.switchTab({ url: '/pages/device/device' });
});
},
onHangup() {
CallKitSDK.getCallkitManager().hangupDevice()
.then((res) => {
wx.switchTab({ url: '/pages/device/device' });
}).catch((err) => {
wx.switchTab({ url: '/pages/device/device' });
});
},
参考信息
开发注意事项
声网推荐在 app.js
或者全局下订阅 userSessionEndEventCallback
事件,来监听用户登录状态的改变和 mqtt 连接状态的改变。如果发生改变,可以强制登出用户并且返回到登录界面。
onLaunch() {
CallKitSDK.getInstanceManager().userSessionEndEventCallback((user) => {
wx.showToast({
title: "登录超时",
icon: 'error',
})
wx.redirectTo({
url: '/pages/login/login',
})
})
}