Merge change 24114 into eclair
* changes: Fix issue 1992233: DTMF tones on Sholes is really long.
This commit is contained in:
@@ -78333,6 +78333,19 @@
|
||||
visibility="public"
|
||||
>
|
||||
</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"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
@@ -78345,6 +78358,8 @@
|
||||
>
|
||||
<parameter name="toneType" type="int">
|
||||
</parameter>
|
||||
<parameter name="durationMs" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="stopTone"
|
||||
return="void"
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user