java – 在Android中通过HTTP / 2发布流式传输音频

一些背景:

我正在尝试在Android应用程序上开发语音相关功能,用户可以使用语音进行搜索,服务器在用户说话时发送中间结果(进而更新UI),并在查询完成时发送最终结果.由于服务器只接受HTTP / 2单插槽连接和Android HTTPUrlConnection doesn’t support HTTP / 2,我使用的是Retrofit2.

我已经看了this,this和this,但是每个例子都有固定长度的数据,或者可以预先确定大小……这不是音频搜索的情况.

这是我的POST方法:

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

该方法以下列方式发送配置文件(包含音频参数–JSON结构)和流式音频. (预期的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--

不确定如何发送流媒体(!!)< audio_data> .我尝试使用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;
    }

这当然不起作用.这是继续向ResponseBody写入音频样本的正确方法吗?我应该在哪里调用Service.post(config,audio)方法,这样每次音频缓冲区中都有东西时我都不会发布配置文件.

此外,由于我必须继续发送流式音频,如何在用户停止讲话之前保持相同的POST连接打开而不关闭它?

我基本上是OkHttp和Okio的新手.如果我遗漏了任何内容或部分代码不清楚,请告诉我,我会上传该代码段.谢谢.

最佳答案 您可以使用 Pipe从音频线程生成数据并在网络线程上使用它.

从newly-created OkHttp recipe开始:

/**
 * 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());
  }
}

如果您的数据可以作为连续流写入,则此方法最有效.如果它不能,你可能最好用BlockingQueue< byte []>做类似的事情.或类似的.

点赞