franksunny的个人技术空间
获得人生中的成功需要的专注与坚持不懈多过天才与机会。 ——C.W. Wendte

 

声音提示和震动提示的开发

 

声音提示可以采用两种方法:一种是利用系统自带的CoeSoundPlayer类来实现单音铃声的播放;另一种则是利用S60提供的多媒体框架CMda*类来实现音频播放。

关于声音提示的使用

CoeSoundPlayer类使用

该类声明于coesndpy.h头文件,库是cone.lib,最简单的使用莫过于如下格式的代码应用

TBaSystemSoundType a(KSystemSoundMessageUID);

CoeSoundPlayer::PlaySoundNow(a);

在以上代码的使用时,第一行声明一个系统tone的类型,该类型声明在bassnd.h文件中,同时在mmp中加上bafl.lib库文件。通常这种简单应用,在模拟器上能够听到声音(3rd MR版本的模拟器上都听不到声音),但是在真机上,基本听不到声音,一个原因据说是默认的缺省音量被置成了KSystemSoundDefaultVolume,其值最大可以到100(我亲测的结果是最小为0,没有声音,最大只能到10,超过10之后和传负值一样都会报MMFAudioClient 4的错误,程序也会Crash。所以关于这点最好还是有高人指点下)。另外bassnd.h中定义的类型还有KSystemSoundRingUID, KSystemSoundAlarmUID, KUidSystemSoundError, KUidSystemSoundEvent等,具体的效果,可以自己亲测下。

 

稍微复杂一点的应用代码如下:

TBaSystemSoundType soundType(KSystemSoundMessageUID);

//TBaSystemSoundInfo::TTone soundTone(aFrequency, aDuration);

TBaSystemSoundInfo::TTone soundTone(1500, 3*1000*1000);

TBaSystemSoundInfo soundInfo(soundType, soundTone);

BaSystemSound::SetSoundL(CCoeEnv::Static()->FsSession(), soundInfo);

CoeSoundPlayer::PlaySoundNow(soundType);

在这里,我对音调不是很懂,但是aFrequency的值,经人测试1003400是工作正常,效果很好(可能10003000最好), 36003800就变弱了,再往上到4000基本上已经听不到了。这种方法一般在真机上还是可以感受出来的,并非像第一种情况,只有模拟器上有效果。

 

只是长时间播放简单的音调估计很刺耳,那么我们就可以通过事先设计好的rng文件来进行播放单音铃声,具体代码如下:

_LIT(KRingToneFileName1, "\\Data\\Sounds\\simple\\alarm.rng");

const TInt KRingingTypeSilent = 4; // Silent

TInt tRingingType (0);

CRepository* tRepository = CRepository::NewLC(KCRUidProfileEngine);

User::LeaveIfError( tRepository ->Get(KProEngActiveRingingType, tRingingType ) );

if ( tRingingType != KRingingTypeSilent )

{

       TBaSystemSoundType soundType(KSystemSoundRingUID);

       TBaSystemSoundName soundName(KRingToneFileName1);

       CompleteWithAppPath(soundName);

       TBaSystemSoundInfo soundInfo(soundType, soundName, 10,
        KSystemSoundDefaultPriority);

       BaSystemSound::SetSoundL(CCoeEnv::Static()->FsSession(), soundInfo);

       CoeSoundPlayer::PlaySoundNow(soundType);

       //CoeSoundPlayer::PlaySound(soundType);

}

CleanupStack::PopAndDestroy(); // tRepository

使用以上代码需要注意的是alarm.rng文件必须要有,否则会没有声音传出,该文件在FP2版本的模拟器路径下没有,可以在S60_3rd_MR\Epoc32\release\winscw\udeb\z\system\sounds\simple下找到,并将其拷贝到相应的epoc32\release\winscw\udeb\z\system\sounds\simple下面即可。

注:另外,在这里虽然对情景模式是否静音进行了判断,其实不判断也是可以的,因为情景模式设为静音,仍然是可以播放出声音来的。这点很不同于震动。

 

多媒体框架的使用

S60MMF(多媒体框架)提供了对音频进行播放、录制和格式转换等功能函数,具体的功能类如下:

CMdaAudioPlayerUtility:音频播放;

CMdaAudioRecorderUtility:音频录制;

CMdaAudioConvertUtility:音频格式转换;

CMdaAudioToneUtility:音调播放

CMdaAudioInputUtility/ CMdaAudioOutputUtility:音频流操作

