简体中文

基于AVAPIs的文件下载

基于AVAPIs的文件下载

主要内容:

基于AVAPIs的文件下载.png

1.IO交互

2.通道的创建和销毁

3.数据的传输

4.结束标志的判断

IO交互:

1. APP会通过avSendIOCtrl(IOCTRL_FILEMANAGER_FILE_LIST_REQ)查询指定时间内的文件。设备通过avSendIOCtrl(IOCTRL_FILEMANAGER_FILE_LIST_RESP)回复对应的文件列表。

2. 当用户选中部分文件下载的时候,则APP端会avSendIOCtrl(IOCTRL_FILEMANAGER_FILE_DOWNLOAD_REQ)告知设备要下载哪些文件。设备则根据自身的硬件和软件资源,可以自定义使用的通道数,通过avSendIOCtrl(IOCTRL_FILEMANAGER_FILE_DOWNLOAD_RESP)告知APP使用哪些通道以及使用哪种APIs来进行数据传输。

3. APP和设备端分别创建对应的通道。

4. 数据传输。

5. 数据传输后关闭通道。

AV通道的创建和销毁

  • APP端创建
int createDataChannelOfClientForDownload(int sid,int iotc_channel_id)
{
    AVClientStartInConfig in;
    AVClientStartOutConfig out;

    clearMemory(&in,sizeof(in));
    clearMemory(&out,sizeof(out));

    in.cb = sizeof(in);
    in.iotc_session_id = sid;
    in.iotc_channel_id = iotc_channel_id;
    in.timeout_sec = 30;
    in.resend = 1; //此处务必要开启resend模式
    in.security_mode = AV_SECURITY_AUTO;
    if(isSDKV4){
        in.auth_type = AV_AUTH_NEBULA;
        in.account_or_identity = "";
        in.password_or_token = "";
    } else {
        in.auth_type = AV_AUTH_PASSWORD;
        in.account_or_identity = "camera account";
        in.password_or_token = "camera password";
    }

    in.sync_recv_data = 0;
    in.dtls_cipher_suites = nullptr;

    out.cb = sizeof(out);

    return avClientStartEx(&in,&out);
}
  • APP端销毁
void destoryDataChannelOfClient(int avIndex)
{
    if(avIndex < 0)
        return ;
        
    avClientStop(avIndex);
}
  • 设备端创建
int createDataChannelOfDeviceForDownload(int sid,int iotc_channel_id)
{
    AVServStartInConfig avStartInConfig;
    AVServStartOutConfig avStartOutConfig;
    
    clearMemory(&avStartInConfig,sizeof(AVServStartInConfig));
    clearMemory(&avStartOutConfig,sizeof(avStartOutConfig));

    avStartInConfig.cb               = sizeof(AVServStartInConfig);
    avStartInConfig.iotc_session_id  = sid;
    avStartInConfig.iotc_channel_id  = iotc_channel_id;
    avStartInConfig.timeout_sec      = 30;
    avStartInConfig.password_auth    = ExPasswordAuthCallBackFn;
    avStartInConfig.server_type      = 0;
    avStartInConfig.resend           = 1; //此处务必要开启resend模式
    avStartInConfig.security_mode = AV_SECURITY_DTLS;
   //avStartInConfig.json_request = ExJsonRequest;
   
    avStartOutConfig.cb = sizeof(AVServStartOutConfig);
    return avServStartEx(&avStartInConfig, &avStartOutConfig);
}
  • 设备端销毁
void destoryDataChannelOfDevice(int avIndex)
{
    if(avIndex < 0)
        return ;

    avServStop(avIndex);
}

数据的传输

AV协议本身提供了三套数据传输接口,这里我们会用到avSendIOCtrl/avRecvIOCtrl以及avSendFrameData/avRecvFrameData2这两套接口,分别用做IO和文件数据的传输,文件信息会通过FRAMEINFO_FOR_UPLOAD_DOWNLOAD_t来传输,具体定义请参考:文件传输通用定义

  • 设备端
    设备端每次发送数据,会包含2部分的数据,一部分是文件的信息,一部分是文件的二进制流。

发送数据相关(伪)代码:

#define MAX_BUFFER_SIZE 10243
int readBinaryDataFromFile(file f,char* buffer,size_t bufferSize)
{
    return f.read(buffer,bufferSize);
}

void sendFileList(void* arg)
{
    int avIndex = createDataChannelOfDeviceForDownload(sid,iotc_channel_id);
    if(avIndex < 0){
        printf("createDataChannelOfDeviceForDownload failed,error code:%d\n",avIndex);
        return ;
    }
    
    foreach(auto f,files){
    //打开文件
    f.open();
    //读取和发送文件
    FRAMEINFO_FOR_UPLOAD_DOWNLOAD_t frmInfo = {0};
    strcpy(frmInfo.fileName,fileName);
    frmInfo.fileSize = f.size();
    while(1){
        char buffer[MAX_BUFFER_SIZE] = {0};
        int readSize = readBinaryDataFromFile(f,buffer,MAX_BUFFER_SIZE);
        if(readSize < MAX_BUFFER_SIZE){
            if(readSize <= 0)
                break;
            if(f.isLastFileOfList()){
                frmInfo.endFlag = 1;                                      
            }
        } 
        
        frmInfo.frmSize = readSize;
        int ret = 0;
        
        //发送数据,如遇-20006,进行重传
        do{
            ret = avSendFrameData(avIndex,buffer,readsize,(const void*)&frmInfo,sizeof(FRAMEINFO_FOR_UPLOAD_DOWNLOAD_t));
            if(ret < 0){
                //重新发送
                if(ret == -20006){
                    msleep(20);
                } else {
                    break;
                }
            }
        } while(ret == -20006);

        //异常退出
        if(ret < 0){
            printf("avSendFrameData error :%d\n",ret);
            f.close();
            goto LAB_END;
        }
        
        //如果是最后一帧,停止发送
        if(frmInfo.endFlag){
            break;
        }
    }
    f.close();
 }

 int i_count = 0;

 while(i_count++ < 10*300){
     float userate = avResendBufUsageRate(avIndex);
     if(userate > 0.0){
         msleep(100);
     } else {
         break;
     }
  }
  
LAB_END:
    destoryDataChannelOfDevice(avIndex);

}
  • APP端
    接收端按帧读取数据,每次读取一帧,需判断是否是一个新的文件,如果是新文件,则需要关闭旧文件,打开新文件。如果endFlag为1,表示收到数据已收齐,则关闭相关的文件和通道,释放资源。接收端也可以加一些文件大小等校验,这里不另外实作。

读取通道数据和解析方法(伪)代码:

#define MAX_BUFFER_SIZE 300*1024

void recvDataAndSaveToLocalFile(void *arg)
{
    //创建通道
    int avIndex = createDataChannelOfClientForDownload(sid,iotc_channel_id);
    if(avIndex < 0){
        return;
    }

    char buffer[MAX_BUFFER_SIZE];
    QString fileName;
    uint fileSize;
    uint dataSize;
    int endFlag;
    FRAMEINFO_FOR_UPLOAD_DOWNLOAD_t frmInfo;
    int tmpInt1, tmpInt2, tmpInt3, tmpInt4;
    int ret = -1;
    uint frmNo;
    QFile f;
    
    //循环读取数据。
    while(1){
        int ret = avRecvFrameData2(dataChannelId,buffer,MAX_BUFFER_SIZE,&tmpInt1,&tmpInt2,(char*)&frmInfo,sizeof(FRAMEINFO_FOR_UPLOAD_DOWNLOAD_t),&tmpInt3,&frmNo);
        if(ret < 0){
            if(ret == AV_ER_DATA_NOREADY){
                msleep(5);
                continue;
            }
            
            if(ret == AV_ER_INCOMPLETE_FRAME || ret == AV_ER_LOSED_THIS_FRAME){
                printf("lost data\n");
                continue;
            }else{
                printf("avRecvFrameData2 return error:%d\n",ret));
                break;
            }
        }
        //拿到第一包数据,打开本地文件
        if(!f.isOpen()){
            fileName = frmInfo.fileName;
            f.open(fileName);
        }else{
            //上个文件已经读完,读取到下个文件。
            if(fileName != frmInfo.fileName()){
                f.close();
                fileName = frmInfo.fileName;
                f.open(fileName);
         }
     }
     
     f.write(buffer,ret);
     if(frmInfo.endFlag){
         printf("endFlag: true\n");
         break;
     }
  }
  
  if(f.isOpen()){
      f.close();
  }
  
  //关闭通道
  destoryDataChannelOfClient(avIndex);
}

结束标志的判断

结束标志,是从FRAMEINFO_KalayDownload_t的endFlag标志位来判读的,只有最后一个文件最后一包,endFlag才会为1,其他都为0。

即刻开启您的物联网之旅

联系解决方案专家
Kalay App
资讯安全白皮书
全球专利布局
解决方案
新闻动态
公司动态
行业资讯
媒体报道
永续发展
经营者的话
社会参与
环境永续
公司治理

+86 755 27702549

7×24小时服务热线

法律声明 隐私权条款

关注“TUTK”

TUTK服务尽在掌握

© 2022 物联智慧科技(深圳)有限公司版权所有粤ICP备14023641号
在线咨询
扫一扫

TUTK服务尽在掌握

全国免费服务热线
+86 755 27702549

返回顶部