Skip to content

Audio

Sound plays audio, Recorder records it, and Audio.set_mode sets how the app's audio relates to the device and other apps. Enable it with use = ["audio"] under [plugins]. See the Audio guide.

Audio playback and recording.

Enable it in pythonnative.toml. Playback needs nothing else; recording also needs a microphone usage string:

[plugins]
use = ["audio"]

[permissions]
microphone = "Record voice notes."
Example
from pythonnative.audio import Audio, Recorder, Sound

async def chime() -> None:
    Audio.set_mode(category="playback")
    sound = await Sound.load("https://example.com/chime.mp3")
    sound.on_end(sound.unload)
    sound.play()

async def voice_note() -> None:
    recorder = await Recorder.start()
    await asyncio.sleep(3)
    recording = await recorder.stop()
    async with await Sound.load(recording.path) as sound:
        sound.play()
        await asyncio.sleep(recording.duration)

Classes:

Name Description
Recording

A finished recording.

Sound

One loaded sound. Create it with Sound.load.

Recorder

A recording in progress. Create it with Recorder.start.

Audio

App-wide audio behavior.

Attributes:

Name Type Description
AudioCategory

An AVAudioSession category, spelled in Python's style.

RecordingQuality

AAC in an MPEG-4 container at 16 kHz and 32 kbps, 22 kHz and 64 kbps, or 44.1 kHz and 128 kbps.

SoundSource

An http(s) URL, a file path, a bundled Asset, or a path under app/assets/.

AudioCategory module-attribute

AudioCategory = Literal[
    "ambient",
    "solo_ambient",
    "playback",
    "record",
    "play_and_record",
    "multi_route",
]

An AVAudioSession category, spelled in Python's style.

RecordingQuality module-attribute

RecordingQuality = Literal['low', 'medium', 'high']

AAC in an MPEG-4 container at 16 kHz and 32 kbps, 22 kHz and 64 kbps, or 44.1 kHz and 128 kbps.

SoundSource module-attribute

SoundSource = Union[str, Asset, 'os.PathLike[str]']

An http(s) URL, a file path, a bundled Asset, or a path under app/assets/.

Recording dataclass

Recording(path: str, duration: float)

A finished recording.

Attributes:

Name Type Description
path str

Absolute path of the .m4a file.

duration float

Recorded length in seconds, not counting pauses.

Sound

Sound(id: int, *, looping: bool = False)

One loaded sound. Create it with Sound.load.

After a sound plays to its end, it rewinds to the start, so play() plays it again. Playback pauses when the app goes to the background.

Using it as an async context manager unloads it on exit:

async with await Sound.load(asset) as sound:
    sound.play()

Raises:

Type Description
NativeModuleError

From any method once the sound is unloaded, with the code unloaded.

Methods:

Name Description
load

Load source, ready to play. Playback doesn't need any permission.

play

Start or resume playback.

pause

Pause, keeping the position.

stop

Stop and rewind to the start. The sound stays loaded.

seek

Jump to seconds from the start.

set_volume

Set the level from 0.0 to 1.0.

set_rate

Set the speed, where 1.0 is normal. Pitch is preserved.

on_end

Call callback each time the sound plays to its end.

unload

Release the player. Calling it again does nothing.

Attributes:

Name Type Description
looping bool

Whether the sound restarts at its end. A looping sound doesn't call on_end callbacks.

position float

The current position in seconds.

duration float

The length in seconds, or 0 when it isn't known (a live stream).

looping property writable

looping: bool

Whether the sound restarts at its end. A looping sound doesn't call on_end callbacks.

position property

position: float

The current position in seconds.

duration property

duration: float

The length in seconds, or 0 when it isn't known (a live stream).

load async classmethod

load(
    source: SoundSource,
    *,
    volume: float = 1.0,
    rate: float = 1.0,
    looping: bool = False
) -> "Sound"

Load source, ready to play. Playback doesn't need any permission.

Parameters:

Name Type Description Default
source SoundSource

What to play: an http(s) URL, a file path, a bundled Asset, or a path under app/assets/.

required
volume float

Initial level from 0.0 to 1.0.

1.0
rate float

Initial speed, where 1.0 is normal.

