Skip to content

Commit a443567

Browse files
committed
fix: everything working except info while phone is locked
1 parent e2212e0 commit a443567

File tree

2 files changed

+148
-58
lines changed

2 files changed

+148
-58
lines changed

apps/common-app/src/examples/AudioFile/AudioFile.tsx

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ import {
66
AudioBufferSourceNode,
77
AudioManager,
88
} from 'react-native-audio-api';
9+
import { AudioPlayer } from '../../utils/AudioPlayer';
910

1011
import { Container, Button, Spacer, Slider } from '../../components';
1112

1213
const URL =
1314
'https://software-mansion.github.io/react-native-audio-api/audio/voice/example-voice-01.mp3';
1415

15-
const LOOP_START = 0;
16-
const LOOP_END = 10;
17-
1816
const INITIAL_RATE = 1;
19-
const INITIAL_DETUNE = 0;
17+
const TRACK_LENGTH = 25;
2018

2119
const labelWidth = 80;
2220

@@ -26,72 +24,71 @@ const AudioFile: FC = () => {
2624

2725
const [offset, setOffset] = useState(0);
2826
const [playbackRate, setPlaybackRate] = useState(INITIAL_RATE);
29-
const [detune, setDetune] = useState(INITIAL_DETUNE);
27+
const [elapsedTime, setElapsedTime] = useState(0);
3028

3129
const [audioBuffer, setAudioBuffer] = useState<AudioBuffer | null>(null);
32-
33-
const audioContextRef = useRef<AudioContext | null>(null);
34-
const bufferSourceRef = useRef<AudioBufferSourceNode | null>(null);
30+
const timerRef = useRef<NodeJS.Timeout | null>(null);
3531

3632
const handlePlaybackRateChange = (newValue: number) => {
3733
setPlaybackRate(newValue);
38-
39-
if (bufferSourceRef.current) {
40-
bufferSourceRef.current.playbackRate.value = newValue;
41-
}
34+
audioPlayer.setPlaybackRate(newValue);
4235
};
4336

44-
const handleDetuneChange = (newValue: number) => {
45-
setDetune(newValue);
37+
const audioContext = useMemo(() => new AudioContext(), []);
38+
const audioPlayer = useMemo(() => new AudioPlayer(audioContext), []);
4639

47-
if (bufferSourceRef.current) {
48-
bufferSourceRef.current.detune.value = newValue;
40+
useEffect(() => {
41+
return () => {
42+
audioPlayer.stop();
43+
audioContext.close();
4944
}
50-
};
45+
}, []);
46+
47+
useEffect(() => {
48+
timerRef.current = setTimeout(() => {
49+
if (isPlaying) {
50+
setElapsedTime((prev) => prev + 1);
51+
}
52+
}, 1000 / playbackRate);
53+
54+
return () => clearTimeout(timerRef.current!);
55+
}, [isPlaying, playbackRate, elapsedTime]);
56+
57+
useEffect(() => {
58+
AudioManager.setLockScreenInfo({
59+
elapsedTime: elapsedTime * 1000,
60+
});
61+
if (elapsedTime > TRACK_LENGTH) {
62+
setElapsedTime(0);
63+
setIsPlaying(false);
64+
audioPlayer.stop();
65+
AudioManager.setLockScreenInfo({
66+
state: 'state_paused',
67+
});
68+
}
69+
}, [elapsedTime]);
5170

52-
const handlePress = () => {
53-
if (!audioContextRef.current) {
54-
return;
55-
}
5671

72+
const handlePress = useCallback(() => {
5773
if (isPlaying) {
58-
bufferSourceRef.current?.stop(audioContextRef.current.currentTime);
74+
audioPlayer.stop();
5975
AudioManager.setLockScreenInfo({
6076
state: 'state_paused',
6177
});
6278
} else {
6379
if (!audioBuffer) {
6480
fetchAudioBuffer();
6581
}
66-
6782
AudioManager.setLockScreenInfo({
6883
state: 'state_playing',
69-
});
70-
71-
AudioManager.observeAudioInterruptions(true);
72-
73-
bufferSourceRef.current = audioContextRef.current.createBufferSource({
74-
pitchCorrection: true,
75-
});
76-
bufferSourceRef.current.buffer = audioBuffer;
77-
bufferSourceRef.current.loop = true;
78-
bufferSourceRef.current.onended = (event) => {
79-
setOffset((_prev) => event.value || 0);
80-
};
81-
bufferSourceRef.current.loopStart = LOOP_START;
82-
bufferSourceRef.current.loopEnd = LOOP_END;
83-
bufferSourceRef.current.playbackRate.value = playbackRate;
84-
bufferSourceRef.current.detune.value = detune;
85-
bufferSourceRef.current.connect(audioContextRef.current.destination);
86-
87-
bufferSourceRef.current.start(
88-
audioContextRef.current.currentTime,
89-
offset
90-
);
84+
})
85+
audioPlayer.buffer = audioBuffer!;
86+
audioPlayer.playbackRate = playbackRate;
87+
audioPlayer.play();
9188
}
9289

9390
setIsPlaying((prev) => !prev);
94-
};
91+
}, [isPlaying, audioBuffer, playbackRate]);
9592

