xamarin / XamarinCommunityToolkit

The Xamarin Community Toolkit is a collection of Animations, Behaviors, Converters, and Effects for mobile development with Xamarin.Forms. It simplifies and demonstrates common developer tasks building iOS, Android, and UWP apps with Xamarin.Forms.
MIT License
1.58k stars 471 forks source link

[Bug] MediaElement Errors logged opening audio files from app temp folder on Android #1190

Open KnoxCameron opened 3 years ago

KnoxCameron commented 3 years ago

Description

I am writing an app which generates audio files in the app temp folder and plays them using MediaElement. I am currently working only on the Android version. It is a port of a UWP app which uses the native media player on that platform.

I have found it unstable - sometimes the audio doesn't play or stutters. Sometimes it works fine. Behaviour seems the same on emulator and physical devices. I thought my code might not be generating the audio files correctly so I put in debugs to prove that the files are being created and the correct path is being passed. Eventually, I substituted an audio player control for MediaElement and all the audio files play correctly.

As shown below, MediaElement throws errors (java.io.FileNotFoundException: No content provider:) each time I play the audio file, but still (sometimes) works to play the file. The files are referenced using the "ms-appdata:///temp/" URI convention.

I would prefer to use MediaElement to inherit the standard playback controls for the user. Is this error an issue which can be easily fixed? If not, I will continue with the other audio player and write custom playback controls.

Steps to Reproduce

MediaElement XAML:

        <xct:MediaElement x:Name="mediaElement" 
                          Source="{Binding MyMediaSource}"
                          Volume="{Binding MyVolume}"
                          ShowsPlaybackControls="True" Aspect="AspectFill" HeightRequest="80" 
                          MediaEnded="mediaElement_MediaEnded"
                          AutoPlay="False" IsVisible="{Binding IsMediaVisible}" KeepScreenOn="{Binding KeepScreenOn}"
                          />

ViewModel snippets:

    private MediaSource _myMediaSource;
    public MediaSource MyMediaSource
    {
        get => _myMediaSource;
        set
        {
            SetProperty(ref _myMediaSource, value);
        }
    }

    public DialogueViewModel(INavigation pageNav, Scenes currentScene)
    {
        // this is in Resources\raw in Droid, build action AndroidResource; Resources for iOS
        MyMediaSource = new Uri("ms-appx:///ding_sound_effect.mp3");
        MyVolume = 1;
        IsMediaVisible = false;
        KeepScreenOn = false;
    }

Code snippet that sets the media source to point at the temp file:

                        string folder = Path.GetTempPath();
                        string tempFilePath = Path.Combine(folder, audioToPlay.SoundTempFileName);
                        bool fileExistsFlag = File.Exists(tempFilePath);
                        FileInfo fileInfo = new FileInfo(tempFilePath);
                        if (fileExistsFlag)
                        {
                            System.Console.WriteLine("DEBUG - PlayQueuedSound - file exists at " + tempFilePath);
                            System.Console.WriteLine("DEBUG - PlayQueuedSound - setting media player to " + audioToPlay.SoundTempFileName);
                            System.Console.WriteLine("DEBUG - PlayQueuedSound - file length " + fileInfo.Length.ToString());
                            mediaControlBusyFlag = true;
                            MyMediaSource = new Uri($"ms-appdata:///temp/{audioToPlay.SoundTempFileName}");

This is followed by a mediaElement.Play(); issued by the code behind.

Expected Behavior

Audio plays

Actual Behavior

Audio sometimes plays. Each time the audio source is set and play is triggered, errors like the following are logged:

DEBUG - PlayQueuedSound - processing queue soundbytes00000002 DEBUG - PlayQueuedSound - file exists at /data/user/0/com.scenesteeler/cache/soundbytes00000002.wav DEBUG - PlayQueuedSound - setting media player to soundbytes00000002.wav DEBUG - PlayQueuedSound - file length 113564 [MediaPlayer] resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false [MediaPlayer] cleanDrmObj: mDrmObj=null mDrmSessionId=null DEBUG - DeleteOldTempFile soundbytes00000001.mp3 DEBUG - Deleted /data/user/0/com.scenesteeler/cache/soundbytes00000001.mp3 [Choreographer] Skipped 44 frames! The application may be doing too much work on its main thread. [OpenGLRenderer] Davey! duration=787ms; Flags=1, IntendedVsync=36967969900485, Vsync=36968703233789, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=36968716024940, AnimationStart=36968716120140, PerformTraversalsStart=36968716188140, DrawStart=36968747976140, SyncQueued=36968749120240, SyncStart=36968750426940, IssueDrawCommandsStart=36968750624840, SwapBuffers=36968754702240, FrameCompleted=36968758974440, DequeueBufferDuration=904000, QueueBufferDuration=1851000, [MediaPlayer] resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false [MediaPlayer] cleanDrmObj: mDrmObj=null mDrmSessionId=null [MediaPlayer] resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false [MediaPlayer] cleanDrmObj: mDrmObj=null mDrmSessionId=null [MediaPlayer] Couldn't open /data/user/0/com.scenesteeler/cache/soundbytes00000002.wav [MediaPlayer] java.io.FileNotFoundException: No content provider: /data/user/0/com.scenesteeler/cache/soundbytes00000002.wav [MediaPlayer] at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1673) [MediaPlayer] 04-11 10:04:14.636 W/MediaPlayer(18411): at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1503) [MediaPlayer] at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1420) [MediaPlayer] at android.media.MediaPlayer.attemptDataSource(MediaPlayer.java:1101) [MediaPlayer] at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1073) [MediaPlayer] at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1097) [MediaPlayer] at android.widget.VideoView.openVideo(VideoView.java:412) [MediaPlayer] at android.widget.VideoView.setVideoURI(VideoView.java:287) [MediaPlayer] at mono.java.lang.RunnableImplementor.n_run(Native Method) [MediaPlayer] at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:30) [MediaPlayer] at android.os.Handler.handleCallback(Handler.java:883) [MediaPlayer] at android.os.Handler.dispatchMessage(Handler.java:100) [MediaPlayer] at android.os.Looper.loop(Looper.java:214) [MediaPlayer] at co04-11 10:04:14.636 W/MediaPlayer(18411): at android.app.ActivityThread.main(ActivityThread.java:7356) [MediaPlayer] at java.lang.reflect.Method.invoke(Native Method) [MediaPlayer] at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) [MediaPlayer] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) [MediaPlayer] resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false [MediaPlayer] cleanDrmObj: mDrmObj=null mDrmSessionId=null [MediaPlayer] resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false [MediaPlayer] cleanDrmObj: mDrmObj=null mDrmSessionId=null [MediaPlayer] Couldn't open /data/user/0/com.scenesteeler/cache/soundbytes00000002.wav [MediaPlayer] java.io.FileNotFoundException: No content provider: /data/user/0/com.scenesteeler/cache/soundbytes00000002.wav [MediaPlayer] at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1673) [MediaPlayer] at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1503) [MediaPlayer] at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1420) [MediaPlayer] at android.media.MediaPlayer.attemptDataSource(MediaPlayer.java:1101) [MediaPlayer] at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1073) [MediaPlayer] at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1097) [MediaPlayer] at android.widget.VideoView.openVideo(VideoView.java:412) [MediaPlayer] at android.widget.VideoView.setVideoURI(VideoView.java:287) [MediaPlayer] at mono.java.lang.RunnableImplementor.n_run(Native Method) [MediaPlayer] at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:30) [MediaPlayer] at android.os.Handler.handleCallback(Handler.java:883) [MediaPlayer] at android.os.Handler.dispatchMessage(Handler.java:100) [MediaPlayer] at android.os.Looper.loop(Looper.java:214) [MediaPlayer] at android.app.ActivityThread.main(ActivityThread.java:7356) [MediaPlayer] at java.lang.reflect.Method.invoke(Native Method) [MediaPlayer] at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) [MediaPlayer] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) [MediaPlayerNative] getMetadata [Choreographer] Skipped 36 frames! The application may be doing too much work on its main thread. [om.scenesteele] Explicit concurrent copying GC freed 7012(564KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 2486KB/4973KB, paused 957us total 40.191ms [Mono] GC_TAR_BRIDGE bridges 13 objects 13 opaque 0 colors 13 colors-bridged 13 colors-visible 13 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.12ms tarjan 0.04ms scc-setup 0.18ms gather-xref 0.06ms xref-setup 0.03ms cleanup 0.08ms [Mono] GC_BRIDGE: Complete, was running for 55.95ms [Mono] GC_MINOR: (Nursery full) time 58.67ms, stw 65.57ms promoted 667K major size: 78368K in use: 75733K los size: 22528K in use: 20099K DEBUG - MediaEnded - entering

Basic Information

pictos commented 3 years ago

@KnoxCameron could you please update the issue's title and attach a small repro? Thanks in advance

KnoxCameron commented 3 years ago

@pictos sure will do (may take a few days to put a repro together)

KnoxCameron commented 3 years ago

@pictos I have created a small solution that demonstrates the issue at https://github.com/KnoxCameron/MediaElementTest. Does this give you what you need for a repro? Thanks!

pictos commented 3 years ago

@KnoxCameron Thanks for the quick reply, I'll take a look tomorrow or Monday and let you know if I can reproduce the issue