diff --git a/ZuneHost.Wpf/ZuneHost.Wpf.csproj b/ZuneHost.Wpf/ZuneHost.Wpf.csproj
index fa637df..0678a68 100644
--- a/ZuneHost.Wpf/ZuneHost.Wpf.csproj
+++ b/ZuneHost.Wpf/ZuneHost.Wpf.csproj
@@ -6,13 +6,17 @@
11.0
true
Assets\ZuneFluentGem.ico
- App.config
+ App.config
+
+
+
+
diff --git a/ZuneHost/ZuneHost.csproj b/ZuneHost/ZuneHost.csproj
index efc0241..27edeea 100644
--- a/ZuneHost/ZuneHost.csproj
+++ b/ZuneHost/ZuneHost.csproj
@@ -1,21 +1,25 @@
-
- Exe
- net461;net6.0-windows10.0.22000;net6.0;
- AnyCPU;x64;x86;ARM32
- 11.0
- App.config
-
+
+ Exe
+ net461;net6.0-windows10.0.22000;net6.0;
+ AnyCPU;x64;x86;ARM32
+ 11.0
+ App.config
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
diff --git a/ZuneImpl/Extensions.cs b/ZuneImpl/Extensions.cs
index 74148eb..98da979 100644
--- a/ZuneImpl/Extensions.cs
+++ b/ZuneImpl/Extensions.cs
@@ -5,6 +5,8 @@ using System.Net.Http;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Text;
+using System.Diagnostics.CodeAnalysis;
+using System.Collections.Generic;
namespace Microsoft.Zune;
@@ -50,4 +52,29 @@ internal static class Extensions
MD5 md5 = MD5.Create();
return md5.ComputeHash(Encoding.Default.GetBytes(id));
}
+
+ ///
+ /// Returns a value that indicates whether there is an object at the top of the System.Collections.Generic.Stack`1,
+ /// and if one is present, copies it to the result parameter, and removes it from
+ /// the System.Collections.Generic.Stack`1.
+ ///
+ ///
+ /// If present, the object at the top of the System.Collections.Generic.Stack`1;
+ /// otherwise, the default value of T.
+ ///
+ ///
+ /// true if there is an object at the top of the System.Collections.Generic.Stack`1;
+ /// false if the System.Collections.Generic.Stack`1 is empty.
+ ///
+ public static bool TryPop(this Stack stack, [MaybeNullWhen(false)] out T result)
+ {
+ if (stack.Count > 0)
+ {
+ result = stack.Pop();
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
}
diff --git a/ZuneImpl/Library/StrixLibraryDataProviderQuery.cs b/ZuneImpl/Library/StrixLibraryDataProviderQuery.cs
index f8c9faf..8ad8b4c 100644
--- a/ZuneImpl/Library/StrixLibraryDataProviderQuery.cs
+++ b/ZuneImpl/Library/StrixLibraryDataProviderQuery.cs
@@ -470,118 +470,7 @@ namespace Microsoft.Zune.Library
}
var stTracks = m_dataRoot.Library.GetTracksAsync(int.MaxValue, 0);
- await foreach (var stTrack in stTracks)
- {
- var stAlbum = stTrack.Album;
- var stAlbumArtist = stAlbum != null
- ? await stAlbum.GetArtistItemsAsync(1, 0).FirstOrDefaultAsync()
- : null;
-
- // Handle filters
- if (queryType == EQueryType.eQueryTypeTracksForAlbumId)
- {
- var currentAlbumId = stAlbum?.Id.HashToInt32();
- if (currentAlbumId != albumId) continue;
- }
- else if (queryType == EQueryType.eQueryTypeTracksForAlbumArtistId)
- {
- var currentAlbumArtistId = stAlbumArtist?.Id.HashToInt32();
- if (currentAlbumArtistId != albumArtistId) continue;
- }
- else if (queryType == EQueryType.eQueryTypeTracksByGenreId)
- {
- var containsCurrentGenre = await stTrack.GetGenresAsync(int.MaxValue, 0)
- .Select(g => g.Name.HashToInt32())
- .AnyAsync(g => g == genreId);
-
- if (!containsCurrentGenre && stAlbum != null)
- {
- // If the track doesn't have the genre, the album might.
- containsCurrentGenre = await stAlbum.GetGenresAsync(int.MaxValue, 0)
- .Select(g => g.Name.HashToInt32())
- .AnyAsync(g => g == genreId);
- }
-
- if (!containsCurrentGenre) continue;
- }
-
- Schemas.Track track = new(m_dataType)
- {
- AlbumName = stTrack.Album?.Name,
- AlbumLibraryId = stTrack.Album?.Id.HashToInt32() ?? 0,
-
- TitleYomi = stTrack.Name,
- ReleaseDate = DateTime.Now,
- ZuneMediaId = stTrack.Id.HashToGuid(),
- TrackNumber = stTrack.TrackNumber ?? 0,
- Duration = stTrack.Duration,
- ComponentId = "strix",
- FileName = System.IO.Path.GetFileName(stTrack.Id),
- FolderName = System.IO.Path.GetDirectoryName(stTrack.Id),
- FilePath = stTrack.Id,
- NowPlaying = false,
- InLibrary = true,
- DateLastPlayed = stTrack.LastPlayed ?? DateTime.MinValue,
- PlayCount = 0,
- FileSize = 0,
- ComposerName = null,
- ConductorName = null,
- IsProtected = 0,
- DateAdded = stTrack.AddedAt ?? DateTime.Now,
- Bitrate = 0,
- MediaType = "track",
- DiscNumber = stTrack.DiscNumber ?? 0,
- DateAlbumAdded = DateTime.Now,
- FileCount = 1L,
- DrmState = 0,
- DrmStateMask = 0L,
- QuickMixState = 0,
-
- LibraryId = stTrack.Id.HashToInt32(),
- Title = stTrack.Name,
- SyncState = 0,
- Type = "track",
- DeviceFileSize = 0L,
-
- UserRating = 0,
-
- AlbumArtistName = stAlbumArtist?.Name,
- AlbumArtistLibraryId = stAlbumArtist?.Id.HashToInt32() ?? 0
- };
-
- var stArtists = stTrack.GetArtistItemsAsync(int.MaxValue, 0);
- bool setPrimaryArtist = false;
- List contributingArtists = new();
- await foreach (var stArtist in stArtists)
- {
- if (!setPrimaryArtist)
- {
- track.ArtistLibraryId = stArtist.Id.HashToInt32();
- track.ArtistName = stArtist.Name;
- track.ArtistNameYomi = stArtist.Name;
- setPrimaryArtist = true;
- }
- else if (!string.IsNullOrEmpty(stArtist.Name))
- {
- contributingArtists.Add(stArtist.Name);
- }
- }
- track.ContributingArtistCount = contributingArtists.Count;
- track.ContributingArtistNames = contributingArtists;
-
- // No artists
- if (!setPrimaryArtist)
- {
- track.ArtistLibraryId = 0;
- track.ArtistName = null;
- track.ArtistNameYomi = null;
- }
-
- var stGenre = await stTrack.GetGenresAsync(1, 0).FirstOrDefaultAsync();
- track.Genre = stGenre?.Name;
-
- queryList.Add(track.Item);
- }
+
}
else if (text == "AlbumByTOC")
{
@@ -659,6 +548,8 @@ namespace Microsoft.Zune.Library
if (!TryGetProperty("PinType", out EPinType pinType))
pinType = EPinType.ePinTypeGeneric;
+ var pinnedTracks = m_dataRoot.Library.GetTracksAsync(3, 0);
+
Schemas.Pin pin = new(m_dataType)
{
PinId = 42,
@@ -715,6 +606,123 @@ namespace Microsoft.Zune.Library
Result = libraryDataProviderQueryResult;
Status = DataProviderQueryStatus.Complete;
}
+
+ private Schemas.Track CreateTrack(ZuneQueryList queryList, )
+ {
+ await foreach (var stTrack in stTracks)
+ {
+ var stAlbum = stTrack.Album;
+ var stAlbumArtist = stAlbum != null
+ ? await stAlbum.GetArtistItemsAsync(1, 0).FirstOrDefaultAsync()
+ : null;
+
+ // Handle filters
+ if (queryType == EQueryType.eQueryTypeTracksForAlbumId)
+ {
+ var currentAlbumId = stAlbum?.Id.HashToInt32();
+ if (currentAlbumId != albumId) continue;
+ }
+ else if (queryType == EQueryType.eQueryTypeTracksForAlbumArtistId)
+ {
+ var currentAlbumArtistId = stAlbumArtist?.Id.HashToInt32();
+ if (currentAlbumArtistId != albumArtistId) continue;
+ }
+ else if (queryType == EQueryType.eQueryTypeTracksByGenreId)
+ {
+ var containsCurrentGenre = await stTrack.GetGenresAsync(int.MaxValue, 0)
+ .Select(g => g.Name.HashToInt32())
+ .AnyAsync(g => g == genreId);
+
+ if (!containsCurrentGenre && stAlbum != null)
+ {
+ // If the track doesn't have the genre, the album might.
+ containsCurrentGenre = await stAlbum.GetGenresAsync(int.MaxValue, 0)
+ .Select(g => g.Name.HashToInt32())
+ .AnyAsync(g => g == genreId);
+ }
+
+ if (!containsCurrentGenre) continue;
+ }
+
+ Schemas.Track track = new(m_dataType)
+ {
+ AlbumName = stTrack.Album?.Name,
+ AlbumLibraryId = stTrack.Album?.Id.HashToInt32() ?? 0,
+
+ TitleYomi = stTrack.Name,
+ ReleaseDate = DateTime.Now,
+ ZuneMediaId = stTrack.Id.HashToGuid(),
+ TrackNumber = stTrack.TrackNumber ?? 0,
+ Duration = stTrack.Duration,
+ ComponentId = "strix",
+ FileName = System.IO.Path.GetFileName(stTrack.Id),
+ FolderName = System.IO.Path.GetDirectoryName(stTrack.Id),
+ FilePath = stTrack.Id,
+ NowPlaying = false,
+ InLibrary = true,
+ DateLastPlayed = stTrack.LastPlayed ?? DateTime.MinValue,
+ PlayCount = 0,
+ FileSize = 0,
+ ComposerName = null,
+ ConductorName = null,
+ IsProtected = 0,
+ DateAdded = stTrack.AddedAt ?? DateTime.Now,
+ Bitrate = 0,
+ MediaType = "track",
+ DiscNumber = stTrack.DiscNumber ?? 0,
+ DateAlbumAdded = DateTime.Now,
+ FileCount = 1L,
+ DrmState = 0,
+ DrmStateMask = 0L,
+ QuickMixState = 0,
+
+ LibraryId = stTrack.Id.HashToInt32(),
+ Title = stTrack.Name,
+ SyncState = 0,
+ Type = "track",
+ DeviceFileSize = 0L,
+
+ UserRating = 0,
+
+ AlbumArtistName = stAlbumArtist?.Name,
+ AlbumArtistLibraryId = stAlbumArtist?.Id.HashToInt32() ?? 0
+ };
+
+ var stArtists = stTrack.GetArtistItemsAsync(int.MaxValue, 0);
+ bool setPrimaryArtist = false;
+ List contributingArtists = new();
+ await foreach (var stArtist in stArtists)
+ {
+ if (!setPrimaryArtist)
+ {
+ track.ArtistLibraryId = stArtist.Id.HashToInt32();
+ track.ArtistName = stArtist.Name;
+ track.ArtistNameYomi = stArtist.Name;
+ setPrimaryArtist = true;
+ }
+ else if (!string.IsNullOrEmpty(stArtist.Name))
+ {
+ contributingArtists.Add(stArtist.Name);
+ }
+ }
+ track.ContributingArtistCount = contributingArtists.Count;
+ track.ContributingArtistNames = contributingArtists;
+
+ // No artists
+ if (!setPrimaryArtist)
+ {
+ track.ArtistLibraryId = 0;
+ track.ArtistName = null;
+ track.ArtistNameYomi = null;
+ }
+
+ var stGenre = await stTrack.GetGenresAsync(1, 0).FirstOrDefaultAsync();
+ track.Genre = stGenre?.Name;
+
+ track.Item.Storage["StrixItem"] = stTrack;
+ queryList.Add(track.Item);
+ }
+ }
}
internal class DeferredSetResultArgs
diff --git a/ZuneImpl/Playback/VlcAudioService.cs b/ZuneImpl/Playback/VlcAudioService.cs
index 2a85a17..e4da2b2 100644
--- a/ZuneImpl/Playback/VlcAudioService.cs
+++ b/ZuneImpl/Playback/VlcAudioService.cs
@@ -3,6 +3,7 @@
using LibVLCSharp.Shared;
using StrixMusic.Sdk.MediaPlayback;
using System;
+using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -16,6 +17,7 @@ namespace Microsoft.Zune.Playback
readonly LibVLC m_vlc;
readonly MediaPlayer m_player;
private Media m_media, m_nextMedia;
+ private Stack m_toDisposeOnEnd = new(2);
private PlaybackItem m_currentSource;
private TimeSpan m_position;
@@ -46,6 +48,11 @@ namespace Microsoft.Zune.Playback
m_player = new(m_vlc);
m_player.TimeChanged += (sender, e) => Position = TimeSpan.FromMilliseconds(e.Time);
+ m_player.EndReached += (sender, e) =>
+ {
+ while (m_toDisposeOnEnd.TryPop(out var item))
+ item.Dispose();
+ };
}
public PlaybackItem CurrentSource
@@ -179,12 +186,24 @@ namespace Microsoft.Zune.Playback
var uri = sourceConfig.MediaConfig.MediaSourceUri;
var stream = sourceConfig.MediaConfig.FileStreamSource;
+ Media media = null;
if (uri != null)
- return new(m_vlc, uri);
+ {
+ media = new(m_vlc, uri);
+ }
else if (stream != null)
- return new(m_vlc, new StreamMediaInput(stream));
-
- throw new NotImplementedException();
+ {
+ StreamMediaInput streamInput = new(stream);
+ media = new(m_vlc, streamInput);
+
+ m_toDisposeOnEnd.Push(streamInput);
+ }
+
+ if (media is null)
+ throw new NotImplementedException();
+
+ m_toDisposeOnEnd.Push(media);
+ return media;
}
}
}
diff --git a/ZuneImpl/ZuneImpl.csproj b/ZuneImpl/ZuneImpl.csproj
index c993763..0da9e3b 100644
--- a/ZuneImpl/ZuneImpl.csproj
+++ b/ZuneImpl/ZuneImpl.csproj
@@ -21,8 +21,4 @@
-
-
-
-
diff --git a/ZuneShell.sln b/ZuneShell.sln
index d4733af..762c581 100644
--- a/ZuneShell.sln
+++ b/ZuneShell.sln
@@ -83,8 +83,8 @@ Global
{CB2B7609-C7B8-4E2A-82D8-DD631B70B621}.Release|x64.Build.0 = Release|x64
{CB2B7609-C7B8-4E2A-82D8-DD631B70B621}.Release|x86.ActiveCfg = Release|x86
{CB2B7609-C7B8-4E2A-82D8-DD631B70B621}.Release|x86.Build.0 = Release|x86
- {4041A91F-EF2A-4C47-9EBE-F4E862532345}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4041A91F-EF2A-4C47-9EBE-F4E862532345}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4041A91F-EF2A-4C47-9EBE-F4E862532345}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {4041A91F-EF2A-4C47-9EBE-F4E862532345}.Debug|Any CPU.Build.0 = Debug|x64
{4041A91F-EF2A-4C47-9EBE-F4E862532345}.Debug|ARM32.ActiveCfg = Debug|ARM32
{4041A91F-EF2A-4C47-9EBE-F4E862532345}.Debug|ARM32.Build.0 = Debug|ARM32
{4041A91F-EF2A-4C47-9EBE-F4E862532345}.Debug|x64.ActiveCfg = Debug|x64
@@ -99,8 +99,8 @@ Global
{4041A91F-EF2A-4C47-9EBE-F4E862532345}.Release|x64.Build.0 = Release|x64
{4041A91F-EF2A-4C47-9EBE-F4E862532345}.Release|x86.ActiveCfg = Release|x86
{4041A91F-EF2A-4C47-9EBE-F4E862532345}.Release|x86.Build.0 = Release|x86
- {1FEAC59B-F012-4ACC-9F11-E7ADF4C77593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1FEAC59B-F012-4ACC-9F11-E7ADF4C77593}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1FEAC59B-F012-4ACC-9F11-E7ADF4C77593}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {1FEAC59B-F012-4ACC-9F11-E7ADF4C77593}.Debug|Any CPU.Build.0 = Debug|x64
{1FEAC59B-F012-4ACC-9F11-E7ADF4C77593}.Debug|ARM32.ActiveCfg = Debug|x64
{1FEAC59B-F012-4ACC-9F11-E7ADF4C77593}.Debug|ARM32.Build.0 = Debug|x64
{1FEAC59B-F012-4ACC-9F11-E7ADF4C77593}.Debug|x64.ActiveCfg = Debug|x64
diff --git a/ZuneShell/Microsoft/Zune/Shell/ZuneApplication.cs b/ZuneShell/Microsoft/Zune/Shell/ZuneApplication.cs
index 9d3a746..c848480 100644
--- a/ZuneShell/Microsoft/Zune/Shell/ZuneApplication.cs
+++ b/ZuneShell/Microsoft/Zune/Shell/ZuneApplication.cs
@@ -150,7 +150,7 @@ namespace Microsoft.Zune.Shell
cacheFolderPath.Create();
OwlCore.Storage.SystemIO.SystemFolder cacheFolder = new(cacheFolderPath);
- OwlCore.Storage.SystemIO.SystemFolder musicFolder = new(@"D:\Music\Zune\Test");
+ OwlCore.Storage.SystemIO.SystemFolder musicFolder = new(@"C:\Users\jjask\OneDrive\Music\Rush");
var localCore = new StrixMusic.Cores.Storage.StorageCore(musicFolder, cacheFolder, "Local Test")
{
ScannerWaitBehavior = StrixMusic.Cores.Storage.ScannerWaitBehavior.AlwaysWait,
diff --git a/ZuneShell/ZuneUI/PlaylistManager.cs b/ZuneShell/ZuneUI/PlaylistManager.cs
index 4fd5a98..39ed87d 100644
--- a/ZuneShell/ZuneUI/PlaylistManager.cs
+++ b/ZuneShell/ZuneUI/PlaylistManager.cs
@@ -465,8 +465,17 @@ namespace ZuneUI
case QuickMixItem _:
AddQuickMixItemToTrackList((QuickMixItem)obj, tracks, containerPlayMarkerOverride);
continue;
+
+#if OPENZUNE
+ case Microsoft.Iris.UI.Class ozMediaItem:
+ var stTrack = (StrixMusic.Sdk.AppModels.ITrack)ozMediaItem.Storage["StrixItem"];
+ var zuneMediaId = (Guid)ozMediaItem.Storage["ZuneMediaId"];
+ tracks.Add(new Strix.StrixPlaybackTrack(stTrack, zuneMediaId));
+ break;
+#endif
+
default:
- continue;
+ continue;
}
}
}
diff --git a/ZuneShell/ZuneUI/Strix/StrixPlaybackTrack.cs b/ZuneShell/ZuneUI/Strix/StrixPlaybackTrack.cs
new file mode 100644
index 0000000..8d24854
--- /dev/null
+++ b/ZuneShell/ZuneUI/Strix/StrixPlaybackTrack.cs
@@ -0,0 +1,37 @@
+using Microsoft.Zune;
+using StrixMusic.Sdk.AppModels;
+using System;
+using System.Linq;
+
+namespace ZuneUI.Strix;
+
+public class StrixPlaybackTrack : PlaybackTrack
+{
+ public StrixPlaybackTrack(ITrack stTrack, Guid zuneId)
+ {
+ Track = stTrack;
+ ZuneMediaId = zuneId;
+ }
+
+ public ITrack Track { get; }
+
+ public override string Title => Track.Name;
+
+ public override TimeSpan Duration => Track.Duration;
+
+ public override Guid ZuneMediaId { get; }
+
+ public override HRESULT GetURI(out string uri)
+ {
+ uri = null;
+ if (Track.TotalUrlCount <= 0)
+ return HRESULT._DB_E_NOTFOUND;
+
+ var url = AsyncHelper.Run(
+ () => Track.GetUrlsAsync(1, 0).FirstAsync().AsTask()
+ );
+
+ uri = url.Url.ToString();
+ return HRESULT._S_OK;
+ }
+}
diff --git a/ZuneShell/ZuneUI/TransportControls/TransportControls.cs b/ZuneShell/ZuneUI/TransportControls/TransportControls.cs
index 453f762..51a34f9 100644
--- a/ZuneShell/ZuneUI/TransportControls/TransportControls.cs
+++ b/ZuneShell/ZuneUI/TransportControls/TransportControls.cs
@@ -24,6 +24,7 @@ using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using UIXControls;
+using ZuneUI.Strix;
namespace ZuneUI
{
@@ -1838,20 +1839,19 @@ namespace ZuneUI
int myID = ++_lastKnownSetUriCallID;
ThreadPool.QueueUserWorkItem(args =>
{
+ var dataRoot = Microsoft.Zune.Shell.ZuneApplication.DataRoot;
if (track != null)
{
- HRESULT hr = track.GetURI(out string trackUri);
- if (string.IsNullOrEmpty(trackUri))
- trackUri = ".:* INVALID URI *:.";
+ try
+ {
+ var stTrack = ((StrixPlaybackTrack)track).Track;
- if (hr.IsSuccess)
Application.DeferredInvoke(delegate
{
if (IsDisposed || myID != _lastKnownSetUriCallID)
return;
- PlaybackItem item = ZuneMediaSourceConfig.CreatePlaybackItem(trackUri, track.PlaybackID);
- _player.PlaySync(item);
+ AsyncHelper.Run(dataRoot.Library.PlayTrackCollectionAsync(stTrack));
ReportStreamingAction(PlayerState.Stopped);
_tracksSubmittedToPlayer.Remove(track);
@@ -1862,35 +1862,40 @@ namespace ZuneUI
// TODO: _playbackWrapper.CancelNext();
UpdatePropertiesAndCommands();
}, null);
- else
+ }
+ catch (Exception ex)
+ {
OnAlertSent(new Announcement()
{
- HResult = hr.Int,
+ HResult = ex.HResult,
PlaybackID = track.PlaybackID
});
+ }
}
if (nextTrack == null)
return;
- HRESULT nextTrackHr = nextTrack.GetURI(out string nextTrackUri);
- if (string.IsNullOrEmpty(nextTrackUri))
- nextTrackUri = ".:* INVALID URI *:.";
- if (!nextTrackHr.IsSuccess)
- return;
-
- Application.DeferredInvoke(delegate
+ try
{
- if (IsDisposed || myID != _lastKnownSetUriCallID)
- return;
+ var stTrack = ((StrixPlaybackTrack)nextTrack).Track;
- PlaybackItem item = ZuneMediaSourceConfig.CreatePlaybackItem(nextTrackUri, track.PlaybackID);
- _player.PreloadSync(item);
+ Application.DeferredInvoke(delegate
+ {
+ if (IsDisposed || myID != _lastKnownSetUriCallID)
+ return;
- _tracksSubmittedToPlayer.Remove(nextTrack);
- _tracksSubmittedToPlayer.Add(nextTrack);
- UpdatePropertiesAndCommands();
- }, null);
+ // Preload track
+ //AsyncHelper.Run(dataRoot.Library.PlayTrackCollectionAsync(stTrack));
+
+ _tracksSubmittedToPlayer.Remove(nextTrack);
+ _tracksSubmittedToPlayer.Add(nextTrack);
+ UpdatePropertiesAndCommands();
+ }, null);
+ }
+ catch
+ {
+ }
}, null);
}