如何使用nghttp2发送多块数据? [英] How to send multi chunk data using nghttp2?

查看:126
本文介绍了如何使用nghttp2发送多块数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用nghttp2库格式化多部分框架以与Alexa通信.我目前能够通过多部分消息获得音频的响应.但是,目前只能发送最大16KB的数据,我想对记录的数据进行流传输,整体上可以大于16KB.

I am using the nghttp2 library to format the multipart frames to communicate with Alexa. I am currently able to get the response of audio with a multipart message. But, currently it is only possible to send data up to 16KB, I want to do streaming of my recorded data which can be greater than 16KB as a whole.

有人可以帮助我使用nghttp2将数据块中的音频数据发送到AVS吗?

Can anyone please help me in sending the audio data in the chunk to the AVS using nghttp2?

期待您的回复,请帮忙.

Looking forward to the response, please help.

谢谢.

此外,我正在从代码中添加参考功能.请忽略名称约定和其他逻辑,因为我只是在做一些尝试以发送超过16KB的数据.

In addition, I am adding the reference functions from the code. Please ignore the name convention and other logic as I am just trying this ruffly to send the data over 16KB size.

    //Callback function for the data to be send to the server
ssize_t data_prd_read_callback_1(nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length,uint32_t *data_flags, nghttp2_data_source *source, void *user_data)
{
    //uint8_t send_data[8000]; 
    char send_data[] = "\r\n\r\n--_____FINISH_HERE__________\r\nContent-Disposition: form-data; name=\"metadata\"\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n{\"context\":[{\"header\": {\"namespace\": \"SpeechSynthesizer\",\"name\": \"SpeechState\"},\"payload\": {\"token\":\"\",\"offsetInMilliseconds\":0,\"playerActivity\":\"IDLE\"}}],\"event\":{\"header\":{\"namespace\":\"SpeechRecognizer\",\"name\":\"Recognize\",\"messageId\":\"MID-123456\",\"dialogRequestId\":\"DRID-123456\"},\"payload\":{\"profile\":\"CLOSE_TALK\",\"format\":\"AUDIO_L16_RATE_16000_CHANNELS_1\"}}}\r\n\r\n--_____FINISH_HERE__________\r\nContent-Disposition: form-data; name=\"audio\"\r\nContent-Type: application/octet-stream\r\n\r\n";

    int fd = source->fd;
    uint8_t *audio_data;
    uint8_t *final_data_end, *temp_data;
    audio_data = malloc(AUDIO_FILE_SIZE);
    memset(audio_data, 0, AUDIO_FILE_SIZE);
    final_data_end = malloc(MAX_SIZE_TO_SEND);
    temp_data = final_data_end;
    memset(final_data_end, 0, MAX_SIZE_TO_SEND);
    int r;
    r = read(fd, audio_data, AUDIO_FILE_SIZE);
    if ( r == -1)
    {
        printf("JOSHI error while reading audio file\n");
    }
    int len, i;
    len = strlen(send_data);
    memcpy(final_data_end, send_data, strlen(send_data));
    final_data_end += strlen(send_data);
    memcpy(final_data_end, audio_data, AUDIO_FILE_SIZE);
    final_data_end += AUDIO_FILE_SIZE;
    memcpy(final_data_end, "\r\n--_____FINISH_HERE__________--", 32);
    memcpy(buf, temp_data, (strlen(send_data) + AUDIO_FILE_SIZE + 32));
    return (strlen(send_data) + AUDIO_FILE_SIZE + 32);
}


static int send_request(struct connection *conn, struct request *req) {
    nghttp2_nv nva[] = { 
                MAKE_NV_LL(":method", "POST"),
                MAKE_NV_L(":scheme", "https"),
                MAKE_NV_LL(":path", "/v20160207/events" ),
        MAKE_NV_LL("authorization", "Bearer "ACCESS_TOKEN""),
        MAKE_NV_LL("content-type", "multipart/form-data; boundary=_____FINISH_HERE__________")};
    int rv;

    nghttp2_data_provider data_prd;
    int file_descriptor;
    file_descriptor = open ("./audio.raw", O_RDONLY);
    if (file_descriptor == -1)
    {
        printf("error while reading the audio file\n");
    }
    data_prd.source.fd = file_descriptor;   // set the file descriptor 
    data_prd.read_callback = data_prd_read_callback_1;

    rv = nghttp2_submit_request(conn->ngh2, NULL, nva, ARRLEN(nva), &data_prd, req);
    temp_stream_id = rv;
    if (rv < 0) {
        fprintf(stderr, "In second error: (nghttp2_submit_requset) %s\n",nghttp2_strerror(rv));
        return -1; 
    }   
    return 0;
}

