本章详细描述Linux版本LinkVisual设备端SDK相关API。

SDK生命周期

  • lv_init

    接口详情:int lv_init(const lv_config_s *config)

    SDK初始化。

    请求参数说明如下。

    参数 类型 说明
    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

    接口详情:int lvdestroy(void);

    SDK销毁。

    无请求参数。

    示例代码如下。

    //运行结束后
    lv_destroy();
  • 关于接口调用的其他说明如下。
    • lv_init会打印相关版本号信息,获取技术支持时请提供该版本信息,方便追溯问题。
    • lv_init设备初始化不会因无网络而失败,有可能是入参不正确或者资源分配失败,请您确认入参和资源分配。
    • lv_init注册了大量的回调函数,这些回调函数共用一个消息队列线程,因此一个回调消息的阻塞将导致后续消息的延迟,一个回调的永久阻塞将导致所有回调无法抛出。建议开发者不要在回调中做过于耗时的操作。
    • lv_init定义了日志类型log_level,建议对接初期将日志类型设置为LV_LOG_DEBUG。
    • 推荐lv_init在IOT_Linkkit_Connect成功后调用。
    • 推荐lv_destroy在IOT_Linkkit_Close调用之前调用。

Linkkit消息注入

LinkVisual需要接受Link Kit下发的部分消息并代为处理,处理用接口为lv_linkkit_adapter,已被LinkVisual处理过的消息不再需要开发者处理。

  • lv_linkkit_adapter

    接口详情:int lvlinkkit_adapter(lv_linkkit_adapter_type_s type, const lv_linkkit_adapter_property_s *in);

    SDK初始化。

    请求参数说明如下。

    参数 类型 说明
    type lv_linkkit_adapter_type_s Link Kit的消息适配类型,目前有Link Kit物模型服务类消息和LinkVisual自定义消息。
    in const lv_linkkit_adapter_property_s* Link Kit的消息结构体。

    示例代码如下。

    IOT_RegisterCallback(ITE_LINK_VISUAL, user_link_visual_handler);//订阅了LinkVisual自定义消息回调
    IOT_RegisterCallback(ITE_SERVICE_REQUST, user_service_request_event_handler);//订阅了Linkkit物模型服务类消息回调
  • ITE_LINK_VISUAL

    ITE_LINK_VISUAL是LinkVisual自定义的消息。由于Link Kit v2.3.0接口暂不支持自定义消息,因此LinkVisual修改了Link Kit部分代码,非LinkVisual专用的Link Kit版本将无法使用该功能。

    自定义消息全部由LinkVisual处理业务逻辑。

    //user_link_visual_handler为IOT_RegisterCallback使用ITE_LINK_VISUAL订阅的回调,
    //在回调中,所有消息都使用lv_linkkit_adapter注入
    static int user_link_visual_handler(const int devid, const char *payload,
                                        const int payload_len)
    {
        //Linkvisual自定义的消息,直接全交由LinkVisual来处理
        if (payload == nullptr || payload_len == 0) {
            return 0;
        }
    
        lv_linkkit_adapter_property_s in = {0};
        in.request = payload;
        in.request_len = payload_len;
        int ret = lv_linkkit_adapter(LV_LINKKIT_ADAPTER_TYPE_LINK_VISUAL, &in);
        if (ret < 0) {
            EXAMPLE_TRACE("LinkVisual process service request failed, ret = %d", ret);
            return -1;
        }
    
        return 0;
    }
  • ITE_SERVICE_REQUST

    ITE_SERVICE_REQUST是Link Kit定义的物模型服务类消息,部分物模型消息需要由LinkVisual处理业务逻辑,此类消息需要使用lv_linkkit_adapter来处理。

    //LinkVisual代为处理的服务类消息
    static std::vector<std::string> link_visual_service = {
        "TriggerPicCapture",//触发设备抓图
        "StartVoiceIntercom",//开始语音对讲
        "StopVoiceIntercom",//停止语音对讲
        "StartVod",//开始录像观看
        "StartVodByTime",//开始录像按时间观看
        "StopVod",//停止录像观看
        "QueryRecordList",//查询录像列表
        "StartP2PStreaming",//开始P2P直播
        "StartPushStreaming",//开始直播
        "StopPushStreaming",//停止直播
    };
    
    //user_service_request_event_handler为IOT_RegisterCallback使用ITE_SERVICE_REQUST订阅的回调,
    //在回调中,判断当前消息是否需要LinkVisual处理,如需要,则使用lv_linkkit_adapter注入
    static int user_service_request_event_handler(const int devid, const char *id, const int id_len,
                                                const char *serviceid, const int serviceid_len,
                                                const char *request, const int request_len,
                                                char **response, int *response_len)
    {
          /* 打印方式1 */
        printf("Service Request Received, Devid: %d, ID %.*s, Service ID: %.*s, Payload: %s \n",
                        devid, id_len, id, serviceid_len, serviceid, request);
        /* 打印方式2 */
        printf("Service Request Received, Devid: %d, ID %s, Service ID: %s, Payload: %s \n",
                        devid, id, serviceid, request);
          bool link_visual_process = false;
          //判断当前serviceid是否是LinkVisual需要处理的消息
        for (int i = 0; i < link_visual_service.size(); i++) {
            //这里需要根据字符串的长度来判断
            if (!strncmp(serviceid, link_visual_service[i].c_str(), link_visual_service[i].length())) {
                link_visual_process = true;
                break;
            }
        }
    
           //根据前文的判断,将需要LinkVisual处理的消息使用lv_linkkit_adapter注入
        if (link_visual_process) {
            //ISV将某些服务类消息交由LinkVisual来处理,不需要处理response
            lv_linkkit_adapter_property_s in = {0};
            in.dev_id = devid;
            in.id = id;
            in.id_len = id_len;
            in.service_id = serviceid;
            in.service_id_len = serviceid_len;
            in.request = request;
            in.request_len = request_len;
            int ret = lv_linkkit_adapter(LV_LINKKIT_ADAPTER_TYPE_TSL_SERVICE, &in);
            if (ret < 0) {
                EXAMPLE_TRACE("LinkVisual process service request failed, ret = %d", ret);
                return -1;
            }
        } else {
            //这里给一个非LinkVisual处理的消息示例
            if (!strncmp(serviceid, "PTZActionControl", (serviceid_len > 0)?serviceid_len:0)) {
                cJSON *root = cJSON_Parse(request);
                if (root == NULL) {
                    EXAMPLE_TRACE("JSON Parse Error");
                    return -1;
                }
    
                int action_type = 0;
                cJSON *child = cJSON_GetObjectItem(root, "ActionType");
                if (!child) {
                    EXAMPLE_TRACE("JSON Parse Error");
                    cJSON_Delete(root);
                    return -1;
                }
                action_type = child->valueint;
    
                int step = 0;
                child = cJSON_GetObjectItem(root, "Step");
                if (!child) {
                    EXAMPLE_TRACE("JSON Parse Error");
                    cJSON_Delete(root);
                    return -1;
                }
                step = child->valueint;
    
                cJSON_Delete(root);
                EXAMPLE_TRACE("PTZActionControl %d %d", action_type, step);
            }
        }
    
        return 0;
    }
  • PTZ功能

    LinkVisual定义了PTZ属性,但是这些PTZ消息,需要开发者自行处理。

    ITE_SERVICE_REQUST的示例代码中已经给出了PTZ的解析示例代码,此处补充PTZ的定义。

    PTZActionControl 物模型服务类标识符 说明
    ActionType 动作类型
    • 0:左
    • 1:右
    • 2:上
    • 3:下
    • 4:上左
    • 5:上右
    • 6:下左
    • 7:下右
    • 8: 放大
    • 9:缩小
    Step 步进量
    • 取值范围:0 ~ 10
    • 步长:1
  • 关于接口调用的其他说明如下。
    • 任何一个自定义消息或者物模型消息缺失,都将影响SDK的功能。若开发者不使用Demo中的示例代码,请确保自写代码中的消息成功注入了lv_linkkit_adapter。
    • 通过云产品的后台控制台的设备调试功能,云端可下发测试数据至设备,开发者可通过此方式测试注册消息。
    • Link Kit的IOT_RegisterCallback注册的回调,共用一个消息队列线程,因此一个回调消息的阻塞将导致后续消息的延迟,一个回调的永久阻塞将导致所有回调无法抛出。建议开发者不要在回调中做过于耗时的操作。
    • 在Link Kit注册IOT_RegisterCallback的ITE_SERVICE_REQUST回调中,id、serviceid、request指向同一个字符串的不同位置(对比示例代码中打印方式1和打印方式2),因此对serviceid的比较时,需要带 serviceid_len。
    • PTZ功能中,单位步进量在设备的具体步进大小可由开发者自行定义。实现了画面翻转功能的开发者,需要翻转PTZ方向的调整。

直播和卡录像点播

  • 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,定义了回调函数startPushStreamingCallback作为lv_start_push_streaming_cb的实现
    lv_start_push_streaming_cb = startPushStreamingCallback;
    
    //demo,回调函数startPushStreamingCallback
    int startPushStreamingCallback(int service_id, lv_stream_type_e cmd_type, const lv_stream_param_s *param)
    {
            //忽略不合法的service_id
            if (service_id < 0) {
            return -1;
        }
    
        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

    接口详情:typedef int (*lv_stop_push_streaming_cb)(int service_id)

    回调函数,通知直播或者卡录像点播链路已经断开。在此回调收到后,开发者应该停止推送音视频数据。

    请求参数说明如下。

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

    示例代码如下。

    //demo,定义了回调函数stopPushStreamingCallback作为lv_start_push_streaming_cb的实现
    lv_stop_push_streaming_cb = stopPushStreamingCallback;
    
    //demo,回调函数stopPushStreamingCallback
    int stopPushStreamingCallback(int service_id)
    {
            //忽略不合法的service_id
        if (service_id < 0) {
            return -1;
        }
    
        if (service_id == g_live_service_id) {
            //开发者停止推流
        } else if (service_id == g_storage_record_service_id) {
           //开发者停止推流
        }
    
        return 0;
    }
  • 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, unsigned int timestamp_ms)

    回调函数,直播、卡录像点播链接建立期间,进行一些命令控制,例如要求发送I帧命令。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
    cmd lv_on_push_streaming_cmd_type_e 控制命令,目前有开始播放、停止播放、暂停播放、恢复播放、定位、强制I帧。
    timestamp_ms unsigned int 卡录像点播的定位的时间戳。

    示例代码如下。

    //demo,定义了回调函数stopPushStreamingCallback作为lv_start_push_streaming_cb的实现
    on_push_streaming_cmd_cb = onPushStreamingCmdCb;
    
    int onPushStreamingCmdCb(int service_id, lv_on_push_streaming_cmd_type_e cmd, unsigned int timestamp_ms)
    {
        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

    接口详情: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

    接口详情:int lv_stream_send_video(int service_id, unsigned char* buffer, unsigned int buffer_len, bool key_frame, unsigned int timestamp_ms)

    视频数据发送。

    请求参数说明如下。

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

    示例代码如下。

    //demo,这个函数回调输入音频帧数据
    void handleVideoBuffer(unsigned char *buffer, unsigned int buffer_size,
        unsigned int present_time, int nal_type, int service_id) 
    {
          if (nal_type == 5) {
            lv_stream_send_video(service_id, buffer, buffer_size, 1, present_time);
        } else if (nal_type == 1) {
            lv_stream_send_video(service_id, buffer, buffer_size, 0, present_time);
        }
    }
  • lv_stream_send_audio

    接口详情:int lv_stream_send_audio(int service_id, unsigned char* buffer, unsigned int buffer_len, unsigned int timestamp_ms)

    音频数据发送。

    请求参数说明如下。

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

    示例代码如下。

    //demo,这个函数回调输入音频帧数据
    void handleAudioBuffer(unsigned char *buffer, unsigned int buffer_size,
            unsigned int present_time, int service_id) 
    {
        lv_stream_send_audio(service_id, buffer, buffer_size, present_time);
    }
  • 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 函数指针 将查询结果通过该函数同步返回。

    示例代码如下。

    //demo,该函数是lv_query_storage_record_cb的实际实现
    void queryStorageRecordCallback(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))
    {
        DEMO_TRACE("start_time:%d stop_time:%d num:%d", start_time, stop_time, num);
    
        if (num <= 0) {
            return ;
        }
        int answer_num = (num > 1)?(num - 1):1;
    
        static int index = 0;
        auto *response =  new lv_query_storage_record_response_s[num];
        memset(response, 0, sizeof(lv_query_storage_record_response_s) * answer_num);
        for (int i = 0; i < answer_num; i ++) {
            response[i].file_size = 15320990;
            response[i].record_type = (lv_storage_record_type_e)(i % 3);
            response[i].start_time = (int)start_time + index * 60;
            response[i].stop_time = (int)start_time + index * 60 + 59;
            response[i].file_size = 15320990;
            snprintf(response[i].file_name, 64, "%d.mp4", index);//注意不要溢出
            index ++;
        }
        int result = on_complete(answer_num, id, response);
        DEMO_TRACE("result:%d", result);
        delete [] response;
    }
  • lv_stream_force_stop

    接口详情:int lv_stream_force_stop(int service_id)

    强制断开一路直播、卡录像点播。开发者在自身的功能出错等无法继续正常往一路流发送数据时,自行断开连接。

    请求参数说明如下。

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

    示例代码如下。

    //demo,在收到推流通知的回调中,直接强制关闭该路链接
    int startPushStreamingCallback(int service_id, lv_stream_type_e cmd_type, const lv_stream_param_s *param)
    {
        DEMO_TRACE("startPushStreamingCallback:%d %d", service_id, cmd_type);
        if (service_id < 0) {
            return -1;
        }
          lv_stream_force_stop(service_id);
    }
  • 关于接口调用的其他说明如下。
    • 强制I帧命令发出时,为了保证尽可能快速的发出I帧,SDK内部将清空缓冲区,并不再接受音频数据和视频的P帧数据,直到I帧到达。
    • 强制I帧命令发出时,为了保证尽可能快速的发出I帧,开发者应尽可能快的产生I帧。若300毫秒(ms)内未收到I帧,SDK会重发若干次强制I帧请求。
    • 强制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/G711U/LC-AAC编码方式,编码参数的支持需要参考头文件link_visual_def.h中的宏定义值。

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

