watson-developer-cloud / android-sdk

:high_brightness: Android SDK to use the IBM Watson services.
http://watson-developer-cloud.github.io/android-sdk/
Apache License 2.0
146 stars 94 forks source link

Socket error hangs Speech To Text code. #59

Closed smccants closed 6 years ago

smccants commented 6 years ago

Socket errors, 403 errors and likely similar errors that occur when sending speech data to Watson are not handled correctly and result in the app's ability to do speech to text being hung until the app is restarted.

Steps to reproduce:

  1. Use the example provided with the library.
  2. Set the URL to something wrong, such as: https://stream.watsonplatform.net/speech-tot-text/api
  3. Run the application and tap the microphone button once.
  4. Now you have the MicrophoneCaptureThread in a hung state that can only be cleared by restarting the app.

The hung thread has this stack trace:

"Thread-5@5006" prio=5 tid=0x757 nid=NA waiting
  java.lang.Thread.State: WAITING
     blocks Thread-5@5006
      at java.lang.Object.wait(Object.java:-1)
      at java.lang.Object.wait(Object.java:407)
      at java.io.PipedInputStream.awaitSpace(PipedInputStream.java:280)
      at java.io.PipedInputStream.receive(PipedInputStream.java:238)
      - locked <0x1506> (a java.io.PipedInputStream)
      at java.io.PipedOutputStream.write(PipedOutputStream.java:149)
      at java.io.OutputStream.write(OutputStream.java:75)
      at com.ibm.watson.developer_cloud.android.library.audio.MicrophoneInputStream.consume(MicrophoneInputStream.java:142)
      at com.ibm.watson.developer_cloud.android.library.audio.opus.OpusWriter.write(OpusWriter.java:236)
      at com.ibm.watson.developer_cloud.android.library.audio.opus.OpusWriter.flush(OpusWriter.java:209)
      at com.ibm.watson.developer_cloud.android.library.audio.opus.OpusWriter.writePacket(OpusWriter.java:184)
      at com.ibm.watson.developer_cloud.android.library.audio.opus.OggOpusEnc.encodeAndWrite(OggOpusEnc.java:116)
      at com.ibm.watson.developer_cloud.android.library.audio.MicrophoneCaptureThread.run(MicrophoneCaptureThread.java:99)

In the stack above, you can see MicrophoneInputStream's PipedOutputStream is waiting for available space in MicrophoneInputStream's PipedInputStream, but the reader from the PipedInputStream is SpeechToTextWebSocketListener, which has already exited without closing the stream! This is a stalemate and hang that will last forever.

Then when the code does try to close the MicrophoneInputStream (someone calls MicrophoneInputStream.end()), that thread will hang in a spin loop(!) because end() first tries to push any remaining data through the PipedOutputStream which is already hung waiting forever for the PipedInputStream that will never be read from.

This may be the same problem I reported in #50 .

smccants commented 6 years ago

I believe I have a reasonable fix for the problem.