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:
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user