summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2009-05-05 00:49:01 -0700
committerEric Laurent <elaurent@google.com>2009-05-06 11:35:46 -0700
commit0b62e242d112d46e9357242b0a4e11c720c98ca0 (patch)
tree6f85343724e3daca261f9c9da07925a035a08fd0
parent65e5f79102e39cb2e9ab71ced0b62347bf1512a5 (diff)
downloadframeworks_av-0b62e242d112d46e9357242b0a4e11c720c98ca0.zip
frameworks_av-0b62e242d112d46e9357242b0a4e11c720c98ca0.tar.gz
frameworks_av-0b62e242d112d46e9357242b0a4e11c720c98ca0.tar.bz2
Fixed issue 1709450: Requirements for CDMA Tone Generator
Added new tone types for CDMA IS-95 specific tones. Automatic selection between IS-95, CEPT and JAPAN version base on operator country code for call supervisory tones. Also improved tone generator capabilities: - Each tone segment can now generate its own set of frequencies - A tone does not have to be a succession of alternating ON/OFF segments - The sequence repetition does not have to start from first segment
-rw-r--r--include/media/ToneGenerator.h89
-rw-r--r--media/libmedia/ToneGenerator.cpp427
2 files changed, 412 insertions, 104 deletions
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index ec64e4d..6b0cc8a 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -18,7 +18,7 @@
#define ANDROID_TONEGENERATOR_H_
#include <utils/RefBase.h>
-#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
@@ -49,21 +49,30 @@ public:
TONE_DTMF_C, // C key: 1633Hz, 852Hz
TONE_DTMF_D, // D key: 1633Hz, 941Hz
// Call supervisory tones: 3GPP TS 22.001 (CEPT)
- TONE_SUP_DIAL, // Dial tone: 425Hz, continuous
- TONE_SUP_BUSY, // Busy tone: 425Hz, 500ms ON, 500ms OFF...
- TONE_SUP_CONGESTION, // Congestion tone: 425Hz, 200ms ON, 200ms OFF...
- TONE_SUP_RADIO_ACK, // Radio path acknowlegment: 425Hz, 200ms ON
+ TONE_SUP_DIAL, // Dial tone: CEPT: 425Hz, continuous
+ FIRST_SUP_TONE = TONE_SUP_DIAL,
+ TONE_SUP_BUSY, // Busy tone, CEPT: 425Hz, 500ms ON, 500ms OFF...
+ TONE_SUP_CONGESTION, // Congestion tone CEPT, JAPAN: 425Hz, 200ms ON, 200ms OFF...
+ TONE_SUP_RADIO_ACK, // Radio path acknowlegment, CEPT, ANSI: 425Hz, 200ms ON
TONE_SUP_RADIO_NOTAVAIL, // Radio path not available: 425Hz, 200ms ON, 200 OFF 3 bursts
TONE_SUP_ERROR, // Error/Special info: 950Hz+1400Hz+1800Hz, 330ms ON, 1s OFF...
- TONE_SUP_CALL_WAITING, // Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
- TONE_SUP_RINGTONE, // Ring Tone: 425Hz, 1s ON, 4s OFF...
+ TONE_SUP_CALL_WAITING, // Call Waiting CEPT,JAPAN: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
+ TONE_SUP_RINGTONE, // Ring Tone CEPT, JAPAN: 425Hz, 1s ON, 4s OFF...
+ LAST_SUP_TONE = TONE_SUP_RINGTONE,
// Proprietary tones: 3GPP TS 31.111
TONE_PROP_BEEP, // General beep: 400Hz+1200Hz, 35ms ON
TONE_PROP_ACK, // Positive Acknowlgement: 1200Hz, 100ms ON, 100ms OFF 2 bursts
- TONE_PROP_NACK, // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON
+ TONE_PROP_NACK, // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON
TONE_PROP_PROMPT, // Prompt tone: 400Hz+1200Hz, 200ms ON
TONE_PROP_BEEP2, // General double beep: 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms on
- NUM_TONES
+ // Additional call supervisory tones: specified by IS-95 only
+ TONE_SUP_INTERCEPT, // Intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms.
+ TONE_SUP_INTERCEPT_ABBREV, // Abbreviated intercept: intercept tone limited to 4 seconds
+ TONE_SUP_CONGESTION_ABBREV, // Abbreviated congestion: congestion tone limited to 4 seconds
+ TONE_SUP_CONFIRM, // Confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle.
+ TONE_SUP_PIP, // Pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off).
+ NUM_TONES,
+ NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1
};
ToneGenerator(int streamType, float volume);
@@ -85,13 +94,45 @@ private:
TONE_RESTARTING //
};
- static const unsigned int TONEGEN_MAX_WAVES = 3;
- static const unsigned int TONEGEN_MAX_SEGMENTS = 4; // Maximun number of elenemts in
+
+ // Region specific tones.
+ // These supervisory tones are different depending on the region (USA/CANADA, JAPAN, rest of the world).
+ // When a tone in the range [FIRST_SUP_TONE, LAST_SUP_TONE] is requested, the region is determined
+ // from system property gsm.operator.iso-country and the proper tone descriptor is selected with the
+ // help of sToneMappingTable[]
+ enum regional_tone_type {
+ // ANSI supervisory tones
+ TONE_ANSI_DIAL = NUM_TONES, // Dial tone: a continuous 350 Hz + 440 Hz tone.
+ TONE_ANSI_BUSY, // Busy tone on: a 480 Hz + 620 Hz tone repeated in a 500 ms on, 500 ms off cycle.
+ TONE_ANSI_CONGESTION, // Network congestion (reorder) tone on: a 480 Hz + 620 Hz tone repeated in a 250 ms on, 250 ms off cycle.
+ TONE_ANSI_CALL_WAITING, // Call waiting tone on: 440 Hz, on for 300 ms, 9,7 s off followed by
+ // (440 Hz, on for 100 ms off for 100 ms, on for 100 ms, 9,7s off and repeated as necessary).
+ TONE_ANSI_RINGTONE, // Ring Tone: a 440 Hz + 480 Hz tone repeated in a 2 s on, 4 s off pattern.
+ // JAPAN Supervisory tones
+ TONE_JAPAN_DIAL, // Dial tone: 400Hz, continuous
+ TONE_JAPAN_BUSY, // Busy tone: 400Hz, 500ms ON, 500ms OFF...
+ TONE_JAPAN_RADIO_ACK, // Radio path acknowlegment: 400Hz, 1s ON, 2s OFF...
+ NUM_ALTERNATE_TONES
+ };
+
+ enum region {
+ ANSI,
+ JAPAN,
+ CEPT,
+ NUM_REGIONS
+ };
+
+ static const unsigned char sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES];
+
+ static const unsigned int TONEGEN_MAX_WAVES = 3; // Maximun number of sine waves in a tone segment
+ static const unsigned int TONEGEN_MAX_SEGMENTS = 5; // Maximun number of segments in a tone descriptor
static const unsigned int TONEGEN_INF = 0xFFFFFFFF; // Represents infinite time duration
static const float TONEGEN_GAIN = 0.9; // Default gain passed to WaveGenerator().
// ToneDescriptor class contains all parameters needed to generate a tone:
- // - The array waveFreq[] contains the frequencies of all individual waves making the multi-tone.
+ // - The array waveFreq[]:
+ // 1 for static tone descriptors: contains the frequencies of all individual waves making the multi-tone.
+ // 2 for active tone descritors: contains the indexes of the WaveGenerator objects in mWaveGens
// The number of sine waves varies from 1 to TONEGEN_MAX_WAVES.
// The first null value indicates that no more waves are needed.
// - The array segments[] is used to generate the tone pulses. A segment is a period of time
@@ -100,17 +141,25 @@ private:
// The data stored in segments[] is the duration of the corresponding period in ms.
// The first segment encountered with a 0 duration indicates that no more segment follows.
// - repeatCnt indicates the number of times the sequence described by segments[] array must be repeated.
- // When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount.
- // If mCurCount > repeatCnt, the tone is stopped automatically.
+ // When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount.
+ // If mCurCount > repeatCnt, the tone is stopped automatically. Otherwise, tone sequence will be
+ // restarted from segment repeatSegment.
+ // - repeatSegment number of the first repeated segment when repeatCnt is not null
- class ToneDescriptor {
+ class ToneSegment {
public:
+ unsigned int duration;
unsigned short waveFreq[TONEGEN_MAX_WAVES+1];
- unsigned long segments[TONEGEN_MAX_SEGMENTS+1];
+ };
+
+ class ToneDescriptor {
+ public:
+ ToneSegment segments[TONEGEN_MAX_SEGMENTS+1];
unsigned long repeatCnt;
+ unsigned long repeatSegment;
};
- static const ToneDescriptor toneDescriptors[NUM_TONES];
+ static const ToneDescriptor sToneDescriptors[];
unsigned int mTotalSmp; // Total number of audio samples played (gives current time)
unsigned int mNextSegSmp; // Position of next segment transition expressed in samples
@@ -121,6 +170,7 @@ private:
unsigned short mCurSegment; // Current segment index in ToneDescriptor segments[]
unsigned short mCurCount; // Current sequence repeat count
volatile unsigned short mState; // ToneGenerator state (tone_state)
+ unsigned short mRegion;
const ToneDescriptor *mpToneDesc; // pointer to active tone descriptor
const ToneDescriptor *mpNewToneDesc; // pointer to next active tone descriptor
@@ -136,8 +186,9 @@ private:
bool initAudioTrack();
static void audioCallback(int event, void* user, void *info);
bool prepareWave();
- unsigned int numWaves();
+ unsigned int numWaves(unsigned int segmentIdx);
void clearWaveGens();
+ int getToneForRegion(int toneType);
// WaveGenerator generates a single sine wave
class WaveGenerator {
@@ -167,7 +218,7 @@ private:
short mAmplitude_Q15; // Q15 amplitude
};
- Vector<WaveGenerator *> mWaveGens; // list of active wave generators.
+ KeyedVector<unsigned short, WaveGenerator *> mWaveGens; // list of active wave generators.
};
}
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 8560593..d1789ad 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -24,44 +24,235 @@
#include <sys/resource.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
+#include <cutils/properties.h>
#include "media/ToneGenerator.h"
+
namespace android {
+
// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
-const ToneGenerator::ToneDescriptor
- ToneGenerator::toneDescriptors[NUM_TONES] = {
- // waveFreq[] segments[] repeatCnt
- { { 1336, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_0
- { { 1209, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_1
- { { 1336, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_2
- { { 1477, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_3
- { { 1209, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_4
- { { 1336, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_5
- { { 1477, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_6
- { { 1209, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_7
- { { 1336, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_8
- { { 1477, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_9
- { { 1209, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_S
- { { 1477, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_P
- { { 1633, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_A
- { { 1633, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_B
- { { 1633, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_C
- { { 1633, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_D
- { { 425, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_DIAL
- { { 425, 0 }, { 500, 500, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_BUSY
- { { 425, 0 }, { 200, 200, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CONGESTION
- { { 425, 0 }, { 200, 0 }, 0 }, // TONE_SUP_RADIO_ACK
- { { 425, 0 }, { 200, 200, 0 }, 2 }, // TONE_SUP_RADIO_NOTAVAIL
- { { 950, 1400, 1800, 0 }, { 330, 1000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_ERROR
- { { 425, 0 }, { 200, 600, 200, 3000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CALL_WAITING
- { { 425, 0 }, { 1000, 4000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_RINGTONE
- { { 400, 1200, 0 }, { 40, 0 }, 0 }, // TONE_PROP_BEEP
- { { 1200, 0 }, { 100, 100, 0 }, 1 }, // TONE_PROP_ACK
- { { 300, 400, 500, 0 }, { 400, 0 }, 0 }, // TONE_PROP_NACK
- { { 400, 1200, 0 }, { 200, 0 }, 0 }, // TONE_PROP_PROMPT
- { { 400, 1200, 0 }, { 40, 200, 40, 0 }, 0 } // TONE_PROP_BEEP2
- };
+const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
+ { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 941, 0 }},
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_0
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 697, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_1
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 697, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_2
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 697, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_3
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 770, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_4
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 770, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_5
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 770, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_6
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 852, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_7
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 852, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_8
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 852, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_9
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 941, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_S
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 941, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_P
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 697, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_A
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 770, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_B
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 852, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_C
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 941, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_D
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_DIAL
+ { segments: { { duration: 500 , waveFreq: { 425, 0 }},
+ { duration: 500, waveFreq: { 0 }},
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_BUSY
+ { segments: { { duration: 200, waveFreq: { 425, 0 } },
+ { duration: 200, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_CONGESTION
+ { segments: { { duration: 200, waveFreq: { 425, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_SUP_RADIO_ACK
+ { segments: { { duration: 200, waveFreq: { 425, 0 }},
+ { duration: 200, waveFreq: { 0 }},
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 2,
+ repeatSegment: 0 }, // TONE_SUP_RADIO_NOTAVAIL
+ { segments: { { duration: 330, waveFreq: { 950, 1400, 1800, 0 }},
+ { duration: 1000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_ERROR
+ { segments: { { duration: 200, waveFreq: { 425, 0 } },
+ { duration: 600, waveFreq: { 0 } },
+ { duration: 200, waveFreq: { 425, 0 } },
+ { duration: 3000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_CALL_WAITING
+ { segments: { { duration: 1000, waveFreq: { 425, 0 } },
+ { duration: 4000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_RINGTONE
+ { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_PROP_BEEP
+ { segments: { { duration: 100, waveFreq: { 1200, 0 } },
+ { duration: 100, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 1,
+ repeatSegment: 0 }, // TONE_PROP_ACK
+ { segments: { { duration: 400, waveFreq: { 300, 400, 500, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_PROP_NACK
+ { segments: { { duration: 200, waveFreq: { 400, 1200, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_PROP_PROMPT
+ { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } },
+ { duration: 200, waveFreq: { 0 } },
+ { duration: 40, waveFreq: { 400, 1200, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_PROP_BEEP2
+ { segments: { { duration: 250, waveFreq: { 440, 0 } },
+ { duration: 250, waveFreq: { 620, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_INTERCEPT
+ { segments: { { duration: 250, waveFreq: { 440, 0 } },
+ { duration: 250, waveFreq: { 620, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 7,
+ repeatSegment: 0 }, // TONE_SUP_INTERCEPT_ABBREV
+ { segments: { { duration: 250, waveFreq: { 480, 620, 0 } },
+ { duration: 250, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 7,
+ repeatSegment: 0 }, // TONE_SUP_CONGESTION_ABBREV
+ { segments: { { duration: 100, waveFreq: { 350, 440, 0 } },
+ { duration: 100, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 2,
+ repeatSegment: 0 }, // TONE_SUP_CONFIRM
+ { segments: { { duration: 100, waveFreq: { 480, 0 } },
+ { duration: 100, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 3,
+ repeatSegment: 0 }, // TONE_SUP_PIP
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 350, 440, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_ANSI_DIAL
+ { segments: { { duration: 500, waveFreq: { 480, 620, 0 } },
+ { duration: 500, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_ANSI_BUSY
+ { segments: { { duration: 250, waveFreq: { 480, 620, 0 } },
+ { duration: 250, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_ANSI_CONGESTION
+ { segments: { { duration: 300, waveFreq: { 440, 0 } },
+ { duration: 9700, waveFreq: { 0 } },
+ { duration: 100, waveFreq: { 440, 0 } },
+ { duration: 100, waveFreq: { 0 } },
+ { duration: 100, waveFreq: { 440, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 1 }, // TONE_ANSI_CALL_WAITING
+ { segments: { { duration: 2000, waveFreq: { 440, 480, 0 } },
+ { duration: 4000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_ANSI_RINGTONE
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 400, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_JAPAN_DIAL
+ { segments: { { duration: 500, waveFreq: { 400, 0 } },
+ { duration: 500, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_JAPAN_BUSY
+ { segments: { { duration: 1000, waveFreq: { 400, 0 } },
+ { duration: 2000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_JAPAN_RADIO_ACK
+};
+
+// Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
+// to actual tone for current region.
+const unsigned char ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = {
+ { // ANSI
+ TONE_ANSI_DIAL, // TONE_SUP_DIAL
+ TONE_ANSI_BUSY, // TONE_SUP_BUSY
+ TONE_ANSI_CONGESTION, // TONE_SUP_CONGESTION
+ TONE_SUP_RADIO_ACK, // TONE_SUP_RADIO_ACK
+ TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL
+ TONE_SUP_ERROR, // TONE_SUP_ERROR
+ TONE_ANSI_CALL_WAITING, // TONE_SUP_CALL_WAITING
+ TONE_ANSI_RINGTONE // TONE_SUP_RINGTONE
+ },
+ { // JAPAN
+ TONE_JAPAN_DIAL, // TONE_SUP_DIAL
+ TONE_JAPAN_BUSY, // TONE_SUP_BUSY
+ TONE_SUP_CONGESTION, // TONE_SUP_CONGESTION
+ TONE_JAPAN_RADIO_ACK, // TONE_SUP_RADIO_ACK
+ TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL
+ TONE_SUP_ERROR, // TONE_SUP_ERROR
+ TONE_SUP_CALL_WAITING, // TONE_SUP_CALL_WAITING
+ TONE_SUP_RINGTONE // TONE_SUP_RINGTONE
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////
// ToneGenerator class Implementation
@@ -105,6 +296,17 @@ ToneGenerator::ToneGenerator(int streamType, float volume) {
// Generate tone by chunks of 20 ms to keep cadencing precision
mProcessSize = (mSamplingRate * 20) / 1000;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("gsm.operator.iso-country", value, "");
+ if (strcmp(value,"us") == 0 ||
+ strcmp(value,"ca") == 0) {
+ mRegion = ANSI;
+ } else if (strcmp(value,"jp") == 0) {
+ mRegion = JAPAN;
+ } else {
+ mRegion = CEPT;
+ }
+
if (initAudioTrack()) {
LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
} else {
@@ -170,7 +372,8 @@ bool ToneGenerator::startTone(int toneType) {
mLock.lock();
// Get descriptor for requested tone
- mpNewToneDesc = &toneDescriptors[toneType];
+ toneType = getToneForRegion(toneType);
+ mpNewToneDesc = &sToneDescriptors[toneType];
if (mState == TONE_INIT) {
if (prepareWave()) {
@@ -333,6 +536,7 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
short *lpOut = buffer->i16;
unsigned int lNumSmp = buffer->size/sizeof(short);
+ const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc;
if (buffer->size == 0) return;
@@ -377,7 +581,7 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
// Exit if tone sequence is over
- if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
if (lpToneGen->mState == TONE_PLAYING) {
lpToneGen->mState = TONE_STOPPING;
}
@@ -390,52 +594,64 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
lGenSmp = lReqSmp;
-
- if (lpToneGen->mCurSegment & 0x0001) {
- // If odd segment, OFF -> ON transition : reset wave generator
- lWaveCmd = WaveGenerator::WAVEGEN_START;
-
- LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
- } else {
- // If even segment, ON -> OFF transition : ramp volume down
+
+ // If segment, ON -> OFF transition : ramp volume down
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
lWaveCmd = WaveGenerator::WAVEGEN_STOP;
-
+ unsigned int lFreqIdx = 0;
+ unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
+
+ while (lFrequency != 0) {
+ WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
+ lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+ lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
+ }
LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
}
-
- // Pre increment segment index and handle loop if last segment reached
- if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
+
+ // Go to next segment
+ lpToneGen->mCurSegment++;
+
+ // Handle loop if last segment reached
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
// Pre increment loop count and restart if total count not reached. Stop sequence otherwise
- if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
+ if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
- lpToneGen->mCurSegment = 0;
+ lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
+ if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+ }
LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
(lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
} else {
+ lGenSmp = 0;
LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
-
- // Cancel OFF->ON transition in case previous segment tone state was OFF
- if (!(lpToneGen->mCurSegment & 0x0001)) {
- lGenSmp = 0;
- }
}
} else {
LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
(lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
+ // If next segment is not silent, OFF -> ON transition : reset wave generator
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+
+ LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ } else {
+ lGenSmp = 0;
+ }
}
// Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
lpToneGen->mNextSegSmp
- += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
+ += (lpToneDesc->segments[lpToneGen->mCurSegment].duration * lpToneGen->mSamplingRate) / 1000;
} else {
// Inside a segment keep tone ON or OFF
- if (lpToneGen->mCurSegment & 0x0001) {
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] == 0) {
lGenSmp = 0; // If odd segment, tone is currently OFF
} else {
lGenSmp = lReqSmp; // If event segment, tone is currently ON
@@ -444,11 +660,13 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
if (lGenSmp) {
// If samples must be generated, call all active wave generators and acumulate waves in lpOut
- unsigned int lWaveIdx;
+ unsigned int lFreqIdx = 0;
+ unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
- for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
- WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
+ while (lFrequency != 0) {
+ WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+ lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
}
}
@@ -501,7 +719,7 @@ audioCallback_EndLoop:
// Method: ToneGenerator::prepareWave()
//
// Description: Prepare wave generators and reset tone sequencer state machine.
-// mpNewToneDesc must have been initialized befoire calling this function.
+// mpNewToneDesc must have been initialized before calling this function.
// Input:
// none
//
@@ -510,40 +728,48 @@ audioCallback_EndLoop:
//
////////////////////////////////////////////////////////////////////////////////
bool ToneGenerator::prepareWave() {
- unsigned int lCnt = 0;
- unsigned int lNumWaves;
+ unsigned int segmentIdx = 0;
if (!mpNewToneDesc) {
return false;
}
+
// Remove existing wave generators if any
clearWaveGens();
mpToneDesc = mpNewToneDesc;
- // Get total number of sine waves: needed to adapt sine wave gain.
- lNumWaves = numWaves();
-
- // Instantiate as many wave generators as listed in descriptor
- while (lCnt < lNumWaves) {
- ToneGenerator::WaveGenerator *lpWaveGen =
- new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
- mpToneDesc->waveFreq[lCnt],
- TONEGEN_GAIN/lNumWaves);
- if (lpWaveGen == 0) {
- goto prepareWave_exit;
+ while (mpToneDesc->segments[segmentIdx].duration) {
+ // Get total number of sine waves: needed to adapt sine wave gain.
+ unsigned int lNumWaves = numWaves(segmentIdx);
+ unsigned int freqIdx = 0;
+ unsigned int frequency = mpToneDesc->segments[segmentIdx].waveFreq[freqIdx];
+ while (frequency) {
+ // Instantiate a wave generator if ot already done for this frequency
+ if (mWaveGens.indexOfKey(frequency) == NAME_NOT_FOUND) {
+ ToneGenerator::WaveGenerator *lpWaveGen =
+ new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
+ frequency,
+ TONEGEN_GAIN/lNumWaves);
+ if (lpWaveGen == 0) {
+ goto prepareWave_exit;
+ }
+ mWaveGens.add(frequency, lpWaveGen);
+ }
+ frequency = mpNewToneDesc->segments[segmentIdx].waveFreq[++freqIdx];
}
-
- mWaveGens.push(lpWaveGen);
- LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]);
- lCnt++;
+ segmentIdx++;
}
// Initialize tone sequencer
mTotalSmp = 0;
mCurSegment = 0;
mCurCount = 0;
- mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000;
+ if (mpToneDesc->segments[0].duration == TONEGEN_INF) {
+ mNextSegSmp = TONEGEN_INF;
+ } else{
+ mNextSegSmp = (mpToneDesc->segments[0].duration * mSamplingRate) / 1000;
+ }
return true;
@@ -559,19 +785,22 @@ prepareWave_exit:
//
// Method: ToneGenerator::numWaves()
//
-// Description: Count number of sine waves needed to generate tone (e.g 2 for DTMF).
+// Description: Count number of sine waves needed to generate a tone segment (e.g 2 for DTMF).
//
// Input:
-// none
+// segmentIdx tone segment index
//
// Output:
// returned value: nummber of sine waves
//
////////////////////////////////////////////////////////////////////////////////
-unsigned int ToneGenerator::numWaves() {
+unsigned int ToneGenerator::numWaves(unsigned int segmentIdx) {
unsigned int lCnt = 0;
- while (mpToneDesc->waveFreq[lCnt]) {
+ if (mpToneDesc->segments[segmentIdx].duration) {
+ while (mpToneDesc->segments[segmentIdx].waveFreq[lCnt]) {
+ lCnt++;
+ }
lCnt++;
}
@@ -595,10 +824,38 @@ unsigned int ToneGenerator::numWaves() {
void ToneGenerator::clearWaveGens() {
LOGV("Clearing mWaveGens:");
- while (!mWaveGens.isEmpty()) {
- delete mWaveGens.top();
- mWaveGens.pop();
+ for (size_t lIdx = 0; lIdx < mWaveGens.size(); lIdx++) {
+ delete mWaveGens.valueAt(lIdx);
}
+ mWaveGens.clear();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::getToneForRegion()
+//
+// Description: Get correct ringtone type according to current region.
+// The corrected ring tone type is the tone descriptor index in sToneDescriptors[].
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+int ToneGenerator::getToneForRegion(int toneType) {
+ int regionTone;
+
+ if (mRegion == CEPT || toneType < FIRST_SUP_TONE || toneType > LAST_SUP_TONE) {
+ regionTone = toneType;
+ } else {
+ regionTone = sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE];
+ }
+
+ LOGV("getToneForRegion, tone %d, region %d, regionTone %d", toneType, mRegion, regionTone);
+
+ return regionTone;
}