简体   繁体   English

在Android中通过HTTP / 2进行POST流音频

[英]POST Streaming Audio over HTTP/2 in Android

Some background: 一些背景:

I am trying to develop a voice-related feature on the android app where a user can search using voice and the server sends intermediate results while user is speaking (which in turn updates the UI) and the final result when the query is complete. 我正在尝试在android应用程序上开发与语音相关的功能,用户可以在其中使用语音进行搜索,并且服务器会在用户讲话时发送中间结果(依次更新UI),并在查询完成后发送最终结果。 Since the server accepts only HTTP/2 single socket connection and Android HTTPUrlConnection doesn't support HTTP/2 yet, I am using Retrofit2. 由于服务器仅接受HTTP / 2单套接字连接,而Android HTTPUrlConnection 尚不支持 HTTP / 2,因此我正在使用Retrofit2。

I have looked at this , this and this but each example has fixed length data or the size can be determined beforehand... which is not the case for audio search. 我已经看过了这个这个这个,但是每个示例都有固定长度的数据,或者可以事先确定大小……对于音频搜索而言,情况并非如此。

Here's what my method for POST looks like: 这是我的POST方法:

  public interface Service{
    @Streaming
    @Multipart
    @POST("/api/1.0/voice/audio")
    Call<ResponseBody> post(
            @Part("configuration") RequestBody configuration,
            @Part ("audio") RequestBody audio);
}

The method sends configuration file(containing audio parameters - JSON structure) and streaming audio in the following manner. 该方法以以下方式发送配置文件(包含音频参数-JSON结构)和流音频。 (Expected POST request) (预期的POST请求)

Content-Type = multipart/form-data;boundary=----------------------------41464684449247792368259
//HEADERS
----------------------------414646844492477923682591
Content-Type: application/json; charset=utf-8
Content-Disposition: form-data; name="configuration"
//JSON data structure with different audio parameters.
----------------------------414646844492477923682591
Content-Type: audio/wav; charset=utf-8
Content-Disposition: form-data; name="audio"
<audio_data>
----------------------------414646844492477923682591--

Not really sure about how to send streaming(!!) <audio_data> . 不太确定如何发送流(!!) <audio_data> I tried using Okio to create multipart for audio in this way (From: https://github.com/square/okhttp/wiki/Recipes#post-streaming ) 我尝试使用Okio以这种方式为音频创建多部分(来自: https : //github.com/square/okhttp/wiki/Recipes#post-streaming

public RequestBody createPartForAudio(final byte[] samples){
        RequestBody requestBody = new RequestBody() {
            @Override
            public MediaType contentType() {
                return MediaType.parse("audio/wav; charset=utf-8");
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                //Source source = null;
                sink.write(samples);        

            }
        };

        return requestBody;
    }

This didn't work of course. 这当然没有用。 Is this a right way to keep on writing audio samples to ResponseBody? 这是继续将音频样本写入ResponseBody的正确方法吗? Where exactly should I call Service.post(config, audio) method so that I don't end up posting configuration file every time there is something in the audio buffer. 我到底应该在哪里调用Service.post(config, audio)方法,这样我就不会在每次音频缓冲区中有东西时都结束发布配置文件。

Also, since I have to keep on sending streaming audio, how can I keep the same POST connection open and not close it until user has stopped speaking? 另外,由于必须继续发送流音频,因此如何保持相同的POST连接保持打开状态,直到用户停止讲话才将其关闭?

I am basically new to OkHttp and Okio. 我基本上是OkHttp和Okio的新手。 If I have missed anything or part of the code is not clear please let me know and I'll upload that snippet. 如果我错过了任何内容或部分代码不清楚,请让我知道,我将上传该代码段。 Thank you. 谢谢。

You might be able to use a Pipe to produce data from your audio thread and consume it on your networking thread. 您也许可以使用Pipe从音频线程中产生数据并在网络线程中使用它。

From a newly-created OkHttp recipe : 通过新创建的OkHttp配方

/**
 * This request body makes it possible for another
 * thread to stream data to the uploading request.
 * This is potentially useful for posting live event
 * streams like video capture. Callers should write
 * to {@code sink()} and close it to complete the post.
 */
static final class PipeBody extends RequestBody {
  private final Pipe pipe = new Pipe(8192);
  private final BufferedSink sink = Okio.buffer(pipe.sink());

  public BufferedSink sink() {
    return sink;
  }

  @Override public MediaType contentType() {
    ...
  }

  @Override public void writeTo(BufferedSink sink) throws IOException {
    sink.writeAll(pipe.source());
  }
}

This approach will work best if your data can be written as a continuous stream. 如果您的数据可以连续写入,则此方法最有效。 If it can't, you might be better off doing something similar with a BlockingQueue<byte[]> or similar. 如果不能,那么最好用BlockingQueue<byte[]>或类似的方法做些类似的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM