Loading api/current.xml +15 −0 Original line number Original line Diff line number Diff line Loading @@ -78333,6 +78333,19 @@ visibility="public" visibility="public" > > </method> </method> <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" <method name="startTone" return="boolean" return="boolean" abstract="false" abstract="false" Loading @@ -78345,6 +78358,8 @@ > > <parameter name="toneType" type="int"> <parameter name="toneType" type="int"> </parameter> </parameter> <parameter name="durationMs" type="int"> </parameter> </method> </method> <method name="stopTone" <method name="stopTone" return="void" return="void" core/jni/android_media_ToneGenerator.cpp +3 −3 Original line number Original line Diff line number Diff line Loading @@ -38,7 +38,7 @@ struct fields_t { }; }; static fields_t fields; 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); LOGV("android_media_ToneGenerator_startTone: %x\n", (int)thiz); ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz, ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz, Loading @@ -48,7 +48,7 @@ static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, return false; return false; } } return lpToneGen->startTone(toneType); return lpToneGen->startTone(toneType, durationMs); } } static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) { static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) { Loading Loading @@ -120,7 +120,7 @@ static void android_media_ToneGenerator_native_finalize(JNIEnv *env, // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { 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 }, { "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone }, { "release", "()V", (void *)android_media_ToneGenerator_release }, { "release", "()V", (void *)android_media_ToneGenerator_release }, { "native_setup", "(II)V", (void *)android_media_ToneGenerator_native_setup }, { "native_setup", "(II)V", (void *)android_media_ToneGenerator_native_setup }, Loading include/media/ToneGenerator.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -154,7 +154,7 @@ public: ToneGenerator(int streamType, float volume); ToneGenerator(int streamType, float volume); ~ToneGenerator(); ~ToneGenerator(); bool startTone(int toneType); bool startTone(int toneType, int durationMs = -1); void stopTone(); void stopTone(); bool isInited() { return (mState == TONE_IDLE)?false:true;} bool isInited() { return (mState == TONE_IDLE)?false:true;} Loading Loading @@ -246,6 +246,7 @@ private: // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly // 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, // 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. // 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 mCurSegment; // Current segment index in ToneDescriptor segments[] unsigned short mCurCount; // Current sequence repeat count unsigned short mCurCount; // Current sequence repeat count Loading libs/audioflinger/AudioFlinger.cpp +63 −55 Original line number Original line Diff line number Diff line Loading @@ -1160,7 +1160,7 @@ AudioFlinger::MixerThread::~MixerThread() bool AudioFlinger::MixerThread::threadLoop() bool AudioFlinger::MixerThread::threadLoop() { { unsigned long sleepTime = kBufferRecoveryInUsecs; unsigned long sleepTime = 0; int16_t* curBuf = mMixBuffer; int16_t* curBuf = mMixBuffer; Vector< sp<Track> > tracksToRemove; Vector< sp<Track> > tracksToRemove; size_t enabledTracks = 0; size_t enabledTracks = 0; Loading Loading @@ -1215,6 +1215,7 @@ bool AudioFlinger::MixerThread::threadLoop() } } standbyTime = systemTime() + kStandbyTimeInNsecs; standbyTime = systemTime() + kStandbyTimeInNsecs; sleepTime = 0; continue; continue; } } } } Loading @@ -1222,14 +1223,31 @@ bool AudioFlinger::MixerThread::threadLoop() enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove); enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove); } } if (LIKELY(enabledTracks)) { // mix buffers... mAudioMixer->process(curBuf); // output audio to hardware // output audio to hardware if (mSuspended) { if (mSuspended) { usleep(kMaxBufferRecoveryInUsecs); usleep(kMaxBufferRecoveryInUsecs); } else { } 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(); mLastWriteTime = systemTime(); mInWrite = true; mInWrite = true; int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); Loading @@ -1237,24 +1255,11 @@ bool AudioFlinger::MixerThread::threadLoop() mNumWrites++; mNumWrites++; mInWrite = false; mInWrite = false; mStandby = false; mStandby = false; nsecs_t temp = systemTime(); nsecs_t delta = systemTime() - mLastWriteTime; standbyTime = temp + kStandbyTimeInNsecs; nsecs_t delta = temp - mLastWriteTime; if (delta > maxPeriod) { if (delta > maxPeriod) { LOGW("write blocked for %llu msecs", ns2ms(delta)); LOGW("write blocked for %llu msecs", ns2ms(delta)); mNumDelayedWrites++; 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; } } } } Loading Loading @@ -1568,7 +1573,7 @@ AudioFlinger::DirectOutputThread::~DirectOutputThread() bool AudioFlinger::DirectOutputThread::threadLoop() bool AudioFlinger::DirectOutputThread::threadLoop() { { unsigned long sleepTime = kBufferRecoveryInUsecs; unsigned long sleepTime = 0; sp<Track> trackToRemove; sp<Track> trackToRemove; sp<Track> activeTrack; sp<Track> activeTrack; nsecs_t standbyTime = systemTime(); nsecs_t standbyTime = systemTime(); Loading Loading @@ -1618,6 +1623,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } standbyTime = systemTime() + kStandbyTimeInNsecs; standbyTime = systemTime() + kStandbyTimeInNsecs; sleepTime = 0; continue; continue; } } } } Loading Loading @@ -1710,13 +1716,15 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } } } // output audio to hardware if (mSuspended) { usleep(kMaxBufferRecoveryInUsecs); } else { if (activeTrack != 0) { if (activeTrack != 0) { AudioBufferProvider::Buffer buffer; AudioBufferProvider::Buffer buffer; size_t frameCount = mFrameCount; size_t frameCount = mFrameCount; curBuf = (int8_t *)mMixBuffer; curBuf = (int8_t *)mMixBuffer; // output audio to hardware // output audio to hardware mLastWriteTime = systemTime(); mInWrite = true; while(frameCount) { while(frameCount) { buffer.frameCount = frameCount; buffer.frameCount = frameCount; activeTrack->getNextBuffer(&buffer); activeTrack->getNextBuffer(&buffer); Loading @@ -1729,27 +1737,27 @@ bool AudioFlinger::DirectOutputThread::threadLoop() curBuf += buffer.frameCount * mFrameSize; curBuf += buffer.frameCount * mFrameSize; activeTrack->releaseBuffer(&buffer); activeTrack->releaseBuffer(&buffer); } } if (mSuspended) { sleepTime = 0; usleep(kMaxBufferRecoveryInUsecs); standbyTime = systemTime() + kStandbyTimeInNsecs; } else { sleepTime += kBufferRecoveryInUsecs; if (sleepTime < kMaxBufferRecoveryInUsecs) { usleep(kBufferRecoveryInUsecs); } else { } 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); int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); if (bytesWritten) mBytesWritten += bytesWritten; if (bytesWritten) mBytesWritten += bytesWritten; mNumWrites++; mNumWrites++; mInWrite = false; mInWrite = false; mStandby = 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; } } } } Loading media/java/android/media/ToneGenerator.java +13 −2 Original line number Original line Diff line number Diff line Loading @@ -744,7 +744,7 @@ public class ToneGenerator * This method starts the playback of a tone of the specified type. * 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, * 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. * 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> * <ul> * <li>{@link #TONE_DTMF_0} * <li>{@link #TONE_DTMF_0} * <li>{@link #TONE_DTMF_1} * <li>{@link #TONE_DTMF_1} Loading Loading @@ -846,7 +846,18 @@ public class ToneGenerator * </ul> * </ul> * @see #ToneGenerator(int, int) * @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. * This method stops the tone currently playing playback. Loading Loading
api/current.xml +15 −0 Original line number Original line Diff line number Diff line Loading @@ -78333,6 +78333,19 @@ visibility="public" visibility="public" > > </method> </method> <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" <method name="startTone" return="boolean" return="boolean" abstract="false" abstract="false" Loading @@ -78345,6 +78358,8 @@ > > <parameter name="toneType" type="int"> <parameter name="toneType" type="int"> </parameter> </parameter> <parameter name="durationMs" type="int"> </parameter> </method> </method> <method name="stopTone" <method name="stopTone" return="void" return="void"
core/jni/android_media_ToneGenerator.cpp +3 −3 Original line number Original line Diff line number Diff line Loading @@ -38,7 +38,7 @@ struct fields_t { }; }; static fields_t fields; 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); LOGV("android_media_ToneGenerator_startTone: %x\n", (int)thiz); ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz, ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz, Loading @@ -48,7 +48,7 @@ static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, return false; return false; } } return lpToneGen->startTone(toneType); return lpToneGen->startTone(toneType, durationMs); } } static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) { static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) { Loading Loading @@ -120,7 +120,7 @@ static void android_media_ToneGenerator_native_finalize(JNIEnv *env, // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { 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 }, { "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone }, { "release", "()V", (void *)android_media_ToneGenerator_release }, { "release", "()V", (void *)android_media_ToneGenerator_release }, { "native_setup", "(II)V", (void *)android_media_ToneGenerator_native_setup }, { "native_setup", "(II)V", (void *)android_media_ToneGenerator_native_setup }, Loading
include/media/ToneGenerator.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -154,7 +154,7 @@ public: ToneGenerator(int streamType, float volume); ToneGenerator(int streamType, float volume); ~ToneGenerator(); ~ToneGenerator(); bool startTone(int toneType); bool startTone(int toneType, int durationMs = -1); void stopTone(); void stopTone(); bool isInited() { return (mState == TONE_IDLE)?false:true;} bool isInited() { return (mState == TONE_IDLE)?false:true;} Loading Loading @@ -246,6 +246,7 @@ private: // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly // 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, // 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. // 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 mCurSegment; // Current segment index in ToneDescriptor segments[] unsigned short mCurCount; // Current sequence repeat count unsigned short mCurCount; // Current sequence repeat count Loading
libs/audioflinger/AudioFlinger.cpp +63 −55 Original line number Original line Diff line number Diff line Loading @@ -1160,7 +1160,7 @@ AudioFlinger::MixerThread::~MixerThread() bool AudioFlinger::MixerThread::threadLoop() bool AudioFlinger::MixerThread::threadLoop() { { unsigned long sleepTime = kBufferRecoveryInUsecs; unsigned long sleepTime = 0; int16_t* curBuf = mMixBuffer; int16_t* curBuf = mMixBuffer; Vector< sp<Track> > tracksToRemove; Vector< sp<Track> > tracksToRemove; size_t enabledTracks = 0; size_t enabledTracks = 0; Loading Loading @@ -1215,6 +1215,7 @@ bool AudioFlinger::MixerThread::threadLoop() } } standbyTime = systemTime() + kStandbyTimeInNsecs; standbyTime = systemTime() + kStandbyTimeInNsecs; sleepTime = 0; continue; continue; } } } } Loading @@ -1222,14 +1223,31 @@ bool AudioFlinger::MixerThread::threadLoop() enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove); enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove); } } if (LIKELY(enabledTracks)) { // mix buffers... mAudioMixer->process(curBuf); // output audio to hardware // output audio to hardware if (mSuspended) { if (mSuspended) { usleep(kMaxBufferRecoveryInUsecs); usleep(kMaxBufferRecoveryInUsecs); } else { } 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(); mLastWriteTime = systemTime(); mInWrite = true; mInWrite = true; int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); Loading @@ -1237,24 +1255,11 @@ bool AudioFlinger::MixerThread::threadLoop() mNumWrites++; mNumWrites++; mInWrite = false; mInWrite = false; mStandby = false; mStandby = false; nsecs_t temp = systemTime(); nsecs_t delta = systemTime() - mLastWriteTime; standbyTime = temp + kStandbyTimeInNsecs; nsecs_t delta = temp - mLastWriteTime; if (delta > maxPeriod) { if (delta > maxPeriod) { LOGW("write blocked for %llu msecs", ns2ms(delta)); LOGW("write blocked for %llu msecs", ns2ms(delta)); mNumDelayedWrites++; 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; } } } } Loading Loading @@ -1568,7 +1573,7 @@ AudioFlinger::DirectOutputThread::~DirectOutputThread() bool AudioFlinger::DirectOutputThread::threadLoop() bool AudioFlinger::DirectOutputThread::threadLoop() { { unsigned long sleepTime = kBufferRecoveryInUsecs; unsigned long sleepTime = 0; sp<Track> trackToRemove; sp<Track> trackToRemove; sp<Track> activeTrack; sp<Track> activeTrack; nsecs_t standbyTime = systemTime(); nsecs_t standbyTime = systemTime(); Loading Loading @@ -1618,6 +1623,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } standbyTime = systemTime() + kStandbyTimeInNsecs; standbyTime = systemTime() + kStandbyTimeInNsecs; sleepTime = 0; continue; continue; } } } } Loading Loading @@ -1710,13 +1716,15 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } } } // output audio to hardware if (mSuspended) { usleep(kMaxBufferRecoveryInUsecs); } else { if (activeTrack != 0) { if (activeTrack != 0) { AudioBufferProvider::Buffer buffer; AudioBufferProvider::Buffer buffer; size_t frameCount = mFrameCount; size_t frameCount = mFrameCount; curBuf = (int8_t *)mMixBuffer; curBuf = (int8_t *)mMixBuffer; // output audio to hardware // output audio to hardware mLastWriteTime = systemTime(); mInWrite = true; while(frameCount) { while(frameCount) { buffer.frameCount = frameCount; buffer.frameCount = frameCount; activeTrack->getNextBuffer(&buffer); activeTrack->getNextBuffer(&buffer); Loading @@ -1729,27 +1737,27 @@ bool AudioFlinger::DirectOutputThread::threadLoop() curBuf += buffer.frameCount * mFrameSize; curBuf += buffer.frameCount * mFrameSize; activeTrack->releaseBuffer(&buffer); activeTrack->releaseBuffer(&buffer); } } if (mSuspended) { sleepTime = 0; usleep(kMaxBufferRecoveryInUsecs); standbyTime = systemTime() + kStandbyTimeInNsecs; } else { sleepTime += kBufferRecoveryInUsecs; if (sleepTime < kMaxBufferRecoveryInUsecs) { usleep(kBufferRecoveryInUsecs); } else { } 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); int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); if (bytesWritten) mBytesWritten += bytesWritten; if (bytesWritten) mBytesWritten += bytesWritten; mNumWrites++; mNumWrites++; mInWrite = false; mInWrite = false; mStandby = 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; } } } } Loading
media/java/android/media/ToneGenerator.java +13 −2 Original line number Original line Diff line number Diff line Loading @@ -744,7 +744,7 @@ public class ToneGenerator * This method starts the playback of a tone of the specified type. * 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, * 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. * 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> * <ul> * <li>{@link #TONE_DTMF_0} * <li>{@link #TONE_DTMF_0} * <li>{@link #TONE_DTMF_1} * <li>{@link #TONE_DTMF_1} Loading Loading @@ -846,7 +846,18 @@ public class ToneGenerator * </ul> * </ul> * @see #ToneGenerator(int, int) * @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. * This method stops the tone currently playing playback. Loading