目录
📂 前言
AR 眼镜系统版本
蓝牙电话
来电铃声
系统音效
1. 🔱 Android9 原生的来电铃声,走的哪个通道?
2. 💠 Android9 原生的来电铃声,使用什么播放?
2.1 来电铃声创建准备
2.2 来电铃声播放过程
3. ⚛️ Android9 内部定义的系统音量,共有几类?
4. ✅ 蓝牙电话的来电铃声,使用手机 or 眼镜的来电铃声?是否与 SoundPool 播放的接听音效冲突?
4.1 手机铃声最大情况下
4.2 手机铃声静音情况下
4.3 结论
承接上一篇章:AR 眼镜之-蓝牙电话-实现方案
📂 前言
AR 眼镜系统版本
W517 Android9。
蓝牙电话
主要实现 HFP 协议,主要实现拨打、接听、挂断电话(AG 侧、HF 侧)、切换声道等功能。
-
HFP(Hands-Free Profile)协议——一种蓝牙通信协议,实现 AR 眼镜与手机之间的通信;
-
AG(Audio Gate)音频网关——音频设备输入输出网关 ;
-
HF(Hands Free)免提——该设备作为音频网关的远程音频输入/输出机制,并可提供若干遥控功能。
在 AR 眼镜蓝牙中,手机侧是 AG,AR 眼镜蓝牙侧是 HF,在 Android 源代码中,将 AG 侧称为 HFP/AG,将 HF 侧称为 HFPClient/HF。
来电铃声
Andriod 来电的铃声默认保存在 system/media/audio/ 下面,有四个文件夹,分别是 alarms(闹钟)、notifications(通知)、ringtones(铃声)、ui(UI音效),源码中这些文件保存在 frameworks\base\data\sounds 目录下面。
系统音效
Android 系统中,音量都是分开控制的,这些包括媒体、铃声、闹铃、蓝牙、通话以及通知,通过音频流来区别不同的音量类型,每种流类型都定义最大音量、最小音量及默认音量。
1. 🔱 Android9 原生的来电铃声,走的哪个通道?
走的 STREAM_RING 通道,在 RingtoneFactory.getRingtone 中通过 setStreamType 指定通道为 AudioManager.STREAM_RING。
RingtoneFactory:.\packages\services\Telecomm\src\com.android.server.telecom\RingtoneFactory
public Ringtone getRingtone(Call incomingCall) {
// Use the default ringtone of the work profile if the contact is a work profile contact.
Context userContext = isWorkContact(incomingCall) ?
getWorkProfileContextForUser(mCallsManager.getCurrentUserHandle()) :
getContextForUserHandle(mCallsManager.getCurrentUserHandle());
Uri ringtoneUri = incomingCall.getRingtone();
Ringtone ringtone = null;
int phoneId = TelecomUtils.getSlotIdForPhoneAccountHandle(
incomingCall.getContext(),
incomingCall.getTargetPhoneAccount());
if(ringtoneUri != null && userContext != null) {
// Ringtone URI is explicitly specified. First, try to create a Ringtone with that.
ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri);
}
if(ringtone == null) {
// Contact didn't specify ringtone or custom Ringtone creation failed. Get default
// ringtone for user or profile.
RingtoneManagerEx.setSlotId(phoneId);
Context contextToUse = hasDefaultRingtoneForUserForSlot(userContext, phoneId)
? userContext : mContext;
Uri defaultRingtoneUri;
if (UserManager.get(contextToUse).isUserUnlocked(contextToUse.getUserId())) {
defaultRingtoneUri = RingtoneManagerEx.getActualDefaultRingtoneUri(contextToUse,
RingtoneManager.TYPE_RINGTONE, phoneId);
} else {
defaultRingtoneUri = phoneId == 1 ? Settings.System.DEFAULT_RINGTONE1_URI
: Settings.System.DEFAULT_RINGTONE_URI;
}
if (defaultRingtoneUri == null) {
return null;
}
ringtone = RingtoneManager.getRingtone(contextToUse, defaultRingtoneUri);
}
if (ringtone != null) {
ringtone.setStreamType(AudioManager.STREAM_RING);
}
return ringtone;
}
2. 💠 Android9 原生的来电铃声,使用什么播放?
使用 MediaPlayer 播放,主要分为铃声创建准备、铃声播放过程(只考虑本地播放流程,暂不考虑远程播放流程使用 mRemotePlayer、以及本地和远程均播放失败使用 playFallbackRingtone 的情况)。
-
.\packages\services\Telecomm 仓库:
-
Ringer:\src\com.android.server.telecom\Ringer.java;
-
AsyncRingtonePlayer:\src\com.android.server.telecom\AsyncRingtonePlayer.java;
-
RingtoneFactory:\src\com.android.server.telecom\RingtoneFactory.java。
-
-
.\frameworks\base 仓库:
-
RingtoneManager:\media\java\android\media\RingtoneManager.java;
-
Ringtone:\media\java\android\media\Ringtone.java;
-
MediaPlayer:\media\java\android\media\MediaPlayer.java。
-
2.1 来电铃声创建准备
Ringer.startRinging -> AsyncRingtonePlayer.play -> AsyncRingtonePlayer.handlePlay -> RingtoneFactory.getRingtone -> RingtoneManager.getRingtone -> Ringtone.setUri -> new MediaPlayer -> MediaPlayer.setDataSource.
2.2 来电铃声播放过程
Ringer.startRinging -> AsyncRingtonePlayer.play -> AsyncRingtonePlayer.handlePlay -> AsyncRingtonePlayer.handleRepeat -> Ringtone.play -> Ringtone.startLocalPlayer -> MediaPlayer.start.
3. ⚛️ Android9 内部定义的系统音量,共有几类?
一共6类,分别是 STREAM_VOICE_CALL、STREAM_RING、STREAM_MUSIC、STREAM_ALARM、STREAM_NOTIFICATION 以及 STREAM_BLUETOOTH_SCO。
-
STREAM_VOICE_CALL:通话声音
-
STREAM_RING:来电响铃
-
STREAM_MUSIC:媒体声音(包括音乐,视频,游戏声音)
-
STREAM_ALARM:闹钟声音
-
STREAM_NOTIFICATION:通知声音
-
STREAM_BLUETOOTH_SCO:蓝牙声音
private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
AudioSystem.STREAM_RING, // STREAM_SYSTEM
AudioSystem.STREAM_RING, // STREAM_RING
AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
AudioSystem.STREAM_ALARM, // STREAM_ALARM
AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION
AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
AudioSystem.STREAM_RING, // STREAM_DTMF
AudioSystem.STREAM_MUSIC, // STREAM_TTS
AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
};
注:
1)STREAM_SYSTEM 指系统声音,包括按键声音等,与 STREAM_RING 映射一样的音频通道,即:设置应用-声音-铃声可调节此值;
2)STREAM_MUSIC,即:设置应用-声音-媒体可调节此值;
3)STREAM_NOTIFICATION,即:设置应用-声音-通知可调节此值。
4. ✅ 蓝牙电话的来电铃声,使用手机 or 眼镜的来电铃声?是否与 SoundPool 播放的接听音效冲突?
前提:蓝牙电话,眼镜铃声调到最大。
4.1 手机铃声最大情况下
-
Mate 60:Android12,蓝牙电话来电铃声使用的眼镜铃声,有接听音效;——在“开发者人员选项”中打开“来电铃声同步(来电时,蓝牙设备播放手机铃声)”按钮开关后,蓝牙电话来电铃声使用的手机铃声,无接听音效;
-
小米 14:Android14,蓝牙电话来电铃声使用的眼镜铃声,有接听音效;——在“开发者人员选项”中没有“来电铃声同步“按钮开关;
-
华为 P9:Android8,蓝牙电话来电铃声使用的眼镜铃声,有接听音效;——在“开发者人员选项”中没有“来电铃声同步“按钮开关;
-
Motorola:Android14,蓝牙电话来电铃声使用的手机铃声,无接听音效;
-
VIVO X100:Android14,蓝牙电话来电铃声使用的手机铃声,无接听音效;
4.2 手机铃声静音情况下
-
Mate 60:Android12,蓝牙电话来电铃声使用的眼镜铃声,有接听音效;——在“开发者人员选项”中打开“来电铃声同步(来电时,蓝牙设备播放手机铃声)”按钮开关后,蓝牙电话来电铃声有铃声且使用的手机铃声,无接听音效;
-
小米 14:Android14,蓝牙电话来电铃声使用的眼镜铃声,有接听音效;——在“开发者人员选项”中没有“来电铃声同步“按钮开关;
-
华为 P9:Android8,蓝牙电话来电铃声使用的眼镜铃声,有接听音效;——在“开发者人员选项”中没有“来电铃声同步“按钮开关;
-
Motorola:Android14,蓝牙电话来电铃声无铃声,无接听音效;
-
VIVO X100:Android14,蓝牙电话来电铃声无铃声,无接听音效;
4.3 结论
-
对于不同 Android 手机的蓝牙来电,使用的来电铃声不一样,Mate60、小米14、华为 P9 使用眼镜铃声,Mate60 打开“来电铃声同步“按钮开关后使用手机铃声,Motorola、VIVO X100 使用手机铃声;
-
有无接听音效与来电铃声相关,使用手机来电铃声无接听音效,使用眼镜来电铃声有接听音效——因为使用手机来电铃声会切换为蓝牙音频通道,导致眼镜使用 SoundPool 播放的接听音效未生效,待后续兼容。
另外,由于本人能力有限,如有错误,敬请批评指正,谢谢。