Fix bug in BlockingAudioTrack.

Will be seen when createStreamingAudioTrack() returns null,
which will happen if the audioflinger / audiomanager are unhealthy.

Also removes some confusing synchronization from this class.

bug:6636401
Change-Id: Iaf68a305665b7bc973898145e9cd1563e2569a2b
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index fcadad7..47e2129 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -67,12 +67,10 @@
     private int mAudioBufferSize;
     private int mBytesWritten = 0;
 
-    private AudioTrack mAudioTrack;
+    // Need to be seen by stop() which can be called from another thread. mAudioTrack will be
+    // set to null only after waitAndRelease().
+    private volatile AudioTrack mAudioTrack;
     private volatile boolean mStopped;
-    // Locks the initialization / uninitialization of the audio track.
-    // This is required because stop() will throw an illegal state exception
-    // if called before init() or after mAudioTrack.release().
-    private final Object mAudioTrackLock = new Object();
 
     BlockingAudioTrack(int streamType, int sampleRate,
             int audioFormat, int channelCount,
@@ -93,19 +91,21 @@
         mStopped = false;
     }
 
-    public void init() {
+    public boolean init() {
         AudioTrack track = createStreamingAudioTrack();
+        mAudioTrack = track;
 
-        synchronized (mAudioTrackLock) {
-            mAudioTrack = track;
+        if (track == null) {
+            return false;
+        } else {
+            return true;
         }
     }
 
     public void stop() {
-        synchronized (mAudioTrackLock) {
-            if (mAudioTrack != null) {
-                mAudioTrack.stop();
-            }
+        AudioTrack track = mAudioTrack;
+        if (track != null) {
+            track.stop();
         }
         mStopped = true;
     }
@@ -120,6 +120,12 @@
     }
 
     public void waitAndRelease() {
+        AudioTrack track = mAudioTrack;
+        if (track == null) {
+            if (DBG) Log.d(TAG, "Audio track null [duplicate call to waitAndRelease ?]");
+            return;
+        }
+
         // For "small" audio tracks, we have to stop() them to make them mixable,
         // else the audio subsystem will wait indefinitely for us to fill the buffer
         // before rendering the track mixable.
@@ -129,11 +135,11 @@
         if (mBytesWritten < mAudioBufferSize && !mStopped) {
             if (DBG) {
                 Log.d(TAG, "Stopping audio track to flush audio, state was : " +
-                        mAudioTrack.getPlayState() + ",stopped= " + mStopped);
+                        track.getPlayState() + ",stopped= " + mStopped);
             }
 
             mIsShortUtterance = true;
-            mAudioTrack.stop();
+            track.stop();
         }
 
         // Block until the audio track is done only if we haven't stopped yet.
@@ -145,11 +151,9 @@
         // The last call to AudioTrack.write( ) will return only after
         // all data from the audioTrack has been sent to the mixer, so
         // it's safe to release at this point.
-        if (DBG) Log.d(TAG, "Releasing audio track [" + mAudioTrack.hashCode() + "]");
-        synchronized (mAudioTrackLock) {
-            mAudioTrack.release();
-            mAudioTrack = null;
-        }
+        if (DBG) Log.d(TAG, "Releasing audio track [" + track.hashCode() + "]");
+        track.release();
+        mAudioTrack = null;
     }
 
 
diff --git a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
index d299d70..e853c9e 100644
--- a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
@@ -87,7 +87,10 @@
         dispatcher.dispatchOnStart();
 
 
-        mAudioTrack.init();
+        if (!mAudioTrack.init()) {
+            dispatcher.dispatchOnError();
+            return;
+        }
 
         try {
             byte[] buffer = null;
@@ -242,4 +245,3 @@
         }
     }
 }
-