summaryrefslogtreecommitdiffstats
path: root/include/media/ToneGenerator.h
blob: 0043bdcff7e8a9e0892ffb847f79941ab9b0876d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_TONEGENERATOR_H_
#define ANDROID_TONEGENERATOR_H_

#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
#include <utils/Compat.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/threads.h>

namespace android {

class ToneGenerator {
public:

    // List of all available tones
    // This enum must be kept consistant with constants in ToneGenerator JAVA class
    enum tone_type {
        // DTMF tones  ITU-T Recommendation Q.23
        TONE_DTMF_0 = 0,  // 0 key: 1336Hz, 941Hz
        TONE_DTMF_1,  // 1 key: 1209Hz, 697Hz
        TONE_DTMF_2,  // 2 key: 1336Hz, 697Hz
        TONE_DTMF_3,  // 3 key: 1477Hz, 697Hz
        TONE_DTMF_4,  // 4 key: 1209Hz, 770Hz
        TONE_DTMF_5,  // 5 key: 1336Hz, 770Hz
        TONE_DTMF_6,  // 6 key: 1477Hz, 770Hz
        TONE_DTMF_7,  // 7 key: 1209Hz, 852Hz
        TONE_DTMF_8,  // 8 key: 1336Hz, 852Hz
        TONE_DTMF_9,  // 9 key: 1477Hz, 852Hz
        TONE_DTMF_S,  // * key: 1209Hz, 941Hz
        TONE_DTMF_P,  // # key: 1477Hz, 941Hz
        TONE_DTMF_A,  // A key: 1633Hz, 697Hz
        TONE_DTMF_B,  // B key: 1633Hz, 770Hz
        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: 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 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_PROMPT,  // Prompt tone: 400Hz+1200Hz, 200ms ON
        TONE_PROP_BEEP2,  // General double beep: 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms on
        // 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).

        // CDMA Tones
        TONE_CDMA_DIAL_TONE_LITE,
        TONE_CDMA_NETWORK_USA_RINGBACK,
        TONE_CDMA_INTERCEPT,
        TONE_CDMA_ABBR_INTERCEPT,
        TONE_CDMA_REORDER,
        TONE_CDMA_ABBR_REORDER,
        TONE_CDMA_NETWORK_BUSY,
        TONE_CDMA_CONFIRM,
        TONE_CDMA_ANSWER,
        TONE_CDMA_NETWORK_CALLWAITING,
        TONE_CDMA_PIP,

        // ISDN
        TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL,  // ISDN Alert Normal
        TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP, // ISDN Intergroup
        TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI, // ISDN SP PRI
        TONE_CDMA_CALL_SIGNAL_ISDN_PAT3,  // ISDN Alert PAT3
        TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING, // ISDN Alert PING RING
        TONE_CDMA_CALL_SIGNAL_ISDN_PAT5,  // ISDN Alert PAT5
        TONE_CDMA_CALL_SIGNAL_ISDN_PAT6,  // ISDN Alert PAT6
        TONE_CDMA_CALL_SIGNAL_ISDN_PAT7,  // ISDN Alert PAT7
        // ISDN end

