Android 拨号音之 DTMF

Android 拨号音之 DTMF

音频播放有以下几种方式:

  • SoundPool:适合短促且对反应速度比较高的情况(游戏音效或按键声等)
  • MediaPlayer: 适合比较长且时间要求不高的情况
  • AudioTrack: 播放解码后的PCM码流
  • ToneGenerator: DTMF音的播放(实际是AudioTrack播放)

什么是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)1209133614771633
697123A
770456B
852789C
941*0#D

DTMF音调的产生可以分为硬件和软件的方式。随着数字电路技术和DSP技术的发展,市面上已经有很多DTMF专用的编解码芯片了,如:MITEL公司生产的MT8880。随着DSP技术和大规模集成电路的发展,用纯软件的方式调制和解调DTMF信号已经不再是难事了。

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<AudioTrack::Buffer *>(info);
1150      ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(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

关于sToneDescriptors

 // 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 },
  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安德路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值