summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml15
-rw-r--r--core/jni/android_media_ToneGenerator.cpp6
-rw-r--r--include/media/ToneGenerator.h3
-rw-r--r--libs/audioflinger/AudioFlinger.cpp118
-rw-r--r--media/java/android/media/ToneGenerator.java15
-rw-r--r--media/libmedia/ToneGenerator.cpp29
6 files changed, 120 insertions, 66 deletions
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 a4388de..07bb1ab 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -38,7 +38,7 @@ struct fields_t {
};
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 @@ static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz,
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 void android_media_ToneGenerator_native_finalize(JNIEnv *env,
// ----------------------------------------------------------------------------
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 @@ public:
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 @@ private:
// 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 @@ AudioFlinger::MixerThread::~MixerThread()
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 @@ bool AudioFlinger::MixerThread::threadLoop()
}
standbyTime = systemTime() + kStandbyTimeInNsecs;
+ sleepTime = 0;
continue;
}
}
@@ -1222,14 +1223,31 @@ bool AudioFlinger::MixerThread::threadLoop()
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 @@ bool AudioFlinger::MixerThread::threadLoop()
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 @@ AudioFlinger::DirectOutputThread::~DirectOutputThread()
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 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
}
standbyTime = systemTime() + kStandbyTimeInNsecs;
+ sleepTime = 0;
continue;
}
}
@@ -1710,46 +1716,48 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
}
}
- 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 @@ public class ToneGenerator
* 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 @@ public class ToneGenerator
* </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 @@ const unsigned char ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONE
// 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 @@ ToneGenerator::~ToneGenerator() {
// 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 @@ bool ToneGenerator::startTone(int toneType) {
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 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
// 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) {