        // IS54
        TONE_CDMA_HIGH_L,  // IS54 High Pitch Long
        TONE_CDMA_MED_L, // IS54 Med Pitch Long
        TONE_CDMA_LOW_L, // IS54 Low Pitch Long
        TONE_CDMA_HIGH_SS, // IS54 High Pitch Short Short
        TONE_CDMA_MED_SS, // IS54 Medium Pitch Short Short
        TONE_CDMA_LOW_SS, // IS54 Low Pitch Short Short
        TONE_CDMA_HIGH_SSL, // IS54 High Pitch Short Short Long
        TONE_CDMA_MED_SSL, // IS54 Medium  Pitch Short Short Long
        TONE_CDMA_LOW_SSL, // IS54 Low  Pitch Short Short Long
        TONE_CDMA_HIGH_SS_2, // IS54 High Pitch Short Short 2
        TONE_CDMA_MED_SS_2, // IS54 Med Pitch Short Short 2
        TONE_CDMA_LOW_SS_2, // IS54 Low  Pitch Short Short 2
        TONE_CDMA_HIGH_SLS, // IS54 High Pitch Short Long Short
        TONE_CDMA_MED_SLS, // IS54 Med Pitch Short Long Short
        TONE_CDMA_LOW_SLS, // IS54 Low Pitch Short Long Short
        TONE_CDMA_HIGH_S_X4, // IS54 High Pitch Short Short Short Short
        TONE_CDMA_MED_S_X4, // IS54 Med Pitch Short Short Short Short
        TONE_CDMA_LOW_S_X4, // IS54 Low Pitch Short Short Short Short
        TONE_CDMA_HIGH_PBX_L, // PBX High Pitch Long
        TONE_CDMA_MED_PBX_L, // PBX Med Pitch Long
        TONE_CDMA_LOW_PBX_L, // PBX Low  Pitch Long
        TONE_CDMA_HIGH_PBX_SS, // PBX High Short Short
        TONE_CDMA_MED_PBX_SS, // PBX Med Short Short
        TONE_CDMA_LOW_PBX_SS, // PBX Low  Short Short
        TONE_CDMA_HIGH_PBX_SSL, // PBX High Short Short Long
        TONE_CDMA_MED_PBX_SSL, // PBX Med Short Short Long
        TONE_CDMA_LOW_PBX_SSL,  // PBX Low Short Short Long
        TONE_CDMA_HIGH_PBX_SLS, // PBX High  SLS
        TONE_CDMA_MED_PBX_SLS,  // PBX Med SLS
        TONE_CDMA_LOW_PBX_SLS, // PBX Low SLS
        TONE_CDMA_HIGH_PBX_S_X4, // PBX High SSSS
        TONE_CDMA_MED_PBX_S_X4, // PBX Med SSSS
        TONE_CDMA_LOW_PBX_S_X4, // PBX LOW SSSS
        //IS54 end
        // proprietary
        TONE_CDMA_ALERT_NETWORK_LITE,
        TONE_CDMA_ALERT_AUTOREDIAL_LITE,
        TONE_CDMA_ONE_MIN_BEEP,
        TONE_CDMA_KEYPAD_VOLUME_KEY_LITE,
        TONE_CDMA_PRESSHOLDKEY_LITE,
        TONE_CDMA_ALERT_INCALL_LITE,
        TONE_CDMA_EMERGENCY_RINGBACK,
        TONE_CDMA_ALERT_CALL_GUARD,
        TONE_CDMA_SOFT_ERROR_LITE,
        TONE_CDMA_CALLDROP_LITE,
        // proprietary end
        TONE_CDMA_NETWORK_BUSY_ONE_SHOT,
        TONE_CDMA_ABBR_ALERT,
        TONE_CDMA_SIGNAL_OFF,
        //CDMA end
        TONE_HOLD_RECALL,

        NUM_TONES,
        NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1
    };

    ToneGenerator(audio_stream_type_t streamType, float volume, bool threadCanCallJava = false);
    ~ToneGenerator();

    bool startTone(tone_type toneType, int durationMs = -1);
    void stopTone();

    bool isInited() { return (mState == TONE_IDLE)?false:true;}

    // returns the audio session this ToneGenerator belongs to or 0 if an error occured.
    int getSessionId() { return (mpAudioTrack == 0) ? 0 : mpAudioTrack->getSessionId(); }

private:

    enum tone_state {
        TONE_IDLE,  // ToneGenerator is being initialized or initialization failed
        TONE_INIT,  // ToneGenerator has been successfully initialized and is not playing
        TONE_STARTING,  // ToneGenerator is starting playing
        TONE_PLAYING,  // ToneGenerator is playing
        TONE_STOPPING,  // ToneGenerator is stoping
        TONE_STOPPED,  // ToneGenerator is stopped: the AudioTrack will be stopped
        TONE_RESTARTING  // A start request was received in active state (playing or stopping)
    };


    // 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 = 12;  // Maximun number of segments in a tone descriptor
    static const unsigned int TONEGEN_INF = 0xFFFFFFFF;  // Represents infinite time duration
    static const CONSTEXPR float TONEGEN_GAIN = 0.9;  // Default gain passed to  WaveGenerator().

    // ToneDescriptor class contains all parameters needed to generate a 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
    //        during which the tone is ON or OFF.    Segments with even index (starting from 0)
    //        correspond to tone ON state and segments with odd index to OFF state.
    //        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.
    //    - loopCnt - Number of times to repeat a sequence of seqments after playing this
    //    - loopIndx - The segment index to go back and play is loopcnt > 0
    //    - 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. 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];
        unsigned short loopCnt;
        unsigned short loopIndx;
    };

    class ToneDescriptor {
    public:
        ToneSegment segments[TONEGEN_MAX_SEGMENTS+1];
        unsigned long repeatCnt;
        unsigned long repeatSegment;
    };

    static const ToneDescriptor sToneDescriptors[];

    bool mThreadCanCallJava;
    unsigned int mTotalSmp;  // Total number of audio samples played (gives current time)
    unsigned int mNextSegSmp;  // Position of next segment transition expressed in samples
    // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly
    // only if tone duration is less than about 27 Hours(@44100Hz sampling rate). If this time is exceeded,
    // no crash will occur but tone sequence will show a glitch.
    unsigned int mMaxSmp;  // Maximum number of audio samples played (maximun tone duration)
    int mDurationMs;  // Maximum tone duration in ms

    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

    unsigned short mLoopCounter; // Current tone loopback count

    uint32_t mSamplingRate;  // AudioFlinger Sampling rate
    sp<AudioTrack> mpAudioTrack;  // Pointer to audio track used for playback
    Mutex mLock;  // Mutex to control concurent access to ToneGenerator object from audio callback and application API
    Mutex mCbkCondLock; // Mutex associated to mWaitCbkCond
    Condition mWaitCbkCond; // condition enabling interface to wait for audio callback completion after a change is requested
    float mVolume;  // Volume applied to audio track
    audio_stream_type_t mStreamType; // Audio stream used for output
    unsigned int mProcessSize;  // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
    struct timespec mStartTime; // tone start time: needed to guaranty actual tone duration

    bool initAudioTrack();
    static void audioCallback(int event, void* user, void *info);
    bool prepareWave();
    unsigned int numWaves(unsigned int segmentIdx);
    void clearWaveGens();
    tone_type getToneForRegion(tone_type toneType);

    // WaveGenerator generates a single sine wave
    class WaveGenerator {
    public:
        enum gen_command {
            WAVEGEN_START,  // Start/restart wave from phase 0
            WAVEGEN_CONT,  // Continue wave from current phase
            WAVEGEN_STOP  // Stop wave on zero crossing
        };

        WaveGenerator(unsigned short samplingRate, unsigned short frequency,
                float volume);
        ~WaveGenerator();

        void getSamples(short *outBuffer, unsigned int count,
                unsigned int command);

    private:
        static const short GEN_AMP = 32000;  // amplitude of generator
        static const short S_Q14 = 14;  // shift for Q14
        static const short S_Q15 = 15;  // shift for Q15

        short mA1_Q14;  // Q14 coefficient
        // delay line of full amplitude generator
        short mS1, mS2;  // delay line S2 oldest
        short mS2_0;  // saved value for reinitialisation
        short mAmplitude_Q15;  // Q15 amplitude
    };

    KeyedVector<unsigned short, WaveGenerator *> mWaveGens;  // list of active wave generators.
};

}
;  // namespace android

#endif /*ANDROID_TONEGENERATOR_H_*/