POST Streaming Audio over HTTP / 2 in Android

Some background:

I'm trying to develop a voice-related feature in an Android application where the user can search using voice and the server sends intermediate results while the user says (which in turn updates the user interface) and the end result when the request is complete . Since the server accepts only an HTTP / 2 connection with one socket and Android HTTPUrlConnection does not support HTTP / 2, I use Retrofit2.

I looked at this , this and this , but each example has data of a fixed length or the size can be determined in advance ... which does not apply to audio search.

Here's what my method for POST looks like:

  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 the configuration file (containing audio parameters - JSON structure) and streaming audio as follows. (Expected POST request)

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 sure how to send streams (!!) <audio_data>. I tried using Okio to create a multipart for audio this way (From: 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;
    }

That didn't work, of course. Is it right to keep recording sound samples in ResponseBody? Where exactly should I call the method Service.post(config, audio)so that I do not send the configuration file every time there is something in the sound buffer.

Also, since I have to keep sending streaming audio, how can I leave the same POST message open and not close it until the user stops talking?

OkHttp Okio. - , , . .

+4
1

, Pipe .

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

, . , - BlockingQueue<byte[]> .

+2

Source: https://habr.com/ru/post/1672965/


All Articles