对于这一块内容的介绍在灵活使用EMCCsoft提供的AudioPlayer例子程序就会比较清楚,在这里就不多做展开了。唯一需要提醒的是,相应的回调接口虚函数一定要实现,否则不好控制。另设置音量的函数SetVolume也是只能在0~10之间,否则也会报MMFAudioClient 4错误。

 在用CMdaAudioPlayerUtility进行音乐文件比如*.wav格式播放时,假如一个文件还没有播放完,又开始播放一个新文件,也会引发MMFAudioClient 4的错误。

关于震动提示的使用

震动这个接口的发展历史很奇特,Symbian OS v8.x之前没有提供震动接口,之后开始使用CVibraControl类提供震动接口,而在Symbian OS v9.x之后在保留原有接口基础上又提供了新的CHWRMVibra类来提供震动接口。

网上的代码很多,常见形式如下:

// for S60 2nd FP2 and FP3

#include <vibractrl.h>  // CVibraControl, VibraCtrl.lib

 

void DoVibrateL( TUint16 aDuration )

{

  CVibraControl* control = VibraFactory::NewL();

  // get vibration setting in the user profile

  if ( CVibraControl::EVibraModeON == control->VibraSettings() ) 

  {

     control->StartVibraL( aDuration );

  }

 

  delete control;

  control = NULL;

}

 

// for S60 3rd

#include <hwrmvibra.h>  // CHWRMVibra, HWRMVibraClient.lib

 

void DoVibrateL( TInt aDuration )

{

  CHWRMVibra* vibra = CHWRMVibra::NewLC();

  // get vibration setting in the user profile

  if ( CHWRMVibra::EVibraModeON == vibra->VibraSettings() ) 

  {

     vibra->StartVibraL( aDuration );

  }

 

  CleanupStack::PopAndDestroy( vibra );

}

事实上如果原封不动拷贝如上代码是实现不了震动功能的,因为不管是CHWRMVibra还是CVibraControl对象在被新建并调用完StartVibraL函数之后,立即就被析构了,因为StartVibraL有类似异步函数的功能,并非阻塞在持续时间之内才会返回,所以对象还没起振就删除了。

震动功能的实现代码虽然简单,但是要想震起来还是有点麻烦的,为此我在使用时除了以上问题,还遇到其它几个问题:

当前情景模式里震动提示设置为关时,显然会因为

if ( CVibraControl::EVibraModeON == control->VibraSettings() )

if ( CHWRMVibra::EVibraModeON == vibra->VibraSettings() )

两个条件判断没通过而没有真实调用StartVibraL函数,那么我如果将判断去掉,始终让其调用StartVibraL函数应该也会震动的吧?

结果是震动函数返回-21KErrAccessDenied(拒绝接受),这和播放声音提示时的效果完全两样,所以说读情景配置模式里的参数在这里完全是必要的。

好,那就加判断,总算执行到了StartVibraL (TUint16 aDuration, TInt aIntensity)函数,假如在这里aDuration超过KHWRMVibraMaxDuration,或者aIntensity不在-100100之间(这里的强度值是马达的运转强度值,负值是马达反转,有些文章说该值在+-30范围内会报-2KErrGeneral错误,但是自己用E65亲测过,在+-30以内,没有报错,震动感不强烈而已,可能跟手机和具体硬件有关吧),那么震动效果又没有起来,此时的震动函数返回为-6,即KErrAgument(错误要求)。

我们解决了以上两个问题后,还有两种特殊情况,一种是当你的手机在充电时,如果调用正确的StartVibraL会返回-22错误,即KErrLocked(锁闭)。以上几种情况还好,虽然不震,但是你可以用TRAP机制捕获错误码,但是如果当你是通过数据线的手机PC模式装上软件后没有拔出数据线,就算使用TRAP返回时KErrNone,但是手机还是没有震动起来,你就会头大了,难道这个函数在当前手机上不管用吗?

事实是,当你拔掉数据线,居然震动来了。

唉,问题总算解决了,代码虽简单,但是实现却并不简单啊。

 

posted on 2009-08-12 17:38 frank.sunny 阅读(1878) 评论(1)  编辑 收藏 引用 所属分类: symbian 开发

FeedBack:
# re: 声音提示和震动提示的开发
2009-12-08 18:27 | 雨泥
大哥!你最后是如何实现手机震动的?我试了好多次东搞不定!请解答,最好附上代码!  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理



常用链接

留言簿(13)

随笔分类

个人其它博客

基础知识链接

最新评论

阅读排行榜

评论排行榜