9693
const fetchAudioBuffer = useCallback(async () => {
9794
setIsLoading(true);
@@ -120,7 +117,7 @@ const AudioFile: FC = () => {
120117
title: 'Audio file',
121118
artist: 'Software Mansion',
122119
album: 'Audio API',
123-
duration: 10,
120+
duration: TRACK_LENGTH,
124121
});
125122

126123
const remotePlaySubscription = AudioManager.enableSystemEvent(
@@ -141,7 +138,15 @@ const AudioFile: FC = () => {
141138
AudioManager.enableSystemEvent(
142139
'remoteChangePlaybackPosition',
143140
(event) => {
144-
console.log('remoteChangePlaybackPosition event:', event);
141+
audioPlayer.stop();
142+
if (isPlaying) {
143+
audioPlayer.play(
144+
event.value || 0
145+
);
146+
} else {
147+
audioPlayer.offset = event.value || 0;
148+
}
149+
setElapsedTime(event.value || 0);
145150
}
146151
);
147152

@@ -183,16 +188,6 @@ const AudioFile: FC = () => {
183188
step={0.25}
184189
minLabelWidth={labelWidth}
185190
/>
186-
<Spacer.Vertical size={20} />
187-
<Slider
188-
label="Detune"
189-
value={detune}
190-
onValueChange={handleDetuneChange}
191-
min={-1200}
192-
max={1200}
193-
step={100}
194-
minLabelWidth={labelWidth}
195-
/>
196191
</Container>
197192
);
198193
};
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { AudioContext, AudioBuffer, AudioManager, AudioBufferSourceNode } from "react-native-audio-api";
2+
3+
export class AudioPlayer {
4+
private _audioContext: AudioContext;
5+
private _isPlaying: boolean;
6+
private _buffer: AudioBuffer | null = null;
7+
private _bufferSource: AudioBufferSourceNode | null = null;
8+
private _detune: number = 0;
9+
private _playbackRate: number = 1;
10+
private _offset: number = 0;
11+
12+
constructor(audioContext: AudioContext) {
13+
this._audioContext = audioContext;
14+
this._isPlaying = false;
15+
}
16+
17+
public set buffer(buffer: AudioBuffer) {
18+
this._buffer = buffer;
19+
}
20+
21+
public set offset(offset: number) {
22+
this._offset = offset;
23+
}
24+
25+
public set detune(value: number) {
26+
this._detune = value;
27+
}
28+
29+
public set playbackRate(value: number) {
30+
this._playbackRate = value;
31+
}
32+
33+
public get isPlaying(): boolean {
34+
return this._isPlaying;
35+
}
36+
37+
public play(offset?: number): void {
38+
if (!this._buffer) {
39+
throw new Error("Audio buffer is not set");
40+
}
41+
this._bufferSource?.stop(this._audioContext.currentTime);
42+
this._bufferSource = this._audioContext.createBufferSource({pitchCorrection: true});
43+
this._bufferSource.buffer = this._buffer;
44+
this._bufferSource.playbackRate.value = this._playbackRate;
45+
this._bufferSource.detune.value = this._detune;
46+
this._bufferSource.onended = (event) => {
47+
this._offset = event.value;
48+
}
49+
this._bufferSource.connect(this._audioContext.destination);
50+
if (offset === undefined) {
51+
this._bufferSource.start(this._audioContext.currentTime, this._offset || 0);
52+
} else {
53+
this._bufferSource.start(this._audioContext.currentTime, offset);
54+
}
55+
}
56+
57+
public stop(): void {
58+
this._bufferSource?.stop(this._audioContext.currentTime);
59+
}
60+
61+
public setDetune(value: number): void {
62+
if (this._bufferSource) {
63+
this._bufferSource.detune.value = value;
64+
}
65+
}
66+
67+
public setPlaybackRate(value: number): void {
68+
if (this._bufferSource) {
69+
this._bufferSource.playbackRate.value = value;
70+
}
71+
}
72+
73+
public enableLoop(loop_start: number, loop_end: number): void {
74+
if (loop_start > loop_end) {
75+
throw new Error("Loop start time must be less than loop end time");
76+
}
77+
if (this._bufferSource) {
78+
this._bufferSource.loop = true;
79+
this._bufferSource.loopStart = loop_start;
80+
this._bufferSource.loopEnd = loop_end;
81+
}
82+
}
83+
84+
public disableLoop(): void {
85+
if (this._bufferSource) {
86+
this._bufferSource.loop = false;
87+
}
88+
}
89+
90+
public setOnendedCallback(callback: () => void): void {
91+
if (this._bufferSource) {
92+
this._bufferSource.onended = callback;
93+
};
94+
}
95+
}

0 commit comments

Comments
 (0)