图片服务

  • lv_trigger_pic_capture_cb

    接口详情:typedef int (lv_trigger_pic_capture_cb)(const char id)

    通知设备开始抓取图片。

    请求参数说明如下。

    参数 类型 说明
    id const char * 本次请求的ID,需要回传。
  • 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。

    示例代码如下。

    //demo,读取一个图片文件并上传
    void testPicUpload(lv_event_type_e type, const char *id)
    {
        char *buf = new char[1024*1024];
        FILE *fp = nullptr;
        int ret = 0;
        if((fp = fopen("1.jpg", "r")) == nullptr) {
            DEMO_TRACE("Failed to open file.");
            return;
        }
        ret = fseek(fp, 0, SEEK_SET);
        if(ret != 0) {
            return ;
        }
    
        ret = fread(buf, 1, 1024*1024, fp);
        fclose(fp);
    
        lv_post_alarm_image(buf, ret, type, id);
        delete [] buf;
    }
  • 关于接口调用的其他说明如下。
    • 图片需要有云储存权限才可上传。
    • 上传的最大图片大小为1 MB。
    • 图片上传的最小间隔为1秒,频繁触发的图片将会被丢弃。
    • 图片会由SDK内部保存一份拷贝,并形成待发送的图片队列。图片队列的长度为5张图片,在网络差的情况下,图片队列可能会满,满队列后新生成的图片将会被丢弃。
    • SDK不限制图片的格式,只要云端或者从云端拉取图片的设备能够支持解析即可。推荐使用常见的图片格式,如,jpg格式。

