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
。医生说:
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:
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());
}
我在 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
。医生说:
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:
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());
}