播放生成Android4.0.3中的提示音

题记:写这篇博客要主是加深自己对播放生成的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢。

    

一、ToneGenerator的应用

    参照com.android.contacts.dialpad.DialpadFragment

    ToneGenerator只能播放在ToneGenerator中定义好的TONE_TYPE。

    

1、常量申明

/** Tone音的长度,单位:milliseconds */
private static final int TONE_LENGTH_MS = 150;
/** 主音量的比例:以80%的主音量播放Tone音 */
private static final int TONE_RELATIVE_VOLUME = 80;
/** 主音量的音频种别 */
private static final int DIAL_TONE_STREAM_TYPE =AudioManager.STREAM_MUSIC;

    

2、变量申明

// Tone音播放器
private ToneGenerator mToneGenerator;
// Tone相干的同步锁
private Object mToneGeneratorLock = new Object();
// 设定中的Tone音播放设置
private boolean mDTMFToneEnabled;

    

3、Tone的初始化

public void onResume() {
    super.onResume();
    // 读取设定的值
    mDTMFToneEnabled =Settings.System.getInt(getActivity().getContentResolver(),
           Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
 
    // 失败了也无所谓,不是啥重要的货色
    synchronized (mToneGeneratorLock) {
        if (mToneGenerator == null) {
            try {
                // we want the user to be ableto control the volume of the dial tones
                // outside of a call, so we usethe stream type that is also mapped to the
                // volume control keys for thisactivity
                mToneGenerator = newToneGenerator(DIAL_TONE_STREAM_TYPE, TONE_RELATIVE_VOLUME);
               getActivity().setVolumeControlStream(DIAL_TONE_STREAM_TYPE);
            } catch (RuntimeException e) {
                Log.w(TAG, "Exceptioncaught while creating local tone generator: " + e);
                mToneGenerator = null;
            }
        }
    }
}

    

4、释放Tone资源

public voidonPause() {
    super.onPause();
 
    synchronized (mToneGeneratorLock) {
        if (mToneGenerator != null) {
            mToneGenerator.release();
            mToneGenerator = null;
        }
    }
}

    

5、播放Tone音

    每日一道理
那蝴蝶花依然花开花落,而我心中的蝴蝶早已化作雄鹰飞向了广阔的蓝天。
/**
 * 播放TONE_LENGTH_MS milliseconds的Tone音.
 * 只有在设定中选择了播放Tone,并且不是静音模式才会播放Tone音。
 * @param tone a tone code from {@linkToneGenerator}
 */
void playTone(int tone) {
    // 设定中没有选中的话,就不播
    if (!mDTMFToneEnabled) {
        return;
    }
 
    // 静音模式的时候也不播,需要每次都检查,因为没有Activity切换也能设成静音模式
    // 设定中的那个就不需要,因为要设定必须要先切入设定Activity才行
    AudioManager audioManager =
            (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE);
    int ringerMode =audioManager.getRingerMode();
    if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
        || (ringerMode ==AudioManager.RINGER_MODE_VIBRATE)) {
        return;
    }
 
    synchronized (mToneGeneratorLock) {
        if (mToneGenerator == null) {
            Log.w(TAG, "playTone:mToneGenerator == null, tone: " + tone);
            return;
        }
 
        // Start the new tone (will stop anyplaying tone)
        mToneGenerator.startTone(tone,TONE_LENGTH_MS);
    }
}

    

    

 二、ToneGenerator的实现

    相干代码位置:

    ToneGenerator.java:ICS/frameworks/base/media/java/

    Android_media_ToneGenerator.cpp:ICS/frameworks/base/core/jni/

    ToneGenerator.cpp:ICS/frameworks/base/media/libmedia/

    

1、ToneGenerator.java

    定义了多种ToneType,供给了java的接口

    

2、Android_media_ToneGenerator.cpp

    将Java层的请求转发给Native层。

    android_media_ToneGenerator_native_setup中的有句话看不懂:

ToneGenerator *lpToneGen= new ToneGenerator(streamType,

    

    AudioSystem::linearToLog(volume)

    

    ,true); // change this value tochange volume scaling static const float dBPerStep= 0.5f; // shouldn't need totouch these static const floatdBConvert = -dBPerStep * 2.302585093f / 20.0f; static const floatdBConvertInverse = 1.0f / dBConvert; floatAudioSystem::linearToLog(int volume) { // float v = volume ? exp(float(100 -volume) * dBConvert) : 0; // LOGD("linearToLog(%d)=%f",volume, v); // return v; return volume ? exp(float(100 - volume) *dBConvert) : 0; }

    算出来的值会直接设到AudioTrack中,可是AudioTrack中的音量应该是个0~1.0f的百分比才对,为啥需要这么个公式呢,难道是Bug。应该测试一下!!

    

3、ToneGenerator.cpp

    根据定义的Tone因的频率,长度等信息生成音频数据,最后交给AudioTrack播放。

    

三、AudioPolicyService中的mTonePlaybackThread

  本来认为这个线程是专门处置Tone音设备的,可是根据下面一看本来是直接走AudioTrack的。这就奇怪了,并且AudioSystem中也没有供给对应的接口,这就更奇怪了,难道它没预备让表面的人用。再一检索,发现本来它是供给给AudioPolicyManagerBase应用的一个非同期播放Tone音的接口。

  经过AudioCommandThread的处置,最终还是交给ToneGenerator来处置。

    

四、RingtoneManager与Ringtone

    播放铃声的类,没具体看,最后是通过MediaPlayer来播放的。

    

五、论断

    本来还认为会有个独自硬件来处置Tone音的,最后发现竟然是自动生成后,通过AudioTrack来处置的。

    据说是因为硬件生成的Tone音很难听,所以才用软件来生成的。

文章结束给大家分享下程序员的一些笑话语录: 程序员打油诗   
  写字楼里写字间,写字间里程序员;
  程序人员写程序,又拿程序换酒钱。
  酒醒只在网上坐,酒醉还来网下眠;
  酒醉酒醒日复日,网上网下年复年。
  但愿老死电脑间,不愿鞠躬老板前;
  奔驰宝马贵者趣,公交自行程序员。
  别人笑我忒疯癫,我笑自己命太贱;
  不见满街漂亮妹,哪个归得程序员。

你可能感兴趣的:(Android4.0)