Fix issue 1992233: DTMF tones on Sholes is really long.

Add a parameter to ToneGenerator.startTone() allowing the caller to specify the tone duration. This is used by the phone application to have a precise control on the DTMF tone duration which was not possible with the use of delayed messaged.
Also modified AudioFlinger output threads so that 0s are written to the audio output stream when no more tracks are ready to mix instead of just sleeping. This avoids an issue where the end of a previous DTMF tone could stay in audio hardware buffers and be played just before the beginning of the next DTMF tone.
diff --git a/api/current.xml b/api/current.xml
index 2d13363..c8384e4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -78336,6 +78336,19 @@
 <method name="startTone"
  return="boolean"
  abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toneType" type="int">
+</parameter>
+</method>
+<method name="startTone"
+ return="boolean"
+ abstract="false"
  native="true"
  synchronized="false"
  static="false"
@@ -78345,6 +78358,8 @@
 >
 <parameter name="toneType" type="int">
 </parameter>
+<parameter name="durationMs" type="int">
+</parameter>
 </method>
 <method name="stopTone"
  return="void"
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index a4388de8..07bb1ab 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -38,7 +38,7 @@
 };
 static fields_t fields;
 
-static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, jint toneType) {
+static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, jint toneType, jint durationMs) {
     LOGV("android_media_ToneGenerator_startTone: %x\n", (int)thiz);
 
     ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
@@ -48,7 +48,7 @@
         return false;
     }
 
-    return lpToneGen->startTone(toneType);
+    return lpToneGen->startTone(toneType, durationMs);
 }
 
 static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) {
@@ -120,7 +120,7 @@
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    { "startTone", "(I)Z", (void *)android_media_ToneGenerator_startTone },
+    { "startTone", "(II)Z", (void *)android_media_ToneGenerator_startTone },
     { "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone },
     { "release", "()V", (void *)android_media_ToneGenerator_release },
     { "native_setup", "(II)V", (void *)android_media_ToneGenerator_native_setup },
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index eafa661..ea6bf5d 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -154,7 +154,7 @@
     ToneGenerator(int streamType, float volume);
     ~ToneGenerator();
 
-    bool startTone(int toneType);
+    bool startTone(int toneType, int durationMs = -1);
     void stopTone();
 
     bool isInited() { return (mState == TONE_IDLE)?false:true;}
@@ -246,6 +246,7 @@
     // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly
     // only if tone duration is less than about 27 Hours(@44100Hz sampling rate). If this time is exceeded,
     // no crash will occur but tone sequence will show a glitch.
+    unsigned int mMaxSmp;  // Maximum number of audio samples played (maximun tone duration)
 
     unsigned short mCurSegment;  // Current segment index in ToneDescriptor segments[]
     unsigned short mCurCount;  // Current sequence repeat count
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 8cb89c3..e2b6b51 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1160,7 +1160,7 @@
 
 bool AudioFlinger::MixerThread::threadLoop()
 {
-    unsigned long sleepTime = kBufferRecoveryInUsecs;
+    unsigned long sleepTime = 0;
     int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
     size_t enabledTracks = 0;
@@ -1215,6 +1215,7 @@
                     }
 
                     standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    sleepTime = 0;
                     continue;
                 }
             }
@@ -1222,14 +1223,31 @@
             enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
        }
 
