blob: adef3be7d5d9f0d879032bee005d300aedc56f68 [file] [log] [blame]
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "ToneGenerator"
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080019
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080020#include <math.h>
21#include <utils/Log.h>
Eric Laurent0b62e242009-05-05 00:49:01 -070022#include <cutils/properties.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080023#include "media/ToneGenerator.h"
24
Eric Laurent0b62e242009-05-05 00:49:01 -070025
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080026namespace android {
27
Eric Laurent0b62e242009-05-05 00:49:01 -070028
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080029// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
Eric Laurent0b62e242009-05-05 00:49:01 -070030const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
David Krause5e0a3042009-06-17 15:46:13 -050031 { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 941, 0 }, 0, 0},
32 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070033 repeatCnt: ToneGenerator::TONEGEN_INF,
34 repeatSegment: 0 }, // TONE_DTMF_0
David Krause5e0a3042009-06-17 15:46:13 -050035 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 697, 0 }, 0, 0 },
36 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070037 repeatCnt: ToneGenerator::TONEGEN_INF,
38 repeatSegment: 0 }, // TONE_DTMF_1
David Krause5e0a3042009-06-17 15:46:13 -050039 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 697, 0 }, 0, 0 },
40 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070041 repeatCnt: ToneGenerator::TONEGEN_INF,
42 repeatSegment: 0 }, // TONE_DTMF_2
David Krause5e0a3042009-06-17 15:46:13 -050043 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 697, 0 }, 0, 0 },
44 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070045 repeatCnt: ToneGenerator::TONEGEN_INF,
46 repeatSegment: 0 }, // TONE_DTMF_3
David Krause5e0a3042009-06-17 15:46:13 -050047 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 770, 0 }, 0, 0 },
48 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070049 repeatCnt: ToneGenerator::TONEGEN_INF,
50 repeatSegment: 0 }, // TONE_DTMF_4
David Krause5e0a3042009-06-17 15:46:13 -050051 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 770, 0 }, 0, 0 },
52 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070053 repeatCnt: ToneGenerator::TONEGEN_INF,
54 repeatSegment: 0 }, // TONE_DTMF_5
David Krause5e0a3042009-06-17 15:46:13 -050055 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 770, 0 }, 0, 0 },
56 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070057 repeatCnt: ToneGenerator::TONEGEN_INF,
58 repeatSegment: 0 }, // TONE_DTMF_6
David Krause5e0a3042009-06-17 15:46:13 -050059 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 852, 0 }, 0, 0 },
60 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070061 repeatCnt: ToneGenerator::TONEGEN_INF,
62 repeatSegment: 0 }, // TONE_DTMF_7
David Krause5e0a3042009-06-17 15:46:13 -050063 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 852, 0 }, 0, 0 },
64 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070065 repeatCnt: ToneGenerator::TONEGEN_INF,
66 repeatSegment: 0 }, // TONE_DTMF_8
David Krause5e0a3042009-06-17 15:46:13 -050067 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 852, 0 }, 0, 0 },
68 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070069 repeatCnt: ToneGenerator::TONEGEN_INF,
70 repeatSegment: 0 }, // TONE_DTMF_9
David Krause5e0a3042009-06-17 15:46:13 -050071 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 941, 0 }, 0, 0 },
72 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070073 repeatCnt: ToneGenerator::TONEGEN_INF,
74 repeatSegment: 0 }, // TONE_DTMF_S
David Krause5e0a3042009-06-17 15:46:13 -050075 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 941, 0 }, 0, 0 },
76 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070077 repeatCnt: ToneGenerator::TONEGEN_INF,
78 repeatSegment: 0 }, // TONE_DTMF_P
David Krause5e0a3042009-06-17 15:46:13 -050079 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 697, 0 }, 0, 0 },
80 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070081 repeatCnt: ToneGenerator::TONEGEN_INF,
82 repeatSegment: 0 }, // TONE_DTMF_A
David Krause5e0a3042009-06-17 15:46:13 -050083 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 770, 0 }, 0, 0 },
84 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070085 repeatCnt: ToneGenerator::TONEGEN_INF,
86 repeatSegment: 0 }, // TONE_DTMF_B
David Krause5e0a3042009-06-17 15:46:13 -050087 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 852, 0 }, 0, 0 },
88 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070089 repeatCnt: ToneGenerator::TONEGEN_INF,
90 repeatSegment: 0 }, // TONE_DTMF_C
David Krause5e0a3042009-06-17 15:46:13 -050091 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 941, 0 }, 0, 0 },
92 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070093 repeatCnt: ToneGenerator::TONEGEN_INF,
94 repeatSegment: 0 }, // TONE_DTMF_D
David Krause5e0a3042009-06-17 15:46:13 -050095 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 }, 0, 0 },
96 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -070097 repeatCnt: ToneGenerator::TONEGEN_INF,
98 repeatSegment: 0 }, // TONE_SUP_DIAL
David Krause5e0a3042009-06-17 15:46:13 -050099 { segments: { { duration: 500 , waveFreq: { 425, 0 }, 0, 0},
100 { duration: 500, waveFreq: { 0 }, 0, 0},
101 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700102 repeatCnt: ToneGenerator::TONEGEN_INF,
103 repeatSegment: 0 }, // TONE_SUP_BUSY
David Krause5e0a3042009-06-17 15:46:13 -0500104 { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
105 { duration: 200, waveFreq: { 0 }, 0, 0 },
106 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700107 repeatCnt: ToneGenerator::TONEGEN_INF,
108 repeatSegment: 0 }, // TONE_SUP_CONGESTION
David Krause5e0a3042009-06-17 15:46:13 -0500109 { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
110 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700111 repeatCnt: 0,
112 repeatSegment: 0 }, // TONE_SUP_RADIO_ACK
David Krause5e0a3042009-06-17 15:46:13 -0500113 { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0},
114 { duration: 200, waveFreq: { 0 }, 0, 0},
115 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700116 repeatCnt: 2,
117 repeatSegment: 0 }, // TONE_SUP_RADIO_NOTAVAIL
David Krause5e0a3042009-06-17 15:46:13 -0500118 { segments: { { duration: 330, waveFreq: { 950, 1400, 1800, 0 }, 0, 0},
119 { duration: 1000, waveFreq: { 0 }, 0, 0},
120 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700121 repeatCnt: ToneGenerator::TONEGEN_INF,
122 repeatSegment: 0 }, // TONE_SUP_ERROR
David Krause5e0a3042009-06-17 15:46:13 -0500123 { segments: { { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
124 { duration: 600, waveFreq: { 0 }, 0, 0 },
125 { duration: 200, waveFreq: { 425, 0 }, 0, 0 },
126 { duration: 3000, waveFreq: { 0 }, 0, 0 },
127 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700128 repeatCnt: ToneGenerator::TONEGEN_INF,
129 repeatSegment: 0 }, // TONE_SUP_CALL_WAITING
David Krause5e0a3042009-06-17 15:46:13 -0500130 { segments: { { duration: 1000, waveFreq: { 425, 0 }, 0, 0 },
131 { duration: 4000, waveFreq: { 0 }, 0, 0 },
132 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700133 repeatCnt: ToneGenerator::TONEGEN_INF,
134 repeatSegment: 0 }, // TONE_SUP_RINGTONE
David Krause5e0a3042009-06-17 15:46:13 -0500135 { segments: { { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
136 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700137 repeatCnt: 0,
138 repeatSegment: 0 }, // TONE_PROP_BEEP
David Krause5e0a3042009-06-17 15:46:13 -0500139 { segments: { { duration: 100, waveFreq: { 1200, 0 }, 0, 0 },
140 { duration: 100, waveFreq: { 0 }, 0, 0 },
141 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700142 repeatCnt: 1,
143 repeatSegment: 0 }, // TONE_PROP_ACK
David Krause5e0a3042009-06-17 15:46:13 -0500144 { segments: { { duration: 400, waveFreq: { 300, 400, 500, 0 }, 0, 0 },
145 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700146 repeatCnt: 0,
147 repeatSegment: 0 }, // TONE_PROP_NACK
David Krause5e0a3042009-06-17 15:46:13 -0500148 { segments: { { duration: 200, waveFreq: { 400, 1200, 0 }, 0, 0 },
149 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700150 repeatCnt: 0,
151 repeatSegment: 0 }, // TONE_PROP_PROMPT
David Krause5e0a3042009-06-17 15:46:13 -0500152 { segments: { { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
153 { duration: 200, waveFreq: { 0 }, 0, 0 },
154 { duration: 40, waveFreq: { 400, 1200, 0 }, 0, 0 },
155 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700156 repeatCnt: 0,
157 repeatSegment: 0 }, // TONE_PROP_BEEP2
David Krause5e0a3042009-06-17 15:46:13 -0500158 { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
159 { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
160 { duration: 0 , waveFreq: { 0 }, 0, 0 }},
Eric Laurent0b62e242009-05-05 00:49:01 -0700161 repeatCnt: ToneGenerator::TONEGEN_INF,
162 repeatSegment: 0 }, // TONE_SUP_INTERCEPT
David Krause5e0a3042009-06-17 15:46:13 -0500163 { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
164 { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
165 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700166 repeatCnt: 7,
167 repeatSegment: 0 }, // TONE_SUP_INTERCEPT_ABBREV
David Krause5e0a3042009-06-17 15:46:13 -0500168 { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
169 { duration: 250, waveFreq: { 0 }, 0, 0 },
170 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700171 repeatCnt: 7,
172 repeatSegment: 0 }, // TONE_SUP_CONGESTION_ABBREV
David Krause5e0a3042009-06-17 15:46:13 -0500173 { segments: { { duration: 100, waveFreq: { 350, 440, 0 }, 0, 0 },
174 { duration: 100, waveFreq: { 0 }, 0, 0 },
175 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700176 repeatCnt: 2,
177 repeatSegment: 0 }, // TONE_SUP_CONFIRM
David Krause5e0a3042009-06-17 15:46:13 -0500178 { segments: { { duration: 100, waveFreq: { 480, 0 }, 0, 0 },
179 { duration: 100, waveFreq: { 0 }, 0, 0 },
180 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700181 repeatCnt: 3,
182 repeatSegment: 0 }, // TONE_SUP_PIP
David Krause5e0a3042009-06-17 15:46:13 -0500183 { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 }, 0, 0},
184 { duration: 0 , waveFreq: { 0 }, 0, 0}},
185 repeatCnt: ToneGenerator::TONEGEN_INF,
186 repeatSegment: 0 }, // TONE_CDMA_DIAL_TONE_LITE
187 { segments: { { duration: 2000, waveFreq: { 440, 480, 0 }, 0, 0 },
188 { duration: 4000, waveFreq: { 0 }, 0, 0 },
189 { duration: 0 , waveFreq: { 0 }, 0, 0}},
190 repeatCnt: ToneGenerator::TONEGEN_INF,
191 repeatSegment: 0 }, // TONE_CDMA_NETWORK_USA_RINGBACK
192 { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
193 { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
194 { duration: 0 , waveFreq: { 0 }, 0, 0}},
195 repeatCnt: ToneGenerator::TONEGEN_INF,
196 repeatSegment: 0 }, // TONE_CDMA_INTERCEPT
197 { segments: { { duration: 250, waveFreq: { 440, 0 }, 0, 0 },
198 { duration: 250, waveFreq: { 620, 0 }, 0, 0 },
199 { duration: 0 , waveFreq: { 0 }, 0, 0}},
200 repeatCnt: 0,
201 repeatSegment: 0 }, // TONE_CDMA_ABBR_INTERCEPT
202 { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
203 { duration: 250, waveFreq: { 0 }, 0, 0 },
204 { duration: 0 , waveFreq: { 0 }, 0, 0}},
205 repeatCnt: ToneGenerator::TONEGEN_INF,
206 repeatSegment: 0 }, // TONE_CDMA_REORDER
207 { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
208 { duration: 250, waveFreq: { 0 }, 0, 0 },
209 { duration: 0 , waveFreq: { 0 }, 0, 0}},
210 repeatCnt: 7,
211 repeatSegment: 0 }, // TONE_CDMA_ABBR_REORDER
212 { segments: { { duration: 500, waveFreq: { 480, 620, 0 }, 0, 0 },
213 { duration: 500, waveFreq: { 0 }, 0, 0 },
214 { duration: 0 , waveFreq: { 0 }, 0, 0}},
215 repeatCnt: ToneGenerator::TONEGEN_INF,
216 repeatSegment: 0 }, // TONE_CDMA_NETWORK_BUSY
217 { segments: { { duration: 100, waveFreq: { 350, 440, 0 }, 0, 0 },
218 { duration: 100, waveFreq: { 0 }, 0, 0 },
219 { duration: 0 , waveFreq: { 0 }, 0, 0}},
220 repeatCnt: 2,
221 repeatSegment: 0 }, // TONE_CDMA_CONFIRM
Naveen Kalla981594f2009-10-13 15:29:47 -0700222 { segments: { { duration: 500, waveFreq: { 660, 1000, 0 }, 0, 0 },
223 { duration: 0 , waveFreq: { 0 }, 0, 0}},
David Krause5e0a3042009-06-17 15:46:13 -0500224 repeatCnt: 0,
225 repeatSegment: 0 }, // TONE_CDMA_ANSWER
226 { segments: { { duration: 300, waveFreq: { 440, 0 }, 0, 0 },
227 { duration: 0 , waveFreq: { 0 }, 0, 0}},
228 repeatCnt: 0,
229 repeatSegment: 0 }, // TONE_CDMA_NETWORK_CALLWAITING
230 { segments: { { duration: 100, waveFreq: { 480, 0 }, 0, 0 },
231 { duration: 100, waveFreq: { 0 }, 0, 0 },
232 { duration: 0 , waveFreq: { 0 }, 0, 0}},
233 repeatCnt: 3,
234 repeatSegment: 0 }, // TONE_CDMA_PIP
235
236 { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
237 { duration: 64, waveFreq: { 2556, 0}, 19, 0},
238 { duration: 32, waveFreq: { 2091, 0}, 0, 0},
239 { duration: 48, waveFreq: { 2556, 0}, 0, 0},
240 { duration: 4000, waveFreq: { 0 }, 0, 0},
241 { duration: 0, waveFreq: { 0 }, 0, 0}},
242 repeatCnt: 0,
243 repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL
244 { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
245 { duration: 64, waveFreq: { 2556, 0}, 7, 0 },
246 { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
247 { duration: 400, waveFreq: { 0 }, 0, 0 },
248 { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
249 { duration: 64, waveFreq: { 2556, 0}, 7, 4 },
250 { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
251 { duration: 4000, waveFreq: { 0 }, 0, 0 },
252 { duration: 0, waveFreq: { 0 }, 0, 0 } },
253 repeatCnt: 0,
254 repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP
255 { segments: { { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
256 { duration: 64, waveFreq: { 2556, 0}, 3, 0 },
257 { duration: 16, waveFreq: { 2091, 0}, 0, 0 },
258 { duration: 200, waveFreq: { 0 }, 0, 0 },
259 { duration: 32, waveFreq: { 2091, 0}, 0, 0 },
260 { duration: 64, waveFreq: { 2556, 0}, 3, 4 },
261 { duration: 16, waveFreq: { 2091, 0}, 0, 0 },
262 { duration: 200, waveFreq: { 0 }, 0, 0 },
263 { duration: 0, waveFreq: { 0 }, 0, 0 } },
264 repeatCnt: 0,
265 repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI
266 { segments: { { duration: 0, waveFreq: { 0 }, 0, 0} },
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700267 repeatCnt: 0,
268 repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT3
David Krause5e0a3042009-06-17 15:46:13 -0500269 { segments: { { duration: 32, waveFreq: { 2091, 0 }, 0, 0 },
270 { duration: 64, waveFreq: { 2556, 0 }, 4, 0 },
271 { duration: 20, waveFreq: { 2091, 0 }, 0, 0 },
272 { duration: 0, waveFreq: { 0 } , 0, 0 } },
273 repeatCnt: 0,
274 repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING
275 { segments: { { duration: 0, waveFreq: { 0 }, 0, 0} },
276 repeatCnt: 0,
277 repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT5
278 { segments: { { duration: 0, waveFreq: { 0 }, 0, 0} },
279 repeatCnt: 0,
280 repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT6
281 { segments: { { duration: 0, waveFreq: { 0 }, 0, 0} },
282 repeatCnt: 0,
283 repeatSegment: 0 }, // TONE_CDMA_CALL_SIGNAL_ISDN_PAT7
284
285 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
286 { duration: 25, waveFreq: { 4000, 0 }, 39, 0 },
287 { duration: 4000, waveFreq: { 0 }, 0, 0 },
288 { duration: 0, waveFreq: { 0 }, 0, 0 } },
289 repeatCnt: ToneGenerator::TONEGEN_INF,
290 repeatSegment: 0 }, // TONE_CDMA_HIGH_L
291 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
292 { duration: 25, waveFreq: { 2900, 0 }, 39, 0 },
293 { duration: 4000, waveFreq: { 0 }, 0, 0 },
294 { duration: 0, waveFreq: { 0 }, 0, 0 } },
295 repeatCnt: ToneGenerator::TONEGEN_INF,
296 repeatSegment: 0 }, // TONE_CDMA_MED_L
297 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
298 { duration: 25, waveFreq: { 1450, 0 }, 39, 0 },
299 { duration: 4000, waveFreq: { 0 }, 0, 0 },
300 { duration: 0, waveFreq: { 0 }, 0, 0 } },
301 repeatCnt: ToneGenerator::TONEGEN_INF,
302 repeatSegment: 0 }, // TONE_CDMA_LOW_L
303 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
304 { duration: 25, waveFreq: { 4000, 0 }, 15, 0 },
305 { duration: 400, waveFreq: { 0 }, 0, 0 },
306 { duration: 0, waveFreq: { 0 }, 0, 0 } },
307 repeatCnt: ToneGenerator::TONEGEN_INF,
308 repeatSegment: 0 }, // TONE_CDMA_HIGH_SS
309 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
310 { duration: 25, waveFreq: { 2900, 0 }, 15, 0 },
311 { duration: 400, waveFreq: { 0 }, 0, 0 },
312 { duration: 0, waveFreq: { 0 }, 0, 0 }},
313 repeatCnt: ToneGenerator::TONEGEN_INF,
314 repeatSegment: 0 }, // TONE_CDMA_MED_SS
315 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
316 { duration: 25, waveFreq: { 1450, 0 }, 15, 0 },
317 { duration: 400, waveFreq: { 0 }, 0, 0 },
318 { duration: 0, waveFreq: { 0 }, 0, 0 }},
319 repeatCnt: ToneGenerator::TONEGEN_INF,
320 repeatSegment: 0 }, // TONE_CDMA_LOW_SS
321 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
322 { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
323 { duration: 200, waveFreq: { 0 }, 0, 0 },
324 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
325 { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
326 { duration: 200, waveFreq: { 0 }, 0, 0 },
327 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
328 { duration: 25, waveFreq: { 4000, 0 }, 15, 6 },
329 { duration: 4000, waveFreq: { 0 }, 0, 0 },
330 { duration: 0, waveFreq: { 0 }, 0, 0 }},
331 repeatCnt: ToneGenerator::TONEGEN_INF,
332 repeatSegment: 0 }, // TONE_CDMA_HIGH_SSL
333 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
334 { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
335 { duration: 200, waveFreq: { 0 }, 0, 0 },
336 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
337 { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
338 { duration: 200, waveFreq: { 0 }, 0, 0 },
339 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
340 { duration: 25, waveFreq: { 2900, 0 }, 15, 6 },
341 { duration: 4000, waveFreq: { 0 }, 0, 0 },
342 { duration: 0, waveFreq: { 0 }, 0, 0 }},
343 repeatCnt: ToneGenerator::TONEGEN_INF,
344 repeatSegment: 0 }, // TONE_CDMA_MED_SSL
345 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
346 { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
347 { duration: 200, waveFreq: { 0 }, 0, 0 },
348 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
349 { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
350 { duration: 200, waveFreq: { 0 }, 0, 0 },
351 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
352 { duration: 25, waveFreq: { 1450, 0 }, 15, 6 },
353 { duration: 4000, waveFreq: { 0 }, 0, 0 },
354 { duration: 0, waveFreq: { 0 }, 0, 0 }},
355 repeatCnt: ToneGenerator::TONEGEN_INF,
356 repeatSegment: 0 }, // TONE_CDMA_LOW_SSL
357 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
358 { duration: 25, waveFreq: { 4000, 0 }, 19, 0 },
359 { duration: 1000, waveFreq: { 0 }, 0, 0 },
360 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
361 { duration: 25, waveFreq: { 4000, 0 }, 19, 3 },
362 { duration: 3000, waveFreq: { 0 }, 0, 0 },
363 { duration: 0, waveFreq: { 0 }, 0, 0 }},
364 repeatCnt: ToneGenerator::TONEGEN_INF,
365 repeatSegment: 0 }, // TONE_CDMA_HIGH_SS_2
366 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
367 { duration: 25, waveFreq: { 2900, 0 }, 19, 0 },
368 { duration: 1000, waveFreq: { 0 }, 0, 0 },
369 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
370 { duration: 25, waveFreq: { 2900, 0 }, 19, 3 },
371 { duration: 3000, waveFreq: { 0 }, 0, 0 },
372 { duration: 0, waveFreq: { 0 }, 0, 0 }},
373 repeatCnt: ToneGenerator::TONEGEN_INF,
374 repeatSegment: 0 }, // TONE_CDMA_MED_SS_2
375 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
376 { duration: 25, waveFreq: { 1450, 0 }, 19, 0 },
377 { duration: 1000, waveFreq: { 0 }, 0, 0 },
378 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
379 { duration: 25, waveFreq: { 1450, 0 }, 19, 3 },
380 { duration: 3000, waveFreq: { 0 }, 0, 0 },
381 { duration: 0, waveFreq: { 0 }, 0, 0 }},
382 repeatCnt: ToneGenerator::TONEGEN_INF,
383 repeatSegment: 0 }, // TONE_CDMA_LOW_SS_2
384 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
385 { duration: 25, waveFreq: { 4000, 0 }, 9, 0 },
386 { duration: 500, waveFreq: { 0 }, 0, 0 },
387 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
388 { duration: 25, waveFreq: { 4000, 0 }, 19, 3 },
389 { duration: 500, waveFreq: { 0 }, 0, 0 },
390 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
391 { duration: 25, waveFreq: { 4000, 0 }, 9, 6 },
392 { duration: 3000, waveFreq: { 0 }, 0, 0 },
393 { duration: 0, waveFreq: { 0 }, 0, 0 }},
394 repeatCnt: ToneGenerator::TONEGEN_INF,
395 repeatSegment: 0 }, // TONE_CDMA_HIGH_SLS
396 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
397 { duration: 25, waveFreq: { 2900, 0 }, 9, 0 },
398 { duration: 500, waveFreq: { 0 }, 0, 0 },
399 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
400 { duration: 25, waveFreq: { 2900, 0 }, 19, 3 },
401 { duration: 500, waveFreq: { 0 }, 0, 0 },
402 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
403 { duration: 25, waveFreq: { 2900, 0 }, 9, 6 },
404 { duration: 3000, waveFreq: { 0 }, 0, 0 },
405 { duration: 0, waveFreq: { 0 }, 0, 0 }},
406 repeatCnt: ToneGenerator::TONEGEN_INF,
407 repeatSegment: 0 }, // TONE_CDMA_MED_SLS
408 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
409 { duration: 25, waveFreq: { 1450, 0 }, 9, 0 },
410 { duration: 500, waveFreq: { 0 }, 0, 0 },
411 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
412 { duration: 25, waveFreq: { 1450, 0 }, 19, 3 },
413 { duration: 500, waveFreq: { 0 }, 0, 0 },
414 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
415 { duration: 25, waveFreq: { 1450, 0 }, 9, 6 },
416 { duration: 3000, waveFreq: { 0 }, 0, 0 },
417 { duration: 0, waveFreq: { 0 }, 0, 0 }},
418 repeatCnt: ToneGenerator::TONEGEN_INF,
419 repeatSegment: 0 }, // TONE_CDMA_LOW_SLS
420 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
421 { duration: 25, waveFreq: { 4000, 0 }, 9, 0 },
422 { duration: 500, waveFreq: { 0 }, 0, 0 },
423 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
424 { duration: 25, waveFreq: { 4000, 0 }, 9, 3 },
425 { duration: 500, waveFreq: { 0 }, 0, 0 },
426 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
427 { duration: 25, waveFreq: { 4000, 0 }, 9, 6 },
428 { duration: 500, waveFreq: { 0 }, 0, 0 },
429 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
430 { duration: 25, waveFreq: { 4000, 0 }, 9, 9 },
431 { duration: 2500, waveFreq: { 0 }, 0, 0 },
432 { duration: 0, waveFreq: { 0 }, 0, 0 }},
433 repeatCnt: ToneGenerator::TONEGEN_INF,
434 repeatSegment: 0 }, // TONE_CDMA_HIGH_S_X4
435 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
436 { duration: 25, waveFreq: { 2900, 0 }, 9, 0 },
437 { duration: 500, waveFreq: { 0 }, 0, 0 },
438 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
439 { duration: 25, waveFreq: { 2900, 0 }, 9, 3 },
440 { duration: 500, waveFreq: { 0 }, 0, 0 },
441 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
442 { duration: 25, waveFreq: { 2900, 0 }, 9, 6 },
443 { duration: 500, waveFreq: { 0 }, 0, 0 },
444 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
445 { duration: 25, waveFreq: { 2900, 0 }, 9, 9 },
446 { duration: 2500, waveFreq: { 0 }, 0, 0 },
447 { duration: 0, waveFreq: { 0 }, 0, 0 }},
448 repeatCnt: ToneGenerator::TONEGEN_INF,
449 repeatSegment: 0 }, // TONE_CDMA_MED_S_X4
450 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
451 { duration: 25, waveFreq: { 1450, 0 }, 9, 0 },
452 { duration: 500, waveFreq: { 0 }, 0, 0 },
453 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
454 { duration: 25, waveFreq: { 1450, 0 }, 9, 3 },
455 { duration: 500, waveFreq: { 0 }, 0, 0 },
456 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
457 { duration: 25, waveFreq: { 1450, 0 }, 9, 6 },
458 { duration: 500, waveFreq: { 0 }, 0, 0 },
459 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
460 { duration: 25, waveFreq: { 1450, 0 }, 9, 9 },
461 { duration: 2500, waveFreq: { 0 }, 0, 0 },
462 { duration: 0, waveFreq: { 0 }, 0, 0 }},
463 repeatCnt: ToneGenerator::TONEGEN_INF,
464 repeatSegment: 0 }, // TONE_CDMA_LOW_S_X4
465 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
466 { duration: 25, waveFreq: { 4000, 0 }, 19, 0 },
467 { duration: 2000, waveFreq: { 0 }, 0, 0 },
468 { duration: 0, waveFreq: { 0 }, 0, 0 }},
469 repeatCnt: ToneGenerator::TONEGEN_INF,
470 repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_L
471 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
472 { duration: 25, waveFreq: { 2900, 0 }, 19, 0 },
473 { duration: 2000, waveFreq: { 0 }, 0, 0 },
474 { duration: 0, waveFreq: { 0 }, 0, 0 }},
475 repeatCnt: ToneGenerator::TONEGEN_INF,
476 repeatSegment: 0 }, // TONE_CDMA_MED_PBX_L
477 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
478 { duration: 25, waveFreq: { 1450, 0 }, 19, 0 },
479 { duration: 2000, waveFreq: { 0 }, 0, 0 },
480 { duration: 0, waveFreq: { 0 }, 0, 0 }},
481 repeatCnt: ToneGenerator::TONEGEN_INF,
482 repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_L
483 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
484 { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
485 { duration: 200, waveFreq: { 0 }, 0, 0 },
486 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
487 { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
488 { duration: 2000, waveFreq: { 0 }, 0, 0 },
489 { duration: 0, waveFreq: { 0 }, 0, 0 }},
490 repeatCnt: ToneGenerator::TONEGEN_INF,
491 repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_SS
492 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
493 { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
494 { duration: 200, waveFreq: { 0 }, 0, 0 },
495 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
496 { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
497 { duration: 2000, waveFreq: { 0 }, 0, 0 },
498 { duration: 0, waveFreq: { 0 }, 0, 0 }},
499 repeatCnt: ToneGenerator::TONEGEN_INF,
500 repeatSegment: 0 }, // TONE_CDMA_MED_PBX_SS
501 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
502 { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
503 { duration: 200, waveFreq: { 0 }, 0, 0 },
504 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
505 { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
506 { duration: 2000, waveFreq: { 0 }, 0, 0 },
507 { duration: 0, waveFreq: { 0 }, 0, 0 }},
508 repeatCnt: ToneGenerator::TONEGEN_INF,
509 repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_SS
510 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
511 { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
512 { duration: 200, waveFreq: { 0 }, 0, 0 },
513 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
514 { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
515 { duration: 200, waveFreq: { 0 }, 0, 0 },
516 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
517 { duration: 25, waveFreq: { 4000, 0 }, 15, 6 },
518 { duration: 1000, waveFreq: { 0 }, 0, 0 },
519 { duration: 0, waveFreq: { 0 }, 0, 0 }},
520 repeatCnt: ToneGenerator::TONEGEN_INF,
521 repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_SSL
522 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
523 { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
524 { duration: 200, waveFreq: { 0 }, 0, 0 },
525 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
526 { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
527 { duration: 200, waveFreq: { 0 }, 0, 0 },
528 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
529 { duration: 25, waveFreq: { 2900, 0 }, 15, 6 },
530 { duration: 1000, waveFreq: { 0 }, 0, 0 },
531 { duration: 0, waveFreq: { 0 }, 0, 0 }},
532 repeatCnt: ToneGenerator::TONEGEN_INF,
533 repeatSegment: 0 }, // TONE_CDMA_MED_PBX_SSL
534 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
535 { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
536 { duration: 200, waveFreq: { 0 }, 0, 0 },
537 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
538 { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
539 { duration: 200, waveFreq: { 0 }, 0, 0 },
540 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
541 { duration: 25, waveFreq: { 1450, 0 }, 15, 6 },
542 { duration: 1000, waveFreq: { 0 }, 0, 0 },
543 { duration: 0, waveFreq: { 0 }, 0, 0 }},
544 repeatCnt: ToneGenerator::TONEGEN_INF,
545 repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_SSL
546 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
547 { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
548 { duration: 200, waveFreq: { 0 }, 0, 0 },
549 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
550 { duration: 25, waveFreq: { 4000, 0 }, 15, 3 },
551 { duration: 200, waveFreq: { 0 }, 0, 0 },
552 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
553 { duration: 25, waveFreq: { 4000, 0 }, 7, 6 },
554 { duration: 1000, waveFreq: { 0 }, 0, 0 },
555 { duration: 0, waveFreq: { 0 }, 0, 0 }},
556 repeatCnt: ToneGenerator::TONEGEN_INF,
557 repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_SLS
558 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
559 { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
560 { duration: 200, waveFreq: { 0 }, 0, 0 },
561 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
562 { duration: 25, waveFreq: { 2900, 0 }, 15, 3 },
563 { duration: 200, waveFreq: { 0 }, 0, 0 },
564 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
565 { duration: 25, waveFreq: { 2900, 0 }, 7, 6 },
566 { duration: 1000, waveFreq: { 0 }, 0, 0 },
567 { duration: 0, waveFreq: { 0 }, 0, 0 }},
568 repeatCnt: ToneGenerator::TONEGEN_INF,
569 repeatSegment: 0 }, // TONE_CDMA_MED_PBX_SLS
570 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
571 { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
572 { duration: 200, waveFreq: { 0 }, 0, 0 },
573 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
574 { duration: 25, waveFreq: { 1450, 0 }, 15, 3 },
575 { duration: 200, waveFreq: { 0 }, 0, 0 },
576 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
577 { duration: 25, waveFreq: { 1450, 0 }, 7, 6 },
578 { duration: 1000, waveFreq: { 0 }, 0, 0 },
579 { duration: 0, waveFreq: { 0 }, 0, 0 }},
580 repeatCnt: ToneGenerator::TONEGEN_INF,
581 repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_SLS
582 { segments: { { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
583 { duration: 25, waveFreq: { 4000, 0 }, 7, 0 },
584 { duration: 200, waveFreq: { 0 }, 0, 0 },
585 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
586 { duration: 25, waveFreq: { 4000, 0 }, 7, 3 },
587 { duration: 200, waveFreq: { 0 }, 0, 0 },
588 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
589 { duration: 25, waveFreq: { 4000, 0 }, 7, 6 },
590 { duration: 200, waveFreq: { 0 }, 0, 0 },
591 { duration: 25, waveFreq: { 3700, 0 }, 0, 0 },
592 { duration: 25, waveFreq: { 4000, 0 }, 7, 9 },
593 { duration: 800, waveFreq: { 0 }, 0, 0 },
594 { duration: 0, waveFreq: { 0 }, 0, 0 }},
595 repeatCnt: ToneGenerator::TONEGEN_INF,
596 repeatSegment: 0 }, // TONE_CDMA_HIGH_PBX_S_X4
597 { segments: { { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
598 { duration: 25, waveFreq: { 2900, 0 }, 7, 0 },
599 { duration: 200, waveFreq: { 0 }, 0, 0 },
600 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
601 { duration: 25, waveFreq: { 2900, 0 }, 7, 3 },
602 { duration: 200, waveFreq: { 0 }, 0, 0 },
603 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
604 { duration: 25, waveFreq: { 2900, 0 }, 7, 6 },
605 { duration: 200, waveFreq: { 0 }, 0, 0 },
606 { duration: 25, waveFreq: { 2600, 0 }, 0, 0 },
607 { duration: 25, waveFreq: { 2900, 0 }, 7, 9 },
608 { duration: 800, waveFreq: { 0 }, 0, 0 },
609 { duration: 0, waveFreq: { 0 }, 0, 0 }},
610 repeatCnt: ToneGenerator::TONEGEN_INF,
611 repeatSegment: 0 }, // TONE_CDMA_MED_PBX_S_X4
612 { segments: { { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
613 { duration: 25, waveFreq: { 1450, 0 }, 7, 0 },
614 { duration: 200, waveFreq: { 0 }, 0, 0 },
615 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
616 { duration: 25, waveFreq: { 1450, 0 }, 7, 3 },
617 { duration: 200, waveFreq: { 0 }, 0, 0 },
618 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
619 { duration: 25, waveFreq: { 1450, 0 }, 7, 6 },
620 { duration: 200, waveFreq: { 0 }, 0, 0 },
621 { duration: 25, waveFreq: { 1300, 0 }, 0, 0 },
622 { duration: 25, waveFreq: { 1450, 0 }, 7, 9 },
623 { duration: 800, waveFreq: { 0 }, 0, 0 },
624 { duration: 0, waveFreq: { 0 }, 0, 0 }},
625 repeatCnt: ToneGenerator::TONEGEN_INF,
626 repeatSegment: 0 }, // TONE_CDMA_LOW_PBX_S_X4
627
628 { segments: { { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
629 { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
630 { duration: 62, waveFreq: { 740, 0 }, 0, 0 },
631 { duration: 62, waveFreq: { 622, 0 }, 0, 0 },
632 { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
633 { duration: 0, waveFreq: { 0 }, 0, 0 } },
634 repeatCnt: 0,
635 repeatSegment: 0 }, // TONE_CDMA_ALERT_NETWORK_LITE
636 { segments: { { duration: 62, waveFreq: { 1245, 0 }, 0, 0 },
637 { duration: 62, waveFreq: { 659, 0 }, 2, 0 },
638 { duration: 62, waveFreq: { 1245, 0 }, 0, 0 },
639 { duration: 0, waveFreq: { 0 }, 0, 0 } },
640 repeatCnt: 0,
641 repeatSegment: 0 }, // TONE_CDMA_ALERT_AUTOREDIAL_LITE
642 { segments: { { duration: 400, waveFreq: { 1150, 770, 0 }, 0, 0 },
643 { duration: 0, waveFreq: { 0 }, 0, 0 } },
644 repeatCnt: 0,
645 repeatSegment: 0 }, // TONE_CDMA_ONE_MIN_BEEP
646 { segments: { { duration: 120, waveFreq: { 941, 1477, 0 }, 0, 0 },
647 { duration: 0, waveFreq: { 0 }, 0, 0 } },
648 repeatCnt: 0,
649 repeatSegment: 0 }, // TONE_CDMA_KEYPAD_VOLUME_KEY_LITE
650 { segments: { { duration: 375, waveFreq: { 587, 0 }, 0, 0 },
651 { duration: 125, waveFreq: { 1175, 0 }, 0, 0 },
652 { duration: 0, waveFreq: { 0 }, 0, 0 } },
653 repeatCnt: 0,
654 repeatSegment: 0 }, // TONE_CDMA_PRESSHOLDKEY_LITE
655 { segments: { { duration: 62, waveFreq: { 587, 0 }, 0, 0 },
656 { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
657 { duration: 62, waveFreq: { 831, 0 }, 0, 0 },
658 { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
659 { duration: 62, waveFreq: { 1109, 0 }, 0, 0 },
660 { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
661 { duration: 62, waveFreq: { 831, 0 }, 0, 0 },
662 { duration: 62, waveFreq: { 784, 0 }, 0, 0 },
663 { duration: 0, waveFreq: { 0 }, 0, 0 } },
664 repeatCnt: 0,
665 repeatSegment: 0 }, // TONE_CDMA_ALERT_INCALL_LITE
666 { segments: { { duration: 125, waveFreq: { 941, 0 }, 0, 0 },
667 { duration: 10, waveFreq: { 0 }, 2, 0 },
668 { duration: 4990, waveFreq: { 0 }, 0, 0 },
669 { duration: 0, waveFreq: { 0 }, 0, 0 } },
670 repeatCnt: ToneGenerator::TONEGEN_INF,
671 repeatSegment: 0 }, // TONE_CDMA_EMERGENCY_RINGBACK
672 { segments: { { duration: 125, waveFreq: { 1319, 0 }, 0, 0 },
673 { duration: 125, waveFreq: { 0 }, 0, 0 },
674 { duration: 0, waveFreq: { 0 }, 0, 0 } },
675 repeatCnt: 2,
676 repeatSegment: 0 }, // TONE_CDMA_ALERT_CALL_GUARD
677 { segments: { { duration: 125, waveFreq: { 1047, 0 }, 0, 0 },
678 { duration: 125, waveFreq: { 370, 0 }, 0, 0 },
679 { duration: 0, waveFreq: { 0 }, 0, 0 } },
680 repeatCnt: 0,
681 repeatSegment: 0 }, // TONE_CDMA_SOFT_ERROR_LITE
682 { segments: { { duration: 125, waveFreq: { 1480, 0 }, 0, 0 },
683 { duration: 125, waveFreq: { 1397, 0 }, 0, 0 },
684 { duration: 125, waveFreq: { 784, 0 }, 0, 0 },
685 { duration: 0, waveFreq: { 0 }, 0, 0 } },
686 repeatCnt: 0,
687 repeatSegment: 0 }, // TONE_CDMA_CALLDROP_LITE
688
689 { segments: { { duration: 500, waveFreq: { 425, 0 }, 0, 0 },
690 { duration: 500, waveFreq: { 0 }, 0, 0 },
691 { duration: 0, waveFreq: { 0 }, 0, 0 }},
692 repeatCnt: 0,
693 repeatSegment: 0 }, // TONE_CDMA_NETWORK_BUSY_ONE_SHOT
694 { segments: { { duration: 400, waveFreq: { 1150, 770 }, 0, 0 },
695 { duration: 0, waveFreq: { 0 }, 0, 0 }},
696 repeatCnt: 0,
697 repeatSegment: 0 }, // TONE_CDMA_ABBR_ALERT
698 { segments: { { duration: 0, waveFreq: { 0 }, 0, 0 }},
699 repeatCnt: 0,
700 repeatSegment: 0 }, // TONE_CDMA_SIGNAL_OFF
701
702 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 350, 440, 0 }, 0, 0 },
703 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700704 repeatCnt: ToneGenerator::TONEGEN_INF,
705 repeatSegment: 0 }, // TONE_ANSI_DIAL
David Krause5e0a3042009-06-17 15:46:13 -0500706 { segments: { { duration: 500, waveFreq: { 480, 620, 0 }, 0, 0 },
707 { duration: 500, waveFreq: { 0 }, 0, 0 },
708 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700709 repeatCnt: ToneGenerator::TONEGEN_INF,
710 repeatSegment: 0 }, // TONE_ANSI_BUSY
David Krause5e0a3042009-06-17 15:46:13 -0500711 { segments: { { duration: 250, waveFreq: { 480, 620, 0 }, 0, 0 },
712 { duration: 250, waveFreq: { 0 }, 0, 0 },
713 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700714 repeatCnt: ToneGenerator::TONEGEN_INF,
715 repeatSegment: 0 }, // TONE_ANSI_CONGESTION
David Krause5e0a3042009-06-17 15:46:13 -0500716 { segments: { { duration: 300, waveFreq: { 440, 0 }, 0, 0 },
717 { duration: 9700, waveFreq: { 0 }, 0, 0 },
718 { duration: 100, waveFreq: { 440, 0 }, 0, 0 },
719 { duration: 100, waveFreq: { 0 }, 0, 0 },
720 { duration: 100, waveFreq: { 440, 0 }, 0, 0 },
721 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700722 repeatCnt: ToneGenerator::TONEGEN_INF,
723 repeatSegment: 1 }, // TONE_ANSI_CALL_WAITING
David Krause5e0a3042009-06-17 15:46:13 -0500724 { segments: { { duration: 2000, waveFreq: { 440, 480, 0 }, 0, 0 },
725 { duration: 4000, waveFreq: { 0 }, 0, 0 },
726 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700727 repeatCnt: ToneGenerator::TONEGEN_INF,
728 repeatSegment: 0 }, // TONE_ANSI_RINGTONE
David Krause5e0a3042009-06-17 15:46:13 -0500729 { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 400, 0 }, 0, 0 },
730 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700731 repeatCnt: ToneGenerator::TONEGEN_INF,
732 repeatSegment: 0 }, // TONE_JAPAN_DIAL
David Krause5e0a3042009-06-17 15:46:13 -0500733 { segments: { { duration: 500, waveFreq: { 400, 0 }, 0, 0 },
734 { duration: 500, waveFreq: { 0 }, 0, 0 },
735 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700736 repeatCnt: ToneGenerator::TONEGEN_INF,
737 repeatSegment: 0 }, // TONE_JAPAN_BUSY
David Krause5e0a3042009-06-17 15:46:13 -0500738 { segments: { { duration: 1000, waveFreq: { 400, 0 }, 0, 0 },
739 { duration: 2000, waveFreq: { 0 }, 0, 0 },
740 { duration: 0 , waveFreq: { 0 }, 0, 0}},
Eric Laurent0b62e242009-05-05 00:49:01 -0700741 repeatCnt: ToneGenerator::TONEGEN_INF,
742 repeatSegment: 0 }, // TONE_JAPAN_RADIO_ACK
David Krause5e0a3042009-06-17 15:46:13 -0500743
744
745
Eric Laurent0b62e242009-05-05 00:49:01 -0700746};
747
748// Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
749// to actual tone for current region.
Glenn Kasten3d2f8772012-01-27 15:25:25 -0800750const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = {
Eric Laurent0b62e242009-05-05 00:49:01 -0700751 { // ANSI
752 TONE_ANSI_DIAL, // TONE_SUP_DIAL
753 TONE_ANSI_BUSY, // TONE_SUP_BUSY
754 TONE_ANSI_CONGESTION, // TONE_SUP_CONGESTION
755 TONE_SUP_RADIO_ACK, // TONE_SUP_RADIO_ACK
756 TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL
757 TONE_SUP_ERROR, // TONE_SUP_ERROR
758 TONE_ANSI_CALL_WAITING, // TONE_SUP_CALL_WAITING
759 TONE_ANSI_RINGTONE // TONE_SUP_RINGTONE
760 },
761 { // JAPAN
762 TONE_JAPAN_DIAL, // TONE_SUP_DIAL
763 TONE_JAPAN_BUSY, // TONE_SUP_BUSY
764 TONE_SUP_CONGESTION, // TONE_SUP_CONGESTION
765 TONE_JAPAN_RADIO_ACK, // TONE_SUP_RADIO_ACK
766 TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL
767 TONE_SUP_ERROR, // TONE_SUP_ERROR
768 TONE_SUP_CALL_WAITING, // TONE_SUP_CALL_WAITING
769 TONE_SUP_RINGTONE // TONE_SUP_RINGTONE
770 }
771};
772
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800773
774////////////////////////////////////////////////////////////////////////////////
775// ToneGenerator class Implementation
776////////////////////////////////////////////////////////////////////////////////
777
778
779//---------------------------------- public methods ----------------------------
780
781
782////////////////////////////////////////////////////////////////////////////////
783//
784// Method: ToneGenerator::ToneGenerator()
785//
786// Description: Constructor. Initializes the tone sequencer, intantiates required sine wave
787// generators, instantiates output audio track.
788//
789// Input:
Glenn Kasten99e53b82012-01-19 08:59:58 -0800790// streamType: Type of stream used for tone playback
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800791// volume: volume applied to tone (0.0 to 1.0)
792//
793// Output:
794// none
795//
796////////////////////////////////////////////////////////////////////////////////
Glenn Kastenfff6d712012-01-12 16:38:12 -0800797ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool threadCanCallJava) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800798
Glenn Kasten90bebef2012-01-27 15:24:38 -0800799 ALOGV("ToneGenerator constructor: streamType=%d, volume=%f", streamType, volume);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800800
801 mState = TONE_IDLE;
802
803 if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
Steve Block29357bc2012-01-06 19:20:56 +0000804 ALOGE("Unable to marshal AudioFlinger");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800805 return;
806 }
Eric Laurent34f1d8e2009-11-04 08:27:26 -0800807 mThreadCanCallJava = threadCanCallJava;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800808 mStreamType = streamType;
809 mVolume = volume;
Glenn Kastena0d68332012-01-27 16:47:15 -0800810 mpToneDesc = NULL;
811 mpNewToneDesc = NULL;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800812 // Generate tone by chunks of 20 ms to keep cadencing precision
813 mProcessSize = (mSamplingRate * 20) / 1000;
814
Eric Laurent0b62e242009-05-05 00:49:01 -0700815 char value[PROPERTY_VALUE_MAX];
816 property_get("gsm.operator.iso-country", value, "");
817 if (strcmp(value,"us") == 0 ||
818 strcmp(value,"ca") == 0) {
819 mRegion = ANSI;
820 } else if (strcmp(value,"jp") == 0) {
821 mRegion = JAPAN;
822 } else {
823 mRegion = CEPT;
824 }
825
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800826 if (initAudioTrack()) {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800827 ALOGV("ToneGenerator INIT OK, time: %d", (unsigned int)(systemTime()/1000000));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800828 } else {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800829 ALOGV("!!!ToneGenerator INIT FAILED!!!");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800830 }
831}
832
833
834
835
836////////////////////////////////////////////////////////////////////////////////
837//
838// Method: ToneGenerator::~ToneGenerator()
839//
840// Description: Destructor. Stop sound playback and delete audio track if
841// needed and delete sine wave generators.
842//
843// Input:
844// none
845//
846// Output:
847// none
848//
849////////////////////////////////////////////////////////////////////////////////
850ToneGenerator::~ToneGenerator() {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800851 ALOGV("ToneGenerator destructor");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800852
Glenn Kasten2799d742013-05-30 14:33:29 -0700853 if (mpAudioTrack != 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800854 stopTone();
Glenn Kasten2799d742013-05-30 14:33:29 -0700855 ALOGV("Delete Track: %p", mpAudioTrack.get());
856 mpAudioTrack.clear();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800857 }
858}
859
860////////////////////////////////////////////////////////////////////////////////
861//
862// Method: ToneGenerator::startTone()
863//
864// Description: Starts tone playback.
865//
866// Input:
Eric Laurent85fa14d2009-09-07 08:38:38 -0700867// toneType: Type of tone generated (values in enum tone_type)
868// durationMs: The tone duration in milliseconds. If the tone is limited in time by definition,
869// the actual duration will be the minimum of durationMs and the defined tone duration.
870// Ommiting or setting durationMs to -1 does not limit tone duration.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800871//
872// Output:
873// none
874//
875////////////////////////////////////////////////////////////////////////////////
Glenn Kasten3d2f8772012-01-27 15:25:25 -0800876bool ToneGenerator::startTone(tone_type toneType, int durationMs) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800877 bool lResult = false;
Eric Laurente33e00e2009-10-05 20:29:18 -0700878 status_t lStatus;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800879
Dave Sparks4afdfa72009-05-07 09:26:06 -0700880 if ((toneType < 0) || (toneType >= NUM_TONES))
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800881 return lResult;
882
Eric Laurent6eb954f2013-03-25 14:38:10 -0700883 toneType = getToneForRegion(toneType);
884 if (toneType == TONE_CDMA_SIGNAL_OFF) {
885 return true;
886 }
887
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800888 if (mState == TONE_IDLE) {
Steve Block3856b092011-10-20 11:56:00 +0100889 ALOGV("startTone: try to re-init AudioTrack");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800890 if (!initAudioTrack()) {
891 return lResult;
892 }
893 }
894
Glenn Kasten90bebef2012-01-27 15:24:38 -0800895 ALOGV("startTone");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800896
897 mLock.lock();
898
899 // Get descriptor for requested tone
Eric Laurent0b62e242009-05-05 00:49:01 -0700900 mpNewToneDesc = &sToneDescriptors[toneType];
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800901
Eric Laurente33e00e2009-10-05 20:29:18 -0700902 mDurationMs = durationMs;
903
904 if (mState == TONE_STOPPED) {
Steve Block3856b092011-10-20 11:56:00 +0100905 ALOGV("Start waiting for previous tone to stop");
Eric Laurenta9a43902009-10-23 04:46:30 -0700906 lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
Eric Laurente33e00e2009-10-05 20:29:18 -0700907 if (lStatus != NO_ERROR) {
Steve Block29357bc2012-01-06 19:20:56 +0000908 ALOGE("--- start wait for stop timed out, status %d", lStatus);
Eric Laurente33e00e2009-10-05 20:29:18 -0700909 mState = TONE_IDLE;
Eric Laurenta9a43902009-10-23 04:46:30 -0700910 mLock.unlock();
Eric Laurente33e00e2009-10-05 20:29:18 -0700911 return lResult;
Eric Laurent85fa14d2009-09-07 08:38:38 -0700912 }
Eric Laurent85fa14d2009-09-07 08:38:38 -0700913 }
914
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800915 if (mState == TONE_INIT) {
916 if (prepareWave()) {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800917 ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800918 lResult = true;
919 mState = TONE_STARTING;
Eric Laurent681be032013-03-27 12:05:40 -0700920 if (clock_gettime(CLOCK_MONOTONIC, &mStartTime) != 0) {
921 mStartTime.tv_sec = 0;
922 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800923 mLock.unlock();
924 mpAudioTrack->start();
925 mLock.lock();
926 if (mState == TONE_STARTING) {
Steve Block3856b092011-10-20 11:56:00 +0100927 ALOGV("Wait for start callback");
Eric Laurenta9a43902009-10-23 04:46:30 -0700928 lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
The Android Open Source Project83655292009-03-09 11:52:12 -0700929 if (lStatus != NO_ERROR) {
Steve Block29357bc2012-01-06 19:20:56 +0000930 ALOGE("--- Immediate start timed out, status %d", lStatus);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800931 mState = TONE_IDLE;
932 lResult = false;
933 }
934 }
935 } else {
Eric Laurent5a22b902009-08-11 01:26:35 -0700936 mState = TONE_IDLE;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800937 }
938 } else {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800939 ALOGV("Delayed start");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800940 mState = TONE_RESTARTING;
Eric Laurent681be032013-03-27 12:05:40 -0700941 mStartTime.tv_sec = 0;
Eric Laurenta9a43902009-10-23 04:46:30 -0700942 lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
The Android Open Source Project83655292009-03-09 11:52:12 -0700943 if (lStatus == NO_ERROR) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800944 if (mState != TONE_IDLE) {
945 lResult = true;
946 }
Steve Block3856b092011-10-20 11:56:00 +0100947 ALOGV("cond received");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800948 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000949 ALOGE("--- Delayed start timed out, status %d", lStatus);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800950 mState = TONE_IDLE;
951 }
952 }
953 mLock.unlock();
954
Glenn Kasten90bebef2012-01-27 15:24:38 -0800955 ALOGV_IF(lResult, "Tone started, time %d", (unsigned int)(systemTime()/1000000));
956 ALOGW_IF(!lResult, "Tone start failed!!!, time %d", (unsigned int)(systemTime()/1000000));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800957
958 return lResult;
959}
960
961////////////////////////////////////////////////////////////////////////////////
962//
963// Method: ToneGenerator::stopTone()
964//
965// Description: Stops tone playback.
966//
967// Input:
968// none
969//
970// Output:
971// none
972//
973////////////////////////////////////////////////////////////////////////////////
974void ToneGenerator::stopTone() {
Steve Block3856b092011-10-20 11:56:00 +0100975 ALOGV("stopTone");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800976
977 mLock.lock();
Eric Laurent09108ad2013-03-26 16:37:19 -0700978 if (mState != TONE_IDLE && mState != TONE_INIT) {
979 if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) {
Eric Laurent681be032013-03-27 12:05:40 -0700980 struct timespec stopTime;
981 // If the start time is valid, make sure that the number of audio samples produced
982 // corresponds at least to the time between the start and stop commands.
983 // This is needed in case of cold start of the output stream.
Eric Laurenta8eccec2013-03-28 11:58:45 -0700984 if ((mStartTime.tv_sec != 0) && (clock_gettime(CLOCK_MONOTONIC, &stopTime) == 0)) {
Eric Laurent681be032013-03-27 12:05:40 -0700985 time_t sec = stopTime.tv_sec - mStartTime.tv_sec;
986 long nsec = stopTime.tv_nsec - mStartTime.tv_nsec;
987 long durationMs;
988 if (nsec < 0) {
989 --sec;
990 nsec += 1000000000;
991 }
992
993 if ((sec + 1) > ((long)(INT_MAX / mSamplingRate))) {
994 mMaxSmp = sec * mSamplingRate;
995 } else {
996 // mSamplingRate is always > 1000
997 sec = sec * 1000 + nsec / 1000000; // duration in milliseconds
Eric Laurenta8eccec2013-03-28 11:58:45 -0700998 mMaxSmp = (unsigned int)(((int64_t)sec * mSamplingRate) / 1000);
Eric Laurent681be032013-03-27 12:05:40 -0700999 }
1000 ALOGV("stopTone() forcing mMaxSmp to %d, total for far %d", mMaxSmp, mTotalSmp);
1001 } else {
1002 mState = TONE_STOPPING;
1003 }
Eric Laurent09108ad2013-03-26 16:37:19 -07001004 }
Steve Block3856b092011-10-20 11:56:00 +01001005 ALOGV("waiting cond");
Eric Laurenta9a43902009-10-23 04:46:30 -07001006 status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001007 if (lStatus == NO_ERROR) {
Eric Laurent09108ad2013-03-26 16:37:19 -07001008 // If the tone was restarted exit now before calling clearWaveGens();
1009 if (mState != TONE_INIT) {
Eric Laurent704455a2013-05-13 12:47:53 -07001010 mLock.unlock();
Eric Laurent09108ad2013-03-26 16:37:19 -07001011 return;
1012 }
Steve Block3856b092011-10-20 11:56:00 +01001013 ALOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001014 } else {
Steve Block29357bc2012-01-06 19:20:56 +00001015 ALOGE("--- Stop timed out");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001016 mState = TONE_IDLE;
1017 mpAudioTrack->stop();
1018 }
Eric Laurent09108ad2013-03-26 16:37:19 -07001019 clearWaveGens();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001020 }
1021
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001022 mLock.unlock();
1023}
1024
1025//---------------------------------- private methods ---------------------------
1026
1027
1028
1029
1030////////////////////////////////////////////////////////////////////////////////
1031//
1032// Method: ToneGenerator::initAudioTrack()
1033//
1034// Description: Allocates and configures AudioTrack used for PCM output.
1035//
1036// Input:
1037// none
1038//
1039// Output:
1040// none
1041//
1042////////////////////////////////////////////////////////////////////////////////
1043bool ToneGenerator::initAudioTrack() {
1044
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001045 // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001046 mpAudioTrack = new AudioTrack();
Glenn Kasten2799d742013-05-30 14:33:29 -07001047 ALOGV("Create Track: %p", mpAudioTrack.get());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001048
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001049 mpAudioTrack->set(mStreamType,
Glenn Kasten2120fe52012-04-11 12:33:31 -07001050 0, // sampleRate
Dima Zavinfce7a472011-04-19 22:30:36 -07001051 AUDIO_FORMAT_PCM_16_BIT,
1052 AUDIO_CHANNEL_OUT_MONO,
Glenn Kasten2120fe52012-04-11 12:33:31 -07001053 0, // frameCount
Glenn Kasten98f15302012-04-24 16:48:20 -07001054 AUDIO_OUTPUT_FLAG_FAST,
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001055 audioCallback,
Glenn Kasten2120fe52012-04-11 12:33:31 -07001056 this, // user
1057 0, // notificationFrames
1058 0, // sharedBuffer
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001059 mThreadCanCallJava,
1060 0, // sessionId
1061 AudioTrack::TRANSFER_CALLBACK);
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001062
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001063 if (mpAudioTrack->initCheck() != NO_ERROR) {
Steve Block29357bc2012-01-06 19:20:56 +00001064 ALOGE("AudioTrack->initCheck failed");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001065 goto initAudioTrack_exit;
1066 }
1067
Glenn Kastenb1c09932012-02-27 16:21:04 -08001068 mpAudioTrack->setVolume(mVolume);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001069
1070 mState = TONE_INIT;
1071
1072 return true;
1073
1074initAudioTrack_exit:
1075
Glenn Kasten2799d742013-05-30 14:33:29 -07001076 ALOGV("Init failed: %p", mpAudioTrack.get());
1077
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001078 // Cleanup
Glenn Kasten2799d742013-05-30 14:33:29 -07001079 mpAudioTrack.clear();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001080
1081 return false;
1082}
1083
1084
1085////////////////////////////////////////////////////////////////////////////////
1086//
1087// Method: ToneGenerator::audioCallback()
1088//
1089// Description: AudioTrack callback implementation. Generates a block of
1090// PCM samples
1091// and manages tone generator sequencer: tones pulses, tone duration...
1092//
1093// Input:
1094// user reference (pointer to our ToneGenerator)
1095// info audio buffer descriptor
1096//
1097// Output:
1098// returned value: always true.
1099//
1100////////////////////////////////////////////////////////////////////////////////
Glenn Kastend217a8c2011-06-01 15:20:35 -07001101void ToneGenerator::audioCallback(int event, void* user, void *info) {
David Krause5e0a3042009-06-17 15:46:13 -05001102
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001103 if (event != AudioTrack::EVENT_MORE_DATA) return;
David Krause5e0a3042009-06-17 15:46:13 -05001104
Eric Laurent824b6a42009-09-24 07:03:14 -07001105 AudioTrack::Buffer *buffer = static_cast<AudioTrack::Buffer *>(info);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001106 ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
1107 short *lpOut = buffer->i16;
1108 unsigned int lNumSmp = buffer->size/sizeof(short);
Eric Laurent0b62e242009-05-05 00:49:01 -07001109 const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001110
1111 if (buffer->size == 0) return;
1112
1113
1114 // Clear output buffer: WaveGenerator accumulates into lpOut buffer
1115 memset(lpOut, 0, buffer->size);
1116
1117 while (lNumSmp) {
1118 unsigned int lReqSmp = lNumSmp < lpToneGen->mProcessSize*2 ? lNumSmp : lpToneGen->mProcessSize;
1119 unsigned int lGenSmp;
1120 unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
1121 bool lSignal = false;
David Krause5e0a3042009-06-17 15:46:13 -05001122
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001123 lpToneGen->mLock.lock();
1124
Eric Laurenta9a43902009-10-23 04:46:30 -07001125
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001126 // Update pcm frame count and end time (current time at the end of this process)
1127 lpToneGen->mTotalSmp += lReqSmp;
David Krause5e0a3042009-06-17 15:46:13 -05001128
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001129 // Update tone gen state machine and select wave gen command
1130 switch (lpToneGen->mState) {
1131 case TONE_PLAYING:
1132 lWaveCmd = WaveGenerator::WAVEGEN_CONT;
1133 break;
1134 case TONE_STARTING:
Steve Block3856b092011-10-20 11:56:00 +01001135 ALOGV("Starting Cbk");
David Krause5e0a3042009-06-17 15:46:13 -05001136
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001137 lWaveCmd = WaveGenerator::WAVEGEN_START;
1138 break;
1139 case TONE_STOPPING:
1140 case TONE_RESTARTING:
Steve Block3856b092011-10-20 11:56:00 +01001141 ALOGV("Stop/restart Cbk");
David Krause5e0a3042009-06-17 15:46:13 -05001142
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001143 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
1144 lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
1145 break;
Eric Laurent824b6a42009-09-24 07:03:14 -07001146 case TONE_STOPPED:
Steve Block3856b092011-10-20 11:56:00 +01001147 ALOGV("Stopped Cbk");
Eric Laurent824b6a42009-09-24 07:03:14 -07001148 goto audioCallback_EndLoop;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001149 default:
Steve Block3856b092011-10-20 11:56:00 +01001150 ALOGV("Extra Cbk");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001151 goto audioCallback_EndLoop;
1152 }
David Krause5e0a3042009-06-17 15:46:13 -05001153
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001154 // Exit if tone sequence is over
Eric Laurent85fa14d2009-09-07 08:38:38 -07001155 if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0 ||
1156 lpToneGen->mTotalSmp > lpToneGen->mMaxSmp) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001157 if (lpToneGen->mState == TONE_PLAYING) {
David Krause5e0a3042009-06-17 15:46:13 -05001158 lpToneGen->mState = TONE_STOPPING;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001159 }
Eric Laurent85fa14d2009-09-07 08:38:38 -07001160 if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
1161 goto audioCallback_EndLoop;
1162 }
Eric Laurent824b6a42009-09-24 07:03:14 -07001163 // fade out before stopping if maximum duration reached
Eric Laurent85fa14d2009-09-07 08:38:38 -07001164 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
1165 lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001166 }
David Krause5e0a3042009-06-17 15:46:13 -05001167
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001168 if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
1169 // Time to go to next sequence segment
David Krause5e0a3042009-06-17 15:46:13 -05001170
Glenn Kasten90bebef2012-01-27 15:24:38 -08001171 ALOGV("End Segment, time: %d", (unsigned int)(systemTime()/1000000));
David Krause5e0a3042009-06-17 15:46:13 -05001172
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001173 lGenSmp = lReqSmp;
Eric Laurent0b62e242009-05-05 00:49:01 -07001174
1175 // If segment, ON -> OFF transition : ramp volume down
1176 if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001177 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
Eric Laurent0b62e242009-05-05 00:49:01 -07001178 unsigned int lFreqIdx = 0;
1179 unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
1180
1181 while (lFrequency != 0) {
1182 WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
1183 lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
1184 lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
1185 }
Glenn Kasten90bebef2012-01-27 15:24:38 -08001186 ALOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001187 }
Eric Laurent0b62e242009-05-05 00:49:01 -07001188
David Krause5e0a3042009-06-17 15:46:13 -05001189 // check if we need to loop and loop for the reqd times
1190 if (lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
1191 if (lpToneGen->mLoopCounter < lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
Glenn Kasten90bebef2012-01-27 15:24:38 -08001192 ALOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
David Krause5e0a3042009-06-17 15:46:13 -05001193 lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
1194 lpToneGen->mLoopCounter,
1195 lpToneGen->mCurSegment);
1196 lpToneGen->mCurSegment = lpToneDesc->segments[lpToneGen->mCurSegment].loopIndx;
1197 ++lpToneGen->mLoopCounter;
1198 } else {
1199 // completed loop. go to next segment
1200 lpToneGen->mLoopCounter = 0;
1201 lpToneGen->mCurSegment++;
Glenn Kasten90bebef2012-01-27 15:24:38 -08001202 ALOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
David Krause5e0a3042009-06-17 15:46:13 -05001203 lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
1204 lpToneGen->mLoopCounter,
1205 lpToneGen->mCurSegment);
1206 }
1207 } else {
1208 lpToneGen->mCurSegment++;
Glenn Kasten90bebef2012-01-27 15:24:38 -08001209 ALOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d)",
David Krause5e0a3042009-06-17 15:46:13 -05001210 lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
1211 lpToneGen->mLoopCounter,
1212 lpToneGen->mCurSegment);
1213
1214 }
Eric Laurent0b62e242009-05-05 00:49:01 -07001215
1216 // Handle loop if last segment reached
1217 if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
Glenn Kasten90bebef2012-01-27 15:24:38 -08001218 ALOGV("Last Seg: %d", lpToneGen->mCurSegment);
David Krause5e0a3042009-06-17 15:46:13 -05001219
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001220 // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
Eric Laurent0b62e242009-05-05 00:49:01 -07001221 if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
Glenn Kasten90bebef2012-01-27 15:24:38 -08001222 ALOGV("Repeating Count: %d", lpToneGen->mCurCount);
David Krause5e0a3042009-06-17 15:46:13 -05001223
Eric Laurent0b62e242009-05-05 00:49:01 -07001224 lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
1225 if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
1226 lWaveCmd = WaveGenerator::WAVEGEN_START;
1227 }
David Krause5e0a3042009-06-17 15:46:13 -05001228
Glenn Kasten90bebef2012-01-27 15:24:38 -08001229 ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001230 (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
David Krause5e0a3042009-06-17 15:46:13 -05001231
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001232 } else {
Eric Laurent0b62e242009-05-05 00:49:01 -07001233 lGenSmp = 0;
Glenn Kasten90bebef2012-01-27 15:24:38 -08001234 ALOGV("End repeat, time: %d", (unsigned int)(systemTime()/1000000));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001235 }
1236 } else {
Glenn Kasten90bebef2012-01-27 15:24:38 -08001237 ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001238 (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
Eric Laurent0b62e242009-05-05 00:49:01 -07001239 if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
1240 // If next segment is not silent, OFF -> ON transition : reset wave generator
1241 lWaveCmd = WaveGenerator::WAVEGEN_START;
1242
Glenn Kasten90bebef2012-01-27 15:24:38 -08001243 ALOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
Eric Laurent0b62e242009-05-05 00:49:01 -07001244 } else {
1245 lGenSmp = 0;
1246 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001247 }
David Krause5e0a3042009-06-17 15:46:13 -05001248
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001249 // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
1250 lpToneGen->mNextSegSmp
Eric Laurent0b62e242009-05-05 00:49:01 -07001251 += (lpToneDesc->segments[lpToneGen->mCurSegment].duration * lpToneGen->mSamplingRate) / 1000;
David Krause5e0a3042009-06-17 15:46:13 -05001252
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001253 } else {
1254 // Inside a segment keep tone ON or OFF
Eric Laurent0b62e242009-05-05 00:49:01 -07001255 if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] == 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001256 lGenSmp = 0; // If odd segment, tone is currently OFF
1257 } else {
1258 lGenSmp = lReqSmp; // If event segment, tone is currently ON
1259 }
1260 }
David Krause5e0a3042009-06-17 15:46:13 -05001261
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001262 if (lGenSmp) {
1263 // If samples must be generated, call all active wave generators and acumulate waves in lpOut
Eric Laurent0b62e242009-05-05 00:49:01 -07001264 unsigned int lFreqIdx = 0;
1265 unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
David Krause5e0a3042009-06-17 15:46:13 -05001266
Eric Laurent0b62e242009-05-05 00:49:01 -07001267 while (lFrequency != 0) {
1268 WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001269 lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
Eric Laurent0b62e242009-05-05 00:49:01 -07001270 lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001271 }
1272 }
David Krause5e0a3042009-06-17 15:46:13 -05001273
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001274 lNumSmp -= lReqSmp;
1275 lpOut += lReqSmp;
David Krause5e0a3042009-06-17 15:46:13 -05001276
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001277audioCallback_EndLoop:
David Krause5e0a3042009-06-17 15:46:13 -05001278
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001279 switch (lpToneGen->mState) {
1280 case TONE_RESTARTING:
Glenn Kasten90bebef2012-01-27 15:24:38 -08001281 ALOGV("Cbk restarting track");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001282 if (lpToneGen->prepareWave()) {
1283 lpToneGen->mState = TONE_STARTING;
Eric Laurent681be032013-03-27 12:05:40 -07001284 if (clock_gettime(CLOCK_MONOTONIC, &lpToneGen->mStartTime) != 0) {
1285 lpToneGen->mStartTime.tv_sec = 0;
1286 }
Eric Laurentc38bb062009-07-09 01:56:20 -07001287 // must reload lpToneDesc as prepareWave() may change mpToneDesc
1288 lpToneDesc = lpToneGen->mpToneDesc;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001289 } else {
Glenn Kasten90bebef2012-01-27 15:24:38 -08001290 ALOGW("Cbk restarting prepareWave() failed");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001291 lpToneGen->mState = TONE_IDLE;
1292 lpToneGen->mpAudioTrack->stop();
1293 // Force loop exit
1294 lNumSmp = 0;
1295 }
1296 lSignal = true;
1297 break;
1298 case TONE_STOPPING:
Glenn Kasten90bebef2012-01-27 15:24:38 -08001299 ALOGV("Cbk Stopping");
Eric Laurent824b6a42009-09-24 07:03:14 -07001300 lpToneGen->mState = TONE_STOPPED;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001301 // Force loop exit
1302 lNumSmp = 0;
1303 break;
Eric Laurent824b6a42009-09-24 07:03:14 -07001304 case TONE_STOPPED:
1305 lpToneGen->mState = TONE_INIT;
Glenn Kasten90bebef2012-01-27 15:24:38 -08001306 ALOGV("Cbk Stopped track");
Eric Laurent824b6a42009-09-24 07:03:14 -07001307 lpToneGen->mpAudioTrack->stop();
1308 // Force loop exit
1309 lNumSmp = 0;
1310 buffer->size = 0;
1311 lSignal = true;
1312 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001313 case TONE_STARTING:
Glenn Kasten90bebef2012-01-27 15:24:38 -08001314 ALOGV("Cbk starting track");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001315 lpToneGen->mState = TONE_PLAYING;
1316 lSignal = true;
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001317 break;
Eric Laurent824b6a42009-09-24 07:03:14 -07001318 case TONE_PLAYING:
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001319 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001320 default:
Eric Laurent824b6a42009-09-24 07:03:14 -07001321 // Force loop exit
1322 lNumSmp = 0;
1323 buffer->size = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001324 break;
1325 }
1326
1327 if (lSignal)
Eric Laurent09108ad2013-03-26 16:37:19 -07001328 lpToneGen->mWaitCbkCond.broadcast();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001329 lpToneGen->mLock.unlock();
1330 }
1331}
1332
1333
1334////////////////////////////////////////////////////////////////////////////////
1335//
1336// Method: ToneGenerator::prepareWave()
1337//
1338// Description: Prepare wave generators and reset tone sequencer state machine.
Eric Laurent0b62e242009-05-05 00:49:01 -07001339// mpNewToneDesc must have been initialized before calling this function.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001340// Input:
1341// none
1342//
1343// Output:
1344// returned value: true if wave generators have been created, false otherwise
1345//
1346////////////////////////////////////////////////////////////////////////////////
1347bool ToneGenerator::prepareWave() {
Eric Laurent0b62e242009-05-05 00:49:01 -07001348 unsigned int segmentIdx = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001349
Glenn Kastena0d68332012-01-27 16:47:15 -08001350 if (mpNewToneDesc == NULL) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001351 return false;
1352 }
Eric Laurent0b62e242009-05-05 00:49:01 -07001353
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001354 // Remove existing wave generators if any
1355 clearWaveGens();
1356
1357 mpToneDesc = mpNewToneDesc;
1358
Eric Laurente33e00e2009-10-05 20:29:18 -07001359 if (mDurationMs == -1) {
1360 mMaxSmp = TONEGEN_INF;
1361 } else {
1362 if (mDurationMs > (int)(TONEGEN_INF / mSamplingRate)) {
1363 mMaxSmp = (mDurationMs / 1000) * mSamplingRate;
1364 } else {
1365 mMaxSmp = (mDurationMs * mSamplingRate) / 1000;
1366 }
Steve Block3856b092011-10-20 11:56:00 +01001367 ALOGV("prepareWave, duration limited to %d ms", mDurationMs);
Eric Laurente33e00e2009-10-05 20:29:18 -07001368 }
1369
Eric Laurent0b62e242009-05-05 00:49:01 -07001370 while (mpToneDesc->segments[segmentIdx].duration) {
1371 // Get total number of sine waves: needed to adapt sine wave gain.
1372 unsigned int lNumWaves = numWaves(segmentIdx);
1373 unsigned int freqIdx = 0;
1374 unsigned int frequency = mpToneDesc->segments[segmentIdx].waveFreq[freqIdx];
1375 while (frequency) {
1376 // Instantiate a wave generator if ot already done for this frequency
1377 if (mWaveGens.indexOfKey(frequency) == NAME_NOT_FOUND) {
1378 ToneGenerator::WaveGenerator *lpWaveGen =
1379 new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
1380 frequency,
1381 TONEGEN_GAIN/lNumWaves);
Eric Laurent0b62e242009-05-05 00:49:01 -07001382 mWaveGens.add(frequency, lpWaveGen);
1383 }
1384 frequency = mpNewToneDesc->segments[segmentIdx].waveFreq[++freqIdx];
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001385 }
Eric Laurent0b62e242009-05-05 00:49:01 -07001386 segmentIdx++;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001387 }
1388
1389 // Initialize tone sequencer
1390 mTotalSmp = 0;
1391 mCurSegment = 0;
1392 mCurCount = 0;
David Krause5e0a3042009-06-17 15:46:13 -05001393 mLoopCounter = 0;
Eric Laurent0b62e242009-05-05 00:49:01 -07001394 if (mpToneDesc->segments[0].duration == TONEGEN_INF) {
1395 mNextSegSmp = TONEGEN_INF;
1396 } else{
1397 mNextSegSmp = (mpToneDesc->segments[0].duration * mSamplingRate) / 1000;
1398 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001399
1400 return true;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001401}
1402
1403
1404////////////////////////////////////////////////////////////////////////////////
1405//
1406// Method: ToneGenerator::numWaves()
1407//
Eric Laurent0b62e242009-05-05 00:49:01 -07001408// Description: Count number of sine waves needed to generate a tone segment (e.g 2 for DTMF).
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001409//
1410// Input:
Eric Laurent0b62e242009-05-05 00:49:01 -07001411// segmentIdx tone segment index
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001412//
1413// Output:
1414// returned value: nummber of sine waves
1415//
1416////////////////////////////////////////////////////////////////////////////////
Eric Laurent0b62e242009-05-05 00:49:01 -07001417unsigned int ToneGenerator::numWaves(unsigned int segmentIdx) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001418 unsigned int lCnt = 0;
1419
Eric Laurent0b62e242009-05-05 00:49:01 -07001420 if (mpToneDesc->segments[segmentIdx].duration) {
1421 while (mpToneDesc->segments[segmentIdx].waveFreq[lCnt]) {
1422 lCnt++;
1423 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001424 lCnt++;
1425 }
1426
1427 return lCnt;
1428}
1429
1430
1431////////////////////////////////////////////////////////////////////////////////
1432//
1433// Method: ToneGenerator::clearWaveGens()
1434//
1435// Description: Removes all wave generators.
1436//
1437// Input:
1438// none
1439//
1440// Output:
1441// none
1442//
1443////////////////////////////////////////////////////////////////////////////////
1444void ToneGenerator::clearWaveGens() {
Steve Block3856b092011-10-20 11:56:00 +01001445 ALOGV("Clearing mWaveGens:");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001446
Eric Laurent0b62e242009-05-05 00:49:01 -07001447 for (size_t lIdx = 0; lIdx < mWaveGens.size(); lIdx++) {
1448 delete mWaveGens.valueAt(lIdx);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001449 }
Eric Laurent0b62e242009-05-05 00:49:01 -07001450 mWaveGens.clear();
1451}
1452
1453////////////////////////////////////////////////////////////////////////////////
1454//
1455// Method: ToneGenerator::getToneForRegion()
1456//
1457// Description: Get correct ringtone type according to current region.
1458// The corrected ring tone type is the tone descriptor index in sToneDescriptors[].
1459//
1460// Input:
1461// none
1462//
1463// Output:
1464// none
1465//
1466////////////////////////////////////////////////////////////////////////////////
Glenn Kasten3d2f8772012-01-27 15:25:25 -08001467ToneGenerator::tone_type ToneGenerator::getToneForRegion(tone_type toneType) {
1468 tone_type regionTone;
Eric Laurent0b62e242009-05-05 00:49:01 -07001469
1470 if (mRegion == CEPT || toneType < FIRST_SUP_TONE || toneType > LAST_SUP_TONE) {
1471 regionTone = toneType;
1472 } else {
Glenn Kasten3d2f8772012-01-27 15:25:25 -08001473 regionTone = (tone_type) sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE];
Eric Laurent0b62e242009-05-05 00:49:01 -07001474 }
1475
Steve Block3856b092011-10-20 11:56:00 +01001476 ALOGV("getToneForRegion, tone %d, region %d, regionTone %d", toneType, mRegion, regionTone);
Eric Laurent0b62e242009-05-05 00:49:01 -07001477
1478 return regionTone;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001479}
1480
1481
1482////////////////////////////////////////////////////////////////////////////////
1483// WaveGenerator::WaveGenerator class Implementation
1484////////////////////////////////////////////////////////////////////////////////
1485
1486//---------------------------------- public methods ----------------------------
1487
1488////////////////////////////////////////////////////////////////////////////////
1489//
1490// Method: WaveGenerator::WaveGenerator()
1491//
1492// Description: Constructor.
1493//
1494// Input:
1495// samplingRate: Output sampling rate in Hz
1496// frequency: Frequency of the sine wave to generate in Hz
1497// volume: volume (0.0 to 1.0)
1498//
1499// Output:
1500// none
1501//
1502////////////////////////////////////////////////////////////////////////////////
1503ToneGenerator::WaveGenerator::WaveGenerator(unsigned short samplingRate,
1504 unsigned short frequency, float volume) {
1505 double d0;
1506 double F_div_Fs; // frequency / samplingRate
1507
1508 F_div_Fs = frequency / (double)samplingRate;
1509 d0 = - (float)GEN_AMP * sin(2 * M_PI * F_div_Fs);
1510 mS2_0 = (short)d0;
1511 mS1 = 0;
1512 mS2 = mS2_0;
1513
1514 mAmplitude_Q15 = (short)(32767. * 32767. * volume / GEN_AMP);
1515 // take some margin for amplitude fluctuation
1516 if (mAmplitude_Q15 > 32500)
1517 mAmplitude_Q15 = 32500;
1518
1519 d0 = 32768.0 * cos(2 * M_PI * F_div_Fs); // Q14*2*cos()
1520 if (d0 > 32767)
1521 d0 = 32767;
1522 mA1_Q14 = (short) d0;
1523
Glenn Kasten90bebef2012-01-27 15:24:38 -08001524 ALOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d",
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001525 mA1_Q14, mS2_0, mAmplitude_Q15);
1526}
1527
1528////////////////////////////////////////////////////////////////////////////////
1529//
1530// Method: WaveGenerator::~WaveGenerator()
1531//
1532// Description: Destructor.
1533//
1534// Input:
1535// none
1536//
1537// Output:
1538// none
1539//
1540////////////////////////////////////////////////////////////////////////////////
1541ToneGenerator::WaveGenerator::~WaveGenerator() {
1542}
1543
1544////////////////////////////////////////////////////////////////////////////////
1545//
1546// Method: WaveGenerator::getSamples()
1547//
1548// Description: Generates count samples of a sine wave and accumulates
1549// result in outBuffer.
1550//
1551// Input:
1552// outBuffer: Output buffer where to accumulate samples.
1553// count: number of samples to produce.
1554// command: special action requested (see enum gen_command).
1555//
1556// Output:
1557// none
1558//
1559////////////////////////////////////////////////////////////////////////////////
1560void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
1561 unsigned int count, unsigned int command) {
1562 long lS1, lS2;
1563 long lA1, lAmplitude;
1564 long Sample; // current sample
1565
1566 // init local
1567 if (command == WAVEGEN_START) {
1568 lS1 = (long)0;
1569 lS2 = (long)mS2_0;
1570 } else {
1571 lS1 = (long)mS1;
1572 lS2 = (long)mS2;
1573 }
1574 lA1 = (long)mA1_Q14;
1575 lAmplitude = (long)mAmplitude_Q15;
1576
1577 if (command == WAVEGEN_STOP) {
1578 lAmplitude <<= 16;
1579 if (count == 0) {
1580 return;
1581 }
1582 long dec = lAmplitude/count;
1583 // loop generation
1584 while (count--) {
1585 Sample = ((lA1 * lS1) >> S_Q14) - lS2;
1586 // shift delay
1587 lS2 = lS1;
1588 lS1 = Sample;
1589 Sample = ((lAmplitude>>16) * Sample) >> S_Q15;
1590 *(outBuffer++) += (short)Sample; // put result in buffer
1591 lAmplitude -= dec;
1592 }
1593 } else {
1594 // loop generation
1595 while (count--) {
1596 Sample = ((lA1 * lS1) >> S_Q14) - lS2;
1597 // shift delay
1598 lS2 = lS1;
1599 lS1 = Sample;
1600 Sample = (lAmplitude * Sample) >> S_Q15;
1601 *(outBuffer++) += (short)Sample; // put result in buffer
1602 }
1603 }
1604
1605 // save status
1606 mS1 = (short)lS1;
1607 mS2 = (short)lS2;
1608}
1609
1610} // end namespace android