Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f4af099
feat: new android notification system
poneciak57 Nov 10, 2025
3cbbb8e
feat: playback notification in new system
poneciak57 Nov 11, 2025
11249a7
chore: formatting
poneciak57 Nov 11, 2025
30c524f
fix: fixed some issues and dropped old FS
poneciak57 Nov 12, 2025
5563fdf
chore: minor touches
poneciak57 Nov 12, 2025
ea93261
feat: types update
poneciak57 Nov 13, 2025
59c02e6
feat: docs draft
miloszwielgus Nov 13, 2025
12db627
fix: minor doc imrovements
miloszwielgus Nov 13, 2025
8b8a402
feat: recording notification
poneciak57 Nov 13, 2025
260d781
Merge branch 'feat/fs_android_recording' of https://github.com/softwa…
poneciak57 Nov 13, 2025
0812d1c
chore: formatting
poneciak57 Nov 13, 2025
61624a5
feat: recording notification manager docs
miloszwielgus Nov 13, 2025
1300350
feat: mock web methods
miloszwielgus Nov 14, 2025
af1ebd7
feat: ios omfg why is it so bad
poneciak57 Nov 14, 2025
6ac246a
chore: formatting
poneciak57 Nov 16, 2025
e218cc8
feat: changed recording notification to be simpler
poneciak57 Nov 20, 2025
d5c87e4
feat: added more options to recording notification
poneciak57 Nov 20, 2025
3a3b9f5
chore: formatting
poneciak57 Nov 20, 2025
dbe4abb
Merge branch 'main' into feat/fs_android_recording
poneciak57 Nov 20, 2025
b432ff7
chore: formatting
poneciak57 Nov 20, 2025
313eaa6
chore: bump ktlint to 1.7
poneciak57 Nov 20, 2025
42e6259
chore: docs updt
poneciak57 Nov 24, 2025
a980113
docs: added examples to documentation
poneciak57 Nov 24, 2025
4b9c13e
feat: made foreground service more centralized
poneciak57 Nov 24, 2025
35a19b6
feat: made foreground service more centralized
poneciak57 Nov 24, 2025
e02c3d1
chore: neatpicks
poneciak57 Nov 24, 2025
5a5dcc3
docs: better color for dark theme
mdydek Nov 25, 2025
ff4f914
feat: removed unused android imports
mdydek Nov 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ runs:
- name: Install ktlint
shell: bash
run: |
curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.5.0/ktlint
curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.7.0/ktlint
chmod a+x ktlint
sudo mv ktlint /usr/local/bin/

Expand Down
99 changes: 64 additions & 35 deletions apps/common-app/src/examples/AudioFile/AudioFile.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useState, FC } from 'react';
import { ActivityIndicator, View, StyleSheet } from 'react-native';
import { AudioManager } from 'react-native-audio-api';
import { AudioManager, PlaybackNotificationManager } from 'react-native-audio-api';
import { Container, Button, Spacer } from '../../components';
import AudioPlayer from './AudioPlayer';
import { colors } from '../../styles';
Expand All @@ -13,6 +13,7 @@ const AudioFile: FC = () => {
const [isPlaying, setIsPlaying] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [positionPercentage, setPositionPercentage] = useState(0);
const [shouldResume, setShouldResume] = useState(false);

const togglePlayPause = async () => {
if (isPlaying) {
Expand Down Expand Up @@ -41,76 +42,104 @@ const AudioFile: FC = () => {
}, []);

useEffect(() => {
AudioManager.setLockScreenInfo({
title: 'Audio file',
artist: 'Software Mansion',
album: 'Audio API',
duration: 10,
});

AudioManager.enableRemoteCommand('remotePlay', true);
AudioManager.enableRemoteCommand('remotePause', true);
AudioManager.enableRemoteCommand('remoteSkipForward', true);
AudioManager.enableRemoteCommand('remoteSkipBackward', true);
// Register notification first
const setupNotification = async () => {
try {
await PlaybackNotificationManager.register();

// Load audio buffer first
await fetchAudioBuffer();

// Show notification with correct duration after buffer is loaded
const duration = AudioPlayer.getDuration();
await PlaybackNotificationManager.show({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add also RecordingNotificationManager to the recording example

title: 'Audio file',
artist: 'Software Mansion',
album: 'Audio API',
duration: duration,
state: 'paused',
speed: 1.0,
elapsedTime: 0,
});
} catch (error) {
console.error('Failed to setup notification:', error);
}
};

setupNotification();

AudioManager.observeAudioInterruptions(true);
AudioManager.activelyReclaimSession(true);

const remotePlaySubscription = AudioManager.addSystemEventListener(
'remotePlay',
// Listen to notification control events
const playListener = PlaybackNotificationManager.addEventListener(
'playbackNotificationPlay',
() => {
AudioPlayer.play();
setIsPlaying(true);
}
);

const remotePauseSubscription = AudioManager.addSystemEventListener(
'remotePause',
const pauseListener = PlaybackNotificationManager.addEventListener(
'playbackNotificationPause',
() => {
AudioPlayer.pause();
setIsPlaying(false);
}
);

const remoteSkipForwardSubscription = AudioManager.addSystemEventListener(
'remoteSkipForward',
const skipForwardListener = PlaybackNotificationManager.addEventListener(
'playbackNotificationSkipForward',
(event) => {
AudioPlayer.seekBy(event.value);
}
);

const remoteSkipBackwardSubscription = AudioManager.addSystemEventListener(
'remoteSkipBackward',
const skipBackwardListener = PlaybackNotificationManager.addEventListener(
'playbackNotificationSkipBackward',
(event) => {
AudioPlayer.seekBy(-event.value);
}
);

// Keep interruption handling through AudioManager
const interruptionSubscription = AudioManager.addSystemEventListener(
'interruption',
async (event) => {
if (event.type === 'began') {
await AudioPlayer.pause();
setIsPlaying(false);
} else if (event.type === 'ended' && event.shouldResume) {
BackgroundTimer.setTimeout(async () => {
AudioManager.setAudioSessionActivity(true);
await AudioPlayer.play();
setIsPlaying(true);
}, 1000);
// Store whether we were playing before interruption
setShouldResume(isPlaying && event.isTransient);

if (isPlaying) {
await AudioPlayer.pause();
setIsPlaying(false);
}
} else if (event.type === 'ended') {

if (shouldResume) {
BackgroundTimer.setTimeout(async () => {
AudioManager.setAudioSessionActivity(true);
await AudioPlayer.play();
setIsPlaying(true);
console.log('Auto-resumed after transient interruption');
}, 500);
}

// Reset the flag
setShouldResume(false);
}
}
);

fetchAudioBuffer();

return () => {
remotePlaySubscription?.remove();
remotePauseSubscription?.remove();
remoteSkipForwardSubscription?.remove();
remoteSkipBackwardSubscription?.remove();
playListener.remove();
pauseListener.remove();
skipForwardListener.remove();
skipBackwardListener.remove();
interruptionSubscription?.remove();
AudioManager.resetLockScreenInfo();
PlaybackNotificationManager.unregister();
AudioPlayer.reset();
console.log('Cleanup AudioFile component');
};
}, [fetchAudioBuffer]);

Expand Down
16 changes: 11 additions & 5 deletions apps/common-app/src/examples/AudioFile/AudioPlayer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AudioContext, AudioManager } from 'react-native-audio-api';
import { AudioContext, PlaybackNotificationManager } from 'react-native-audio-api';
import type {
AudioBufferSourceNode,
AudioBuffer,
Expand Down Expand Up @@ -58,8 +58,9 @@ class AudioPlayer {

this.sourceNode.start(this.audioContext.currentTime, this.offset);

AudioManager.setLockScreenInfo({
state: 'state_playing',
PlaybackNotificationManager.update({
state: 'playing',
elapsedTime: this.offset,
});
};

Expand All @@ -71,8 +72,9 @@ class AudioPlayer {

this.sourceNode?.stop(this.audioContext.currentTime);

AudioManager.setLockScreenInfo({
state: 'state_paused',
PlaybackNotificationManager.update({
state: 'paused',
elapsedTime: this.offset,
});

await this.audioContext.suspend();
Expand Down Expand Up @@ -133,6 +135,10 @@ class AudioPlayer {
) => {
this.onPositionChanged = callback;
};

getDuration = (): number => {
return this.audioBuffer?.duration ?? 0;
};
}

export default new AudioPlayer();
Loading