# 快速开始
# 简介
菊风现在提供两种 Cat.1 类型的 SDK,一种是 ASR SDK,一种是 8910 SDK。两者的集成方式类似,本章节将指导您快速集成 SDK 到您的设备中,实现 Cat.1 设备间一对一通话功能。
# 前提条件
- 具有 ASR 3601 芯片 或 展锐 8910FF 芯片的设备
- 确保菊风账号具有 IoT 权限
- 有效的菊风 AppKey
# 通话集成
# 流程图
IoT 设备和其他设备通话时的流程图如下所示:
(实线部分为需要集成的内容,虚线部分为 SDK 实现的内容)
# 集成步骤
您可以一边参考时序图,一边按照以下步骤集成:
获取通讯秘钥,用于传入下文中的 jrtc_config 函数。
导入 IoT 账号,用于传入下文中的 jrtc_config 函数。
主叫和被叫调用 jrtc_config 配置环境,只需调用一次。
主叫调用 jrtc_open 打开通话通道,返回 jrtc_t 对象(通话对象)。
主叫调用 jrtc_activate 激活设备的某种媒体功能,其中第二个参数将决定开启设备的功能类型:
- 传 1 激活设备的扬声器功能;
- 传 2 激活设备的麦克风功能;
- 传 3 激活设备的扬声器和麦克风功能;
- 传 4 激活设备的摄像头功能;
- 传 7 激活设备的扬声器、麦克风和摄像头功能。
该方法仅修改本地全局变量,并不会发送请求到服务器。
通过客户自己的服务器,主叫发起长连接通知被叫。
被叫在收到长连接通知的时候,调用 jrtc_open 和 jrtc_activate 。
在通话通道状态变为 jrtc_joined 后,新建 UI 线程,不断渲染本地画面和远端画面。参考 渲染流程 。
调用 jrtc_close 关闭通话通道,通话通道状态将变为 JRTC_LEAVING 或 JRTC_CLOSED 。通过 jrtc_error 可以获取挂断的原因。
// 配置环境,只需调用一次
jrtc_config(appkey, uid, key[16], tokens);
// (被叫)被叫在接收到长连接后,打开通话通道,获取通话对象 jc
// (主叫)主叫打开通话通道,获取通话对象 jc。并在此时发送长连接通知被叫
jc = jrtc_open("对方uid", ticket, video, camera);
// 激活设备的麦克风和扬声器功能
jrtc_activate(jc,JRTC_AUDIO);
// 激活设备的摄像头功能
// jrtc_activate(jc,JRTC_CAMERA);
// 在通话通道状态变为 jrtc_joined 后。
// 新建 UI 线程,不断渲染本地画面和远端画面,参考下一章 渲染流程
//关闭通话通道, 并且等待网络线程结束
jrtc_close(jc, JRTC_EBYE);
# 渲染流程
Cat.1 设备端按照下列步骤进行视频渲染:
获取
jrtc_image_t
对象 (jrtc_open 中传入的最后两个参数均为 jrtc_image_t 对象):jrtc_image_t* img = "jrtc_open函数中传入的video或camera对象";
检查当前是否处于连接(JRTC_JOINED)状态,若不是,则无需渲染:
if (jrtc_state(jc) < JRTC_JOINED) break;
建立 UI 线程(App 界面层)负责绘制图像。在绘制前需要对
jrtc_image_t
对象的数据进行判断:if (img->get != img->put) { '界面绘制操作: 即使用img中的data, 更新界面控件' img->get = img->put;//增加读计数 }
利用
img->get != img->put
作为判断条件是因为:一旦发生数据传输,SDK 内部会不断修改 img 对象中的数据。所以当img->get != img->put
的时候说明有新的数据产生。// 内部逻辑,非集成部分 if (img->get == img->put) { //'更新图像内容: 即对img中的data, width, height, format 赋值' img->put++;//增加写计数 }
由于界面系统不同,界面绘制需要由开发者自行实现。例如 ASR 原生 LittlevGL 的 lv_watch 界面中, 界面绘制操作如下:
//yuv420_2_rgb565 是内置的格式转换函数 extern void yuv420_2_rgb565(int width, int height, const unsigned char *src, unsigned short *dst, unsigned semi); yuv420_2_rgb565(img->width, img->height, img->data, img_dsc->data, img->format); img->get = img->put; lv_img_set_src(img, img_dsc);//img, img_dsc 都是界面中的相应UI控件
8910 的界面渲染示例代码
//8910的渲染代码 static void lcd_show(struct jrtc_image_t*image) { uint8 *yuv_addr = image->data; unsigned short width = image->width, height = image->height; LCD_INFO_T lcd_info; uint16 *dest_ptr; uint32 i; BLOCKCFG_T cfg; //uint32 frame_size = width * height * 3 / 2;//yuv420p uint32 frame_size = width * height * 2;//UYVY LCD_DisableAllBlock(MAIN_LCD_ID); LCD_EnterSleep(MAIN_LCD_ID, FALSE); GPIO_SetLcdBackLight(TRUE); cfg.end_x = 240-1; cfg.start_x = cfg.end_x + 1 - width; cfg.start_y = 0; cfg.end_y = cfg.start_y + height - 1; cfg.resolution = LCD_RESOLUTION_YUV422; if (LCD_RESOLUTION_YUV420 == cfg.resolution) cfg.width = width; if (LCD_RESOLUTION_YUV422 == cfg.resolution) cfg.width = height * 2; cfg.colorkey_en = FALSE; cfg.alpha_sel = 1; cfg.alpha = 0xFF; cfg.priority = 0; cfg.type = 1; //0:OSD; 1:image cfg.rotation = 0; if (LCD_RESOLUTION_YUV420 == cfg.resolution) { LCD_SetBlockBuffer(MAIN_LCD_ID, 0, (uint32*)yuv_addr); LCD_SetUVBuffer(MAIN_LCD_ID, 0, (uint32*)(yuv_addr + width * height));//YUV420p } if (LCD_RESOLUTION_YUV422 == cfg.resolution) { //LCD_SetBlockBuffer(0, 0, yuv_addr->yaddr);//UYVY LCD_SetBlockBuffer(0, 0, yuv_addr);//UYVY } LCD_SetImageLayerSourceSize(MAIN_LCD_ID, width, height); LCD_ConfigBlock(0, 0, cfg); LCD_EnableBlock(0, 0); LCD_InvalidateRect(0, cfg.start_x, cfg.start_y, cfg.end_x, cfg.end_y); }
# 主要函数
# jrtc_config
配置环境。会修改内部的全局变量,仅需在通话前调用一次。
函数原型:
void jrtc_config (const char* appkey, const char* uid, const char key[16], const char* tokens);
参数详细如下:
参数 | 说明 |
---|---|
appkey | AppKey 是应用在 菊风云平台 中的唯一标识,类似应用的身份证。通过在控制台创建应用获取。 |
uid | 自己的账号 id,需要自行导入,参考 导入 IoT 账号 。 |
key[] | 通讯秘钥,在控制台获取,参考 获取通讯秘钥 。 |
token | 用于鉴权的 token,默认设置为""。对于非token鉴权的用户使用默认值即可。 |
# jrtc_open
打开通话通道,分配通话资源,返回 jrtc_t 对象。如果希望仅发起一对一音频通话,那么将后两个参数设置为空即可。
函数原型:
struct jrtc_t* jrtc_open (const char* uid, const char* ticket, struct jrtc_image_t* video, struct jrtc_image_t* camera);
参数详细如下:
参数 | 类型 | 说明 |
---|---|---|
uid | char* | 对方的账号 id |
ticket | char* | 开发者自定义的唯一 ID 。对呼时, 必须使用相同的ticket, 以便服务器精确标识会话。注意:不能包含JSON需转义的字符。且不能超过 64 位 |
video | struct jrtc_image_t* | 期望接收的视频尺寸和帧速,码率. 若 NULL,则不接收视频 |
camera | struct jrtc_image_t* | 用于预览图像,建议的发送尺寸和帧速,码率. 若 NULL, 则不使用镜头 |
# jrtc_activate
激活设备的某个媒体功能,开启的功能类型取决于第二个参数的值:
- 传 1 激活设备的扬声器功能;
- 传 2 激活设备的麦克风功能;
- 传 3 激活设备的扬声器和麦克风功能;
- 传 4 激活设备的摄像头功能;
- 传 7 激活设备的扬声器、麦克风和摄像头功能。
函数原型:
void jrtc_activate (struct jrtc_t* jc, int devices);
参数详细如下:
参数 | 类型 | 说明 |
---|---|---|
jc | struct jrtc_t* | jrtc_t 对象,通过 jrtc_open 获取 |
devices | int | jrtc_device 的集合:
|
# jrtc_close
关闭通话通道,释放通话资源。
调动该函数可能会出现停顿是因为正在关闭设备的通话资源。
函数原型:
void jrtc_close (struct jrtc_t* jc, enum jrtc_error err);
参数详细如下:
参数 | 类型 | 说明 |
---|---|---|
jc | struct jrtc_t* | jrtc_t 对象,通过 jrtc_open 获取 |
err | enum jrtc_error | jrtc_error 的集合:
|
# 次要函数
# jrtc_set_camera
动态设置前后镜头。传入 0 表示开启后镜头,传入1 表示开启前镜头。
函数原型:
void jrtc_set_camera (struct jrtc_t* jc, int camera);
TIP
- ASR 设备通过
extern int mci_videocall_camera_get_sensor(void);
(设备厂商自带的函数)获取当前摄像头。 - 8910 设备无此接口。
# jrtc_deactivate
关闭设备的媒体功能。
函数原型:
void jrtc_deactivate (struct jrtc_t* jc, int devices);
# jrtc_state
获取通话通道状态。
函数原型:
enum jrtc_state jrtc_state (const struct jrtc_t *jc);
# jrtc_error
返回最近的出错值。
函数原型:
enum jrtc_error jrtc_error (const struct jrtc_t *jc);
# 枚举说明
# jrtc_state
通话通道状态。
参数 | 说明 |
---|---|
JRTC_CLOSED = 0 | 初始状态 |
JRTC_LEAVING | jrtc_leave 或内部出错后的状态 |
JRTC_OPENED | 调用jrtc_open 后的状态 |
JRTC_JOINING | 加入中的状态 |
JRTC_JOINED | 成功加入会话 |
JRTC_TALKING | 收到媒体后的状态 |
# jrtc_error
通话错误值。
参数 | 说明 |
---|---|
JRTC_ENIL = 0 | unknown error |
JRTC_EPERM = 1 | Operation not permitted |
JRTC_ENONET = 64 | Machine is not on the network |
JRTC_EPROTO = 71 | Protocol error |
JRTC_EMSGSIZE = 90 | Message too long |
JRTC_ECONNRESET=104 | Connection reset by peer |
JRTC_ETIMEDOUT =101 | Connection timed out |
JRTC_ECONNREFUSED=111 | Connection refused or closed |
JRTC_EOFFLINE =128 | Peer offline or over |
JRTC_EDECLINE = 129 | Peer decline the call |
JRTC_EINVOKETIMEOUT = 130 | IoTUnit invoke timeout |
JRTC_ECALLSERVERERROR = 131 | Call server error |
JRTC_EROOMNOTFND = 132 | Room or callee not found |
JRTC_ECALLTIMEOUT = 133 | Call timeout |
JRTC_ENOTREG = 134 | device id not registered |
JRTC_ELOGIN = 135 | device id login failed |
JRTC_ETOKEN_NOTFOUND = 136 | secret not found |
JRTC_ETOKEN_INV = 137 | token invalid |
JRTC_ETOKEN_EXPIRE = 138 | token expire |
JRTC_ECODECINVALID = 139 | Codec params invalid |
JRTC_EAUDIOCALL = 252 | external audio call, don't close audio deivce |
JRTC_EAUDIO=253 | Audio device error |
JRTC_EVIDEO=254 | Video device error |
JRTC_EBYE = 255 | Success, Closed by peer leave |
# jrtc_device
通话中的媒体设备。
参数 | 说明 |
---|---|
JRTC_SPEAKER = 1 | 喇叭 |
JRTC_MICROPHONE = 2 | 麦克风 |
JRTC_AUDIO = 3 | 所有音频设备 包含JRTC_SPEAKER 和 JRTC_MICROPHONE |
JRTC_CAMERA = 4 | 摄像头 |