支付宝小程序如何实现音视频通话

你们的小程序音视频SDK支持支付宝吗?支付宝小程序如何实现音视频通话?有不少开发者都咨询过这些问题。9月20,Zego Express SDK 支付宝小程序初版发布,包含房间、推拉流、信令消息等功能,意味我们的SDK终于支持支付宝小程序的音视频功能了。

本文将介绍如何在支付宝小程序内快速实现一个简单的实时音视频通话。

前提条件

在实现基本的实时音视频功能之前,请确保:

  • 已联系 ZEGO 技术支持,提供您的 支付宝 APPID,开通了相关权限,并获取到了接入 MRTC 的相应参数,以及完成了挂包(Android 设备需要下载挂包)后,才可以正常使用 RTC room 组件。
  • 确保您的支付宝小程序符合以下类目,并开通实时音视频权限(获取到对应的小程序 AppID),详情请参考 申请开通
支付宝小程序如何实现音视频通话

示例代码

请参考 基础推拉流 1v1

实现流程

用户通过 ZEGO Express SDK 进行视频通话的基本流程为:

用户 A、B 加入房间,用户 B 预览并将音视频流推送到 ZEGO 云服务(推流),用户 A 收到用户 B 推送音视频流的通知之后,在通知中播放用户 B 的音视频流(拉流)。

支付宝小程序如何实现音视频通话

配置支付宝小程序后台

1. 在初始化 SDK 前,需要在支付宝平台中进行如下配置:服务器 IP 白名单:在 “开放平台控制台 > 对应应用概览页 > 开发设置 > 开发信息 > 服务器IP白名单”,点击 “设置/查看”,进入 IP 白名单管理页面,按照协议分类,将 ZEGO 的 LogUrl、以及用户业务需要用到的地址填到指定的“服务器 IP 白名单”中。

注意:ZEGO 控制台提供的 LogUrl 地址格式为:https://xxxxxxxxxx.com/httplog。在支付宝平台填写时,不能直接复制原地址,需要删除原地址的 “/httplog”,应填入地址的格式为:xxxxxxxxxx.com。

2. 输入 RTC room 组件 所必须的 MRTC 参数、以及身份验证签名 signature,支付宝服务器会直接和 ZEGO 的 RTMP 网关进行推拉流对接。

MRTC 参数,包含 bizName、subBiz、以及 serverUrl。

RTC room 组件的参数 signature,是由 bizName、subBiz、秘钥 key 等加密生成,具体生成规则请参考 流媒体签名使用说明

初始化

1. 创建界面

根据场景需要,为您的项目创建视频通话的用户界面。我们推荐您在项目中添加如下元素:

  • 本地预览窗口
  • 远端视频窗口
  • 结束按钮

参考界面代码:

<view class="body">
  <view class="containerBase">
    <rtc-room
      a:if="{{showRtcroom}}"
      class="rtcContent"
      id="{{rtcroomID}}"
      roomId="{{rtcroom.roomId}}"
      token="{{rtcroom.token}}"
      userId="{{rtcroom.userId}}"
      signature="{{rtcroom.signature}}"
      autoplay="{{rtcroom.autoplay}}"
      enable-camera="{{rtcroom.enableCamera}}"
      mute="{{rtcroom.mute}}"
      fps="{{rtcroom.fps}}"
      resolution="{{rtcroom.resolution}}"
      record="{{rtcroom.record}}"
      min-bitrate="{{rtcroom.minBitrate}}"
      max-bitrate="{{rtcroom.maxBitrate}}"
      extraInfo="{{rtcroom.extraInfo}}"
      onError="onError"
      onRoomInfo="onRoomInfo"
      onParticipantEnter="onParticipantEnter"
      onParticipantLeave="onParticipantLeave"
      onAudioPlayoutMode="onAudioPlayoutMode"
      onReceiveRecordId="onReceiveRecordId"
      onRtmpEvent="onRtmpEvent"
    />
  </view>
  <view class="index-container">
    <view class='input-container'>
      <input
        value="{{roomID}}"
        onInput="keyInput"
        placeholder="请输入房间 ID"
        placeholder-style='color: #b3b3b3; font-size: 14px;'
        class="room-input"
      />
      <text class="tip"></text>
    </view>
    <view class="button-container">
      <button type="primary" onTap="openRoom" data-role="1" class="btn">
        加入房间(推流)
      </button>
      <button type="primary" onTap="openRoom2" data-role="0" class="btn">
        加入房间(不推流)
      </button>
      <button type="primary" onTap="publishStream" data-role="1" class="btn">
        推流
      </button>

      <button type="primary" onTap="stopPushStream" data-role="1" class="btn">
        停止推流
      </button>
      <button type="primary" onTap="stopPullStream" data-role="0" class="btn">
        停止拉流
      </button>
      <button type="primary" onTap="enableCamera" data-role="0" class="btn">
        {{ rtcroom.enableCamera ? "关闭摄像头" : "开启摄像头"}}
      </button>
      <button type="primary" onTap="enableMicrophone" data-role="0" class="btn">
        {{ rtcroom.mute ? "开启麦克风" : "关闭麦克风"}}
      </button>
      <button type="primary" onTap="logout" class="logoutBtn">退出房间</button>
    </view>
  </view>
</view>

2. 创建引擎

创建 ZegoExpressEngine 引擎实例,将申请到的 AppID 传入参数 “appID”,将获取到的 Server 地址传入参数 “server”。

// 初始化实例
zg = new ZegoExpressEngine(appID, server);

如果需要注册回调,开发者可根据实际需要,实现 ZegoEvent 中的某些方法,创建引擎后可通过调用 on 接口设置回调。

zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
    if (state == 'DISCONNECTED') {
        // 与房间断开了连接
    // ...
    }

    if (state == 'CONNECTING') {
        // 与房间尝试连接中
    // ...
    }

    if (state == 'CONNECTED') {
        // 与房间连接成功
    // ...
    }
})

登录房间

1. 获取登录 Token

登录房间需要用于验证身份的 Token,获取方式请参考 用户权限控制。如需快速调试,建议使用控制台生成的临时 Token,生成临时 Token 的具体操作请参考 控制台 – 项目管理

2. 登录房间

您可以调用 SDK 的 loginRoom 接口,传入房间 ID 参数 “roomID”、“token” 和用户参数 “user”,登录房间。如果房间不存在,调用该接口时会创建并登录此房间。

您可通过监听 roomStateUpdate 回调实时监控自己在本房间内的连接状态,具体请参考下文的 —— “常见通知回调 ”中的“我在房间内的连接状态变化通知”。

roomID 和 user 的参数由您本地生成,但是需要满足以下条件:

  • 同一个 AppID 内,需保证 “roomID” 全局唯一。
  • 同一个 AppID 内,需保证 “userID” 全局唯一,建议开发者将 “userID” 与自己业务的账号系统进行关联。
// 登录房间,成功则返回 true
const result = await zg.loginRoom(roomID, token, {
    userID: "user1", // userID,需用户自己定义,保证全局唯一,建议设置为业务系统中的用户唯一标识
    userName: "user1_name" // userName 用户名
}, {
    userUpdate: true // 是否接收用户进出房间的回调,设置为 true 才能接收到房间内其他用户进出房间的回调
});

将自己的音视频流推送到 ZEGO 音视频云

必须完成创建业务场景的 AXML 之后,才能调用 SDK 接口创建推流和拉流实例。

调用 startPublishingStream 获取推流地址,并将推流地址赋值给 <rtc-room> 组件 的 extraInfo 扩展参数的 rtmpPushUrl 属性。请注意,必须在创建组件时传入,直接通过 setData 更新无效。

“streamID” 由您本地生成,但是需要保证:

  • 同一个 AppID 下,“streamID” 全局唯一。如果同一个 AppID 下,不同用户各推了一条 “streamID” 相同的流,后推流的用户推流失败。
  • “streamID” 长度不超过 256 字节的字符串。仅支持数字、英文字符和 “-“、”_”。
// 控制 <rtc-room> 组件的显示隐藏
handleShowRtcroom() {
    const extraInfo = this.data.rtcroom.extraInfo
    const isShow = Boolean(extraInfo.rtmpPullUrl || extraInfo.rtmpPushUrl);
    this.setData({
        showRtcroom: false,
    }, () => {
        this.data.rtcroomContext && this.data.rtcroomContext.stop();
        const id = "rtcroom-" + Date.now()
        this.setData({
            rtcroomID: id,
            showRtcroom: isShow,
            rtcroomContext: my.createRtcRoomContext(id)
        })
    })
}

