# 快速开始

# 简介

菊风现在提供两种 Cat.1 类型的 SDK,一种是 ASR SDK,一种是 8910 SDK。两者的集成方式类似,本章节将指导您快速集成 SDK 到您的设备中,实现 Cat.1 设备间一对一通话功能。

# 前提条件

  • 具有 ASR 3601 芯片 或 展锐 8910FF 芯片的设备
  • 确保菊风账号具有 IoT 权限
  • 有效的菊风 AppKey

# 通话集成

# 流程图

IoT 设备和其他设备通话时的流程图如下所示:

(实线部分为需要集成的内容,虚线部分为 SDK 实现的内容)

asr2asr

# 集成步骤

您可以一边参考时序图,一边按照以下步骤集成:

  1. 获取通讯秘钥,用于传入下文中的 jrtc_config 函数。

  2. 导入 IoT 账号,用于传入下文中的 jrtc_config 函数。

  3. 主叫和被叫调用 jrtc_config 配置环境,只需调用一次

  4. 主叫调用 jrtc_open 打开通话通道,返回 jrtc_t 对象(通话对象)。

  5. 主叫调用 jrtc_activate 激活设备的某种媒体功能,其中第二个参数将决定开启设备的功能类型:

    • 传 1 激活设备的扬声器功能;
    • 传 2 激活设备的麦克风功能;
    • 传 3 激活设备的扬声器和麦克风功能;
    • 传 4 激活设备的摄像头功能;
    • 传 7 激活设备的扬声器、麦克风和摄像头功能。

    该方法仅修改本地全局变量,并不会发送请求到服务器。

  6. 通过客户自己的服务器,主叫发起长连接通知被叫。

  7. 被叫在收到长连接通知的时候,调用 jrtc_openjrtc_activate

  8. 在通话通道状态变为 jrtc_joined 后,新建 UI 线程,不断渲染本地画面和远端画面。参考 渲染流程

  9. 调用 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 设备端按照下列步骤进行视频渲染:

  1. 获取 jrtc_image_t 对象 (jrtc_open 中传入的最后两个参数均为 jrtc_image_t 对象):

    jrtc_image_t* img = "jrtc_open函数中传入的video或camera对象";
    
  2. 检查当前是否处于连接(JRTC_JOINED)状态,若不是,则无需渲染:

    if (jrtc_state(jc) <  JRTC_JOINED) break;
    
  3. 建立 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_SPEAKER = 1
  • JRTC_MICROPHONE = 2
  • JRTC_AUDIO = 3
  • JRTC_CAMERA = 4

# 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_EBYE
  • 语音中断可设置为JRTC_EAUDIOCALL
  • 其他未知情况可设置为 JRTC_ENIL

# 次要函数

# 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 摄像头
最后更新时间: 2023/9/5 14:12:15