Skip to content

Commit

Permalink
Merge pull request #41 from GrandDynamo/fix-memory-leak
Browse files Browse the repository at this point in the history
Fix various memory leaks
  • Loading branch information
JohannesKauffmann authored Dec 24, 2020
2 parents 40fd9ad + c905cd3 commit 41a02be
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 72 deletions.
6 changes: 5 additions & 1 deletion OneDrive-Cloud-Player/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
Expand All @@ -22,7 +24,7 @@ sealed partial class App : Application
{
//Other classes can now call this class with the use of 'App.Current'.
public static new App Current => (App)Application.Current;

public CoreDispatcher UIDispatcher { get; private set; }
public IPublicClientApplication PublicClientApplication { get; private set; }
public string[] Scopes { get; private set; }
public CacheHelper CacheHelper { get; private set; }
Expand Down Expand Up @@ -111,6 +113,8 @@ protected override async void OnLaunched(LaunchActivatedEventArgs e)
// Ensure the current window is active
Window.Current.Activate();
}

UIDispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
}

/// <summary>
Expand Down
144 changes: 79 additions & 65 deletions OneDrive-Cloud-Player/ViewModels/VideoPlayerPageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,16 @@ public class VideoPlayerPageViewModel : ViewModelBase, INotifyPropertyChanged, I
private readonly ApplicationDataContainer localMediaVolumeLevelSetting;
private readonly INavigationService _navigationService;
private readonly GraphHelper graphHelper = GraphHelper.Instance();
private readonly Timer fileNameOverlayTimer = new Timer();
/// <summary>
/// Fires every two minutes to indicate the OneDrive download URL has expired.
/// </summary>
private readonly Timer reloadIntervalTimer = new Timer(120000);
/// <summary>
/// Single-shot timer to hide the filename shortly after playing a video.
/// </summary>
private readonly Timer fileNameOverlayTimer = new Timer(5000);
private MediaWrapper MediaWrapper = null;
private bool InvalidOneDriveSession = false;
private Timer reloadIntervalTimer;
private MediaPlayer mediaPlayer;
private int MediaListIndex;

Expand Down Expand Up @@ -227,70 +233,76 @@ private async void InitializeLibVLC(InitializedEventArgs eventArgs)
VideoLength = 0;
PlayPauseButtonFontIcon = "\xE768";

CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;

// Create LibVLC instance and subscribe to events.
LibVLC = new LibVLC(eventArgs.SwapChainOptions);
MediaPlayer = new MediaPlayer(LibVLC);

// Initialize timers.
// Create a timer that fires the elapsed event when its time to retrieve
// and play the media from a new OneDrive download URL (2 minutes).
reloadIntervalTimer = new Timer(120000);
// Hook up the Elapsed event for the timer.
reloadIntervalTimer.Elapsed += (sender, e) =>
{
InvalidOneDriveSession = true;
};
reloadIntervalTimer.Enabled = true;

/*
* Subscribing to LibVLC events.
*/
//Subscribes to the Playing event.
MediaPlayer.Playing += async (sender, args) =>
{
Debug.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + ": Media is playing");
await dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
{
MediaVolumeLevel = (int)this.localMediaVolumeLevelSetting.Values["MediaVolume"];
Debug.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + ": Set volume in container: " + this.localMediaVolumeLevelSetting.Values["MediaVolume"]);
Debug.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + ": Set volume in our property: " + MediaVolumeLevel);
Debug.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + ": Actual volume: " + MediaPlayer.Volume);
//Sets the max value of the seekbar.
VideoLength = MediaPlayer.Length;
MediaPlayer.Playing += MediaPlayer_Playing;
MediaPlayer.Paused += MediaPlayer_Paused;
MediaPlayer.TimeChanged += MediaPlayer_TimeChanged;

PlayPauseButtonFontIcon = "\xE769";
});
};
// Subscribe to the timer events and start the reloadInterval timer.
fileNameOverlayTimer.Elapsed += FileNameOverlayTimer_Elapsed;
reloadIntervalTimer.Elapsed += ReloadIntervalTimer_Elapsed;
reloadIntervalTimer.Start();

//Subscribes to the Paused event.
MediaPlayer.Paused += async (sender, args) =>
// Finally, play the media.
await PlayMedia();
}

private async void MediaPlayer_Playing(object sender, EventArgs e)
{
Debug.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + ": Media is playing");
await App.Current.UIDispatcher.RunAsync(CoreDispatcherPriority.High, () =>
{
await dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
PlayPauseButtonFontIcon = "\xE768";
});
};
MediaVolumeLevel = (int)this.localMediaVolumeLevelSetting.Values["MediaVolume"];
Debug.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + ": Set volume in container: " + this.localMediaVolumeLevelSetting.Values["MediaVolume"]);
Debug.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + ": Set volume in our property: " + MediaVolumeLevel);
Debug.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + ": Actual volume: " + MediaPlayer.Volume);
//Sets the max value of the seekbar.
VideoLength = MediaPlayer.Length;

PlayPauseButtonFontIcon = "\xE769";
});
}

MediaPlayer.TimeChanged += async (sender, args) =>
private async void MediaPlayer_Paused(object sender, EventArgs e)
{
await App.Current.UIDispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
await dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
PlayPauseButtonFontIcon = "\xE768";
});
}

private async void MediaPlayer_TimeChanged(object sender, EventArgs e)
{
await App.Current.UIDispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
// Updates the value of the seekbar on TimeChanged event
// when the user is not seeking.
if (!IsSeeking)
{
// Updates the value of the seekbar on TimeChanged event
// when the user is not seeking.
if (!IsSeeking)
// Sometimes the MediaPlayer is already null upon
// navigating away and this still gets called.
if (MediaPlayer != null)
{
// Sometimes the MediaPlayer is already null upon
// navigating away and this still gets called.
if (MediaPlayer != null)
{
TimeLineValue = MediaPlayer.Time;
}
TimeLineValue = MediaPlayer.Time;
}
});
};
}
});
}

await PlayMedia();
private void ReloadIntervalTimer_Elapsed(object sender, ElapsedEventArgs e)
{
InvalidOneDriveSession = true;
}

private async void FileNameOverlayTimer_Elapsed(object sender, ElapsedEventArgs e)
{
await App.Current.UIDispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
FileNameOverlayVisiblity = Visibility.Collapsed;
});
}

/// <summary>
Expand Down Expand Up @@ -318,23 +330,17 @@ private async Task PlayMedia(long startTime = 0)

FileName = MediaWrapper.CachedDriveItem.Name;

CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;

FileNameOverlayVisiblity = Visibility.Visible;

fileNameOverlayTimer.Interval = 5000;
fileNameOverlayTimer.AutoReset = false;
fileNameOverlayTimer.Start();
fileNameOverlayTimer.Elapsed += async (sender, e) =>
{
await dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
FileNameOverlayVisiblity = Visibility.Collapsed;
});
};

string mediaDownloadURL = await RetrieveDownloadURLMedia(MediaWrapper);
// Play the OneDrive file.
MediaPlayer.Play(new Media(LibVLC, new Uri(mediaDownloadURL)));
using (Media media = new Media(LibVLC, new Uri(mediaDownloadURL)))
{
MediaPlayer.Play(media);
}

if (MediaPlayer is null)
{
Expand Down Expand Up @@ -602,6 +608,14 @@ public void Deactivate(object parameter)
/// </summary>
public void Dispose()
{
// Unsubscribe from event handlers.
MediaPlayer.Playing -= MediaPlayer_Playing;
MediaPlayer.Paused -= MediaPlayer_Paused;
MediaPlayer.TimeChanged -= MediaPlayer_TimeChanged;
reloadIntervalTimer.Elapsed -= ReloadIntervalTimer_Elapsed;
fileNameOverlayTimer.Elapsed -= FileNameOverlayTimer_Elapsed;

// Dispose of the LibVLC instance and the mediaplayer.
var mediaPlayer = MediaPlayer;
MediaPlayer = null;
mediaPlayer?.Dispose();
Expand Down
17 changes: 11 additions & 6 deletions OneDrive-Cloud-Player/Views/VideoPlayerPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using OneDrive_Cloud_Player.ViewModels;
using System;
using System.Diagnostics;
using Windows.System;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
Expand Down Expand Up @@ -211,12 +210,15 @@ private void ExitFullscreenMode()
{
view.ExitFullScreenMode();
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto;
// The SizeChanged event will be raised when the exit from full-screen mode is complete.
// The SizeChanged event will be raised when the exitfrom full-screen
// mode is complete.
}
}

/// <summary>
/// Gets called when a user presses down a key on the videoplayer page. When the key is not listed in the switch case, it calls the view model to handle the key event.
/// Gets called when a user presses down a key on the videoplayer page.
/// When the key is not listed in the switch case, it calls the viewmodel
/// to handle the key event.
/// </summary>
/// <param name="sender"></param>
/// <param name="keyEvent"></param>
Expand All @@ -243,7 +245,8 @@ void VideoPlayerPage_KeyDown(CoreWindow sender, KeyEventArgs keyEvent)
}

/// <summary>
/// Executes after the user navigates to this page. This is used to add an event handler for the keydown event on this page.
/// Executes after the user navigates to this page. This is used to add an
/// event handler for the keydown event on this page.
/// </summary>
/// <param name="e"></param>
protected override void OnNavigatedTo(NavigationEventArgs e)
Expand All @@ -254,14 +257,16 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
}

/// <summary>
/// Executes before the user navigates away from this page. This is used to remove an event handler for the keydown event on this page,
/// and exit out of fullscreen if the app is still in fullscreen mode.
/// Executes before the user navigates away from this page. This is used to
/// remove an event handler for the keydown event on this page, and exit out
/// of fullscreen if the app is still in fullscreen mode.
/// </summary>
/// <param name="e"></param>
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
ExitFullscreenMode();

pointerMovementDispatcherTimer.Tick -= PointerMovementDispatcherTimer_Tick;
Window.Current.CoreWindow.KeyDown -= VideoPlayerPage_KeyDown;

base.OnNavigatingFrom(e);
Expand Down

0 comments on commit 41a02be

Please sign in to comment.