-        if (LIKELY(enabledTracks)) {
-            // mix buffers...
-            mAudioMixer->process(curBuf);
 
-            // output audio to hardware
-            if (mSuspended) {
-                usleep(kMaxBufferRecoveryInUsecs);
+        // output audio to hardware
+        if (mSuspended) {
+            usleep(kMaxBufferRecoveryInUsecs);
+        } else {
+            if (LIKELY(enabledTracks)) {
+                // mix buffers...
+                mAudioMixer->process(curBuf);
+                sleepTime = 0;
+                standbyTime = systemTime() + kStandbyTimeInNsecs;
             } else {
+                sleepTime += kBufferRecoveryInUsecs;
+                // There was nothing to mix this round, which means all
+                // active tracks were late. Sleep a little bit to give
+                // them another chance. If we're too late, write 0s to audio
+                // hardware to avoid underrun.
+                if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                    usleep(kBufferRecoveryInUsecs);
+                } else {
+                    memset (curBuf, 0, mixBufferSize);
+                    sleepTime = 0;
+                }
+            }
+            // sleepTime == 0 means PCM data were written to mMixBuffer[]
+            if (sleepTime == 0) {
                 mLastWriteTime = systemTime();
                 mInWrite = true;
                 int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
@@ -1237,24 +1255,11 @@
                 mNumWrites++;
                 mInWrite = false;
                 mStandby = false;
-                nsecs_t temp = systemTime();
-                standbyTime = temp + kStandbyTimeInNsecs;
-                nsecs_t delta = temp - mLastWriteTime;
+                nsecs_t delta = systemTime() - mLastWriteTime;
                 if (delta > maxPeriod) {
                     LOGW("write blocked for %llu msecs", ns2ms(delta));
                     mNumDelayedWrites++;
                 }
-                sleepTime = kBufferRecoveryInUsecs;
-            }
-        } else {
-            // There was nothing to mix this round, which means all
-            // active tracks were late. Sleep a little bit to give
-            // them another chance. If we're too late, the audio
-            // hardware will zero-fill for us.
-            // LOGV("thread %p no buffers - usleep(%lu)", this, sleepTime);
-            usleep(sleepTime);
-            if (sleepTime < kMaxBufferRecoveryInUsecs) {
-                sleepTime += kBufferRecoveryInUsecs;
             }
         }
 
@@ -1568,7 +1573,7 @@
 
 bool AudioFlinger::DirectOutputThread::threadLoop()
 {
-    unsigned long sleepTime = kBufferRecoveryInUsecs;
+    unsigned long sleepTime = 0;
     sp<Track> trackToRemove;
     sp<Track> activeTrack;
     nsecs_t standbyTime = systemTime();
@@ -1618,6 +1623,7 @@
                     }
 
                     standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    sleepTime = 0;
                     continue;
                 }
             }
@@ -1710,46 +1716,48 @@
             }
        }
 
