@@ -139,7 +139,11 @@ export function AudioPlayer() {
139139 barRadius : 2 ,
140140 height : 80 ,
141141 normalize : true ,
142- backend : 'WebAudio' ,
142+ // Use MediaElement backend (default). Unlike the WebAudio backend,
143+ // MediaElement uses a standard <audio> element for playback which
144+ // benefits from the browser/webview's built-in audio session recovery.
145+ // This prevents audio loss when another app steals audio output or
146+ // the system audio session is interrupted.
143147 interact : true , // Enable interaction (click to seek)
144148 mediaControls : false , // Don't show native controls
145149 } ) ;
@@ -189,15 +193,6 @@ export function AudioPlayer() {
189193 const currentVolume = usePlayerStore . getState ( ) . volume ;
190194 wavesurfer . setVolume ( currentVolume ) ;
191195
192- // Get the underlying audio element and ensure it's not muted
193- // (unless we're using native playback, which will be set later)
194- const mediaElement = wavesurfer . getMediaElement ( ) ;
195- if ( mediaElement && ! isUsingNativePlaybackRef . current ) {
196- mediaElement . volume = currentVolume ;
197- mediaElement . muted = false ;
198- debug . log ( 'Audio element volume:' , mediaElement . volume , 'muted:' , mediaElement . muted ) ;
199- }
200-
201196 // Auto-play when ready - check if we should use native playback
202197 // Get current values from the store and queries at runtime (not captured closure values)
203198 const currentAudioUrl = usePlayerStore . getState ( ) . audioUrl ;
@@ -264,21 +259,8 @@ export function AudioPlayer() {
264259 debug . log ( 'Should use native playback:' , shouldUseNative ) ;
265260
266261 if ( ! shouldUseNative ) {
267- debug . log ( 'No custom devices assigned, falling back to WaveSurfer' ) ;
268- // Reset native playback flag and unmute WaveSurfer
262+ debug . log ( 'No custom devices assigned, using standard playback' ) ;
269263 isUsingNativePlaybackRef . current = false ;
270- const mediaElement = wavesurfer . getMediaElement ( ) ;
271- if ( mediaElement ) {
272- const currentVolume = usePlayerStore . getState ( ) . volume ;
273- mediaElement . volume = currentVolume ;
274- mediaElement . muted = false ;
275- debug . log (
276- 'WaveSurfer unmuted for normal playback - volume:' ,
277- mediaElement . volume ,
278- 'muted:' ,
279- mediaElement . muted ,
280- ) ;
281- }
282264 } else {
283265 const deviceIds = assignedChannels . flatMap ( ( ch : any ) => ch . device_ids ) ;
284266 debug . log ( 'Device IDs to play to:' , deviceIds ) ;
@@ -299,19 +281,10 @@ export function AudioPlayer() {
299281 // Mark that we're using native playback
300282 isUsingNativePlaybackRef . current = true ;
301283
302- // Mute WaveSurfer's audio element to prevent UI audio output
303- // Keep WaveSurfer running for visualization
304- const mediaElement = wavesurfer . getMediaElement ( ) ;
305- if ( mediaElement ) {
306- mediaElement . volume = 0 ;
307- mediaElement . muted = true ;
308- debug . log (
309- 'WaveSurfer muted for native playback - volume:' ,
310- mediaElement . volume ,
311- 'muted:' ,
312- mediaElement . muted ,
313- ) ;
314- }
284+ // Mute WaveSurfer's audio output — native handles the actual sound
285+ // Keep WaveSurfer running for waveform visualization
286+ wavesurfer . setVolume ( 0 ) ;
287+ wavesurfer . setMuted ( true ) ;
315288
316289 // Start WaveSurfer playback for visualization (muted)
317290 wavesurfer . play ( ) . catch ( ( error ) => {
@@ -334,38 +307,15 @@ export function AudioPlayer() {
334307 'Native playback failed during auto-play, falling back to WaveSurfer:' ,
335308 error ,
336309 ) ;
337- // Reset native playback flag and unmute WaveSurfer
338310 isUsingNativePlaybackRef . current = false ;
339- const mediaElement = wavesurfer . getMediaElement ( ) ;
340- if ( mediaElement ) {
341- const currentVolume = usePlayerStore . getState ( ) . volume ;
342- mediaElement . volume = currentVolume ;
343- mediaElement . muted = false ;
344- debug . log (
345- 'WaveSurfer unmuted after native playback failure - volume:' ,
346- mediaElement . volume ,
347- 'muted:' ,
348- mediaElement . muted ,
349- ) ;
350- }
351311 // Fall through to WaveSurfer playback
352312 }
353- } else {
354- debug . log ( 'Not using native playback, using WaveSurfer' ) ;
355- // Reset native playback flag and unmute WaveSurfer
356- isUsingNativePlaybackRef . current = false ;
357- const mediaElement = wavesurfer . getMediaElement ( ) ;
358- if ( mediaElement ) {
359- const currentVolume = usePlayerStore . getState ( ) . volume ;
360- mediaElement . volume = currentVolume ;
361- mediaElement . muted = false ;
362- debug . log (
363- 'WaveSurfer unmuted for normal playback - volume:' ,
364- mediaElement . volume ,
365- 'muted:' ,
366- mediaElement . muted ,
367- ) ;
368- }
313+ }
314+
315+ // Standard playback path — ensure WaveSurfer is unmuted
316+ if ( ! isUsingNativePlaybackRef . current ) {
317+ wavesurfer . setMuted ( false ) ;
318+ wavesurfer . setVolume ( usePlayerStore . getState ( ) . volume ) ;
369319 }
370320
371321 // Only auto-play if shouldAutoPlay flag is set (user explicitly clicked to play)
@@ -389,28 +339,6 @@ export function AudioPlayer() {
389339 // Handle play/pause
390340 wavesurfer . on ( 'play' , ( ) => {
391341 setIsPlaying ( true ) ;
392- // Ensure audio element volume is set correctly
393- const mediaElement = wavesurfer . getMediaElement ( ) ;
394- if ( mediaElement ) {
395- // Double-check: if using native playback, keep WaveSurfer muted
396- // Otherwise, ensure it's unmuted
397- if ( isUsingNativePlaybackRef . current ) {
398- mediaElement . volume = 0 ;
399- mediaElement . muted = true ;
400- debug . log ( 'Playing (native mode) - WaveSurfer muted for visualization only' ) ;
401- } else {
402- // Ensure WaveSurfer is unmuted for normal playback
403- const currentVolume = usePlayerStore . getState ( ) . volume ;
404- mediaElement . volume = currentVolume ;
405- mediaElement . muted = false ;
406- debug . log (
407- 'Playing (normal mode) - volume:' ,
408- mediaElement . volume ,
409- 'muted:' ,
410- mediaElement . muted ,
411- ) ;
412- }
413- }
414342 } ) ;
415343 wavesurfer . on ( 'pause' , ( ) => setIsPlaying ( false ) ) ;
416344 wavesurfer . on ( 'finish' , ( ) => {
@@ -492,11 +420,6 @@ export function AudioPlayer() {
492420 if ( wavesurferRef . current ) {
493421 debug . log ( 'Destroying WaveSurfer instance' ) ;
494422 try {
495- const mediaElement = wavesurferRef . current . getMediaElement ( ) ;
496- if ( mediaElement ) {
497- mediaElement . pause ( ) ;
498- mediaElement . src = '' ;
499- }
500423 wavesurferRef . current . destroy ( ) ;
501424 } catch ( error ) {
502425 debug . error ( 'Error destroying WaveSurfer:' , error ) ;
@@ -537,13 +460,10 @@ export function AudioPlayer() {
537460 }
538461
539462 // Reset native playback flag when loading new audio
540- // Also unmute WaveSurfer if it was muted
463+ // Unmute WaveSurfer if it was muted for native playback
541464 if ( isUsingNativePlaybackRef . current ) {
542- const mediaElement = wavesurfer . getMediaElement ( ) ;
543- if ( mediaElement ) {
544- mediaElement . muted = false ;
545- mediaElement . volume = usePlayerStore . getState ( ) . volume ;
546- }
465+ wavesurfer . setMuted ( false ) ;
466+ wavesurfer . setVolume ( usePlayerStore . getState ( ) . volume ) ;
547467 }
548468 isUsingNativePlaybackRef . current = false ;
549469
@@ -559,16 +479,7 @@ export function AudioPlayer() {
559479 wavesurfer . pause ( ) ;
560480 }
561481
562- // Stop the media element explicitly
563- const mediaElement = wavesurfer . getMediaElement ( ) ;
564- if ( mediaElement ) {
565- debug . log ( 'Stopping media element' ) ;
566- mediaElement . pause ( ) ;
567- mediaElement . currentTime = 0 ;
568- mediaElement . src = '' ;
569- }
570-
571- // Use empty() to completely destroy the waveform and media element
482+ // Use empty() to completely destroy the waveform and reset media
572483 debug . log ( 'Calling wavesurfer.empty() to destroy audio' ) ;
573484 wavesurfer . empty ( ) ;
574485 } catch ( error ) {
@@ -623,20 +534,13 @@ export function AudioPlayer() {
623534 // Sync volume
624535 useEffect ( ( ) => {
625536 if ( wavesurferRef . current ) {
626- wavesurferRef . current . setVolume ( volume ) ;
627- // Also ensure the underlying audio element volume is set
628- const mediaElement = wavesurferRef . current . getMediaElement ( ) ;
629- if ( mediaElement ) {
630- // If using native playback, keep WaveSurfer muted regardless of volume setting
631- if ( isUsingNativePlaybackRef . current ) {
632- mediaElement . volume = 0 ;
633- mediaElement . muted = true ;
634- debug . log ( 'Volume sync: Using native playback, keeping WaveSurfer muted' ) ;
635- } else {
636- mediaElement . volume = volume ;
637- mediaElement . muted = volume === 0 ;
638- debug . log ( 'Volume synced:' , volume , 'muted:' , mediaElement . muted ) ;
639- }
537+ // If using native playback, keep WaveSurfer muted regardless of volume setting
538+ if ( isUsingNativePlaybackRef . current ) {
539+ wavesurferRef . current . setVolume ( 0 ) ;
540+ debug . log ( 'Volume sync: Using native playback, keeping WaveSurfer muted' ) ;
541+ } else {
542+ wavesurferRef . current . setVolume ( volume ) ;
543+ debug . log ( 'Volume synced:' , volume ) ;
640544 }
641545 }
642546 } , [ volume ] ) ;
@@ -757,11 +661,8 @@ export function AudioPlayer() {
757661 isUsingNativePlaybackRef . current = true ;
758662
759663 // Mute WaveSurfer and start it for visualization
760- const mediaElement = wavesurferRef . current . getMediaElement ( ) ;
761- if ( mediaElement ) {
762- mediaElement . volume = 0 ;
763- mediaElement . muted = true ;
764- }
664+ wavesurferRef . current . setVolume ( 0 ) ;
665+ wavesurferRef . current . setMuted ( true ) ;
765666
766667 // Start WaveSurfer for visualization (muted)
767668 wavesurferRef . current . play ( ) . catch ( ( error ) => {
@@ -785,11 +686,8 @@ export function AudioPlayer() {
785686 } else {
786687 // Ensure WaveSurfer is not muted if not using native playback
787688 if ( ! isUsingNativePlaybackRef . current ) {
788- const mediaElement = wavesurferRef . current . getMediaElement ( ) ;
789- if ( mediaElement ) {
790- mediaElement . muted = false ;
791- mediaElement . volume = volume ;
792- }
689+ wavesurferRef . current . setMuted ( false ) ;
690+ wavesurferRef . current . setVolume ( volume ) ;
793691 }
794692
795693 wavesurferRef . current . play ( ) . catch ( ( error ) => {
0 commit comments