Android 拨号音之 DTMF
音频播放有以下几种方式:
DTMF: 即Double Tone Multiple Frequency,双音多频信号
DTMF信号的产生原理:双音频信号是两个正弦波信号的叠加,选定两个频率f1和f2后很容易地得到这种信号的数学表达式
DTMF信号特点:
1.所有音频都位于人的可听范围内,因此按键下去时人可以听到。
2.8个频率中没有一个频率是其他任意一个频率的倍数。
3.任意两个频率的组合,相加或相减都不等于其他任意一个频率。
这些特性不仅简化了DTMF信号的解码同时也降低了DTMF误检的概率。
国际上采用的频率有:低频组(697hz,770hz,852hz,941hz),高频群(1209hz,1366hz,1477hz,1633hz)。用这8种频率可形成16种不同的组合,从而代表16种不同的数字或功能键,具体组合如下表
低频 \ 高频(Hz) | 1209 | 1336 | 1477 | 1633 |
---|---|---|---|---|
697 | 1 | 2 | 3 | A |
770 | 4 | 5 | 6 | B |
852 | 7 | 8 | 9 | C |
941 | * | 0 | # | D |
DTMF音调的产生可以分为硬件和软件的方式。随着数字电路技术和DSP技术的发展,市面上已经有很多DTMF专用的编解码芯片了,如:MITEL公司生产的MT8880。随着DSP技术和大规模集成电路的发展,用纯软件的方式调制和解调DTMF信号已经不再是难事了。
packages/apps/Dialer/java/com/android/dialer/app/dialpad/DialpadFragment.java
拨号应用拨号时创建ToneGenerator,传入TONE_RELATIVE_VOLUME 以及 STREAM_DTMF,由ToneGenerator播放DTMF音。ToneGenerator使用了AudioTrack,先initAudioTrack创建AudioTrack实例,init 完成startTone然后prepareWave生成PCM数据,再通过mpAudioTrack->start()开始播放
34 /** The DTMF tone volume relative to other sounds in the stream */
135 private static final int TONE_RELATIVE_VOLUME = 80;
136 /** Stream type used to play the DTMF tones off call, and mapped to the volume control keys */
137 private static final int DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_DTMF;
...
@Override
681 public void onStart() {
682 LogUtil.d("DialpadFragment.onStart", "first launch: %b", mFirstLaunch);
683 Trace.beginSection(TAG + " onStart");
684 super.onStart();
685 // if the mToneGenerator creation fails, just continue without it. It is
686 // a local audio signal, and is not as important as the dtmf tone itself.
687 final long start = System.currentTimeMillis();
688 synchronized (mToneGeneratorLock) {
689 if (mToneGenerator == null) {
690 try {
691 mToneGenerator = new ToneGenerator(DIAL_TONE_STREAM_TYPE, TONE_RELATIVE_VOLUME);
692 } catch (RuntimeException e) {
693 LogUtil.e(
694 "DialpadFragment.onStart",
695 "Exception caught while creating local tone generator: " + e);
696 mToneGenerator = null;
697 }
698 }
699 }
700 final long total = System.currentTimeMillis() - start;
701 if (total > 50) {
702 LogUtil.i("DialpadFragment.onStart", "Time for ToneGenerator creation: " + total);
703 }
704 Trace.endSection();
705 LogUtil.i("DialpadFragment.onStart", "end ...");
706 }
真正的处理是在android/frameworks/av/media/libaudioclient/ToneGenerator.cpp
////////////////////////////////////////////////////////////////////////////////
845 ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool threadCanCallJava) {
846
847 ALOGV("ToneGenerator constructor: streamType=%d, volume=%f", streamType, volume);
848
849 mState = TONE_IDLE;
850
851 if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
852 ALOGE("Unable to marshal AudioFlinger");
853 return;
854 }
855 mThreadCanCallJava = threadCanCallJava;
856 mStreamType = streamType;
857 mVolume = volume;
858 mpToneDesc = NULL;
859 mpNewToneDesc = NULL;
860 // Generate tone by chunks of 20 ms to keep cadencing precision
......
880 if (initAudioTrack()) {
881 ALOGV("ToneGenerator INIT OK, time: %d", (unsigned int)(systemTime()/1000000));
882 } else {
883 ALOGV("!!!ToneGenerator INIT FAILED!!!");
884 }
885 }
创建ToneGenerator,在构造方法中initAudioTrack()
////////////////////////////////////////////////////////////////////////////////
1097 bool ToneGenerator::initAudioTrack() {
1098 // Open audio track in mono, PCM 16bit, default sampling rate.
1099 mpAudioTrack = new AudioTrack();//创建AudioTrack
1100 ALOGV("AudioTrack(%p) created", mpAudioTrack.get());
1101
1102 const size_t frameCount = mProcessSize;
1103 status_t status = mpAudioTrack->set(
1104 mStreamType,
1105 0, // sampleRate
1106 AUDIO_FORMAT_PCM_16_BIT,
1107 AUDIO_CHANNEL_OUT_MONO,
1108 frameCount,
1109 AUDIO_OUTPUT_FLAG_FAST,
1110 audioCallback, //注册audioCallback,由此回调获取播放的数据
1111 this, // user
1112 0, // notificationFrames
1113 0, // sharedBuffer
1114 mThreadCanCallJava,
1115 AUDIO_SESSION_ALLOCATE,
1116 AudioTrack::TRANSFER_CALLBACK);
1117
1118 if (status != NO_ERROR) {
1119 ALOGE("AudioTrack(%p) set failed with error %d", mpAudioTrack.get(), status);
1120 mpAudioTrack.clear();
1121 return false;
1122 }
1123
1124 mpAudioTrack->setVolume(mVolume);//设置音量
1125 mState = TONE_INIT;//Tone 播放状态 init状态
1126 return true;
1127 }
1129 ////////////////////////////////////////////////////////////////////////////////
1130 //
1131 // Method: ToneGenerator::audioCallback()
1132 //
1133 // Description: AudioTrack callback implementation. Generates a block of
1134 // PCM samples
1135 // and manages tone generator sequencer: tones pulses, tone duration...
1136 //
1137 // Input:
1138 // user reference (pointer to our ToneGenerator)
1139 // info audio buffer descriptor
1140 //
1141 // Output:
1142 // returned value: always true.
1143 //
1144 ////////////////////////////////////////////////////////////////////////////////
1145 void ToneGenerator::audioCallback(int event, void* user, void *info) {
1146
1147 if (event != AudioTrack::EVENT_MORE_DATA) return;
1148
1149 AudioTrack::Buffer *buffer = static_cast(info);
1150 ToneGenerator *lpToneGen = static_cast(user);
1151 short *lpOut = buffer->i16;
1152 unsigned int lNumSmp = buffer->size/sizeof(short);
1153 const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc;
1154
1155 if (buffer->size == 0) return;
1156
1157
1158 // Clear output buffer: WaveGenerator accumulates into lpOut buffer
1159 memset(lpOut, 0, buffer->size);
1160
1161 while (lNumSmp) {
1162 unsigned int lReqSmp = lNumSmp < lpToneGen->mProcessSize*2 ? lNumSmp : lpToneGen->mProcessSize;
1163 unsigned int lGenSmp;
1164 unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
1165 bool lSignal = false;
1166
1167 lpToneGen->mLock.lock();
1168
1169
1170 // Update pcm frame count and end time (current time at the end of this process)
1171 lpToneGen->mTotalSmp += lReqSmp;
1172
1173 // Update tone gen state machine and select wave gen command
1174 switch (lpToneGen->mState) {
1175 case TONE_PLAYING:
1176 lWaveCmd = WaveGenerator::WAVEGEN_CONT;
1177 break;
1178 case TONE_STARTING:
1179 ALOGV("Starting Cbk");
1180
1181 lWaveCmd = WaveGenerator::WAVEGEN_START;
1182 break;
1183 case TONE_STOPPING:
1184 case TONE_RESTARTING:
1185 ALOGV("Stop/restart Cbk");
1186
1187 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
1188 lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
1189 break;
1190 case TONE_STOPPED:
1191 ALOGV("Stopped Cbk");
1192 goto audioCallback_EndLoop;
1193 default:
1194 ALOGV("Extra Cbk");
1195 goto audioCallback_EndLoop;
1196 }
1197
1198 // Exit if tone sequence is over
1199 if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0 ||
1200 lpToneGen->mTotalSmp > lpToneGen->mMaxSmp) {
1201 if (lpToneGen->mState == TONE_PLAYING) {
1202 lpToneGen->mState = TONE_STOPPING;
1203 }
1204 if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
1205 goto audioCallback_EndLoop;
1206 }
1207 // fade out before stopping if maximum duration reached
1208 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
1209 lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
1210 }
1211
1212 if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
1213 // Time to go to next sequence segment
1214
1215 ALOGV("End Segment, time: %d", (unsigned int)(systemTime()/1000000));
1216
1217 lGenSmp = lReqSmp;
1218
1219 // If segment, ON -> OFF transition : ramp volume down
1220 if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
1221 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
1222 unsigned int lFreqIdx = 0;
1223 unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
1224
1225 while (lFrequency != 0) {
1226 WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
1227 lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
1228 lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
1229 }
1230 ALOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
1231 }
1232
1233 // check if we need to loop and loop for the reqd times
1234 if (lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
1235 if (lpToneGen->mLoopCounter < lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
1236 ALOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
1237 lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
1238 lpToneGen->mLoopCounter,
1239 lpToneGen->mCurSegment);
1240 lpToneGen->mCurSegment = lpToneDesc->segments[lpToneGen->mCurSegment].loopIndx;
1241 ++lpToneGen->mLoopCounter;
1242 } else {
1243 // completed loop. go to next segment
1244 lpToneGen->mLoopCounter = 0;
1245 lpToneGen->mCurSegment++;
1246 ALOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
1247 lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
1248 lpToneGen->mLoopCounter,
1249 lpToneGen->mCurSegment);
1250 }
1251 } else {
1252 lpToneGen->mCurSegment++;
1253 ALOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d)",
1254 lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
1255 lpToneGen->mLoopCounter,
1256 lpToneGen->mCurSegment);
1257
1258 }
1259
1260 // Handle loop if last segment reached
1261 if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
1262 ALOGV("Last Seg: %d", lpToneGen->mCurSegment);
1263
1264 // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
1265 if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
1266 ALOGV("Repeating Count: %d", lpToneGen->mCurCount);
1267
1268 lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
1269 if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
1270 lWaveCmd = WaveGenerator::WAVEGEN_START;
1271 }
1272
1273 ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
1274 (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
1275
1276 } else {
1277 lGenSmp = 0;
1278 ALOGV("End repeat, time: %d", (unsigned int)(systemTime()/1000000));
1279 }
1280 } else {
1281 ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
1282 (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
1283 if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
1284 // If next segment is not silent, OFF -> ON transition : reset wave generator
1285 lWaveCmd = WaveGenerator::WAVEGEN_START;
1286
1287 ALOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
1288 } else {
1289 lGenSmp = 0;
1290 }
1291 }
1292
1293 // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
1294 lpToneGen->mNextSegSmp
1295 += (lpToneDesc->segments[lpToneGen->mCurSegment].duration * lpToneGen->mSamplingRate) / 1000;
1296
1297 } else {
1298 // Inside a segment keep tone ON or OFF
1299 if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] == 0) {
1300 lGenSmp = 0; // If odd segment, tone is currently OFF
1301 } else {
1302 lGenSmp = lReqSmp; // If event segment, tone is currently ON
1303 }
1304 }
1305
1306 if (lGenSmp) {
1307 // If samples must be generated, call all active wave generators and acumulate waves in lpOut
1308 unsigned int lFreqIdx = 0;
1309 unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
1310
1311 while (lFrequency != 0) {
1312 WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
1313 lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
1314 lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
1315 }
1316 }
1317
1318 lNumSmp -= lReqSmp;
1319 lpOut += lReqSmp;
1320
1321 audioCallback_EndLoop:
1322
1323 switch (lpToneGen->mState) {
1324 case TONE_RESTARTING:
1325 ALOGV("Cbk restarting track");
1326 if (lpToneGen->prepareWave()) {
1327 lpToneGen->mState = TONE_STARTING;
1328 if (clock_gettime(CLOCK_MONOTONIC, &lpToneGen->mStartTime) != 0) {
1329 lpToneGen->mStartTime.tv_sec = 0;
1330 }
1331 // must reload lpToneDesc as prepareWave() may change mpToneDesc
1332 lpToneDesc = lpToneGen->mpToneDesc;
1333 } else {
1334 ALOGW("Cbk restarting prepareWave() failed");
1335 lpToneGen->mState = TONE_IDLE;
1336 lpToneGen->mpAudioTrack->stop();
1337 // Force loop exit
1338 lNumSmp = 0;
1339 }
1340 lSignal = true;
1341 break;
1342 case TONE_STOPPING:
1343 ALOGV("Cbk Stopping");
1344 lpToneGen->mState = TONE_STOPPED;
1345 // Force loop exit
1346 lNumSmp = 0;
1347 break;
1348 case TONE_STOPPED:
1349 lpToneGen->mState = TONE_INIT;
1350 ALOGV("Cbk Stopped track");
1351 lpToneGen->mpAudioTrack->stop();
1352 // Force loop exit
1353 lNumSmp = 0;
1354 buffer->size = 0;
1355 lSignal = true;
1356 break;
1357 case TONE_STARTING:
1358 ALOGV("Cbk starting track");
1359 lpToneGen->mState = TONE_PLAYING;
1360 lSignal = true;
1361 break;
1362 case TONE_PLAYING:
1363 break;
1364 default:
1365 // Force loop exit
1366 lNumSmp = 0;
1367 buffer->size = 0;
1368 break;
1369 }
1370
1371 if (lSignal)
1372 lpToneGen->mWaitCbkCond.broadcast();
1373 lpToneGen->mLock.unlock();
1374 }
1375 }
init 完成后点击按键,startTone
/**
931 * When a key is pressed, we start playing DTMF tone, do vibration, and enter the digit
932 * immediately. When a key is released, we stop the tone. Note that the "key press" event will be
933 * delivered by the system with certain amount of delay, it won't be synced with user's actual
934 * "touch-down" behavior.
935 */
936 @Override
937 public void onPressed(View view, boolean pressed) {
938 if (DEBUG) {
939 LogUtil.d("DialpadFragment.onPressed", "view: " + view + ", pressed: " + pressed);
940 }
941 if (pressed) {
942 int resId = view.getId();
943 if (resId == R.id.one) {
944 keyPressed(KeyEvent.KEYCODE_1);
945 } else if (resId == R.id.two) {
946 keyPressed(KeyEvent.KEYCODE_2);
947 } else if (resId == R.id.three) {
948 keyPressed(KeyEvent.KEYCODE_3);
949 } else if (resId == R.id.four) {
950 keyPressed(KeyEvent.KEYCODE_4);
951 } else if (resId == R.id.five) {
952 keyPressed(KeyEvent.KEYCODE_5);
953 } else if (resId == R.id.six) {
954 keyPressed(KeyEvent.KEYCODE_6);
955 } else if (resId == R.id.seven) {
956 keyPressed(KeyEvent.KEYCODE_7);
957 } else if (resId == R.id.eight) {
958 keyPressed(KeyEvent.KEYCODE_8);
959 } else if (resId == R.id.nine) {
960 keyPressed(KeyEvent.KEYCODE_9);
961 } else if (resId == R.id.zero) {
962 keyPressed(KeyEvent.KEYCODE_0);
963 } else if (resId == R.id.pound) {
964 keyPressed(KeyEvent.KEYCODE_POUND);
965 } else if (resId == R.id.star) {
966 keyPressed(KeyEvent.KEYCODE_STAR);
967 } else {
968 LogUtil.e(
969 "DialpadFragment.onPressed", "Unexpected onTouch(ACTION_DOWN) event from: " + view);
970 }
971 mPressedDialpadKeys.add(view);
keyPressed -> playTone()
863 private void keyPressed(int keyCode) {
864 if (getView() == null || getView().getTranslationY() != 0) {
865 return;
866 }
867 switch (keyCode) {
868 case KeyEvent.KEYCODE_1:
869 playTone(ToneGenerator.TONE_DTMF_1, TONE_LENGTH_INFINITE);
870 break;
871 case KeyEvent.KEYCODE_2:
872 playTone(ToneGenerator.TONE_DTMF_2, TONE_LENGTH_INFINITE);
873 break;
874 case KeyEvent.KEYCODE_3:
875 playTone(ToneGenerator.TONE_DTMF_3, TONE_LENGTH_INFINITE);
876 break;
877 case KeyEvent.KEYCODE_4:
878 playTone(ToneGenerator.TONE_DTMF_4, TONE_LENGTH_INFINITE);
879 break;
880 case KeyEvent.KEYCODE_5:
881 playTone(ToneGenerator.TONE_DTMF_5, TONE_LENGTH_INFINITE);
882 break;
883 case KeyEvent.KEYCODE_6:
884 playTone(ToneGenerator.TONE_DTMF_6, TONE_LENGTH_INFINITE);
885 break;
886 case KeyEvent.KEYCODE_7:
887 playTone(ToneGenerator.TONE_DTMF_7, TONE_LENGTH_INFINITE);
888 break;
889 case KeyEvent.KEYCODE_8:
890 playTone(ToneGenerator.TONE_DTMF_8, TONE_LENGTH_INFINITE);
891 break;
892 case KeyEvent.KEYCODE_9:
893 playTone(ToneGenerator.TONE_DTMF_9, TONE_LENGTH_INFINITE);
894 break;
895 case KeyEvent.KEYCODE_0:
896 playTone(ToneGenerator.TONE_DTMF_0, TONE_LENGTH_INFINITE);
897 break;
898 case KeyEvent.KEYCODE_POUND:
899 playTone(ToneGenerator.TONE_DTMF_P, TONE_LENGTH_INFINITE);
900 break;
901 case KeyEvent.KEYCODE_STAR:
902 playTone(ToneGenerator.TONE_DTMF_S, TONE_LENGTH_INFINITE);
903 break;
904 default:
905 break;
906 }
最终调用 ToneGenerator::startTone()
////////////////////////////////////////////////////////////////////////////////
916 //
917 // Method: ToneGenerator::startTone()
918 //
919 // Description: Starts tone playback.
920 //
921 // Input:
922 // toneType: Type of tone generated (values in enum tone_type)
923 // durationMs: The tone duration in milliseconds. If the tone is limited in time by definition,
924 // the actual duration will be the minimum of durationMs and the defined tone duration.
925 // Ommiting or setting durationMs to -1 does not limit tone duration.
926 //
927 // Output:
928 // none
929 //
930 ////////////////////////////////////////////////////////////////////////////////
931 bool ToneGenerator::startTone(tone_type toneType, int durationMs) {
932 bool lResult = false;
933 status_t lStatus;
934
935 if ((toneType < 0) || (toneType >= NUM_TONES))
936 return lResult;
937
938 toneType = getToneForRegion(toneType);
939 if (toneType == TONE_CDMA_SIGNAL_OFF) {
940 return true;
941 }
942
943 if (mState == TONE_IDLE) {
944 ALOGV("startTone: try to re-init AudioTrack");
945 if (!initAudioTrack()) {
946 return lResult;
947 }
948 }
949
950 ALOGV("startTone");
951
952 mLock.lock();
953
954 // Get descriptor for requested tone
955 mpNewToneDesc = &sToneDescriptors[toneType];
956
957 mDurationMs = durationMs;
958
959 if (mState == TONE_STOPPED) {
960 ALOGV("Start waiting for previous tone to stop");
961 lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
962 if (lStatus != NO_ERROR) {
963 ALOGE("--- start wait for stop timed out, status %d", lStatus);
964 mState = TONE_IDLE;
965 mLock.unlock();
966 return lResult;
967 }
968 }
969
970 if (mState == TONE_INIT) {
971 if (prepareWave()) {
972 ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000));
973 lResult = true;
974 mState = TONE_STARTING;
975 if (clock_gettime(CLOCK_MONOTONIC, &mStartTime) != 0) {
976 mStartTime.tv_sec = 0;
977 }
978 mLock.unlock();
979 mpAudioTrack->start();
980 mLock.lock();
981 if (mState == TONE_STARTING) {
982 ALOGV("Wait for start callback");
983 lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
984 if (lStatus != NO_ERROR) {
985 ALOGE("--- Immediate start timed out, status %d", lStatus);
986 mState = TONE_IDLE;
987 lResult = false;
988 }
989 }
990 } else {
991 mState = TONE_IDLE;
992 }
993 } else {
994 ALOGV("Delayed start");
然后prepareWave()解析wave参数,通过WaveGenerator计算生成播放的Tone音波形的PCM数据
////////////////////////////////////////////////////////////////////////////////
1527 // WaveGenerator::WaveGenerator class Implementation
1528 ////////////////////////////////////////////////////////////////////////////////
1529
1530 //---------------------------------- public methods ----------------------------
1531
1532 ////////////////////////////////////////////////////////////////////////////////
1533 //
1534 // Method: WaveGenerator::WaveGenerator()
1535 //
1536 // Description: Constructor.
1537 //
1538 // Input:
1539 // samplingRate: Output sampling rate in Hz
1540 // frequency: Frequency of the sine wave to generate in Hz
1541 // volume: volume (0.0 to 1.0)
1542 //
1543 // Output:
1544 // none
1545 //
1546 ////////////////////////////////////////////////////////////////////////////////
1547 ToneGenerator::WaveGenerator::WaveGenerator(uint32_t samplingRate,
1548 unsigned short frequency, float volume) {
1549 double d0;
1550 double F_div_Fs; // frequency / samplingRate
1551
1552 F_div_Fs = frequency / (double)samplingRate;
1553 d0 = - (float)GEN_AMP * sin(2 * M_PI * F_div_Fs);
1554 mS2_0 = (short)d0;
1555 mS1 = 0;
1556 mS2 = mS2_0;
1557
1558 mAmplitude_Q15 = (short)(32767. * 32767. * volume / GEN_AMP);
1559 // take some margin for amplitude fluctuation
1560 if (mAmplitude_Q15 > 32500)
1561 mAmplitude_Q15 = 32500;
1562
1563 d0 = 32768.0 * cos(2 * M_PI * F_div_Fs); // Q14*2*cos()
1564 if (d0 > 32767)
1565 d0 = 32767;
1566 mA1_Q14 = (short) d0;
1567
1568 ALOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d",
1569 mA1_Q14, mS2_0, mAmplitude_Q15);
1570 }
1571
在ToneGenerator::audioCallback回调中调用WaveGenerator::getSamples()填充播放的数据到buffer中
1588 ////////////////////////////////////////////////////////////////////////////////
1589 //
1590 // Method: WaveGenerator::getSamples()
1591 //
1592 // Description: Generates count samples of a sine wave and accumulates
1593 // result in outBuffer.
1594 //
1595 // Input:
1596 // outBuffer: Output buffer where to accumulate samples.
1597 // count: number of samples to produce.
1598 // command: special action requested (see enum gen_command).
1599 //
1600 // Output:
1601 // none
1602 //
1603 ////////////////////////////////////////////////////////////////////////////////
1604 void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
1605 unsigned int count, unsigned int command) {
1606 long lS1, lS2;
1607 long lA1, lAmplitude;
1608 long Sample; // current sample
1609
1610 // init local
1611 if (command == WAVEGEN_START) {
1612 lS1 = (long)0;
1613 lS2 = (long)mS2_0;
1614 } else {
1615 lS1 = mS1;
1616 lS2 = mS2;
1617 }
1618 lA1 = (long)mA1_Q14;
1619 lAmplitude = (long)mAmplitude_Q15;
1620
1621 if (command == WAVEGEN_STOP) {
1622 lAmplitude <<= 16;
1623 if (count == 0) {
1624 return;
1625 }
1626 long dec = lAmplitude/count;
1627 // loop generation
1628 while (count) {
1629 count--;
1630 Sample = ((lA1 * lS1) >> S_Q14) - lS2;
1631 // shift delay
1632 lS2 = lS1;
1633 lS1 = Sample;
1634 Sample = ((lAmplitude>>16) * Sample) >> S_Q15;
1635 *(outBuffer++) += (short)Sample; // put result in buffer
1636 lAmplitude -= dec;
1637 }
1638 } else {
1639 // loop generation
1640 while (count) {
1641 count--;
1642 Sample = ((lA1 * lS1) >> S_Q14) - lS2;
1643 // shift delay
1644 lS2 = lS1;
1645 lS1 = Sample;
1646 Sample = (lAmplitude * Sample) >> S_Q15;
1647 *(outBuffer++) += (short)Sample; // put result in buffer
1648 }
1649 }
1650
1651 // save status
1652 mS1 = lS1;
1653 mS2 = lS2;
1654 }
1655
1656 } // end namespace android
// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
30 const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
31 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1336, 941, 0 }, 0, 0},
32 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
33 .repeatCnt = ToneGenerator::TONEGEN_INF,
34 .repeatSegment = 0 }, // TONE_DTMF_0
35 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1209, 697, 0 }, 0, 0 },
36 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
37 .repeatCnt = ToneGenerator::TONEGEN_INF,
38 .repeatSegment = 0 }, // TONE_DTMF_1
39 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1336, 697, 0 }, 0, 0 },
40 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
41 .repeatCnt = ToneGenerator::TONEGEN_INF,
42 .repeatSegment = 0 }, // TONE_DTMF_2
......
71 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1209, 941, 0 }, 0, 0 },
72 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
73 .repeatCnt = ToneGenerator::TONEGEN_INF,
74 .repeatSegment = 0 }, // TONE_DTMF_S
75 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1477, 941, 0 }, 0, 0 },
76 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
77 .repeatCnt = ToneGenerator::TONEGEN_INF,
78 .repeatSegment = 0 }, // TONE_DTMF_P
79 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1633, 697, 0 }, 0, 0 },
80 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
81 .repeatCnt = ToneGenerator::TONEGEN_INF,
82 .repeatSegment = 0 }, // TONE_DTMF_A
83 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1633, 770, 0 }, 0, 0 },
84 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
85 .repeatCnt = ToneGenerator::TONEGEN_INF,
86 .repeatSegment = 0 }, // TONE_DTMF_B
87 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1633, 852, 0 }, 0, 0 },
88 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
89 .repeatCnt = ToneGenerator::TONEGEN_INF,
90 .repeatSegment = 0 }, // TONE_DTMF_C
91 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 1633, 941, 0 }, 0, 0 },
92 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
93 .repeatCnt = ToneGenerator::TONEGEN_INF,
94 .repeatSegment = 0 }, // TONE_DTMF_D
95 { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 425, 0 }, 0, 0 },
96 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
97 .repeatCnt = ToneGenerator::TONEGEN_INF,
98 .repeatSegment = 0 }, // TONE_SUP_DIAL
99 { .segments = { { .duration = 500 , .waveFreq = { 425, 0 }, 0, 0},
100 { .duration = 500, .waveFreq = { 0 }, 0, 0},
101 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
102 .repeatCnt = ToneGenerator::TONEGEN_INF,
103 .repeatSegment = 0 }, // TONE_SUP_BUSY
104 { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
105 { .duration = 200, .waveFreq = { 0 }, 0, 0 },
106 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
107 .repeatCnt = ToneGenerator::TONEGEN_INF,
108 .repeatSegment = 0 }, // TONE_SUP_CONGESTION
109 { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
110 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
111 .repeatCnt = 0,
112 .repeatSegment = 0 }, // TONE_SUP_RADIO_ACK
113 { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0},
114 { .duration = 200, .waveFreq = { 0 }, 0, 0},
115 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
116 .repeatCnt = 2,
117 .repeatSegment = 0 }, // TONE_SUP_RADIO_NOTAVAIL
118 { .segments = { { .duration = 330, .waveFreq = { 950, 1400, 1800, 0 }, 0, 0},
119 { .duration = 1000, .waveFreq = { 0 }, 0, 0},
120 { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
121 .repeatCnt = ToneGenerator::TONEGEN_INF,
122 .repeatSegment = 0 }, // TONE_SUP_ERROR
//duration为时间间隔,waveFreq为频率, 解释如下:
{ .segments: { { duration: 2000, waveFreq: { 960, 540, 0 }, 0, 0 }, //2s内按照960Hz+540Hz进行响铃
{ duration: 500, waveFreq: { 0 }, 0, 0 }, //暂停0.5s
{ duration: 1000, waveFreq: { 400, 960, 0 }, 0, 0 }, //1s内按照400Hz+960Hz进行响铃
{ duration: 500, waveFreq: { 0 }, 0, 0 }, //暂停0.5s
{ duration: 1000, waveFreq: { 500, 800, 0 }, 0, 0 }, //1s内按照500Hz+800Hz进行响铃
{ duration: 500, waveFreq: { 0 }, 0, 0 }, //暂停0.5s
{ duration: 0 , waveFreq: { 0 }, 0, 0}},
repeatCnt: 3, //重复次数
repeatSegment: 0 },