1.0
looping bool

Whether to restart at the end.

False

Returns:

Type Description
'Sound'

The loaded sound.

Raises:

Type Description
NativeModuleError

With the code load_failed when the source can't be read or decoded, or plugin_not_enabled when audio isn't in the build.

play

play() -> None

Start or resume playback.

pause

pause() -> None

Pause, keeping the position.

stop

stop() -> None

Stop and rewind to the start. The sound stays loaded.

seek

seek(seconds: float) -> None

Jump to seconds from the start.

set_volume

set_volume(volume: float) -> None

Set the level from 0.0 to 1.0.

set_rate

set_rate(rate: float) -> None

Set the speed, where 1.0 is normal. Pitch is preserved.

on_end

on_end(callback: Callable[[], Any]) -> Callable[[], None]

Call callback each time the sound plays to its end.

Parameters:

Name Type Description Default
callback Callable[[], Any]

Takes no arguments. It may call unload.

required

Returns:

Type Description
Callable[[], None]

A function that removes the callback.

unload

unload() -> None

Release the player. Calling it again does nothing.

Recorder

Recorder(id: int)

A recording in progress. Create it with Recorder.start.

Methods:

Name Description
start

Prompt for the microphone if needed, and start recording.

pause

Pause recording. The paused time doesn't count toward the duration.

resume

Continue a paused recording in the same file.

metering

The current input level in decibels relative to full scale, from -160 (silence) to 0.

stop

Finish the file.

start async classmethod

start(
    path: Optional[str] = None,
    quality: RecordingQuality = "high",
) -> "Recorder"

Prompt for the microphone if needed, and start recording.

Needs microphone under [permissions] in pythonnative.toml. It isn't a build requirement of the plugin, since playback alone doesn't use the microphone, so this is where a missing entry surfaces.

Parameters:

Name Type Description Default
path Optional[str]

Where to write the .m4a file. A relative path is under the app's cache directory. When None, a new file there.

None
quality RecordingQuality

The encoding settings.

'high'

Returns:

Type Description
'Recorder'

The running recorder.

Raises:

Type Description
NativeModuleError

With the code missing_usage_string when the app doesn't declare microphone under [permissions], permission_denied when the user refuses, recording_failed when the system can't start recording in time, or plugin_not_enabled when audio isn't in the build.

pause

pause() -> None

Pause recording. The paused time doesn't count toward the duration.

resume

resume() -> None

Continue a paused recording in the same file.

metering

metering() -> float

The current input level in decibels relative to full scale, from -160 (silence) to 0.

stop async

stop() -> Recording

Finish the file.

Returns:

Type Description
Recording

The finished Recording.

Raises:

Type Description
NativeModuleError

With the code recording_failed when no audio was captured, or stopped when it's already finished.

Audio

App-wide audio behavior.

Methods:

Name Description
set_mode

Set how the app's audio relates to the device and to other apps.

set_mode staticmethod

set_mode(
    *,
    category: AudioCategory = "playback",
    mix_with_others: bool = False,
    duck_others: bool = False,
    default_to_speaker: bool = False,
    allow_bluetooth: bool = False
) -> None

Set how the app's audio relates to the device and to other apps.

This is mainly iOS's AVAudioSession. Each call replaces the whole mode. Without a call, iOS uses solo_ambient, which the silent switch mutes; call this with category="playback" for sound the user asked to hear. A running Recorder switches to play_and_record and restores this mode when it stops.

Android has no categories, so category, default_to_speaker, and allow_bluetooth have no effect there. mix_with_others and duck_others control whether a Sound takes audio focus, which pauses or lowers other apps. In the browser preview this does nothing.

Parameters:

Name Type Description Default
category AudioCategory

The AVAudioSession category.

'playback'
mix_with_others bool

Play alongside other apps' audio.

False
duck_others bool

Play over other apps' audio, lowering it.

False
default_to_speaker bool

With play_and_record, use the speaker rather than the receiver.

False
allow_bluetooth bool

With record or play_and_record, offer Bluetooth headsets as inputs.

False

Raises:

Type Description
NativeModuleError

With the code invalid_mode when iOS rejects the combination.