@@ -38,6 +38,7 @@ const INITIAL_STATE: AudioPlayerState = {
3838
3939export type AudioPlayerOptions = AudioDescriptor & {
4040 playbackRates ?: number [ ] ;
41+ previewVoiceRecording ?: boolean ;
4142} ;
4243
4344export class AudioPlayer {
@@ -46,11 +47,14 @@ export class AudioPlayer {
4647 private _id : string ;
4748 private type : 'voiceRecording' | 'audio' ;
4849 private isExpoCLI : boolean ;
50+ // This is a temporary flag to manage audio player for voice recording in preview as the one in message list uses react-native-video.
51+ private previewVoiceRecording : boolean ;
4952
5053 constructor ( options : AudioPlayerOptions ) {
5154 this . isExpoCLI = NativeHandlers . SDK === 'stream-chat-expo' ;
5255 this . _id = options . id ;
5356 this . type = options . type ;
57+ this . previewVoiceRecording = options . previewVoiceRecording ?? false ;
5458 const playbackRates = options . playbackRates ?? DEFAULT_PLAYBACK_RATES ;
5559 this . state = new StateStore < AudioPlayerState > ( {
5660 ...INITIAL_STATE ,
@@ -68,6 +72,19 @@ export class AudioPlayer {
6872 this . playerRef = playerRef ;
6973 return ;
7074 }
75+ if ( this . previewVoiceRecording ) {
76+ if ( NativeHandlers . Audio ?. startPlayer ) {
77+ await NativeHandlers . Audio . startPlayer (
78+ uri ,
79+ { } ,
80+ this . onVoiceRecordingPreviewPlaybackStatusUpdate ,
81+ ) ;
82+ if ( NativeHandlers . Audio ?. pausePlayer ) {
83+ await NativeHandlers . Audio . pausePlayer ( ) ;
84+ }
85+ }
86+ return ;
87+ }
7188 if ( ! this . isExpoCLI || ! uri ) {
7289 return ;
7390 }
@@ -80,6 +97,15 @@ export class AudioPlayer {
8097 }
8198 } ;
8299
100+ onVoiceRecordingPreviewPlaybackStatusUpdate = async ( playbackStatus : PlaybackStatus ) => {
101+ const currentProgress = playbackStatus . currentPosition / playbackStatus . duration ;
102+ if ( currentProgress === 1 ) {
103+ await this . stop ( ) ;
104+ } else {
105+ this . progress = currentProgress ;
106+ }
107+ } ;
108+
83109 // This should be a arrow function to avoid binding the function to the instance
84110 onPlaybackStatusUpdate = async ( playbackStatus : PlaybackStatus ) => {
85111 if ( ! playbackStatus . isLoaded ) {
@@ -92,13 +118,13 @@ export class AudioPlayer {
92118 // Update your UI for the loaded state
93119 // This is done for Expo CLI where we don't get file duration from file picker
94120
95- // The duration given by the expo-av is not same as the one of the voice recording, so we take the actual duration for voice recording.
96121 if ( this . type !== 'voiceRecording' ) {
97122 this . duration = durationMillis ;
98123 }
99124
100125 // Update the position of the audio player when it is playing
101126 if ( playbackStatus . isPlaying ) {
127+ // The duration given by the expo-av is not same as the one of the voice recording, so we take the actual duration for voice recording.
102128 if ( this . type === 'voiceRecording' ) {
103129 if ( positionMillis <= this . duration ) {
104130 this . position = positionMillis ;
@@ -108,12 +134,6 @@ export class AudioPlayer {
108134 this . position = positionMillis ;
109135 }
110136 }
111- } else {
112- // Update your UI for the paused state
113- }
114-
115- if ( playbackStatus . isBuffering ) {
116- // Update your UI for the buffering state
117137 }
118138
119139 // Update the UI when the audio is finished playing
@@ -199,9 +219,24 @@ export class AudioPlayer {
199219 }
200220
201221 _playInternal ( ) {
202- if ( this . isPlaying || ! this . playerRef ) {
222+ if ( this . isPlaying ) {
203223 return ;
204224 }
225+
226+ if ( this . previewVoiceRecording ) {
227+ if ( NativeHandlers . Audio ?. resumePlayer ) {
228+ NativeHandlers . Audio . resumePlayer ( ) ;
229+ }
230+ this . state . partialNext ( {
231+ isPlaying : true ,
232+ } ) ;
233+ return ;
234+ }
235+
236+ if ( ! this . playerRef ) {
237+ return ;
238+ }
239+
205240 if ( this . isExpoCLI ) {
206241 if ( this . playerRef ?. playAsync ) {
207242 this . playerRef . playAsync ( ) ;
@@ -217,9 +252,23 @@ export class AudioPlayer {
217252 }
218253
219254 _pauseInternal ( ) {
220- if ( ! this . isPlaying || ! this . playerRef ) {
255+ if ( ! this . isPlaying ) {
221256 return ;
222257 }
258+ if ( this . previewVoiceRecording ) {
259+ if ( NativeHandlers . Audio ?. pausePlayer ) {
260+ NativeHandlers . Audio . pausePlayer ( ) ;
261+ }
262+ this . state . partialNext ( {
263+ isPlaying : false ,
264+ } ) ;
265+ return ;
266+ }
267+
268+ if ( ! this . playerRef ) {
269+ return ;
270+ }
271+
223272 if ( this . isExpoCLI ) {
224273 if ( this . playerRef ?. pauseAsync ) {
225274 this . playerRef . pauseAsync ( ) ;
@@ -243,6 +292,13 @@ export class AudioPlayer {
243292 }
244293
245294 async seek ( positionInSeconds : number ) {
295+ if ( this . previewVoiceRecording ) {
296+ this . position = positionInSeconds ;
297+ if ( NativeHandlers . Audio ?. seekToPlayer ) {
298+ NativeHandlers . Audio . seekToPlayer ( positionInSeconds * 1000 ) ;
299+ }
300+ return ;
301+ }
246302 if ( ! this . playerRef ) {
247303 return ;
248304 }
@@ -272,6 +328,17 @@ export class AudioPlayer {
272328 }
273329
274330 onRemove ( ) {
331+ if ( this . previewVoiceRecording ) {
332+ if ( NativeHandlers . Audio ?. stopPlayer ) {
333+ NativeHandlers . Audio . stopPlayer ( ) ;
334+ }
335+ this . state . partialNext ( {
336+ ...INITIAL_STATE ,
337+ currentPlaybackRate : this . playbackRates [ 0 ] ,
338+ playbackRates : DEFAULT_PLAYBACK_RATES ,
339+ } ) ;
340+ return ;
341+ }
275342 if ( this . isExpoCLI ) {
276343 if ( this . playerRef ?. stopAsync && this . playerRef . unloadAsync ) {
277344 this . playerRef . stopAsync ( ) ;
0 commit comments