-        if (activeTrack != 0) {
-            AudioBufferProvider::Buffer buffer;
-            size_t frameCount = mFrameCount;
-            curBuf = (int8_t *)mMixBuffer;
-            // output audio to hardware
-            mLastWriteTime = systemTime();
-            mInWrite = true;
-            while(frameCount) {
-                buffer.frameCount = frameCount;
-                activeTrack->getNextBuffer(&buffer);
-                if (UNLIKELY(buffer.raw == 0)) {
-                    memset(curBuf, 0, frameCount * mFrameSize);
-                    break;
+        // output audio to hardware
+        if (mSuspended) {
+            usleep(kMaxBufferRecoveryInUsecs);
+        } else {
+            if (activeTrack != 0) {
+                AudioBufferProvider::Buffer buffer;
+                size_t frameCount = mFrameCount;
+                curBuf = (int8_t *)mMixBuffer;
+                // output audio to hardware
+                while(frameCount) {
+                    buffer.frameCount = frameCount;
+                    activeTrack->getNextBuffer(&buffer);
+                    if (UNLIKELY(buffer.raw == 0)) {
+                        memset(curBuf, 0, frameCount * mFrameSize);
+                        break;
+                    }
+                    memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
+                    frameCount -= buffer.frameCount;
+                    curBuf += buffer.frameCount * mFrameSize;
+                    activeTrack->releaseBuffer(&buffer);
                 }
-                memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
-                frameCount -= buffer.frameCount;
-                curBuf += buffer.frameCount * mFrameSize;
-                activeTrack->releaseBuffer(&buffer);
-            }
-            if (mSuspended) {
-                usleep(kMaxBufferRecoveryInUsecs);
+                sleepTime = 0;
+                standbyTime = systemTime() + kStandbyTimeInNsecs;
             } else {
+                sleepTime += kBufferRecoveryInUsecs;
+                if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                    usleep(kBufferRecoveryInUsecs);
+                } else {
+                    memset (mMixBuffer, 0, mFrameCount * mFrameSize);
+                    sleepTime = 0;
+                }
+            }
+
+            // sleepTime == 0 means PCM data were written to mMixBuffer[]
+            if (sleepTime == 0) {
+                mLastWriteTime = systemTime();
+                mInWrite = true;
                 int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
                 if (bytesWritten) mBytesWritten += bytesWritten;
                 mNumWrites++;
                 mInWrite = false;
                 mStandby = false;
-                nsecs_t temp = systemTime();
-                standbyTime = temp + kStandbyTimeInNsecs;
-                sleepTime = kBufferRecoveryInUsecs;
-            }
-        } else {
-            // There was nothing to mix this round, which means all
-            // active tracks were late. Sleep a little bit to give
-            // them another chance. If we're too late, the audio
-            // hardware will zero-fill for us.
-            //LOGV("no buffers - usleep(%lu)", sleepTime);
-            usleep(sleepTime);
-            if (sleepTime < kMaxBufferRecoveryInUsecs) {
-                sleepTime += kBufferRecoveryInUsecs;
             }
         }
 
diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index c60a1ac..d4ae80f 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -744,7 +744,7 @@
      * This method starts the playback of a tone of the specified type.
      * only one tone can play at a time: if a tone is playing while this method is called,
      * this tone is stopped and replaced by the one requested.
-     * @param toneType   The type of tone generate chosen from the following list:
+     * @param toneType   The type of tone generated chosen from the following list:
      * <ul>
      * <li>{@link #TONE_DTMF_0}
      * <li>{@link #TONE_DTMF_1}
@@ -846,7 +846,18 @@
      * </ul>
      * @see #ToneGenerator(int, int)
     */
-    public native boolean startTone(int toneType);
+    public boolean startTone(int toneType) {
+        return startTone(toneType, -1);
+    }
+
+    /**
+     * This method starts the playback of a tone of the specified type for the specified duration.
+     * @param toneType   The type of tone generated @see #startTone(int).
+     * @param durationMs  The tone duration in milliseconds. If the tone is limited in time by definition,
+     * the actual duration will be the minimum of durationMs and the defined tone duration. Setting durationMs to -1,
+     * is equivalent to calling #startTone(int).
+    */
+    public native boolean startTone(int toneType, int durationMs);
 
     /**
      * This method stops the tone currently playing playback.
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 799c349..4008bfd 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -791,7 +791,6 @@
 //        generators, instantiates output audio track.
 //
 //    Input:
-//        toneType:        Type of tone generated (values in enum tone_type)
 //        streamType:        Type of stream used for tone playback (enum AudioTrack::stream_type)
 //        volume:            volume applied to tone (0.0 to 1.0)
 //
@@ -869,13 +868,16 @@
 //    Description:    Starts tone playback.
 //
 //    Input:
-//        none
+//        toneType:        Type of tone generated (values in enum tone_type)
+//        durationMs:      The tone duration in milliseconds. If the tone is limited in time by definition,
+//              the actual duration will be the minimum of durationMs and the defined tone duration.
+//              Ommiting or setting durationMs to -1 does not limit tone duration.
 //
 //    Output:
 //        none
 //
 ////////////////////////////////////////////////////////////////////////////////
-bool ToneGenerator::startTone(int toneType) {
+bool ToneGenerator::startTone(int toneType, int durationMs) {
     bool lResult = false;
 
     if ((toneType < 0) || (toneType >= NUM_TONES))
@@ -896,6 +898,17 @@
     toneType = getToneForRegion(toneType);
     mpNewToneDesc = &sToneDescriptors[toneType];
 
+    if (durationMs == -1) {
+        mMaxSmp = TONEGEN_INF;
+    } else {
+        if (durationMs > (int)(TONEGEN_INF / mSamplingRate)) {
+            mMaxSmp = (durationMs / 1000) * mSamplingRate;
+        } else {
+            mMaxSmp = (durationMs * mSamplingRate) / 1000;
+        }
+        LOGV("startTone, duration limited to %d ms", durationMs);
+    }
+
     if (mState == TONE_INIT) {
         if (prepareWave()) {
             LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
@@ -1102,11 +1115,17 @@
 
 
         // Exit if tone sequence is over
-        if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
+        if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0 ||
+            lpToneGen->mTotalSmp > lpToneGen->mMaxSmp) {
             if (lpToneGen->mState == TONE_PLAYING) {
                 lpToneGen->mState = TONE_STOPPING;
             }
-            goto audioCallback_EndLoop;
+            if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
+                goto audioCallback_EndLoop;
+            }
+            // fade out before stopping if maximum duraiton reached
+            lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+            lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
         }
 
         if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {