Forcing MediaElement to Release Stream after playback
Asked Answered
C

4

5

I am creating an audio recorder control, with playback functionality.

I use the media element to play the recorded audio like this:

using (var storage = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
{
    using (System.IO.Stream stream = new System.IO.IsolatedStorage.IsolatedStorageFileStream(filePath, System.IO.FileMode.Open, storage))
    {
        player.SetSource(stream);
    }
}

The problem i am facing is that when I use media element to play the recorded audio. The Stream is locked to the media element. I cannot overwrite the file or even play it again as the SetSource() method throws an exception.

Is there a way to force the media element to release the stream?

Crozier answered 10/10, 2013 at 11:14 Comment(0)
C
11

Based on @Sheridan answer this it what I came up with that works.

Whenever MediaElement is stopped using Stop() function set the Source Property to null like this:

ResetMediaElement()
{
    mediaElement.Stop();
    mediaElement.Source = null;
}

This will close the stream attached to the media element, so that the related resource can be used somewhere else.

Crozier answered 11/10, 2013 at 12:42 Comment(0)
R
2

If you use MediaElement, make sure you don't get bitten by this one:
MediaElement.SetSource Method

ArgumentNullException - The mediaStreamSource is null.
...

After calling this method, MediaElement.Source returns null. If this is called and MediaElement.Source is set, the last operation wins.

If a MediaElement is removed from the UI tree while is has an opened MediaStreamSource, subsequent calls to SetSource may be ignored. To ensure featureSetSource calls will work, set the Source property to null before detaching the MediaElement from the UI tree.

naturally one would expect, if they only use SetSource(somestream) to use SetSource(null) to release the resources. Nope, they thought "better", you have to use Source=null instead to release resources and SetSource(null) throws ArgumentNullException

that is what I call a design bug (breaks the rule of "least expected" behavior and causes bugs that bite you at runtime only [unless somebody has made a static analysis rule to catch such a thing - would need metadata of course that some argument can't be null, like in Code Contracts])

I managed to introduce this bug while refactoring some code in ClipFlair Studio's AudioRecorder control the other day :-(

Note that you can’t use at MediaElement something like Source = stream to open a Stream, since that is a Uri property (not an Object property to also accept Stream) and you have to use SetSource(stream) instead, so you’d also expect to be able to use SetSource(null) to release the resources.

Update: Fixed this in AudioRecorderView class (uses MVVM pattern) of AudioRecorderControl, at Audio property’s "set" accessor it needed the following null-guarding pattern:

if (mediaStreamSource != null) 
  player.SetSource(mediaStreamSource); 
      //must set the source once, not every time we play the same audio, 
      //else with Mp3MediaSource it will throw DRM error 
else 
   player.Source = null; 
Reprieve answered 12/12, 2014 at 3:23 Comment(0)
P
2
mediaElement.Stop();
mediaElement.ClearValue(MediaElement.SourceProperty);
Pieper answered 6/12, 2015 at 4:51 Comment(0)
I
0

I had a similar problem with displaying images. In a control with an image, I would get a 'File is in use' error whenever the user tried to update the image. The solution was to set the BitmapImage.CacheOption property to BitmapCacheOption.OnLoad:

MSDN says Set the CacheOption to BitmapCacheOption.OnLoad if you wish to close a stream used to create the BitmapImage. The default OnDemand cache option retains access to the stream until the image is needed, and cleanup is handled by the garbage collector.

After searching for a similar property that you could use for your MediaElement, it turns out that there isn't one. However, according to an answer on the chacheoption for mediaelement post from MSDN, there is a (long winded) way to achieve this... from the relevant answer:

I am not sure if your MediaElement is in an UserControl or not. but whatever the case you can set the UserControl or Control to IsEnabled=false, which in turn will trigger the Event Handler IsEnabledChanged. In it place the necessary code to stop the MediaElement from playback ME.Stop(), then call ME.Clear() and ME.Source = null. After that you should find no problems to delete the source file.

ME.Source = new Uri(MediaFilePath);
ME.Play();
...
private void DeleteButton_Click(object sender, RoutedEventArgs e) 
{ 
    ME.IsEnabled = false;   // This will call the Event Handler IsEnabledChanged 
    System.IO.File.Delete(MediaFilePath); 
    // Now after the player was stopped and cleared and source set to null, it 
    // won't object to deleting the file
}

private void ME_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    ME.Stop();
    ME.Clear();
    ME.Source = null;
}

I hope that this helps.

Immix answered 10/10, 2013 at 12:31 Comment(4)
There is no 'IsEnabled' property on a Media Element. Although your suggestion of setting the source property to null worked. Also thanks for information on the BitmapImage it will be helpful to me in another scenario in my app.Crozier
I'm afraid that you are mistaken about the IsEnabled property and the MediaElement Properties page on MSDN would agree with me, but I'm glad that this fixed your problem.Immix
I don't know about MediaElement on other platforms but on Windows Phone 8 there is no 'IsEnabled' property. It shows on MSDN but if you check in visual studio it's not there.Crozier
Oh sorry, I didn't notice that tag. Glad you sorted it anyway.Immix

© 2022 - 2024 — McMap. All rights reserved.