audiomaui

MAUI: Keep audio playing when navigating to a new page


I am using Webview for playing audio and when I navigate to a new page the audio stops playing. I want to play the audio in background when navigating to new pages, or switching app or locking device.

My Code:

<WebView
    x:Name="audio_webview" 
    BackgroundColor="Transparent" 
    Navigated="OnWebViewNavigated"
    HorizontalOptions="FillAndExpand"
    VerticalOptions="CenterAndExpand" >
    <WebView.HeightRequest>
        <OnIdiom x:TypeArguments="x:Double">
            <OnIdiom.Phone>80</OnIdiom.Phone>
            <OnIdiom.Tablet>120</OnIdiom.Tablet>
            <OnIdiom.Desktop>80</OnIdiom.Desktop>
        </OnIdiom>
    </WebView.HeightRequest>
    <WebView.WidthRequest>
        <OnIdiom x:TypeArguments="x:Double">
            <OnIdiom.Phone>420</OnIdiom.Phone>
            <OnIdiom.Tablet>630</OnIdiom.Tablet>
            <OnIdiom.Desktop>420</OnIdiom.Desktop>
        </OnIdiom>
    </WebView.WidthRequest>
</WebView>

audio_webview.Source = audioUrl;

When I navigate to a new page I am getting below messages in the output box:

11:04:37:012    [AAudio] AAudioStream_requestStop(s#1) called
11:04:37:012    [AAudio] AAudioStream_close(s#1) called ---------------
11:04:37:012    [AAudioStream] setState(s#1) from 10 to 11
11:04:37:012    [AudioTrack] stop(portId:2774, sessionId:48889): 0xb400006eb01c3f40, prior state:STATE_STOPPED
11:04:37:012    [AudioTrackShared] this(0xb400006e500b8550), mCblk(0x6d7fcdc000), front(311736), mIsOut 1, interrupt() FUTEX_WAKE
11:04:37:012    [AudioTrack] requestExitAndWait start
11:04:37:012    [AudioTrack] requestExitAndWait end
11:04:37:012    [AudioTrack] stopAndJoinCallbacks(2774) done
11:04:37:012    [AudioTrack] ~AudioTrack(2774): 0xb400006eb01c3f40
11:04:37:072    [AudioTrack] getpackName client name com.companyname.appname(24146)
11:04:37:072    [AudioTrack] stop(portId:2774, sessionId:48889): 0xb400006eb01c3f40, prior state:STATE_STOPPED
11:04:37:072    [AudioTrack] stopAndJoinCallbacks(2774) done
11:04:37:072    [AAudioStream] setState(s#1) from 11 to 12
11:04:37:072    [AAudioStream] ~AudioStream(s#1) mPlayerBase strongCount = 2
11:04:37:072    [AAudio] AAudioStream_close(s#1) returned 0 ---------

I want to play the audio in background without pausing when opening new pages. This feature is working fine on iOS platform, but in android only the audio is pausing.

Update:

I am playing the audio on a pop-up window and on that I am setting the background color to transparent. So I did some custom logic to make transparent background. When I close the pop up audio is playing, but when navigating to another content page audio stops.

My Code:

public DailyAudioPopUpPage(string audioUrl)
{
    InitializeComponent();
    LoadAudio(audioUrl);
}

private void LoadAudio(string audioUrl)
{
    var html = $@"
    <html>
    <body style='margin:0; background-color: transparent; display:flex; justify-content:center; align-items:center; height:100%;'>
        <audio controls autoplay style='width:90%;'>
            <source src='{audioUrl}' type='audio/mpeg'>
            Your browser does not support the audio element.
        </audio>
    </body>
    </html>";

    audio_webview.Source = new HtmlWebViewSource { Html = html };
}

Solution

  • You can use the MediaElement to display the audio instead of the webview And avoid using the popup to display the UI control.

    I created a sample and show the the play pause controls and progress bar.

    <Grid RowDefinitions="5*,1*,0.2*" ColumnDefinitions="*,*,*">
         <toolkit:MediaElement x:Name="media" HeightRequest="50" Grid.Row="0" Grid.ColumnSpan="3" Source="https://s3.amazonaws.com/catholicbrain/prod/dc/cbrain-app/files/doc-lib/2025/02/07/11/47/33/584/head/feb25_saint.mp3"/>
         <Slider Grid.Row="1" DragCompleted="Slider_DragCompleted" Grid.ColumnSpan="3" Value="{Binding Source={x:Reference media},Path=Position.TotalSeconds}" Maximum="{Binding Source={x:Reference media}, Path=Duration.TotalSeconds}"/>
         <Image Source="preview.png" Grid.Row="2" Grid.Column="0" HorizontalOptions="End"/>
         <Image Source="play.png" Grid.Row="2" Grid.Column="1" HorizontalOptions="Center"/>
         <Image Source="next.png" Grid.Row="2" Grid.Column="2" HorizontalOptions="Start"/>
    </Grid>
    

    And the Slider_DragCompleted method:

    private async void Slider_DragCompleted(object? sender, EventArgs e)
    {
        var newValue = ((Slider)sender).Value;
        await MediaElement.SeekTo(TimeSpan.FromSeconds(newValue), CancellationToken.None);
    }
    

    I used the Slider as the progress bar. I bind the max value to the audio's total seconds and bind the current value to the audio's current position. When user slids the slider, I call the SeekTo method to change the position of the MediaElement.

    In addition, you can check the official sample and it provided many custom functions.