From dd78908b83f5c78f8333de30a7092b520f363b3a Mon Sep 17 00:00:00 2001 From: ycastonguay Date: Wed, 17 Apr 2013 21:44:49 -0400 Subject: [PATCH] PeakFileService: Fixed bug where the Cancelled status was always false. This did not allow proper cancel in WaveFormCacheManager. MobileNavigationManager: Now reusing a single instance of IPlayerView. Related to issue #405 and issue #409. --- .../Navigation/MobileNavigationManager.cs | 30 +++++++++---------- MPfm/MPfm.Sound/PeakFiles/PeakFileService.cs | 15 ++++++++-- .../Controllers/PlayerViewController.cs | 2 +- .../Classes/Controls/MPfmWaveFormView.cs | 14 +++++---- .../Events/GeneratePeakFileEventArgs.cs | 1 + .../Classes/Managers/WaveFormCacheManager.cs | 23 ++++++++++---- 6 files changed, 55 insertions(+), 30 deletions(-) diff --git a/MPfm/MPfm.MVP/Navigation/MobileNavigationManager.cs b/MPfm/MPfm.MVP/Navigation/MobileNavigationManager.cs index f21fac96..a181c4ec 100644 --- a/MPfm/MPfm.MVP/Navigation/MobileNavigationManager.cs +++ b/MPfm/MPfm.MVP/Navigation/MobileNavigationManager.cs @@ -287,23 +287,23 @@ public virtual IPlayerView CreatePlayerView(Action onViewBindedToPres onViewBindedToPresenter(view); }; - // Create view and manage view destruction - _playerView = Bootstrapper.GetContainer().Resolve(new NamedParameterOverloads() { { "onViewReady", onViewReady } }); - _playerView.OnViewDestroy = (view) => + // Re-use the same player instance as before + if(_playerView == null) { - _playerView = null; - _playerPresenter = null; - }; + // Create view and manage view destruction + _playerView = Bootstrapper.GetContainer().Resolve(new NamedParameterOverloads() { { "onViewReady", onViewReady } }); + _playerView.OnViewDestroy = (view) => + { + _playerView = null; + _playerPresenter = null; + }; + } + else + { + // Re-use the same instance + onViewBindedToPresenter(_playerView); + } -// // Re-use the same player instance as before -// if(_playerView == null) -// { -// } -// else -// { -// // Re-use the same instance -// onViewBindedToPresenter(_playerView); -// } return _playerView; } diff --git a/MPfm/MPfm.Sound/PeakFiles/PeakFileService.cs b/MPfm/MPfm.Sound/PeakFiles/PeakFileService.cs index 54c98fb1..a1a057e1 100644 --- a/MPfm/MPfm.Sound/PeakFiles/PeakFileService.cs +++ b/MPfm/MPfm.Sound/PeakFiles/PeakFileService.cs @@ -135,6 +135,7 @@ public void GeneratePeakFile(string audioFilePath, string peakFilePath) // Schedule operation in a new thread IsLoading = true; + bool processSuccessful = false; _currentTask = Task.Factory.StartNew(() => { try @@ -199,6 +200,7 @@ public void GeneratePeakFile(string audioFilePath, string peakFilePath) do { // Check for cancel + //Console.WriteLine("PeakFileService - Bytes read: " + bytesRead.ToString()); if (cancellationToken.IsCancellationRequested) { // Set flags, exit loop @@ -276,8 +278,14 @@ public void GeneratePeakFile(string audioFilePath, string peakFilePath) } while (read == chunkSize); // Free channel + Console.WriteLine("PeakFileService - Freeing channel..."); channelDecode.Free(); + // TODO: This should replace the IsCancelled status since cancelling the task doesn't go end well + Console.WriteLine("PeakFileService - Is process successful? bytesRead: " + bytesRead.ToString() + " audioFileLength: " + audioFileLength.ToString()); + if(bytesRead >= audioFileLength) + processSuccessful = true; + // Set nulls for garbage collection channelDecode = null; floatLeft = null; @@ -288,10 +296,12 @@ public void GeneratePeakFile(string audioFilePath, string peakFilePath) { // Return exception //e.Result = ex; + Console.WriteLine("PeakFileService - Error: " + ex.Message); throw ex; } finally { // Close writer and stream + Console.WriteLine("PeakFileService - Closing file stream..."); gzipStream.Close(); binaryWriter.Close(); fileStream.Close(); @@ -317,14 +327,15 @@ public void GeneratePeakFile(string audioFilePath, string peakFilePath) Tracing.Log("Could not delete peak file " + peakFilePath + "."); } } - } + } } // Set completed IsLoading = false; + Console.WriteLine("PeakFileService - ProcessDone - processSuccessful: " + processSuccessful.ToString() + " filePath: " + audioFilePath); OnProcessDone(new PeakFileDoneData() { AudioFilePath = audioFilePath, - Cancelled = false + Cancelled = !processSuccessful }); }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current); } diff --git a/MPfm/MPfm.iOS/Classes/Controllers/PlayerViewController.cs b/MPfm/MPfm.iOS/Classes/Controllers/PlayerViewController.cs index 63802070..dd4e309e 100644 --- a/MPfm/MPfm.iOS/Classes/Controllers/PlayerViewController.cs +++ b/MPfm/MPfm.iOS/Classes/Controllers/PlayerViewController.cs @@ -257,7 +257,6 @@ public void RefreshSongInformation(AudioFile audioFile, long lengthBytes, int pl if(audioFile != null) { - Console.WriteLine("PlayerViewCtrl - RefreshSongInformation - " + audioFile.FilePath); try { // Check if the album art needs to be refreshed @@ -292,6 +291,7 @@ public void RefreshSongInformation(AudioFile audioFile, long lengthBytes, int pl navCtrl.SetTitle("Now Playing", (playlistIndex+1).ToString() + " of " + playlistCount.ToString()); // Load peak file in background + Console.WriteLine("==> PlayerViewCtrl: LoadPeakFile(" + audioFile.FilePath + ")"); waveFormView.LoadPeakFile(audioFile); } else diff --git a/MPfm/MPfm.iOS/Classes/Controls/MPfmWaveFormView.cs b/MPfm/MPfm.iOS/Classes/Controls/MPfmWaveFormView.cs index e048279a..49e5ff24 100644 --- a/MPfm/MPfm.iOS/Classes/Controls/MPfmWaveFormView.cs +++ b/MPfm/MPfm.iOS/Classes/Controls/MPfmWaveFormView.cs @@ -162,7 +162,7 @@ private void Initialize() private void HandleGeneratePeakFileBegunEvent(object sender, GeneratePeakFileEventArgs e) { InvokeOnMainThread(() => { - Console.WriteLine("MPfmWaveFormView - HandleGeneratePeakFileBegunEvent"); + //Console.WriteLine("MPfmWaveFormView - HandleGeneratePeakFileBegunEvent"); RefreshStatus("Generating wave form (0% done)"); }); } @@ -170,7 +170,7 @@ private void HandleGeneratePeakFileBegunEvent(object sender, GeneratePeakFileEve private void HandleGeneratePeakFileProgressEvent(object sender, GeneratePeakFileEventArgs e) { InvokeOnMainThread(() => { - Console.WriteLine("MPfmWaveFormView - HandleGeneratePeakFileProgressEvent (" + e.PercentageDone.ToString("0") + "% done)"); + //Console.WriteLine("MPfmWaveFormView - HandleGeneratePeakFileProgressEvent (" + e.PercentageDone.ToString("0") + "% done)"); RefreshStatus("Generating wave form (" + e.PercentageDone.ToString("0") + "% done)"); }); } @@ -178,15 +178,17 @@ private void HandleGeneratePeakFileProgressEvent(object sender, GeneratePeakFile private void HandleGeneratePeakFileEndedEvent(object sender, GeneratePeakFileEventArgs e) { InvokeOnMainThread(() => { - Console.WriteLine("MPfmWaveFormView - HandleGeneratePeakFileEndedEvent"); - _waveFormCacheManager.LoadPeakFile(new AudioFile(e.AudioFilePath)); + // TODO: Check if cancelled? This will not fire another LoadPeakFile if the peak file gen was cancelled. + Console.WriteLine("MPfmWaveFormView - HandleGeneratePeakFileEndedEvent - LoadPeakFile Cancelled: " + e.Cancelled.ToString() + " FilePath: " + e.AudioFilePath); + if(!e.Cancelled) + _waveFormCacheManager.LoadPeakFile(new AudioFile(e.AudioFilePath)); }); } private void HandleLoadedPeakFileSuccessfullyEvent(object sender, LoadPeakFileEventArgs e) { InvokeOnMainThread(() => { - Console.WriteLine("MPfmWaveFormView - HandleLoadedPeakFileSuccessfullyEvent"); + //Console.WriteLine("MPfmWaveFormView - HandleLoadedPeakFileSuccessfullyEvent"); _waveFormCacheManager.RequestBitmap(e.AudioFile.FilePath, WaveFormDisplayType.Stereo, Bounds, 1); }); } @@ -231,7 +233,7 @@ public void FlushCache() public void LoadPeakFile(AudioFile audioFile) { - Console.WriteLine("WaveFormView - LoadPeakFile audioFile: " + audioFile.FilePath); + Console.WriteLine("WaveFormView - LoadPeakFile " + audioFile.FilePath); RefreshStatus("Loading peak file..."); _waveFormCacheManager.LoadPeakFile(audioFile); } diff --git a/MPfm/MPfm.iOS/Classes/Managers/Events/GeneratePeakFileEventArgs.cs b/MPfm/MPfm.iOS/Classes/Managers/Events/GeneratePeakFileEventArgs.cs index 7e3e8ed2..e684f90e 100644 --- a/MPfm/MPfm.iOS/Classes/Managers/Events/GeneratePeakFileEventArgs.cs +++ b/MPfm/MPfm.iOS/Classes/Managers/Events/GeneratePeakFileEventArgs.cs @@ -23,6 +23,7 @@ public class GeneratePeakFileEventArgs : EventArgs { public string AudioFilePath { get; set; } public float PercentageDone { get; set; } + public bool Cancelled { get; set; } public GeneratePeakFileEventArgs() : base() diff --git a/MPfm/MPfm.iOS/Classes/Managers/WaveFormCacheManager.cs b/MPfm/MPfm.iOS/Classes/Managers/WaveFormCacheManager.cs index b5fc935e..00ae13ca 100644 --- a/MPfm/MPfm.iOS/Classes/Managers/WaveFormCacheManager.cs +++ b/MPfm/MPfm.iOS/Classes/Managers/WaveFormCacheManager.cs @@ -60,6 +60,7 @@ public class WaveFormCacheManager public WaveFormCacheManager(IPeakFileService peakFileService) { + Console.WriteLine("WaveFormCacheManager - Constructor"); _peakFileService = peakFileService; _peakFileService.OnProcessStarted += HandleOnPeakFileProcessStarted; _peakFileService.OnProcessData += HandleOnPeakFileProcessData; @@ -104,13 +105,13 @@ protected virtual void OnGenerateWaveFormBitmapEnded(GenerateWaveFormEventArgs e void HandleOnPeakFileProcessStarted(PeakFileStartedData data) { - Console.WriteLine("WaveFormCacheManager - HandleOnPeakFileProcessStarted"); + //Console.WriteLine("WaveFormCacheManager - HandleOnPeakFileProcessStarted"); OnGeneratePeakFileBegun(new GeneratePeakFileEventArgs()); } void HandleOnPeakFileProcessData(PeakFileProgressData data) { - Console.WriteLine("WaveFormCacheManager - HandleOnPeakFileProcessData"); + //Console.WriteLine("WaveFormCacheManager - HandleOnPeakFileProcessData"); OnGeneratePeakFileProgress(new GeneratePeakFileEventArgs(){ AudioFilePath = data.AudioFilePath, PercentageDone = data.PercentageDone @@ -119,18 +120,21 @@ void HandleOnPeakFileProcessData(PeakFileProgressData data) void HandleOnPeakFileProcessDone(PeakFileDoneData data) { - Console.WriteLine("WaveFormCacheManager - HandleOnPeakFileProcessDone"); - + Console.WriteLine("WaveFormCacheManager - HandleOnPeakFileProcessDone - Cancelled: " + data.Cancelled.ToString()); OnGeneratePeakFileEnded(new GeneratePeakFileEventArgs(){ AudioFilePath = data.AudioFilePath, - PercentageDone = 100 + PercentageDone = 100, + Cancelled = data.Cancelled }); } public void FlushCache() { + Console.WriteLine("WaveFormCacheManager - FlushCache"); _waveDataCache = null; + _waveDataCache = new Dictionary>(); _bitmapCache = null; + _bitmapCache = new Dictionary, UIImage>();; } public void LoadPeakFile(AudioFile audioFile) @@ -138,7 +142,10 @@ public void LoadPeakFile(AudioFile audioFile) // Check if another peak file is already loading Console.WriteLine("WaveFormCacheManager - LoadPeakFile audioFile: " + audioFile.FilePath); if (_peakFileService.IsLoading) + { + Console.WriteLine("WaveFormCacheManager - Cancelling current peak file generation..."); _peakFileService.Cancel(); + } // Check if the peak file subfolder exists string peakFileFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "PeakFiles"); @@ -164,6 +171,10 @@ public void LoadPeakFile(AudioFile audioFile) { Task>.Factory.StartNew(() => { List data = null; + + // TODO: Flush cache less often. For now, flush cache every time we load a new peak file to save memory. + FlushCache(); + try { Console.WriteLine("WaveFormCacheManager - Reading peak file: " + peakFilePath); @@ -178,7 +189,7 @@ public void LoadPeakFile(AudioFile audioFile) try { - Console.WriteLine("Peak file could not be loaded - Generating " + peakFilePath + "..."); + Console.WriteLine("WaveFormCacheManager - Peak file could not be loaded - Generating " + peakFilePath + "..."); OnGeneratePeakFileBegun(new GeneratePeakFileEventArgs()); _peakFileService.GeneratePeakFile(audioFile.FilePath, peakFilePath); }