private bool CallPlayMediaUsingMediaCollection(MediaCenterEnvironment mediaCenterEnvironment, PlayableItem playable) { var coll = new MediaCollection(); // Create a MediaCollectionItem for each file to play if (playable.HasMediaItems) { PlaybackControllerHelper.PopulateMediaCollectionUsingMediaItems(this, coll, playable); } else { PlaybackControllerHelper.PopulateMediaCollectionUsingFiles(coll, playable); } // Set starting position if we're resuming if (playable.Resume) { var playstate = playable.MediaItems.First().PlaybackStatus; coll.CurrentIndex = playstate.PlaylistPosition; coll[playstate.PlaylistPosition].Start = new TimeSpan(playstate.PositionTicks); } CurrentMediaCollection = coll; bool success = PlaybackControllerHelper.CallPlayMedia(mediaCenterEnvironment, MediaType.MediaCollection, CurrentMediaCollection, false); if (!success) { CurrentMediaCollection = null; } return(success); }
/// <summary> /// Handles a change of Playstate by firing various events and post play processes /// </summary> private void HandleStoppedState(MediaCenterEnvironment env, MediaExperience exp, MediaTransport transport, PlaybackStateEventArgs e) { // Stop listening to the events env.PropertyChanged -= MediaCenterEnvironment_PropertyChanged; transport.PropertyChanged -= MediaTransport_PropertyChanged; // This will prevent us from getting in here twice after playback stops and calling post-play processes more than once. _HasStartedPlaying = false; _CurrentMediaCollection = null; var mediaType = exp.MediaType; // Check if internal wmc player is still playing, which could happen if the user launches live tv while playing something if (mediaType != Microsoft.MediaCenter.Extensibility.MediaType.TV) { Application.CurrentInstance.ShowNowPlaying = false; if (mediaType == Microsoft.MediaCenter.Extensibility.MediaType.Audio || mediaType == Microsoft.MediaCenter.Extensibility.MediaType.DVD) { PlaybackControllerHelper.ReturnToApplication(true); } } // Fire the OnFinished event for each item OnPlaybackFinished(e); }
/// <summary> /// Retrieves the current playback item using properties from MediaExperience and Transport /// </summary> private PlaybackStateEventArgs GetCurrentPlaybackState(string metadataTitle, long metadataDuration, long positionTicks) { int filePlaylistPosition; int currentMediaIndex; PlayableItem currentPlayableItem; if (_CurrentMediaCollection == null) { currentPlayableItem = PlaybackControllerHelper.GetCurrentPlaybackItemUsingMetadataTitle(this, CurrentPlayableItems, metadataTitle, out filePlaylistPosition, out currentMediaIndex); } else { currentPlayableItem = PlaybackControllerHelper.GetCurrentPlaybackItemFromMediaCollection(CurrentPlayableItems, _CurrentMediaCollection, out filePlaylistPosition, out currentMediaIndex); // When playing multiple files with MediaCollections, if you allow playback to finish, CurrentIndex will be reset to 0, but transport.Position will be equal to the duration of the last item played if (filePlaylistPosition == 0 && positionTicks >= metadataDuration) { positionTicks = 0; } } return(new PlaybackStateEventArgs() { Position = positionTicks, CurrentFileIndex = filePlaylistPosition, DurationFromPlayer = metadataDuration, Item = currentPlayableItem, CurrentMediaIndex = currentMediaIndex }); }
/// <summary> /// Moves the player to a given position /// </summary> protected override void SeekInternal(long position) { var mce = AddInHost.Current.MediaCenterEnvironment; Logger.ReportVerbose("Trying to seek position :" + new TimeSpan(position).ToString()); PlaybackControllerHelper.WaitForStream(mce); mce.MediaExperience.Transport.Position = new TimeSpan(position); }
/// <summary> /// Unpauses playback /// </summary> protected override void UnPauseInternal() { var transport = PlaybackControllerHelper.GetCurrentMediaTransport(); if (transport != null) { transport.PlayRate = 2; } }
protected override void Dispose(bool isDisposing) { MediaTransport transport = PlaybackControllerHelper.GetCurrentMediaTransport(); if (transport != null) { transport.PropertyChanged -= MediaTransport_PropertyChanged; } base.Dispose(isDisposing); }
/// <summary> /// Calls PlayMedia /// </summary> private bool CallPlayMediaLegacy(MediaCenterEnvironment mediaCenterEnvironment, PlayableItem playable) { Microsoft.MediaCenter.MediaType type = PlaybackControllerHelper.GetMediaType(playable); bool playedWithPlaylist = false; // Need to create a playlist if (PlaybackControllerHelper.RequiresWPL(playable)) { IEnumerable <string> files = playable.FilesFormattedForPlayer; string playlistFile = PlaybackControllerHelper.CreateWPLPlaylist(playable.Id.ToString(), files, playable.StartPlaylistPosition); if (!PlaybackControllerHelper.CallPlayMedia(mediaCenterEnvironment, type, playlistFile, false)) { return(false); } playedWithPlaylist = true; } // If we're playing a dvd and the last item played was a MediaCollection, we need to make sure the MediaCollection has // fully cleared out of the player or there will be quirks such as ff/rew remote buttons not working if (playable.HasMediaItems) { Video video = playable.MediaItems.First() as Video; Microsoft.MediaCenter.Extensibility.MediaType lastMediaType = PlaybackControllerHelper.GetCurrentMediaType(); if (video != null && video.MediaType == Library.MediaType.DVD && (lastMediaType == Microsoft.MediaCenter.Extensibility.MediaType.MediaCollection || lastMediaType == Microsoft.MediaCenter.Extensibility.MediaType.Unknown)) { System.Threading.Thread.Sleep(500); } } if (!playedWithPlaylist) { bool queue = false; foreach (string fileToPlay in playable.FilesFormattedForPlayer) { if (!PlaybackControllerHelper.CallPlayMedia(mediaCenterEnvironment, type, fileToPlay, queue)) { return(false); } queue = true; } } return(true); }
/// <summary> /// Calls PlayMedia using either a MediaCollection or a single file /// </summary> private bool CallPlayMediaForPlayableItem(MediaCenterEnvironment mediaCenterEnvironment, PlayableItem playable) { if (PlaybackControllerHelper.UseLegacyApi(playable)) { bool success = CallPlayMediaLegacy(mediaCenterEnvironment, playable); CurrentMediaCollection = null; return(success); } else { return(CallPlayMediaUsingMediaCollection(mediaCenterEnvironment, playable)); } }
/// <summary> /// Moves the player to a given position /// </summary> protected override void SeekInternal(long position) { try { Logger.ReportVerbose("Trying to seek position :" + new TimeSpan(position).ToString()); PlaybackControllerHelper.WaitForStream(Application.MediaExperience); Application.MediaExperience.Transport.Position = new TimeSpan(position); } catch (Exception e) { Logger.ReportException("Error attempting to seek", e); } }
public void StopIfOutOfScope(BaseItem item) { if (!IsPlaying) { return; } //if the passed in item is our current scope or our current scope is a parent then we are still in scope and continue playing if (item != CurrentScope && !IsParent(CurrentScope, item)) { PlaybackControllerHelper.Stop(); } }
/// <summary> /// When playback is based purely on files, this will take the files that were supplied to the PlayableItem, /// and create the actual paths that will be sent to the player /// </summary> internal override IEnumerable <string> GetPlayableFiles(IEnumerable <string> files) { foreach (string file in files) { MediaBrowser.Library.MediaType mediaType = MediaBrowser.Library.MediaTypeResolver.DetermineType(file); if (mediaType == Library.MediaType.BluRay) { yield return(PlaybackControllerHelper.GetBluRayPath(file)); } yield return(ShouldTranscode ? PlaybackControllerHelper.GetTranscodedPath(file) : file); } }
/// <summary> /// Puts the player into fullscreen mode /// </summary> public override void GoToFullScreen() { var mce = MediaExperience ?? PlaybackControllerHelper.GetMediaExperienceUsingReflection(); if (mce != null) { Logger.ReportVerbose("Going fullscreen..."); mce.GoToFullScreen(); } else { Logger.ReportError("AddInHost.Current.MediaCenterEnvironment.MediaExperience is null, we have no way to go full screen!"); AddInHost.Current.MediaCenterEnvironment.Dialog(Application.CurrentInstance.StringData("CannotMaximizeDial"), "", Microsoft.MediaCenter.DialogButtons.Ok, 0, true); } }
/// <summary> /// Takes a Media object and returns the list of files that will be sent to the player /// </summary> internal override IEnumerable <string> GetPlayableFiles(Media media) { IEnumerable <string> files = base.GetPlayableFiles(media); Video video = media as Video; if (video != null) { if (video.MediaType == Library.MediaType.BluRay) { files = files.Select(i => PlaybackControllerHelper.GetBluRayPath(i)); } } return(ShouldTranscode ? files.Select(f => PlaybackControllerHelper.GetTranscodedPath(f)) : files); }
private void QueuePlayableItemIntoMediaCollection(PlayableItem playable) { try { // Create a MediaCollectionItem for each file to play if (playable.HasMediaItems) { PlaybackControllerHelper.PopulateMediaCollectionUsingMediaItems(this, CurrentMediaCollection, playable); } else { PlaybackControllerHelper.PopulateMediaCollectionUsingFiles(CurrentMediaCollection, playable); } } catch (Exception ex) { OnErrorPlayingItem(playable, ex); } }
private void QueuePlayableItemLegacy(PlayableItem playable) { Microsoft.MediaCenter.MediaType type = MediaType.Audio; bool success = true; foreach (string file in playable.FilesFormattedForPlayer) { if (!PlaybackControllerHelper.CallPlayMedia(AddInHost.Current.MediaCenterEnvironment, type, file, true)) { success = false; break; } } if (!success) { OnErrorPlayingItem(playable, "PlayMedia returned false"); } }
/// <summary> /// Handles a change of Playstate by firing various events and post play processes /// </summary> private void HandleStoppedState(MediaCenterEnvironment env, MediaExperience exp, MediaTransport transport, PlaybackStateEventArgs e) { Logger.ReportVerbose("In HandleStoppedState"); // Stop listening to the events env.PropertyChanged -= MediaCenterEnvironment_PropertyChanged; transport.PropertyChanged -= MediaTransport_PropertyChanged; Logger.ReportVerbose("Events unhooked"); // This will prevent us from getting in here twice after playback stops and calling post-play processes more than once. _HasStartedPlaying = false; CurrentMediaCollection = null; var mediaType = exp.MediaType; // Check if internal wmc player is still playing, which could happen if the user launches live tv while playing something if (mediaType != Microsoft.MediaCenter.Extensibility.MediaType.TV) { Logger.ReportVerbose("Turning off NPV"); Application.CurrentInstance.ShowNowPlaying = false; if (mediaType == Microsoft.MediaCenter.Extensibility.MediaType.Audio || mediaType == Microsoft.MediaCenter.Extensibility.MediaType.DVD) { PlaybackControllerHelper.ReturnToApplication(true); } } else { Logger.ReportVerbose("Not turning off NPV because Live TV is playing."); } Helper.AllowSleep(); // Fire the OnFinished event for each item Async.Queue(Async.ThreadPoolName.PlaybackFinished, () => OnPlaybackFinished(e)); }
private void SkipTimerExpired(object sender, EventArgs args) { Application.UIDeferredInvokeIfRequired(() => { if (SkipAmount != 0) { lock (SkipTimer) { if (SkipAmount != 0) { Logger.ReportVerbose("================ Skipping {0} seconds", SkipAmount); Application.CurrentInstance.RecentUserInput = true; var current = Application.MediaExperience.Transport.Position.Ticks; var duration = CurrentFileDurationTicks > 0 ? CurrentFileDurationTicks : PlaybackControllerHelper.GetDurationOfCurrentlyPlayingMedia(Application.MediaExperience.MediaMetadata); if (duration == 0) { // last ditch get from our metadata var playable = GetCurrentPlayableItem(); duration = playable != null ? playable.CurrentMedia.RuntimeTicks : long.MaxValue; } var pos = SkipAmount > 0 ? Math.Min(current + TimeSpan.FromSeconds(SkipAmount).Ticks, duration) : Math.Max(current - TimeSpan.FromSeconds(-SkipAmount).Ticks, 0); SkipAmount = 0; Seek(pos); } } } }); }
/// <summary> /// Stops playback /// </summary> protected override void StopInternal() { PlaybackControllerHelper.Stop(); }
private void HandlePropertyChange(MediaCenterEnvironment env, MediaExperience exp, MediaTransport transport, string property) { PlayState state; long positionTicks = 0; // If another application is playing the content, such as the WMC autoplay handler, we will // not have permission to access Transport properties // But we can look at MediaExperience.MediaType to determine if something is playing try { state = transport.PlayState; positionTicks = transport.Position.Ticks; } catch (InvalidOperationException) { Logger.ReportVerbose("HandlePropertyChange was not able to access MediaTransport. Defaulting values."); state = exp.MediaType == Microsoft.MediaCenter.Extensibility.MediaType.Unknown ? Microsoft.MediaCenter.PlayState.Undefined : Microsoft.MediaCenter.PlayState.Playing; } bool playstateChanged = state != _CurrentPlayState; _CurrentPlayState = state; // Determine if playback has stopped. Per MSDN documentation, Finished is no longer used with Windows 7 bool isStopped = state == Microsoft.MediaCenter.PlayState.Finished || state == Microsoft.MediaCenter.PlayState.Stopped || state == Microsoft.MediaCenter.PlayState.Undefined; // Don't get tripped up at the initial state of Stopped with position 0 if (!_HasStartedPlaying) { if (!isStopped) { Logger.ReportVerbose("HandlePropertyChange has recognized that playback has started"); _HasStartedPlaying = true; IsStreaming = Playable.CurrentFile.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || Playable.CurrentFile.StartsWith("https://", StringComparison.OrdinalIgnoreCase); if (Playable.HasMediaItems) { Application.CurrentInstance.CurrentlyPlayingItemId = lastItemId = Playable.CurrentMedia.Id; Application.CurrentInstance.ReportPlaybackStart(Playable.CurrentMedia.ApiId, IsStreaming); } } else { return; } } // protect against really agressive calls if (property == "Position") { Application.CurrentInstance.CurrentlyPlayingItem.CurrentPlaybackPosition = positionTicks; var diff = (DateTime.Now - _LastTransportUpdateTime).TotalMilliseconds; // Only cancel out Position reports if (diff < 5000 && diff >= 0) { return; } } _LastTransportUpdateTime = DateTime.Now; // Get metadata from player MediaMetadata metadata = exp.MediaMetadata; string metadataTitle = PlaybackControllerHelper.GetTitleOfCurrentlyPlayingMedia(metadata); long metadataDuration = PlaybackControllerHelper.GetDurationOfCurrentlyPlayingMedia(metadata); PlaybackStateEventArgs eventArgs = GetCurrentPlaybackState(metadataTitle, metadataDuration, positionTicks); // Only fire the progress handler while playback is still active, because once playback stops position will be reset to 0 OnProgress(eventArgs); if (eventArgs.Item != null && eventArgs.Item.HasMediaItems && eventArgs.Item.CurrentMedia.Id != lastItemId) { // started playing a new item - update Application.CurrentInstance.CurrentlyPlayingItemId = lastItemId = eventArgs.Item.MediaItems.ElementAt(eventArgs.CurrentMediaIndex).Id; } Application.CurrentInstance.ShowNowPlaying = eventArgs.Item == null || eventArgs.Item.ShowNowPlayingView; if (playstateChanged) { FirePropertyChanged("IsPaused"); if (state == Microsoft.MediaCenter.PlayState.Paused) { // allow screensavers/sleep Helper.AllowSleep(); } else if (state == Microsoft.MediaCenter.PlayState.Playing || state == Microsoft.MediaCenter.PlayState.Buffering) { // disallow again Helper.PreventSleep(); } // Get the title from the PlayableItem, if it's available. Otherwise use MediaMetadata string title = eventArgs.Item == null ? metadataTitle : (eventArgs.Item.HasMediaItems ? eventArgs.Item.MediaItems.ElementAt(eventArgs.CurrentMediaIndex).Name : eventArgs.Item.Files.ElementAt(eventArgs.CurrentFileIndex)); Logger.ReportVerbose("Playstate changed to {0} for {1}, PositionTicks:{2}, Playlist Index:{3}", state, title, positionTicks, eventArgs.CurrentFileIndex); //Logger.ReportVerbose("Refresh rate is {0}", DisplayUtil.GetCurrentRefreshRate()); PlayStateChanged(); Logger.ReportVerbose("Back from PlayStateChanged"); } if (isStopped) { Logger.ReportVerbose("Calling HandleStopedState"); HandleStoppedState(env, exp, transport, eventArgs); } }
private void PlayInternal(BaseItem item) { if (!item.ThemesLoaded) { item.LoadThemes(); } var coll = new MediaCollection(); if (item.ThemeVideos != null && item.ThemeVideos.Count > 0) { for (var i = 0; i < Config.Instance.ThemeBackgroundRepeat; i++) { item.ThemeVideos.ForEach(v => coll.AddItem(v.Path)); } IsPlayingVideo = true; } else if (item.ThemeSongs != null && item.ThemeSongs.Count > 0) { for (var i = 0; i < Config.Instance.ThemeBackgroundRepeat; i++) { item.ThemeSongs.ForEach(a => coll.AddItem(a.Path)); } IsPlayingVideo = false; } else if (Config.Instance.PlayTrailerAsBackground) { var movie = item as Movie; if (movie != null && movie.TrailerFiles.Any()) { for (var i = 0; i < Config.Instance.ThemeBackgroundRepeat; i++) { foreach (var trailerFile in movie.TrailerFiles) { coll.AddItem(trailerFile); } } IsPlayingVideo = true; } } if (coll.Any()) { Application.UIDeferredInvokeIfRequired(() => { //stop anything currently playing PlaybackControllerHelper.Stop(); var mce = Application.MediaCenterEnvironment; mce.PropertyChanged += EnvironmentPropertyChange; if (mce.PlayMedia(MediaType.MediaCollection, coll, false)) { IsPlaying = true; Application.CurrentInstance.ShowNowPlaying = IsPlayingVideo; CurrentScope = item; } else { mce.PropertyChanged -= EnvironmentPropertyChange; } }); } }
/// <summary> /// Plays or queues Media /// </summary> protected virtual void PlayPlayableItem(PlayableItem playable) { this.Playable = playable; _HasStartedPlaying = false; // Get this now since we'll be using it frequently MediaCenterEnvironment mediaCenterEnvironment = AddInHost.Current.MediaCenterEnvironment; try { // Attach event handler to MediaCenterEnvironment // We need this because if you press stop on a dvd menu without ever playing, Transport.PropertyChanged will never fire mediaCenterEnvironment.PropertyChanged -= MediaCenterEnvironment_PropertyChanged; mediaCenterEnvironment.PropertyChanged += MediaCenterEnvironment_PropertyChanged; if (!CallPlayMediaForPlayableItem(mediaCenterEnvironment, playable)) { mediaCenterEnvironment.PropertyChanged -= MediaCenterEnvironment_PropertyChanged; OnErrorPlayingItem(playable, "PlayMedia returned false"); return; } MediaExperience exp = mediaCenterEnvironment.MediaExperience ?? PlaybackControllerHelper.GetMediaExperienceUsingReflection(); if (exp != null) { MediaTransport transport = exp.Transport; if (transport != null) { transport.PropertyChanged -= MediaTransport_PropertyChanged; transport.PropertyChanged += MediaTransport_PropertyChanged; // If using the legacy api we have to resume manually if (_CurrentMediaCollection == null) { long startPosition = playable.StartPositionTicks; if (startPosition > 0) { TimeSpan startPos = TimeSpan.FromTicks(startPosition); Logger.ReportVerbose("Seeking to " + startPos.ToString()); transport.Position = startPos; } } } else { Logger.ReportWarning("PlayPlayableItem: MediaTransport is null"); } if (playable.GoFullScreen) { Logger.ReportVerbose("Going fullscreen"); exp.GoToFullScreen(); } } else { Logger.ReportWarning("PlayPlayableItem: MediaExperience is null"); } } catch (Exception ex) { OnErrorPlayingItem(playable, ex); } }