语音对讲服务

  • lv_start_voice_intercom_cb

    接口详情:typedef int (*lv_start_voice_intercom_cb)(int service_id)

    回调函数,通知一路语音对讲服务已可以建立。

    请求参数说明如下。

    参数 类型 说明
    service_id int 链路的ID。
  • 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,startVoiceIntercomCallback是lv_start_voice_intercom_cb的实际实现
    lv_start_voice_intercom_cb = startVoiceIntercomCallback;
    
    int startVoiceIntercomCallback(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

    接口详情:typedef int (*lv_stop_voice_intercom_cb)(int service_id)

    回调函数,通知一路语音对讲服务已可以断开。

    请求参数说明如下。

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

    接口详情:int lv_voice_intercom_stop_service(int service_id)

    断开一路语音对讲链路,在接收到语音对讲结束回调后调用。

    请求参数说明如下。

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

    示例代码如下。

    //demo,stopVoiceIntercomCallback是lv_start_voice_intercom_cb的实际实现
    lv_stop_voice_intercom_cb = stopVoiceIntercomCallback;
    
    int stopVoiceIntercomCallback(int service_id)
    {
        lv_voice_intercom_stop_service(service_id);
    }
  • 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

    接口详情: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

    接口详情: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 handlerVoiceIntercomBuffer(unsigned char *buffer, unsigned int buffer_size,
            unsigned int present_time, int service_id) 
    {
        lv_voice_intercom_send_audio(service_id, (const char *)buffer, buffer_size, present_time);
    }

自验收标准

  • 首帧加载95%的请求,请控制在1.2秒以内。
  • 推流延迟控制在1秒以内,音视频同步应控制在300毫秒以内。
  • 设备端支持强制I帧指令,且两次I帧的最小间隔控制在100毫秒以内。
  • TF卡列表查询一天的录像文件,返回索引时间控制在1秒以内。
  • TF卡视频播放,Seek指令的响应延迟在500毫秒以内,且持续Seek 100次稳定可用。
  • 语音对讲在收到G711A编码之后的解码耗时要小于音频文件的实际时间。
  • PTZ在云台转到底之后,收到该方向的指令需忽略指令,避免指令堆积,保持对后续指令的快速响应。
  • 产生图片的延迟在300毫秒以内,直播时抓图,直播画面帧率无明显受影响。
  • 7*24打开设备,正常使用情况下,设备不会崩溃。
  • 设备支持静默定期重启机制,建议每五天自动静默重启一次,可提供用户设置。
  • 设备需支持OTA。
  • 若采用二维码配网,则二维码扫描成功时间应控制在1.5秒以内。
  • 关于语音对讲,设备端必须支持回声消除器(Acoustic Echo Canceller),确保设备端采集的音频数据没有回声。