summaryrefslogtreecommitdiffstats
path: root/include/media/ToneGenerator.h
blob: 6b0cc8ab8cceb0fb788f28b9df2b3dea7d3430d9 (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
/*
 * 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 <utils/RefBase.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.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).
        NUM_TONES,
        NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1
    };

    ToneGenerator(int streamType, float volume);
    ~ToneGenerator();

    bool startTone(int toneType);
    void stopTone();

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

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_RESTARTING  //
    };


    // 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[]:
    //         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.
    //    - 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];
    };

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

    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
    // 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 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

    int mSamplingRate;  // AudioFlinger Sampling rate
    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
    int mStreamType; // Audio stream used for output
    unsigned int mProcessSize;  // Size of audio blocks generated at a time by audioCallback() (in PCM frames).

    bool initAudioTrack();
    static void audioCallback(int event, void* user, void *info);
    bool prepareWave();
    unsigned int numWaves(unsigned int segmentIdx);
    void clearWaveGens();
    int getToneForRegion(int 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_*/