首先所有需要播放声音的app都需要创建这个组件的一个实例,注册自己的优先级处理函数,运用自己的优先级。
ISHELL_CreateInstance(pThis->a.m_pIShell, SYS_CLSID_IVOICEPRIORITY, (void**)(&pThis->pIVoicePriority));
优先级管理组件提供了一些函数来管理需要播放声音的app,主要的函数有四个:
IVoicePriority_RegisterNotify()
IVoicePriority_UsePriority()
IVoicePriority_UnusePriority()
IVoicePriority_UnregisterNotify()
IVoicePriority_RegisterNotify()函数有一个参数是声音的优先级大小,是定义在一个枚举中的,还有一个是事件处理函数的指针定义如下:
typedef void (*PFNPriorityNotify)(void* pUser, TPriorityNotifyType NotifyType);
TPriorityNotifyType也是一个枚举类型,定义了通知事件的类型,
typedef enum
{
PRI_NOTIFY_ACTIVE,
PRI_NOTIFY_INTERRUPT,
} TPriorityNotifyType;
优先级定义
typedef enum
{
...
PRIORITY_FMRADIO,
...
PRIORITY_ALARM
...
PRIORITY_CALLINGING,
PRIORITY_INCOMINGCALL,
}TVoicePriority;
枚举中的值越大,优先级越大,中间还有一些其他的app,省略掉了。第一次调用IVoicePriority_RegisterNotify()会创建一个链表,链表中的结点包含了每个app的优先级和冲突事件处理函数,以及一些其他的数据。后来调用IVoicePriority_RegisterNotify()会向链表中插入一个结点,同时会对链表进行排序,排序是通过优先级的大小进行的,是大优先级的结点排在最后面。
IVoicePriority_UsePriority()首先判断当前app的优先级是否是最大的,是则调用它在链表中前一个结点的事件处理函数,通过向该函数传递一个PRI_NOTIFY_INTERRUPT参数,来通知该app有声音优先级事件。
IVoicePriority_UnusePriority()和IVoicePriority_UsePriority()一样判断当前app的优先级是否是最大的,是则调用它在链表中前一个结点的事件处理函数,通过向该函数传递一个PRI_NOTIFY_ACTIVE参数,来通知该app有声音优先级事件。
IVoicePriority_UnregisterNotify()从链表中删除当前app的结点。
举个例子来说明优先级管理组件是如何来工作的:假如首先打开收音机,这时收音机app会创建优先级管理组件的实例,调用IVoicePriority_RegisterNotify()注册声音优先级事件处理函数,这时链表中保存了一个结点,结点包括FM收音机的优先级大小,以及声音优先级事件处理函数:
void FMRadio_ICBPriority(void* pUser, TPriorityNotifyType NotifyType)
{
if (PRI_NOTIFY_INTERRUPT == NotifyType)
{
//暂停或者关闭收音机,以及一些其他处理
}
else if (PRI_NOTIFY_ACTIVE == NotifyType)
{
//继续播放收音机
}
}
接着FM收音机app调用IVoicePriority_UsePriority(),它首先判断当前app的优先级是否是最大的,这时只有一个app,链表中只有一个结点,所以它没有前一个结点,也就不会调用前一个结点的事件处理函数。
收音机正在播放时,如果这时闹钟时间到,要播放闹钟声音。闹钟app和FM收音机一样,首先会创建优先级管理组件的实例,调用IVoicePriority_RegisterNotify()注册声音优先级事件处理函数,这时链表已经存在,所以闹钟app向链表中插入一个结点,结点也包含闹钟app的优先级大小,以及事音优先级事件处理函数。
void Alarm_ICBPriority(void* pUser, TPriorityNotifyType NotifyType)
{
if (PRI_NOTIFY_INTERRUPT == NotifyType)
{
//暂停或者关闭闹钟声音,以及一些其他处理
}
else if (PRI_NOTIFY_ACTIVE == NotifyType)
{
//继续播放闹钟声音
}
}
接着闹钟app调用IVoicePriority_UsePriority(),它首先判断自己的优先级是否是最大的,在这里闹钟的优先级比FM收音机大,所以它会调用前一个结点的声音优先级处理函数,也就是FM收音机的声音优先级处理函数,向函数的第二个参数传递PRI_NOTIFY_INTERRUPT,FM收音机这时会暂停,接着闹钟播放声音。闹钟播放完毕之后,闹钟app退出,调用IVoicePriority_UnusePriority()函数,它也首先判断自己的优先级是否是最大,在这里闹钟app的声音优先级是最大,所以它调用前一个结点的声音优先级处理函数,即FM收音机的声音优先级处理函数,并向函数的第二个参数传递PRI_NOTIFY_ACTIVE,这时收音机继续播放,闹钟app继续调用IVoicePriority_UnregisterNotify()把自己的结点从链表中删除,这时收音机成为了优先级最大的结点。
这里是两个app的情况,多个app也进行类似的处理。注意每一时刻只有一个app能够进行声音播放。通过前面的分析,还可以发现,只有优先级高的app才能打断优先级低的app,任何时刻在播放声音的app一定是优先级最高的,最高优先级的app退出时,会通知优先级仅次于自己的app。上述过程还可通过图表描述如下: