Controlling volume and audio channels on KaiOS
Getting Started
All KaiOS phones come with a built-in speaker, microphone, and headphone jack. Additionally, most KaiOS phones come with Bluetooth and suppor for A2DP. Yes, that means you can connect a KaiOS phones to Apple AirPods!
Similar to Android, KaiOS enables app developers to build rich multimedia experience with the Audio Channels, Volume Manager, and Speaker Manager APIs. These collectively allow apps to control volume, known when headphones are unplugged, and force audio output through built-in speakers. KaiOS supports many common Media Formats including:
- audio/webm
- audio/mp4
- audio/mpeg
- audio/ogg
- audio/3gpp
- audio/x-scpls
- audio/opus
Audio Channels
KaiOS creates a hierarchy of importance for app audio content using the Audio Channels API. This determines when audio will be paused and resumed in response to other audio playback (i.e. a notification received), and allows you to control the volume of different types of audio independently. Although KaiOS does not offer true multitasking, Audio Channels are what enables background audio playback.
Apps require permission to use specific audio channels. Below is a list of the available audio channel levels, along with that app types they are allowed on. Permissions start with the prefix "audio-channel-"
, for instance "audio-channel-content"
for the Content channel.
Audio Channel | Web PWA | Privileged Signed | Certified Core |
---|---|---|---|
normal | ☑️ | ☑️ | ☑️ |
content | ☑️ | ☑️ | ☑️ |
notification | X | ☑️ | ☑️ |
alarm | X | ☑️ | ☑️ |
system | X | ☑️ | ☑️ |
ringer | X | X | ☑️ |
publicnotification | X | X | ☑️ |
Once permission is granted, audio channels can be controlled app-wide.
1// KaiOS 2.5
2navigator.mozAudioChannelManager.volumeControlChannel = 'content';
3
4// KaiOS 3.0
5navigator.b2g.audioChannelManager.volumeControlChannel = 'content'
Audio channels can also be set for specific media elements in HTML using the mozAudioChannelType
property.
1<audio mozAudioChannelType="content" />
2<video mozAudioChannelType="content" />
Audio channels can also be controlled in JavaScript for HTMLMediaElement
s and AudioContext
s using the same property.
1const audio = document.createElement('audio');
2audio.mozAudioChannelType = 'content';
The "content"
audio channel is probably the most important channel because it allows background audio playback. This means when the user pressed Back from your app’s homepage, audio playback will continue. Playback will have priority over the "normal"
channel, but will still get paused via the "notification"
when a notification arrives.
The "alarm"
audio channel is also useful for any app that plays sounds when an alarm is triggered. This ensures a wake up alarm paused "content"
playback until the alarm is dismissed.
Volume Manager API
Although KaiOS apps cannot control the system volume directly, volume can be controlled for specific elements using
HTMLMediaElement.volume
. Additionally, apps with the "volumemanager"
permission (only available for Privileged and Certified apps), can trigger the heads up display (HUD) that allows the user to raise or lower the active volume channel.
On KaiOS 2.5 the Volume Manager API is very simple. Each method returns void
, but triggers the HUD to display over your app. Unfortunately, you cannot configure the HUD style, which is different on different devices and OS versions.
1// KaiOS 2.5
2navigator.volumeManager.requestUp();
3navigator.volumeManager.requestDown();
4navigator.volumeManager.requestShow();
Once the HUD is displayed, it’s important to limit what KeyEvent
s your app responds to KeyUp
and KeyDown
using a resetting setTimeout
of 2 seconds. That’s because on older versions of KaiOS 2.5, the System app does not take full focus. Without this, the user might inadvertently shift focus and navigate within your app while only intending to change volume.
Why 2 seconds? From my research, this constant within SoundManager is consistent across all devices I have tested.
1SoundManager.HIDE_SOUND_DELAY = 2000;
The API for KaiOS 3.0 offers the same three methods (only renamed, i.e. requestVolumeUp
instead of requestUp
), but requires lots of scaffolding to access lib_audiovolume.AudioVolumeManager
. See
AudioVolumeManager service for how to use api-daemon on KaiOS 3.0.
Note: some KaiOS phones do not have volume buttons, so it’s important to offer volume controls within your app! One alternative that doesn’t require special permissions is to use Web Activities to launch the Volume page within the Settings app.
1// KaiOS 2.5
2let request = new MozActivity({
3 name: "configure",
4 data: {
5 target: "device",
6 section: "volume"
7 },
8});
9
10// KaiOS 3.0
11let activity = new WebActivity("configure", {
12 target: "device",
13 section: "volume"
14});
15activity.start();
Headphones
On KaiOS it’s possible to check if headphones are plugged in or not. This allows a podcast or music streaming app like PodLP to automatically pause playback when headphones come unplugged to avoid accidentally continuing playback on the device’s default speaker.
1// KaiOS 2.5
2if (navigator.mozAudioChannelManager.headphones) { /* TODO */ }
3navigator.mozAudioChannelManager.onheadphoneschange = () => {
4 /* TODO */
5};
6
7// KaiOS 3.0
8if (navigator.b2g.audioChannelManager.headphones) { /* TODO */ }
9
10navigator.b2g.audioChannelManager.onheadphoneschange = () => {
11 /* TODO */
12};
Speaker Manager
It’s also possible to force audio play through the device’s built-in speakers using the Speaker Manager API, available via global constructors.
1// KaiOS 2.5
2const speakerManager = new SpeakerManager();
3
4// KaiOS 3.0
5const speakerManager = new MozSpeakerManager();
6
7if (speakerManager.speakerforced) { /* TODO */ }
8speakerManager.forcespeaker = true;
9speakerManager.onspeakerforcedchange = () => { /* TODO */ };
The main use case for the Speaker Manager API is building an FM Radio app. Most devices require headphones be plugged in to serve as the FM antenna, but users might still want to listen through built-in speakers.
Note: the Speaker Manager API is available via the "speaker-control"
permission, and is only allowed in Privileged & Certified apps.
Extras
KeyEvents
KaiOS supports several Media Keys for headphone media playback controls, including:
MediaTrackNext
MediaTrackPrevious
MediaPlay
MediaStop
MediaPause
MediaPlayPause
MediaFastForward
MediaRewind
These are defined in b2g/chrome/content/shell.js
, and broadcast via the
System Messages headset-button
and media-button
.
Note: Media KeyEvents may not work as expected in third-party apps for Bluetooth AVRCP media controls. The pre-installed Music & FM Radio apps always handle these events, which can trigger simultaneous audio playback.
Autoplay
If you are developing a hosted web or progressive web app (PWA), then it’s important to check if autoplay is enabled. KaiOS 2.5 has a special boolean property, mozAutoplayEnabled
, that’s true when autoplay is available.
1const audio = document.createElement('audio');
2audio.muted = true;
3if (audio.mozAutoplayEnabled) {
4 /* TODO */
5}
Note: Autoplay should be available by default for Privileged & Certified apps.
Audio Capture
Recording audio using the standard
MediaStream Recording API requires the "audio-capture"
permission, which will prompt the user to grant permission (except in Certified apps).
Media Fragments
Like standard browsers, KaiOS supports
Media Fragments, including a few special identifiers. For the purposes of media playback, these can be used to adjust start time, allow temporal clipping using the Normal Play Time (NPT) format, and select specific tracks for playback. URL Fragments (aka URL Hash) are identified after the #
character and are not sent server-side. Here is an example of a temporal media fragment:
1https://www.example.org/audio.ogg#t=20
Note: For KaiOS media fragment parsing logic, see nsMediaFragmentURIParser.cpp.
Seeking
Although not KaiOS specific, both it’s worth mentioning that there is a method for seeking media content,
HTMLMediaElement.fastSeek
which seeks to the nearest keyframe (SeekTarget::PrevSyncPoint
) rather than accurately seeking (SeekTarget::Accurate
) to the specified timestamp.
1if ('fastSeek' in audio) {
2 audio.fastSeek(time);
3} else {
4 audio.currentTime = time;
5}
Fast seeking is available on Firefox, KaiOS, and Safari. It quickly seeks the media to the new time with precision tradeoff.
Conclusion
KaiOS provides applications with several options for developing rich multimedia experiences. These are integral to developing quality user experiences for music and podcast apps like PodLP, but can provide complex to manage across two OS versions. If you find these details daunting and need support developing top-notch multimedia experiences on KaiOS, contact the author from the About page.