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
This commit is contained in:
Eric Laurent
2009-05-05 00:49:01 -07:00
parent b9c9d260f2
commit f3af740bdf
5 changed files with 538 additions and 113 deletions

View File

@@ -68595,6 +68595,17 @@
visibility="public"
>
</field>
<field name="TONE_SUP_CONFIRM"
type="int"
transient="false"
volatile="false"
value="32"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="TONE_SUP_CONGESTION"
type="int"
transient="false"
@@ -68606,6 +68617,17 @@
visibility="public"
>
</field>
<field name="TONE_SUP_CONGESTION_ABBREV"
type="int"
transient="false"
volatile="false"
value="31"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="TONE_SUP_DIAL"
type="int"
transient="false"
@@ -68628,6 +68650,39 @@
visibility="public"
>
</field>
<field name="TONE_SUP_INTERCEPT"
type="int"
transient="false"
volatile="false"
value="29"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="TONE_SUP_INTERCEPT_ABBREV"
type="int"
transient="false"
volatile="false"
value="30"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="TONE_SUP_PIP"
type="int"
transient="false"
volatile="false"
value="33"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="TONE_SUP_RADIO_ACK"
type="int"
transient="false"

View File

@@ -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 ToneSegment {
public:
unsigned int duration;
unsigned short waveFreq[TONEGEN_MAX_WAVES+1];
};
class ToneDescriptor {
public:
unsigned short waveFreq[TONEGEN_MAX_WAVES+1];
unsigned long segments[TONEGEN_MAX_SEGMENTS+1];
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.
};
}

View File

@@ -130,25 +130,35 @@ public class ToneGenerator
*/
public static final int TONE_DTMF_D = 15;
/**
* Call supervisory tone, Dial tone: 425Hz, continuous
*
* Call supervisory tone, Dial tone:
* CEPT: 425Hz, continuous
* ANSI (IS-95): 350Hz+440Hz, continuous
* JAPAN: 400Hz, continuous
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_DIAL = 16;
/**
* Call supervisory tone, Busy: 425Hz, 500ms ON, 500ms OFF...
*
* Call supervisory tone, Busy:
* CEPT: 425Hz, 500ms ON, 500ms OFF...
* ANSI (IS-95): 480Hz+620Hz, 500ms ON, 500ms OFF...
* JAPAN: 400Hz, 500ms ON, 500ms OFF...
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_BUSY = 17;
/**
* Call supervisory tone, Congestion: 425Hz, 200ms ON, 200ms OFF...
* Call supervisory tone, Congestion:
* CEPT, JAPAN: 425Hz, 200ms ON, 200ms OFF...
* ANSI (IS-95): 480Hz+620Hz, 250ms ON, 250ms OFF...
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_CONGESTION = 18;
/**
* Call supervisory tone, Radio path acknowlegment : 425Hz, 200ms ON
* Call supervisory tone, Radio path acknowlegment :
* CEPT, ANSI: 425Hz, 200ms ON
* JAPAN: 400Hz, 1s ON, 2s OFF...
*
* @see #ToneGenerator(int, int)
*/
@@ -166,13 +176,17 @@ public class ToneGenerator
*/
public static final int TONE_SUP_ERROR = 21;
/**
* Call supervisory tone, Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
* Call supervisory tone, Call Waiting:
* CEPT, JAPAN: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
* ANSI (IS-95): 440 Hz, 300 ms ON, 9.7 s OFF, (100 ms ON, 100 ms OFF, 100 ms ON, 9.7s OFF ...)
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_CALL_WAITING = 22;
/**
* Call supervisory tone, Ring Tone: 425Hz, 1s ON, 4s OFF...
* Call supervisory tone, Ring Tone:
* CEPT, JAPAN: 425Hz, 1s ON, 4s OFF...
* ANSI (IS-95): 440Hz + 480Hz, 2s ON, 4s OFF...
*
* @see #ToneGenerator(int, int)
*/
@@ -207,6 +221,37 @@ public class ToneGenerator
* @see #ToneGenerator(int, int)
*/
public static final int TONE_PROP_BEEP2 = 28;
/**
* Call supervisory tone (IS-95), intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_INTERCEPT = 29;
/**
* Call supervisory tone (IS-95), abbreviated intercept: intercept tone limited to 4 seconds
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_INTERCEPT_ABBREV = 30;
/**
* Call supervisory tone (IS-95), abbreviated congestion: congestion tone limited to 4 seconds
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_CONGESTION_ABBREV = 31;
/**
* Call supervisory tone (IS-95), confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_CONFIRM = 32;
/**
* Call supervisory tone (IS-95), pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off).
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_PIP = 33;
/** Maximum volume, for use with {@link #ToneGenerator(int,int)} */
public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME;
@@ -258,6 +303,11 @@ public class ToneGenerator
* <li>{@link #TONE_PROP_NACK}
* <li>{@link #TONE_PROP_PROMPT}
* <li>{@link #TONE_PROP_BEEP2}
* <li>{@link #TONE_SUP_INTERCEPT}
* <li>{@link #TONE_SUP_INTERCEPT_ABBREV}
* <li>{@link #TONE_SUP_CONGESTION_ABBREV}
* <li>{@link #TONE_SUP_CONFIRM}
* <li>{@link #TONE_SUP_PIP}
* </ul>
* @see #ToneGenerator(int, int)
*/

View File

@@ -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;
}

View File

@@ -74,7 +74,19 @@ import android.media.AudioManager;
break;
}
}
for (type = ToneGenerator.TONE_SUP_INTERCEPT;
type <= ToneGenerator.TONE_SUP_PIP; type++) {
if (toneGen.startTone(type)) {
Thread.sleep(5000);
toneGen.stopTone();
Thread.sleep(200);
} else {
result = false;
break;
}
}
toneGen.release();
return result;
}