Android 上 AVS 下行频道的 OkHttp 半闭流

OkHttp half-closed stream for AVS's downchannel on Android

我在 Android 上使用 OkHttp v3.6.0 与 AVS v20160207 进行通信。我成功地在事件通道上与 AVS 通信,以发送 SpeechRecognizer 事件和接收匹配的 SpeechSynthesizer 指令。

建立下行通道连接时,我收到 HTTP 200 Success 的成功响应,然后阻塞流以接收入站数据。当我要求 Alexa 设置 "timer for 5 seconds" 时,我收到她的提示说她将启动计时器,但我从未在下行频道收到任何指示来告诉我设置计时器。

同样有趣的是,如上所述,我从下行通道收到 HTTP 200 成功,然后可以阻止 response.body().source()。累()。但是在被阻止 10 分钟并且没有收到任何东西后,流被关闭并且我收到以下异常:

Response with Error okhttp3.internal.http2.StreamResetException: stream was reset: CANCEL at okhttp3.internal.http2.Http2Stream$FramingSource.checkNotClosed(Http2Stream.java:436) at okhttp3.internal.http2.Http2Stream$FramingSource.read(Http2Stream.java:338) at okio.ForwardingSource.read(ForwardingSource.java:35) at okio.RealBufferedSource.read(RealBufferedSource.java:409) at java.io.InputStream.read(InputStream.java:101) at com.example.demo.alexaassistant.AlexaVoiceServices.interfaces.DownChannelRunnable.run(DownChannelRunnable.java:192) at java.lang.Thread.run(Thread.java:761)

请注意,我已经尝试了此线程中的所有建议: Establishing a downchannel with Okhttp?

private static final long CONNECTION_POOL_TIMEOUT_MILLISECONDS = 60 * 60 * 1000;

        ConnectionPool connectionPool = new ConnectionPool(5,
            CONNECTION_POOL_TIMEOUT_MILLISECONDS, TimeUnit.MILLISECONDS);

        /**
         * Create a customized HTTP/2 interface.
         *
         * For the AVS's downchannel, we need to
         * disable the timeout on the read.
         */
        OkHttpClient downChannelClient = httpClient.newBuilder()
            .connectTimeout(0, TimeUnit.MILLISECONDS)  // 0 => no timeout.
            .readTimeout(0, TimeUnit.MILLISECONDS)
            .connectionPool(connectionPool)
            .build();

        final Request request = new Request.Builder()
            .url(url)
            .get()
            .addHeader("Authorization", "Bearer " + this.accessToken)
            .build();
        Log.d(TAG, "downchannel URL ==> " + request.url().toString());
        Log.d(TAG, "downchannel headers ==> " + request.headers().toString());

        Response response = null;
        try
        {
            currentCall = downChannelClient.newCall(request);
    response = currentCall.execute();
    BufferedSource bufferedSource = response.body().source();

    Log.i(TAG, "Downchannel ==> HTTP response code: " + response.code());

    Buffer buffer = new Buffer();

    while (!bufferedSource.exhausted())
    {
        Log.w(TAG, "downchannel received data!!!");
        bufferedSource.read(buffer, 8192);
        Log.d(TAG, "Size of data read: " + buffer.size());
    }

    Log.d(TAG, "Response: " + buffer.toString());
}
catch (IOException e)
{
    Log.d(TAG, "Response with Error", e);
}
finally
{
    if (response != null)
    {
        response.close();
    }
}

编辑

Amazon 的文档说,客户端需要与服务器建立一个连接,因此 POST 和 GET 流将发送到该连接以及处于半关闭流状态的下行通道。 OkHttp2 支持吗?

我终于可以在下行通道中从服务器接收数据了。我所做的是在创建下行通道时收到 200 响应后 SynchronizeState。医生说:

  1. To establish a downchannel stream your client must make a GET request to /{{API version}}/directives within 10 seconds of opening the connection with AVS. The request should look like this:

  2. After establishing the downchannel stream, your client must synchronize it’s components’ states with AVS. This requires making a POST request to /{{API version}}/events on a new event stream on the existing connection (Note: Do not open a new connection). This event stream should be closed when your client receives a response (directive). The following is an example SynchronizeState event:

希望对您有所帮助。我现在正在努力尝试解析下行通道中的结果。您的代码应该是:

Log.i(TAG, "Downchannel ==> HTTP response code: " + response.code());

...

synchronizeState();

....

Buffer buffer = new Buffer();

while (!bufferedSource.exhausted())
{
    Log.w(TAG, "downchannel received data!!!");
    bufferedSource.read(buffer, 8192);
    Log.d(TAG, "Size of data read: " + buffer.size());
}