您的位置:首页 > 其它

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

2011-04-28 22:07 309 查看
声音提示可以采用两种方法:一种是利用系统自带的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的值,经人测试100到3400是工作正常,效果很好(可能1000到3000最好), 3600到3800就变弱了,再往上到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下面即可。
注:另外,在这里虽然对情景模式是否静音进行了判断,其实不判断也是可以的,因为情景模式设为静音,仍然是可以播放出声音来的。这点很不同于震动。

多媒体框架的使用

S60的MMF(多媒体框架)提供了对音频进行播放、录制和格式转换等功能函数,具体的功能类如下:
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函数应该也会震动的吧?
结果是震动函数返回-21即KErrAccessDenied(拒绝接受),这和播放声音提示时的效果完全两样,所以说读情景配置模式里的参数在这里完全是必要的。
好,那就加判断,总算执行到了StartVibraL (TUint16 aDuration, TInt aIntensity)函数,假如在这里aDuration超过KHWRMVibraMaxDuration,或者aIntensity不在-100到100之间(这里的强度值是马达的运转强度值,负值是马达反转,有些文章说该值在+-30范围内会报-2即KErrGeneral错误,但是自己用E65亲测过,在+-30以内,没有报错,震动感不强烈而已,可能跟手机和具体硬件有关吧),那么震动效果又没有起来,此时的震动函数返回为-6,即KErrAgument(错误要求)。
我们解决了以上两个问题后,还有两种特殊情况,一种是当你的手机在充电时,如果调用正确的StartVibraL会返回-22错误,即KErrLocked(锁闭)。以上几种情况还好,虽然不震,但是你可以用TRAP机制捕获错误码,但是如果当你是通过数据线的手机PC模式装上软件后没有拔出数据线,就算使用TRAP返回时KErrNone,但是手机还是没有震动起来,你就会头大了,难道这个函数在当前手机上不管用吗?
事实是,当你拔掉数据线,居然震动来了。
唉,问题总算解决了,代码虽简单,但是实现却并不简单啊。

本文出自qxiaoyuan哥。

一直以来为了读取/设置到用户的情景模式, 短信提示音, 都是很郁闷的使用nokia提供的mr的plugin api和fp1自己的api, 因为不同, 所以必须发布2个版本, 提交express时浪费了无数的money和精力(维护, 验证, 测试).

后来, 读到子腾大侠的无敌吸星大法, 才知道还有种方法敲开symbian的重重内幕, 今天终于下定决心, 参考子腾大侠的

http://discussion.forum.nokia.com/forum/showthread.php?p=524967#post524967

无敌吸星大法, 解决了这个问题,
比较发现
0x101F8798是CRepository的key,
而0x7e000001是情景模式的index,
短信提示音是mode的一个位移算法, 类似的手机铃音只是下一个值而已,
贴出我的测试代码的核心, 打击一看即知

Code:
const char* profile[] = { "biaozhun", "wusheng", "huiyi", "huwai", "xunhuji", "lixian", };
CRepository* cenrep = CRepository::NewLC(TUid::Uid(0x101F8798));

TInt mode = -1;
User::LeaveIfError(cenrep->Get(0x7e000001, mode));

TInt k = mode << 24 | 0x04;
TFileName toneFile;
User::LeaveIfError(cenrep->Get(k, toneFile));

CleanupStack::PopAndDestroy(cenrep);

TBuf8<100> pm( (const TUint8*)profile[mode] );
TBuf<512> buf;
buf.Copy(pm);
buf.Append(_L("/r/n"));
buf.Append(toneFile);

CAknInformationNote* informationNote = new ( ELeave ) CAknInformationNote;
informationNote->ExecuteLD( buf );

再次感谢子腾大侠, 这个确实是潘朵拉魔盒, 打开了

Hi,

Assume that the value is stored in a CenRep file, do the following steps,

1. Start the S60 3rd Edition FP2 emulator and then enter the "Settings" application.

2. Remember the default value of the Power-saver timeout setting (15s) and then modify it (to 25s, for example), and then exit the "Settings" application

3. Search in the 'epoc32' folder for recently changed files, there are several modified .cre files.
101f87ef.cre
101f877c.cre
1000a82b.cre
make a copy of them

4. Enter the "Settings" application and then modify the setting again (to 30s, for example), and then exit the "Setting" application

5. Search in the 'epoc32' folder again for recently changed files, still the .cre files. Compare them to the copies made in step 3, and we can see only the 101f877c.cre is changed, and actually only one byte is changed from 0x19 (25s) to 0x1E(30s), so it is must be the one we are looking for.

6. Check the "/epoc32/release/winscw/udeb/z/private/10202be9/101f877c.txt", the key of the item with default value 15 is 0x8, so I guess it is the key for backlight timeout.
...
0x8 int 15 16777216 cap_rd=alwayspass cap_wr=WriteDeviceData
...

You can make a further confirmation by code:

Code:
TInt timeout = 0;
CRepository* cenrep = CRepository::NewLC(TUid::Uid(0x101F877C));
User::LeaveIfError(cenrep->Get(0x8, timeout));
CleanupStack::PopAndDestroy(cenrep);


Regards

Ziteng Chen

//Screen Saver Time out
TInt timeout = 0; CRepository* cenrep = CRepository::NewLC(TUid::Uid(0x101F877C)); User::LeaveIfError(cenrep->Get(0x8, timeout)); CleanupStack::PopAndDestroy(cenrep);

//Backlight Time out
TInt timeout = 0;
CRepository* cenrep = CRepository::NewLC(TUid::Uid(0x101F8781));
User::LeaveIfError(cenrep->Get(0x1, timeout));
CleanupStack::PopAndDestroy(cenrep);

This is for S60 3rd edition. I do not know the others

http://apps.hi.baidu.com/share/detail/32037606

http://blog.csdn.net/linzhiji/archive/2010/02/04/5288682.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: