2017-03-22 135 views
4

一些背景资料/ 2:POST流式音频通过HTTP Android中

我想开发在Android应用程式语音相关的功能,使用户可以使用语音搜索和服务器发送中间结果,而用户说话(反过来更新UI)以及查询完成时的最终结果。由于服务器只接受HTTP/2单套接字连接和Android HTTPUrlConnection doesn't support HTTP/2,我正在使用Retrofit2。

我已经看过thisthisthis但每个实施例中具有固定长度的数据,或者可以预先确定的尺寸...这对于音频搜索的情况。

这里就是我的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>。我试着用奥基奥以这种方式(来源: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的新手。如果我错过了任何东西或部分代码不清楚,请让我知道,我会上传该代码段。谢谢。

回答

2

您可能可以使用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[]>或类似的事情。

+0

那么基本上以生产者 - 消费者的方式解决它?可以使用okio完成吗?如何使用一个POST将音频数据追加到@Part(“audio”)RequestBody audio'中? – Papps

+0

Pipe类应该有所帮助。运行示例以查看控制流的外观。 –

+0

与Pipe有同步问题。目前,它正在使用BlockingQueue 。 – Papps