我正在使用"nghttp2_session_send"进行带有send_callback函数的发送.每当我尝试使用超过16KB的文件时,AVS都会以错误状态为:400的分段数据"答复.如果整个数据小于16KB,那么alexa会回复并附上音频数据作为响应.

I am using "nghttp2_session_send" for the sending with send_callback function. Whenever I try with file beyond the 16KB size AVS will reply with ERROR "there is no multipart data with status:400". If the whole data is less than 16KB then alexa will reply with audio data attached in response.

推荐答案

您需要对尚未完成编写的nghttp进行说明.按照教程:

You need to specity to nghttp that you did not finish writing. As written in tutorial:

static ssize_t file_read_callback(nghttp2_session *session _U_,
                                  int32_t stream_id _U_, uint8_t *buf,
                                  size_t length, uint32_t *data_flags,
                                  nghttp2_data_source *source,
                                  void *user_data _U_) {
  int fd = source->fd;
  ssize_t r;
  while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
    ;
  if (r == -1) {
    return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
  }
  if (r == 0) {
    *data_flags |= NGHTTP2_DATA_FLAG_EOF;
  }
  return r;
}

您可以看到,当没有更多数据要读取时,它们会将* data_flags设置为NGHTTP2_DATA_FLAG_EOF.因此,如果您有几个MB文件且只有16k缓冲区,则必须保持一定的偏移量,并且在data_prd_read_callback_1的每次调用中最多写入16k,然后在最后一次迭代中写入其余部分(例如10k或剩余的任何值).我用这种方式:

You can see that they set the *data_flags to NGHTTP2_DATA_FLAG_EOF when there is no more data to read. So if you have several MB file and only 16k buffer then you have to keep some offset and in every call of your data_prd_read_callback_1 write max 16k and then in the last iteration write the rest (say 10k or whatever is left). I use it this way:

ssize_t Message::Http2DataLoader( nghttp2_session *sess, int32_t sId, uint8_t *buf, size_t bufLen, uint32_t *dataFlags, nghttp2_data_source *src, void *hint )
{
   ssize_t ret = 0;
   Message* theRes = reinterpret_cast< Message* >( src->ptr );

   if ( bufLen <= theRes->getDataLen() - theRes->getWritten() )
   {
      std::memcpy( buf, theRes->getData() + theRes->getWritten(), bufLen );
      ret = bufLen;
   }
   else
   {
      std::memcpy( buf, theRes->getData() + theRes->getWritten(), theRes->getDataLen() - theRes->getWritten() );
      ret = theRes->getDataLen() - theRes->getWritten();
   }

   theRes->addWritten( ret );

   if( theRes->AllDataConsumed() )
   {
      *dataFlags |= NGHTTP2_DATA_FLAG_EOF;
   }

   return ret;
}

Message类是一个可以包含主体数据或多部分的容器,添加后的所有多部分都将其数据写入内部消息缓冲区,然后在dataloader回调中,我仅以16k块的形式编写它(或者最好在中说)bufLen 块).我使用 addWritten getWritten 方法跟踪缓冲区中的位置.比赛由 AllDataConsumed 处理.如果您正在从文件中读取音频片段,则需要类似本教程中的file_read_callback的内容.如果您将其封装到某些 Message 类中,则可以添加一些json多部分和音频多部分,并修改dataLoader回调以首先写入json部分,然后开始读取音频文件并添加写入,这将是很好的以 16k( bufLen )块的形式 buf .

The Message class is a container that can contain either body data or multiparts, all multiparts when added writes its data to internal Message buffer and then in the dataloader callback I just write it in 16k chunks (or better say in bufLen chunks). I keep track where am I in the buffer using addWritten and getWritten methods. The competition is handled by AllDataConsumed. If you are reading the audio multipart from file then you need something like the file_read_callback from tutorial. It would be good if you encapsulate that into some Message class where you can add some json multipart and audio multipart and modify the dataLoader callback to first write the json part and then start reading the audio file and adding writing it to buf in 16k(bufLen) chunks.

nghttp2_session_send 将调用您的 data_prd_read_callback_1 ,直到您写入所有数据或发生某些错误为止.这意味着您可以根据需要处理对缓冲区的JSON写操作和对缓冲区的音频文件写操作.如果一切顺利,它将只是调用您的回调,直到将 * data_flags设置为NGHTTP2_DATA_FLAG_EOF .

The nghttp2_session_send will call your data_prd_read_callback_1 until you write all your data or some error happens. This means that you can handle the JSON write to buffer and audio file write to buffer as you need. If everything goes well it will be just calling your callback until you set the *data_flags to NGHTTP2_DATA_FLAG_EOF.

希望这对您有所帮助.

这篇关于如何使用nghttp2发送多块数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