Audio and Volume Control in KaiOS

Posted by Tom Barrasso on (updated on )

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 ChannelWeb
PWA
Privileged
Signed
Certified
Core
normal☑️☑️☑️
content☑️☑️☑️
notificationX☑️☑️
alarmX☑️☑️
systemX☑️☑️
ringerXX☑️
publicnotificationXX☑️

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 HTMLMediaElements and AudioContexts 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.

KaiOS Volume HUD. Nokia 8110 4G (left), Orange Neva Mini (right)
KaiOS Volume HUD. Nokia 8110 4G (left), Orange Neva Mini (right)

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 KeyEvents 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.

Volume Settings Page
Volume Settings Page

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 */ };

FM Radio App
FM Radio App

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).

Microphone Permission Dialog
Microphone Permission Dialog

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.