生活物联网平台提供Linux版本的Link Visual设备端SDK,您可以基于该SDK开发Link Visual视频设备的直播、点播、语音对讲、抓图等功能。

前提条件

  • 请您先完成Link Visual Demo体验,以提前熟悉整体流程。体验Link Visual请参见快速体验Link Visual
  • 已完成生活物联网平台SDK的开发。这部分请参见开发指导

背景信息

Linux版本的Link Visual SDK的资源占用、平台支持和运行依赖如下。

项目 限制条件
资源占用情况
  • RAM:1 MB的码流,预计占用500 KB的RAM内存。
  • ROM:占用2 MB的ROM存储。
平台支持

目前只能在支持C++11标准(GCC版本4.8.1以上)的Linux平台中使用。

运行依赖

依赖生活物联网平台SDK,您需要同时获取Link Visual SDK和生活物联网平台SDK来完成设备接入。

  • 生活物联网平台SDK:主要提供物联网控制通道能力,包括长连接、消息通知、事件上报等。
  • Link Visual SDK:主要提供音视频流通道能力,并响应生活物联网平台SDK的控制消息,进行流媒体业务处理。

一、获取Link Visual SDK

Linux版本的Link Visual设备端SDK以静态库的形式提供,支持通过编译SDK接入不同芯片的设备,需要您发送邮件申请。

请按以下模板发送邮件至fangyu.hfy@alibaba-inc.com联系我们获取Link Visual设备端SDK。收到邮件后,我们会在收到邮件后的5个工作日内联系您。

  • 邮件主题:获取固件升级SDK和操作说明文档
  • 邮件内容:
    公司名称:
    公司地址:
    联系人:
    联系电话:
    应用场景描述:
说明 我们给您提供Link Visual SDK时会一并提供配套版本的生活物联网平台SDK,您无需单独下载生活物联网平台SDK。

二、了解SDK目录结构及Demo源码

在开发Link Visual SDK前,建议您先了解整个SDK目录结构以及Link Visual Demo的源码,可以帮助您快速熟悉整个开发流程。

  • 了解SDK目录结构

    解压获取到的Link Visual SDK压缩包,并查看压缩包的内容。

    # 解压压缩包,并查看压缩包内容(注:压缩包文件名含有版本等可变信息,执行命令时以实际压缩包名称为准)
    $ tar -xf link_visual_ipc_vxxx.tar.gz
    $ tree -L 2 link_visual_ipc_vxxx
    
    ├── CMakeLists.txt #基于cmake的编译的基础示例
    ├── linkvisual # lv库和头文件
    │   ├── liblink_visual_ipc.a # lv库(注:实际压缩包可能含有动态库)
    │   ├── link_visual_def.h # lv头文件
    │   └── link_visual_ipc.h # lv头文件
    ├── sample # 示例代码
    │   ├── demo.c # 示例代码的入口文件
    │   ├── demo.h # 示例代码的入口头文件
    │   ├── ipc_operation # 示例伪造了ipc的功能,相关实现文件
    │   └── sdk_api_operation # 示例中lv sdk的相关实现文件
    ├── third_party # 三方库
    │   ├── cJSON-1.7.7.tar.gz # JSON解析库,使用版本为1.7.7
    │   ├── libevent-2.1.8-stable.tar.gz # libevent,使用版本为2.1.8
    │   └── linkkit-sdk-c.tar.gz # 生活物联网平台SDK,提供生活物联网平台接入能力
    └── version.txt  # 版本说明
  • 了解Demo源码

    Link Visual Demo的下载请参见快速体验Link Visual

    # 代码取自文件 sample/demo.c
    int main(int argc, char* argv[])
    {
        char product_key[PRODUCT_KEY_LEN + 1] = {0};
        char device_name[DEVICE_NAME_LEN + 1] = {0};
        char device_secret[DEVICE_SECRET_LEN + 1] = {0};
        char product_secret[PRODUCT_SECRET_LEN + 1] = {0};
    
        int ret = 0;
    #ifdef DUMMY_IPC
        /* 0.初始化虚拟IPC的功能 */
        ret = dummy_ipc_start(&dummy_ipc_config);
    #endif // DUMMY_IPC
    
        /* 1. 初始化LinkVisual的资源 */
        ret = linkvisual_client_init(product_key, device_name, device_secret, (lv_log_level_e) log_level);
    
        /* 2. 初始化linkkit的资源,并长连接到服务器 */
        ret = linkkit_client_start(product_key, product_secret, device_name, device_secret);
    
        /* 3. 运行,等待服务器命令 */
        while(1) {
            usleep(1000 * 500);
        }
    
        /* 4. linkkit长连接断开,并释放资源 */
        linkkit_client_destroy();
    
        /* 5. LinkVisual断开音视频连接,并释放资源 */
        linkvisual_client_destroy();
    
    #ifdef DUMMY_IPC
        /* 停止虚拟IPC的功能 */
        dummy_ipc_stop();
    #endif // DUMMY_IPC
    
        return 0;
    }
    如上述代码所示,设备端Link Visual Demo共完成了3个模块的功能。
    • 启动了一个虚拟IPC,用于模拟IPC的出流功能。这部分功能仅用于测试,您无需过多关注其实现原理、细节等,实际产品中您需要替换成实际的IPC出流功能。
    • 启动了生活物联网平台SDK,建立信令通道,用于接收各类命令,如直播命令等。此外配网、OTA等功能,也属于生活物联网平台SDK功能范畴。
    • 启动了视频服务SDK,用于处理视频相关命令,如直播命令等,并建立媒体通道,发送视音频数据。
    这3个模块的功能之间的关系如下图所示(以直播数据转发为例)。
    demo结构

