POST 在 Android 中通过 HTTP/2 流式传输音频
POST Streaming Audio over HTTP/2 in Android
一些背景:
我正在尝试在 android 应用程序上开发一项与语音相关的功能,用户可以在其中使用语音进行搜索,服务器会在用户说话时发送中间结果(这反过来会更新 UI) 和查询完成时的最终结果。由于服务器仅接受 HTTP/2 单套接字连接和 Android HTTPUrlConnection doesn't support HTTP/2,我正在使用 Retrofit2.
我看过 this, this and 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[]>
或类似的东西做类似的事情。
一些背景:
我正在尝试在 android 应用程序上开发一项与语音相关的功能,用户可以在其中使用语音进行搜索,服务器会在用户说话时发送中间结果(这反过来会更新 UI) 和查询完成时的最终结果。由于服务器仅接受 HTTP/2 单套接字连接和 Android HTTPUrlConnection doesn't support HTTP/2,我正在使用 Retrofit2.
我看过 this, this and 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[]>
或类似的东西做类似的事情。