// 推流方登录房间成功后触发推流
/** 开始推流,返回推流地址 */
const pushStreamID = this.data.pushStreamID;
const {
    url
} = await zg.startPublishingStream(pushStreamID, publishOption);
const rtcroom = this.data.rtcroom;
console.warn(`startPush 推流地址${url},推流类型:${publishOption && publishOption.sourceType}`);
rtcroom.extraInfo.rtmpPushUrl = url;
rtcroom.enableCamera = true;
this.setData({
    rtcroom: rtcroom,
    needRepublish: false
}, () => {
    this.handleShowRtcroom()
});

拉取其他用户的音视频

进行视频通话时,我们需要拉取到其他用户的音视频。

通过调用startPlayingStream 获取拉流地址,并将拉流地址赋值给 <rtc-room> 组件 的 extraInfo 扩展参数的 rtmpPullUrl 属性。请注意,必须在创建组件时传入,直接通过 setData 更新无效。

您可通过监听 playerStateUpdate 回调知晓是否成功拉取音视频。远端用户推送的 “streamID” 可以从 roomStreamUpdate 回调中获得,具体回调方式请看下文。

zg.on("roomStreamUpdate", async (roomID, updateType, streamList) => {
    console.warn("roomStreamUpdate", roomID, updateType, streamList);
    const rtcroom = this.data.rtcroom;
    //拉流列表,一次只拉一条
    const pullList = this.data.pullList;
    if (updateType === "ADD") {
        pullList.push(...streamList);
    } else {
        streamList.forEach(i => {
            if (this.data.pullStreamID === i.streamID) {
                // 停止拉流
                zg.stopPlayingStream(i.streamID);
                rtcroom.extraInfo.rtmpPullUrl = ""
                this.setData({
                    rtcroom: rtcroom
                }, () => {
                    this.handleShowRtcroom();
                })
            }
            const index = pullList.findIndex(item => item.streamID === i.streamID);
            if (index !== -1) {
                pullList.splice(index, 1);
            }
        })
    }

    if (!rtcroom.extraInfo.rtmpPullUrl && pullList.length) {
        const pullStreamID = pullList[0].streamID;
        try {
            // 开始拉流
            const {
                url
            } = await zg.startPlayingStream(this.data.pullList[0].streamID)
            rtcroom.extraInfo.rtmpPullUrl = url
            this.setData({
                pullStreamID: pullStreamID,
                rtcroom: rtcroom
            }, () => {
                this.handleShowRtcroom();
            })
        } catch (error) {
            console.error(error)
        }
    }
    this.setData({
        pullList: pullList
    })
});

常用功能

1 常见通知回调

1.1 我在房间内的连接状态变化通知

roomStateUpdate:本地调用 loginRoom 加入房间时,您可通过监听该回调实时监控自己在该房间内的连接状态。

用户可以在回调中根据不同状态处理业务逻辑。

zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
    if (state == 'DISCONNECTED') {
        // 与房间断开了连接
    // ...
    }

    if (state == 'CONNECTING') {
        // 与房间尝试连接中
    // ...
    }

    if (state == 'CONNECTED') {
        // 与房间连接成功
    // ...
    }
})
状态含义
DISCONNECTED未连接状态,在登录房间前/退出房间后进入该状态。如果登录房间的过程中出现稳态异常,比如 AppID 不正确,或者有相同用户名在其他地方登录导致本端被 KickOut,都会进入该状态。
CONNECTING正在请求连接状态,登录房间动作执行成功后会进入该状态。通常情况下,可通过该状态进行 UI 界面的展示。如果是因为网络质量不佳产生的中断,SDK 内部会进行重试,也会进入正在请求连接状态。
CONNECTED连接成功状态,成功登录房间后进入该状态。此时,用户可以正常收到房间内的用户和流信息增删变化的回调通知。

1.2 其他用户进出房间的通知

roomUserUpdate:同一房间内的其他用户进出房间时,您可通过此回调收到通知。登录房间后,当房间内有用户新增或删除时,SDK 会通过该回调通知。

// 用户状态更新回调
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
    console.warn(
        `roomUserUpdate: room ${roomID}, user ${updateType === 'ADD' ? 'added' : 'left'} `,
        JSON.stringify(userList),
    );
});

1.3 房间内流状态变更的通知

roomStreamUpdate:流状态更新回调。登录房间后,当房间内有用户新推送或删除音视频流时,SDK 会通过该回调通知。

// 流状态更新回调
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
    if (updateType == 'ADD') {
        // 流新增,开始拉流
    } else if (updateType == 'DELETE') {
        // 流删除,停止拉流
    }
});

1.4 用户推送音视频流的状态通知

支付宝小程序会在 <rtc-room> 组件 的 “onRtmpEvent” 属性绑定的方法中,通知出推流状态事件,开发者需要:

  • 在 “onRtmpEvent” 绑定的回调函数中,调用 SDK 的 updatePlayerState 接口,将推流状态事件透传给 SDK。
  • 在 SDK 的 publisherStateUpdate 回调中,处理推流的开始、失败状态。
// rtc-room 绑定的 onRtmpEvent 事件,更新推拉流状态
onRtmpEvent(e) {
    console.warn("onRtmpEvent, e=" + JSON.stringify(e));
    if ([3800, 3801].includes(e.detail.code)) {
        // 推流
        zg.updatePlayerState(this.data.pushStreamID, e);
    }
},

// 推流后,服务器主动推过来的,流状态更新
// NO_PUBLISH:未推流状态,PUBLISH_REQUESTING:正在请求推流状态,PUBLISHING:正在推流状态
// state: "PUBLISHING" | "NO_PUBLISH" | "PUBLISH_REQUESTING";
zg.on("publisherStateUpdate", (result) => {
    console.log("publishStateUpdate", result.state);
});

1.5 用户拉取音视频流的状态通知

支付宝小程序会在 <rtc-room> 组件 的 “onRtmpEvent” 属性绑定的方法中,通知出拉流状态事件,开发者需要:

  • 在 “onRtmpEvent” 绑定的回调函数中,调用 SDK 的 updatePlayerState 接口,将拉流状态事件透传给 SDK。
  • 在 SDK 提供的 playerStateUpdate 回调中,处理拉流的开始、失败状态。
// rtc-room 绑定的onRtmpEvent事件,更新推拉流状态
onRtmpEvent(e) {
    console.warn("onRtmpEvent, e=" + JSON.stringify(e));
    if ([3800, 3801].includes(e.detail.code)) {
        // 推流
        zg.updatePlayerState(this.data.pushStreamID, e);
    } else if ([3802, 3803].includes(e.detail.code)) {
        // 拉流
        zg.updatePlayerState(this.data.pullStreamID, e);
    }
},

// 服务器主动推过来的流的播放状态
// 视频播放状态通知;state: "NO_PLAY" | "PLAY_REQUESTING" | "PLAYING";
zg.on("playerStateUpdate", (result) => {
    console.log("playStateUpdate", result.state);
});

2 停止音视频通话

2.1 停止推送/拉取音视频流

  • 停止推流

调用 stopPublishingStream 方法停止推流,并重新渲染 <rtc-room> 组件。

// 停止推流
  stopPushStream() {
    zg.stopPublishingStream(this.data.pushStreamID);
    this.data.rtcroom.extraInfo.rtmpPushUrl = ""
    this.setData({
      rtcroom: this.data.rtcroom,
    });
    this.handleShowrtcRoom()
  },
  • 停止拉流

调用 stopPlayingStream 方法停止拉流,并重新渲染 <rtc-room> 组件。

// 停止拉流
zg.stopPlayingStream(this.data.pullStreamID);
this.data.rtcroom.extraInfo.rtmpPullUrl = ""
this.setData({
    rtcroom: rtcroom
}, () => {
    this.handleShowRtcroom();
})

2.2 退出房间

调用 SDK 的 logoutRoom 接口退出房间。

zg.logoutRoom(roomID);

支付宝小程序视频通话 API 调用时序

整个推拉流过程的 API 调用时序可参考下图:

支付宝小程序如何实现音视频通话

本文为原创稿件,版权归作者所有,如需转载,请注明出处:https://www.nxrte.com/jishu/yinshipin/34734.html

(0)

相关推荐

发表回复

登录后才能评论