三、编译Link Visual SDK

  1. 配置环境。

    编译依赖cmake等一些相关软件,这里以Ubuntu 16.04下安装编译环境为例。

    $ sudo apt-get install -y build-essential make git gcc g++ cmake tree
  2. 编译cJSON。
    1. 进入third_party目录,并解压cJSON-1.7.7
      $ cd third_party
      # 解压代码压缩包
      $ tar -xf cJSON-1.7.7.tar.gz
      $ cd cJSON-1.7.7
    2. Makefile文件中加入工具链的声明,并替换成对应的交叉编译工具链。
      CC        =   arm-linux-gcc
      LD        =   arm-linux-ld
      AR       =   arm-linux-ar
    3. 编译cJSON,并确认是否生成了libcjson.a,以及头文件cJSON.h是否存在。
      $ make
      # 确认libcjosn.a和相关头文件已存在
      $ ls lib*.a
      $ ls *.h
  3. 编译libevent。
    1. third_party目录里解压libevent
      $ cd third_party
      # 解压代码压缩包
      $ tar -xf libevent-2.1.8-stable.tar.gz
    2. 编译libevent。
      $ cd libevent-2.1.8-stable 
      # 配置编译条件,注意host和cc需要改为对应的交叉编译工具链信息,编译条件可根据自身需求调整
      $ ./configure --host=arm-linux CC=arm-linux-gcc --enable-static --disable-samples --disable-openssl
      $ make # 编译
      $ ls .libs/libevent.* # 确认是否有libevent.a生成
  4. 编译生活物联网平台SDK。
    1. third_party目录里解压ali-smartliving-device-sdk-c
      $ cd third_party
      $ tar -xf ali-smartliving-device-sdk-c-1.4.tar.gz;
      #解压代码压缩包
      $ cd ali-smartliving-device-sdk-c
    2. 修改src/board/config.ubuntu.x86来准备交叉编译。
      CROSS_PREFIX :=arm-linux- 
      #在最后加上CROSS_PREFIX :=交叉编译工具链路径前缀(请替换成对应的交叉编译工具链)
    3. 选择Ubuntu编译,并确认生成库libiot_tls.a/libiot_sdk.a/libiot_hal.a
      # 这里选择ubuntu对应的数字,一般是数字6
      $ make reconfig
      $ make
      # 确认有libiot_tls.a/libiot_sdk.a/libiot_hal.a
      $ ls output/lib/*.a
      # 确认有如iot_import.h等头文件
      $ tree include
  5. 整理编译。
    1. 返回到SDK解压后的文件夹根目录,修改CMakeLists.txt里的TOOLCHAINS_PREFIX参数值。
      set(TOOLCHAINS_PREFIX "arm-linux-" CACHE STRING "set the toolchain")
      #第二个参数设置为交叉编译工具链前缀(请替换成对应的交叉编译工具链)
    2. 执行编译操作。
      # 建立一个build文件夹,用于归类编译产物
      $ mkdir -p build
      # 进入build目录,使用根目录的CMakeLists.txt进行cmake
      $ cd build
      $ cmake ..
      # 编译并安装运行所需相关文件
      $ make
      $ make install
      • 编译(compilation)时,您可以添加-std=c++11来支持C++和C++11。
      • 链接(linking)时,您可以在链接选项中添加-lstdc++来支持C++和C++11。
      • 链接(linking)时,库的连接顺序为:link_visual_ipciot_sdk cjsoniot_haliot_tls pthreadrt
  6. 运行设备。
    # 运行方式和Ubuntu Demo或Docker Demo类似,传入设备的激活凭证信息
    $ ./link_visual_demo -p your_product_key -n your_product_name -s your_product_secret

四、API简述

由于Link Visual SDK依赖与生活物联网平台SDK,开发Link Visual SDK前,请确认已完成生活物联网平台SDK的开发。请参见开发指导

  • 生命周期功能

    生命周期相关的API如下。

    功能说明 API名称
    SDK初始化 lv_init
    SDK停止 lv_destroy
  • SDK动态开关等其他功能
    功能说明 API名称
    生活物联网平台SDK消息注入 lv_linkkit_adapter
    SDK功能动态控制 lv_control
  • 直播、卡录像点播、云存等功能
    功能说明 API名称
    通知直播、点播服务已开启 lv_start_push_streaming_cb
    通知直播、点播服务已结束 lv_stop_push_streaming_cb
    推送视音频配置参数 lv_stream_send_config
    推送视频数据 lv_stream_send_video
    推送音频数据 lv_stream_send_audio
    推流过程中命令控制(暂停等) lv_on_push_streaming_cmd_cb
    点播的文件列表查询 lv_query_storage_record_cb
    点播的文件列表按月查询 lv_query_storage_record_by_month_cb
    录像文件播放结束 lv_post_file_close
    预录数据结束 lv_post_pre_complete
  • 抓图功能
    功能说明 API名称
    图片上传 lv_post_alarm_image
    通知上传图片 lv_trigger_pic_capture_cb
  • 语音对讲功能
    功能说明 API名称
    通知开启服务 lv_start_voice_intercom_cb
    通知结束服务 lv_stop_voice_intercom_cb
    开启服务 lv_voice_intercom_start_service
    停止服务 lv_voice_intercom_stop_service
    发送音频 lv_voice_intercom_send_audio
    接收音频 lv_voice_intercom_receive_data_cb
    接收音频参数配置 lv_voice_intercom_receive_metadata_cb

五、API详述-SDK生命周期

SDK生命周期管理相关的API如下。

  • lv_init
    接口名称 接口详情 描述
    lv_init int lv_init(const lv_config_s *config) SDK初始化,该接口的使用说明如下。
    • lv_init主要完成各个IPC功能的回调,以及一些配置类信息。
    • lv_init会打印相关版本号信息,便于您追溯问题。
    • 初始化失败时,一般不会与网络有关,请优先检查入参是否正确或者资源分配是否成功。
    • lv_init注册了大量的回调函数,这些回调函数共用一个消息队列线程,因此建议您不要在回调中做过于耗时的操作。
    • lv_init定义了日志类型log_level,建议对接初期将日志类型设置为LV_LOG_DEBUG
    • 推荐您在调用lv_init成功后再调用IOT_Linkkit_Connect。

    请求参数说明如下。

    参数 类型 说明
    config lv_config_s* 配置参数结构体。

    示例代码如下。

    //新建一个配置结构体,并置空
    lv_config_s config;
    memset(&config, 0, sizeof(lv_config_s));
    
    //以下是设置具体的配置属性
    //设备三元组
    memcpy(config.product_key, product_key.c_str(), product_key.length());
    memcpy(config.device_name, device_name.c_str(), device_name.length());
    memcpy(config.device_secret, device_secret.c_str(), device_secret.length());
    
    //SDK的日志配置
    config.log_level = LV_LOG_DEBUG;
    config.log_dest = LV_LOG_DESTINATION_STDOUT;
    //config.log_dest_file;
    
    //音视频推流服务
    config.start_push_streaming_cb = startPushStreamingCallback;
    config.stop_push_streaming_cb = stopPushStreamingCallback;
    config.on_push_streaming_cmd_cb = onPushStreamingCmdCb;
    
    //语音对讲服务
    config.start_voice_intercom_cb = startVoiceIntercomCallback;
    config.stop_voice_intercom_cb = stopVoiceIntercomCallback;
    config.voice_intercom_receive_metadata_cb = voice_intercom_receive_metadata_cb;
    config.voice_intercom_receive_data_cb = VoiceIntercomReceiveDataCallback;
    
    //获取存储录像录像列表
    config.query_storage_record_cb = queryStorageRecordCallback;
    
    //触发设备抓图
    config.trigger_pic_capture_cb = triggerPicCaptureCallback;
    
    //触发设备录像
    config.trigger_record_cb = triggerRecordCallback;
    
    //初始化SDK,失败则退出
    int ret = lv_init(&config);
    if (ret < 0) {
        return -1;
    }
  • lv_destroy
    接口名称 接口详情 描述
    lv_destroy int lv_destroy(void); SDK销毁,该接口的使用说明如下。
    • 推荐在调用lv_destroy前调用IOT_Linkkit_Close。
    • 调用lv_destroy时,耗时会高达数秒。在正常的业务逻辑内,不建议您反复调用lv_destroy。

    无请求参数。

    示例代码如下。

    //运行结束后
    lv_destroy();

六、API详述-视频播放功能

视频播放分为直播、卡录像点播、云储存播放,在视音频数据传输的过程,SDK采用了同一套API来实现视频播放。相关API如下。

  • lv_start_push_streaming_cb
    接口名称 接口详情 描述
    lv_start_push_streaming_cb typedef int (lv_start_push_streaming_cb)(int service_id, lv_stream_type_e type, const lv_stream_param_s *param) 回调函数,通知视频播放链路已经建立成功,并附带一些配置信息。收到此回调后,您应该根据配置信息初始化编码器,并开始推送音视频数据。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    type lv_stream_type_e 链路的类型,分为直播和卡录像点播。
    param const lv_stream_param_s* 链路的参数,例如卡录像要点播的文件名称。

    示例代码如下。

    //demo,定义了回调函数start_push_streaming_cb作为lv_start_push_streaming_cb的实现
    lv_start_push_streaming_cb = start_push_streaming_cb;
    
    //demo,回调函数startPushStreamingCallback
    int start_push_streaming_cb(int service_id, lv_stream_type_e cmd_type, const lv_stream_param_s *param)
    {
        if (cmd_type == LV_STREAM_CMD_LIVE) {
            //使用lv_stream_send_video/lv_stream_send_audio推送音视频数据;
            //实际使用中建议新建线程进行数据发送
            ......
            return 0;
        } else if (cmd_type == LV_STREAM_CMD_STORAGE_RECORD_BY_FILE) {
           //使用lv_stream_send_video/lv_stream_send_audio推送音视频数据
           //实际使用中建议新建线程进行数据发送
           ......
           return 0;
        }
    
        return 0;
    }
  • lv_stop_push_streaming_cb
    接口名称 接口详情 描述
    lv_stop_push_streaming_cb typedef int (*lv_stop_push_streaming_cb)(int service_id) 回调函数,通知视频播放链路已经断开。收到此回调后,您应该停止推送音视频数据。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。

    示例代码如下。

    //demo,定义了回调函数stop_push_streaming_cb作为lv_start_push_streaming_cb的实现
    lv_stop_push_streaming_cb = stop_push_streaming_cb;
    
    //demo,回调函数stop_push_streaming_cb
    int stop_push_streaming_cb(int service_id)
    {
        if (service_id == g_live_service_id) {
            //您停止推流
        } else if (service_id == g_storage_record_service_id) {
           //您停止推流
        }
    
        return 0;
    }
  • lv_on_push_streaming_cmd_cb
    接口名称 接口详情 描述
    lv_on_push_streaming_cmd_cb typedef int (*lv_on_push_streaming_cmd_cb)(int service_id, lv_on_push_streaming_cmd_type_e cmd, const lv_on_push_streaming_cmd_param_s *param) 回调函数,通知视频播放链路建立期间,可以进行一些命令控制,例如要求发送I帧命令。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    cmd lv_on_push_streaming_cmd_type_e 控制命令,目前有开始播放、停止播放、暂停播放、恢复播放、定位、强制I帧。
    param lv_on_push_streaming_cmd_param_s * 参数值和lv_on_push_streaming_cmd_type_e有关

    示例代码如下。

    //demo,定义了回调函数on_push_streaming_cmd_cb作为lv_on_push_streaming_cmd_cb的实现
    on_push_streaming_cmd_cb = on_push_streaming_cmd_cb;
    
    int on_push_streaming_cmd_cb(int service_id, lv_on_push_streaming_cmd_type_e cmd, const lv_on_push_streaming_cmd_param_s *param)
    {
        if (cmd == LV_STORAGE_RECORD_START) {
            //卡录像开始推流
        } else if (cmd == LV_STORAGE_RECORD_STOP) {
            //卡录像停止推流
        } else if (cmd == LV_STORAGE_RECORD_PAUSE) {
            //卡录像暂停推流
        } else if (cmd == LV_STORAGE_RECORD_UNPAUSE) {
            //卡录像恢复推流
        } else if (cmd == LV_STORAGE_RECORD_SEEK) {
            //卡录像定位到某一段
        } else if (cmd == LV_LIVE_REQUEST_I_FRAME) {
            //对于直播,需要强制生成一个I帧
        }
    
        return 0;
    }
  • lv_stream_send_config
    接口名称 接口详情 描述
    lv_stream_send_config int lv_stream_send_config(int service_id, unsigned int bitrate_kbps, double duration, const lv_video_param_s *video_param, const lv_audio_param_s *audio_param) 配置发送音视频的参数。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    bitrate_kbps unsigned int 链路的码流,设置的码流越大,内部音视频数据缓冲区越大。
    duration double 文件时长,卡录像点播有效。
    video_param const lv_video_param_s* 视频的参数集。
    audio_param const lv_audio_param_s* 音频的参数集。

    示例代码如下。

    lv_video_param_s video_param;
    memset(&video_param, 0, sizeof(lv_video_param_s));
    video_param.format = LV_VIDEO_FORMAT_H264;
    video_param.fps = 25;
    
    lv_audio_param_s audio_param;
    memset(&audio_param, 0, sizeof(lv_audio_param_s));
    audio_param.format = LV_AUDIO_FORMAT_G711A;
    audio_param.channel = LV_AUDIO_CHANNEL_MONO;
    audio_param.sample_bits = LV_AUDIO_SAMPLE_BITS_16BIT;
    audio_param.sample_rate = LV_AUDIO_SAMPLE_RATE_8000;
    
    lv_stream_send_config(service_id, 1000, 0, &video_param, &audio_param);
  • lv_stream_send_video
    接口名称 接口详情 描述
    lv_stream_send_video int lv_stream_send_video(int service_id, lv_video_format_e format,unsigned char* buffer, unsigned int buffer_len, bool key_frame, unsigned int timestamp_ms) 发送视频数据。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    format lv_video_format_e 视频编码类型
    buffer unsigned char* 视频的数据。
    buffer_len unsigned int 视频的数据长度。
    key_frame bool 是否为关键帧。I帧为关键帧,P帧为非关键帧,不接受B帧。
    timestamp_ms unsigned int 视频的时间戳。

    示例代码如下。

    //demo,这个函数回调输入视频帧数据
    void linkvisual_client_video_handler(int service_id, lv_video_format_e format, unsigned char *buffer, unsigned int buffer_size,
                                         unsigned int present_time, int nal_type) {
        lv_stream_send_video(service_id, format, buffer, buffer_size, nal_type, present_time);
    }
  • lv_stream_send_audio
    接口名称 接口详情 描述
    lv_stream_send_audio int lv_stream_send_audio(int service_id, lv_audio_format_e format,unsigned char* buffer, unsigned int buffer_len, unsigned int timestamp_ms) 发送音频数据。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    format lv_audio_format_e 音频编码类型
    buffer unsigned char* 音频的数据。
    buffer_len unsigned int 音频的数据长度。
    timestamp_ms unsigned int 音频的时间戳。

    示例代码如下。

    //demo,这个函数回调输入音频帧数据
    void linkvisual_client_audio_handler(int service_id,
                                         lv_audio_format_e format,
                                         unsigned char *buffer,
                                         unsigned int buffer_size,
                                         unsigned int present_time) {
        lv_stream_send_audio(service_id, format, buffer, buffer_size, present_time);
    }
  • lv_query_storage_record_cb
    接口名称 接口详情 描述
    lv_query_storage_record_cb typedef void (lv_query_storage_record_cb)(unsigned int start_time, unsigned int stop_time, int num, const char *id, int (on_complete)(int num, const char *id, const lv_query_storage_record_response_s *response)) 回调函数,查询卡录像的文件信息。

    请求参数说明如下。

    参数 类型 说明
    start_time unsigned int 查询录像的开始时间。
    stop_time unsigned int 查询录像的结束时间。
    num int 录像数量小于等于0的时候表示已查询全部的录像。
    id const char * 查询的会话ID,需要回传。
    on_complete 函数指针 将查询结果通过该函数同步返回。

    示例代码如下。

    int dummy_ipc_report_vod_list(unsigned int start_time,
                                  unsigned int stop_time,
                                  int num,
                                  const char *id,
                                  int (*on_complete)(int num,
                                                     const char *id,
                                                     const lv_query_storage_record_response_s *response)) {
        int answer_num = g_vod_media_file_group.size();
        auto *response = new lv_query_storage_record_response_s[answer_num];
        memset(response, 0, sizeof(lv_query_storage_record_response_s) * answer_num);
        double duration = 0;
        for (int i = 0; i < answer_num; i ++) {
            MediaParse::GetDuration(g_vod_media_file_group[i], duration);
            response[i].file_size = 0;
            response[i].record_type = LV_STORAGE_RECORD_INITIATIVE;
            snprintf(response[i].file_name, 64, g_vod_media_file_group[i].c_str(), i);//注意不要溢出
            if (i == 0) {
                response[i].start_time = (int)start_time;
                response[i].stop_time = (int)start_time + (int)duration;
            } else {
                response[i].start_time = response[i - 1].stop_time;
                response[i].stop_time = response[i - 1].stop_time + (int)duration;
            }
        }    int result = on_complete(answer_num, id, response);
        printf("dummy_ipc_report_vod_list result: %d\n", result);
        delete[] response;
        return 0;
    }
  • 直播流程图直播
  • 卡录像点播流程图点播
  • 预录事件点播流程图预录
  • 云存

    云存分为事件触发云存和连续云存两种场景。您基于SDK实现直播功能即可同时实现云存功能,无需您额外开发。

视频播放功能的接口调用说明如下。

  • 强制I帧命令发出时,为了保证尽可能快速的发出I帧,您应尽可能快的产生I帧,建议在300毫秒(ms)内完成
  • 强制I帧命令发出时,您需要重新调用lv_stream_send_config发送流配置。
  • 进行卡录像的定位操作时,为了尽可能快速的显示定位后的数据,您在定位操作后,应该尽可能快速的发出I帧,同时SDK在定位操作后也不在接收音频数据和视频的P帧数据,直到I帧到达。
  • H264/H265的帧结构会有一定的要求,可以打印I帧的前256个字节进行查看,打印代码如下。
    for (int i = 0; i < ((buffer_size > 256)?256:buffer_size); i++) {
        printf("%02x ", buffer[i]);
        if ((i + 1) % 30 == 0) {
            printf("\n");
        }
    }
    printf("\n");

    H264要求I帧为:帧分隔符+SPS+帧分隔符+PPS+帧分隔符+IDR。如下图所示。

    I帧

    0x000001或者0x00000001是帧分隔符,0x67是SPS的开始,0x68是PPS的开始,0x65是IDR的开始。

    H265要求I帧为:帧分隔符+VPS+帧分隔符+SPS+帧分隔符+PPS+帧分隔符+IDR,如下图所示。

    I帧
    说明 音频目前支持G711A/LC-AAC编码方式,编码参数的支持需要参考头文件link_visual_def.h中的宏定义值。

    同一路流切换视频码流时(如主码流切为子码流、修改码流分辨率、H264/H265切换等),请保证切换后的第一帧为I帧,否则会引发花屏等现象。

七、API详述-图片服务

图片服务相关的API如下。

  • lv_trigger_pic_capture_cb
    接口名称 接口详情 描述
    lv_trigger_pic_capture_cb typedef int (lv_trigger_pic_capture_cb)(const char *id) 通知设备开始抓取图片。

    请求参数说明如下。

    参数 类型 说明
    id const char * 本次请求的ID,需要回传。
  • lv_post_alarm_image
    接口名称 接口详情 描述
    lv_post_alarm_image int lv_post_alarm_image(const char *buffer, int buffer_len, lv_event_type_e type, const char *id) 发送图片和报警事件,适用于抓图回调后进行上报,或者设备主动发起上报。

    请求参数说明如下。

    参数 类型 说明
    buffer const char * 图片数据。
    buffer_len int 图片数据长度。
    type lv_event_type_e 上报类型,分为抓图回调后进行上报和设备主动发起上报。
    id const char * 抓图回调的ID回传,主动上报时传空字符串或者NULL。

抓图功能分为App端触发抓图请求和事件侦测触发设备端主动抓图两种场景。

抓图

调用图片服务相关接口的说明如下。

  • 上传的最大图片大小为1MB。
  • 图片上传的最小间隔为1秒,频繁触发的图片将会被丢弃。
  • 图片会由SDK内部保存一份拷贝,并形成待发送的图片队列。图片队列的长度为5,在网络差的情况下,图片队列可能会满,满队列后新生成的图片将会被丢弃。
  • SDK不限制图片的格式,只要云端或者从云端拉取图片的设备能够支持解析即可。推荐使用常见的图片格式,如,jpg格式。

八、API详述-语音对讲服务

语音对讲服务相关的API如下。

  • lv_start_voice_intercom_cb
    接口名称 接口详情 描述
    lv_start_voice_intercom_cb typedef int (*lv_start_voice_intercom_cb)(int service_id) 回调函数,返回一路语音对讲服务链路已可以建立的通知。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
  • lv_voice_intercom_start_service
    接口名称 接口详情 描述
    lv_voice_intercom_start_service int lv_voice_intercom_start_service(int service_id, const lv_audio_param_s *audio_param) 建立一路语音对讲链路,在收到语音对讲开始的回调后,调用该接口。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    audio_param const lv_audio_param_s * 设备的音频参数结构体。

    示例代码如下。

    //demo,start_voice_intercom_cb是lv_start_voice_intercom_cb的实际实现
    lv_start_voice_intercom_cb = start_voice_intercom_cb;
    
    int start_voice_intercom_cb(int service_id)
    {
        //收到开始语音对讲请求时,主动开启对讲服务
        lv_audio_param_s audio_param;
        memset(&audio_param, 0, sizeof(lv_audio_param_s));
        audio_param.format = LV_AUDIO_FORMAT_G711A;
        audio_param.channel = LV_AUDIO_CHANNEL_MONO;
        audio_param.sample_bits = LV_AUDIO_SAMPLE_BITS_16BIT;
        audio_param.sample_rate = LV_AUDIO_SAMPLE_RATE_8000;
        int ret = lv_voice_intercom_start_service(service_id, &audio_param);
    
        return 0;
    }
  • lv_stop_voice_intercom_cb
    接口名称 接口详情 描述
    lv_stop_voice_intercom_cb typedef int (*lv_stop_voice_intercom_cb)(int service_id) 回调函数,返回一路语音对讲服务链路已可以断开的通知。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
  • lv_voice_intercom_stop_service
    接口名称 接口详情 描述
    lv_voice_intercom_stop_service int lv_voice_intercom_stop_service(int service_id) 断开一路语音对讲链路,在收到语音对讲结束的回调后,调用该接口。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。

    示例代码如下。

    //demo,stop_voice_intercom_cb是lv_start_voice_intercom_cb的实际实现
    lv_stop_voice_intercom_cb = stop_voice_intercom_cb;
    
    int stop_voice_intercom_cb(int service_id)
    {
        lv_voice_intercom_stop_service(service_id);
    }
  • lv_voice_intercom_receive_metadata_cb
    接口名称 接口详情 描述
    lv_voice_intercom_receive_metadata_cb typedef int (lv_voice_intercom_receive_metadata_cb)(int service_id, const lv_audio_param_s *audio_param) 回调函数,通知语音对讲时,App发送的音频参数格式。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    audio_param const lv_audio_param_s * APP发送的音频格式结构体。
  • lv_voice_intercom_receive_data_cb
    接口名称 接口详情 描述
    lv_voice_intercom_receive_data_cb typedef void (lv_voice_intercom_receive_data_cb)(const char *buffer, unsigned int buffer_len) 回调函数,语音对讲时,App发送的音频数据。

    请求参数说明如下。

    参数 类型 说明
    buffer const char * APP发送的音频数据。
    buffer_len int APP发送的音频数据长度。
  • lv_voice_intercom_send_audio
    接口名称 接口详情 描述
    lv_voice_intercom_send_audio int lv_voice_intercom_send_audio(int service_id, const char *buffer, int buffer_len , unsigned int timestamp_ms) 向其中一路语音对讲链路发送音频数据。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    buffer const char * 设备音频数据。
    buffer_len int 设备音频数据长度。
    timestamp_ms unsigned int 设备音频时间戳。

    示例代码如下。

    void linkvisual_client_audio_handler(int service_id,
                                         lv_audio_format_e format,
                                         unsigned char *buffer,
                                         unsigned int buffer_size,
                                         unsigned int present_time) {
        lv_voice_intercom_send_audio(g_voice_intercom_service_id, buffer, buffer_size, present_time);
    }

语音对讲流程图如下:

对讲

九、后续操作

生成设备固件后,您可以将固件烧录到设备中,并使用App调试Link Visual功能。建议您直接使用公版App来调试。公版App的下载请参见公版App介绍