/// <summary>
        /// Starts this instance.
        /// </summary>
        /// <returns>Task.</returns>
        public async Task Start()
        {
            var item = _mediaPlayer.CurrentMedia;

            if (item == null)
            {
                return;
            }

            if (item.Id == null)
            {
                // Item is local media to the client (i.e playing local dvd)
                // todo - fix up local media progress reporting
                return;
            }

            try
            {
                var queueTypes = _mediaPlayer.CanQueue
                                     ? new List<string> { item.MediaType }
                                     : new List<string> { };

                var info = new PlaybackStartInfo
                {
                    ItemId = item.Id,
                    CanSeek = _mediaPlayer.CanSeek,
                    QueueableMediaTypes = queueTypes.ToList(),

                    // TODO: Remove this hardcoding
                    PlayMethod = PlayMethod.DirectPlay
                };

                var apiClient = _connectionManager.GetApiClient(item);

                await apiClient.ReportPlaybackStartAsync(info);

                if (_mediaPlayer.CanTrackProgress)
                {
                    _timer = new Timer(TimerCallback, null, 100, 900);
                }

                _mediaPlayer.MediaChanged += _mediaPlayer_MediaChanged;
                _mediaPlayer.PlaybackCompleted += _mediaPlayer_PlaybackCompleted;
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Error sending playback start checking for {0}", ex, item.Name);

                throw;
            }
        }
        /// <summary>
        /// Starts this instance.
        /// </summary>
        /// <returns>Task.</returns>
        public async Task Start()
        {
            var item = _mediaPlayer.CurrentMedia;

            if (item == null)
            {
                throw new InvalidOperationException("Nothing is currently playing");
            }

            if (item.Id == null)
            {
                // Item is local media to the client (i.e playing local dvd)
                // todo - fix up local media progress reporting
                return;
            }

            try
            {
                var queueTypes = _mediaPlayer.CanQueue
                                     ? new List<string> { item.MediaType }
                                     : new List<string> { };

                var info = new PlaybackStartInfo
                {
                    ItemId = item.Id,
                    UserId = _apiClient.CurrentUserId,
                    IsSeekable = _mediaPlayer.CanSeek,
                    QueueableMediaTypes = queueTypes.ToArray()
                };

                await _apiClient.ReportPlaybackStartAsync(info);

                if (_mediaPlayer.CanTrackProgress)
                {
                    _timer = new Timer(TimerCallback, null, 1000, 1000);
                }

                _mediaPlayer.MediaChanged += _mediaPlayer_MediaChanged;
                _mediaPlayer.PlaybackCompleted += _mediaPlayer_PlaybackCompleted;
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Error sending playback start checking for {0}", ex, item.Name);

                throw;
            }
        }
Beispiel #3
0
        /// <summary>
        /// Used to report that playback has started for an item
        /// </summary>
        /// <param name="info">The info.</param>
        /// <returns>Task.</returns>
        /// <exception cref="System.ArgumentNullException">info</exception>
        public async Task OnPlaybackStart(PlaybackStartInfo info)
        {
            if (info == null)
            {
                throw new ArgumentNullException("info");
            }

            var session = GetSession(info.SessionId);

            var libraryItem = string.IsNullOrWhiteSpace(info.ItemId)
                ? null
                : _libraryManager.GetItemById(new Guid(info.ItemId));

            UpdateNowPlayingItem(session, info, libraryItem);

            if (!string.IsNullOrEmpty(session.DeviceId) && info.PlayMethod != PlayMethod.Transcode)
            {
                ClearTranscodingInfo(session.DeviceId);
            }

            session.QueueableMediaTypes = info.QueueableMediaTypes;

            var users = GetUsers(session);

            if (libraryItem != null)
            {
                var key = libraryItem.GetUserDataKey();

                foreach (var user in users)
                {
                    await OnPlaybackStart(user.Id, key, libraryItem).ConfigureAwait(false);
                }
            }

            // Nothing to save here
            // Fire events to inform plugins
            EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs
            {
                Item = libraryItem,
                Users = users,
                MediaSourceId = info.MediaSourceId,
                MediaInfo = info.Item,
                DeviceName = session.DeviceName,
                ClientName = session.Client,
                DeviceId = session.DeviceId

            }, _logger);

            await SendPlaybackStartNotification(session, CancellationToken.None).ConfigureAwait(false);
        }
        private async Task InitiatePlayback(bool isResume, int? subtitleIndex = null)
        {
            Messenger.Default.Send(new NotificationMessage(Constants.Messages.ClearNowPlayingMsg));
            EndTime = TimeSpan.Zero;

            var streamInfo = new StreamInfo();
            switch (PlayerSourceType)
            {
                case PlayerSourceType.Playlist:
                case PlayerSourceType.Video:
                    if (SelectedItem.VideoType != VideoType.VideoFile)
                    {
                        var result = MessageBox.Show(AppResources.MessageExperimentalVideo, AppResources.MessageExperimentalTitle, MessageBoxButton.OKCancel);
                        if (result == MessageBoxResult.Cancel)
                        {
                            NavigationService.GoBack();
                            return;
                        }
                    }

                    if (SelectedItem.UserData != null && isResume)
                    {
                        _startPositionTicks = SelectedItem.UserData.PlaybackPositionTicks;
                    }

                    if (_startPositionTicks == 0)
                    {
                        // Although the API will return 0 items if the user doesn't have cinema mode enabled,
                        // that's still precious time on a slow connection needlessly wasted. So let's make sure
                        // the user actually has it enabled first.
                        if (AuthenticationService.Current.LoggedInUser.Configuration.EnableCinemaMode)
                        {
                            try
                            {
                                var items = await ApiClient.GetIntrosAsync(SelectedItem.Id, AuthenticationService.Current.LoggedInUserId);
                                if (items != null && !items.Items.IsNullOrEmpty())
                                {
                                    if (PlaylistItems == null)
                                    {
                                        PlaylistItems = new List<BaseItemDto>(items.Items) {SelectedItem};
                                    }
                                    else
                                    {
                                        var list = items.Items.ToList();
                                        list.AddRange(PlaylistItems);

                                        PlaylistItems = list;
                                    }

                                    var firstItem = PlaylistItems.FirstOrDefault();
                                    if (firstItem != null) SelectedItem = firstItem;
                                }
                            }
                            catch (HttpException ex)
                            {
                                Log.ErrorException("GetIntros (Cinema Mode)", ex);
                            }
                        }
                    }

                    streamInfo = await CreateVideoStream(SelectedItem.Id, _startPositionTicks, SelectedItem.MediaSources, SelectedItem.Type.ToLower().Equals("channelvideoitem"));

                    if (SelectedItem.RunTimeTicks.HasValue)
                        EndTime = TimeSpan.FromTicks(SelectedItem.RunTimeTicks.Value);

                    Log.Info("Playing {0} [{1}] ({2})", SelectedItem.Type, SelectedItem.Name, SelectedItem.Id);
                    break;
                case PlayerSourceType.Recording:
                    streamInfo = await CreateVideoStream(RecordingItem.Id, _startPositionTicks);

                    if (RecordingItem.RunTimeTicks.HasValue)
                        EndTime = TimeSpan.FromTicks(RecordingItem.RunTimeTicks.Value);

                    Log.Info("Playing {0} [{1}] ({2})", RecordingItem.Type, RecordingItem.Name, RecordingItem.Id);
                    break;
                case PlayerSourceType.Programme:
                    try
                    {
                        var channel = await ApiClient.GetItemAsync(ProgrammeItem.ChannelId, AuthenticationService.Current.LoggedInUserId);
                        streamInfo = await CreateVideoStream(ProgrammeItem.ChannelId, _startPositionTicks, channel.MediaSources, useHls: true);
                    }
                    catch (HttpException ex)
                    {
                        Utils.HandleHttpException(ex, "GetVideoChannel", NavigationService, Log);
                        NavigationService.GoBack();
                        return;
                    }

                    if (ProgrammeItem.RunTimeTicks.HasValue)
                        EndTime = TimeSpan.FromTicks(ProgrammeItem.RunTimeTicks.Value);

                    Log.Info("Playing {0} [{1}] ({2})", ProgrammeItem.Type, ProgrammeItem.Name, ProgrammeItem.Id);
                    break;
            }

            if (streamInfo == null)
            {
                NavigationService.GoBack();
                return;
            }

            if (subtitleIndex.HasValue)
            {
                streamInfo.SubtitleStreamIndex = subtitleIndex.Value;
            }

            var url = streamInfo.ToUrl(ApiClient.GetApiUrl("/"), ApiClient.AccessToken);
            _streamInfo = streamInfo;
            //Captions = GetSubtitles(SelectedItem);

            var isSyncedVideo = url.StartsWith("AnyTime", StringComparison.InvariantCultureIgnoreCase);

            if (EndTime.Ticks > 0 && !IsDirectStream)
            {
                EndTime = TimeSpan.FromTicks(EndTime.Ticks - _startPositionTicks);
            }

            StopAudioPlayback();

            _streamInfo = streamInfo;

            if (_isResume && IsDirectStream)
            {
                StartFrom = TimeSpan.FromTicks(_startPositionTicks);
            }

            RaisePropertyChanged(() => IsDirectStream);
            
            if (isSyncedVideo)
            {
                SetVideoUrl(string.Empty);
                if (VideoStream == null || _storageUrl != url)
                {           
                    _storageUrl = url;
                    using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        var stream = storage.OpenFile(url, FileMode.Open);
                        VideoStream = stream;
                    }
                }
            }
            else
            {
                VideoStream = null;
                SetVideoUrl(url);
                _storageUrl = string.Empty;
            }
            
            Debug.WriteLine(VideoUrl);
            Log.Debug(VideoUrl);

            try
            {
                Log.Info("Sending playback started message to the server.");

                _itemId = streamInfo.ItemId;

                var info = new PlaybackStartInfo
                {
                    ItemId = _itemId,
                    CanSeek = false,
                    QueueableMediaTypes = new List<string>()
                };

                await ApiClient.ReportPlaybackStartAsync(info);
            }
            catch (HttpException ex)
            {
                Utils.HandleHttpException("VideoPageLoaded", ex, NavigationService, Log);
            }
        }
        /// <summary>
        /// Reports the playback start.
        /// </summary>
        /// <param name="message">The message.</param>
        private void OnPlaybackStart(WebSocketMessageInfo message)
        {
            _logger.Debug("Received PlaybackStart message");

            var session = GetSessionFromMessage(message);

            if (session != null && session.UserId.HasValue)
            {
                var vals = message.Data.Split('|');

                var itemId = vals[0];

                var queueableMediaTypes = string.Empty;
                var canSeek = true;

                if (vals.Length > 1)
                {
                    canSeek = string.Equals(vals[1], "true", StringComparison.OrdinalIgnoreCase);
                }
                if (vals.Length > 2)
                {
                    queueableMediaTypes = vals[2];
                }

                var info = new PlaybackStartInfo
                {
                    CanSeek = canSeek,
                    ItemId = itemId,
                    SessionId = session.Id,
                    QueueableMediaTypes = queueableMediaTypes.Split(',').ToList()
                };

                if (vals.Length > 3)
                {
                    info.MediaSourceId = vals[3];
                }

                if (vals.Length > 4 && !string.IsNullOrWhiteSpace(vals[4]))
                {
                    info.AudioStreamIndex = int.Parse(vals[4], _usCulture);
                }

                if (vals.Length > 5 && !string.IsNullOrWhiteSpace(vals[5]))
                {
                    info.SubtitleStreamIndex = int.Parse(vals[5], _usCulture);
                }

                _sessionManager.OnPlaybackStart(info);
            }
        }
        private async Task InitiatePlayback(bool isResume, int? subtitleIndex = null)
        {
            Messenger.Default.Send(new NotificationMessage(Constants.Messages.ClearNowPlayingMsg));
            EndTime = TimeSpan.Zero;

            var streamInfo = new StreamInfo();
            //var query = new VideoStreamOptions();
            switch (PlayerSourceType)
            {
                case PlayerSourceType.Playlist:
                case PlayerSourceType.Video:
                    if (SelectedItem.VideoType != VideoType.VideoFile)
                    {
                        var result = MessageBox.Show(AppResources.MessageExperimentalVideo, AppResources.MessageExperimentalTitle, MessageBoxButton.OKCancel);
                        if (result == MessageBoxResult.Cancel)
                        {
                            NavigationService.GoBack();
                            return;
                        }
                    }

                    if (SelectedItem.UserData != null && isResume)
                    {
                        _startPositionTicks = SelectedItem.UserData.PlaybackPositionTicks;
                    }

                    if (_startPositionTicks == 0)
                    {
                        try
                        {
                            var items = await ApiClient.GetIntrosAsync(SelectedItem.Id, AuthenticationService.Current.LoggedInUserId);
                            if (items != null && !items.Items.IsNullOrEmpty())
                            {
                                if (PlaylistItems == null)
                                {
                                    PlaylistItems = new List<BaseItemDto>(items.Items) {SelectedItem};
                                }
                                else
                                {
                                    var list = items.Items.ToList();
                                    list.AddRange(PlaylistItems);

                                    PlaylistItems = list;
                                }

                                var firstItem = PlaylistItems.FirstOrDefault();
                                if (firstItem != null) SelectedItem = firstItem;
                            }
                        }
                        catch (HttpException ex)
                        {
                            Log.ErrorException("GetIntros (Cinema Mode)", ex);
                        }
                    }

                    streamInfo = CreateVideoStream(SelectedItem.Id, _startPositionTicks, SelectedItem.MediaSources, SelectedItem.Type.ToLower().Equals("channelvideoitem"));
                    //query = CreateVideoStreamOptions(SelectedItem.Id, _startPositionTicks, SelectedItem.Type.ToLower().Equals("channelvideoitem"));

                    if (SelectedItem.RunTimeTicks.HasValue)
                        EndTime = TimeSpan.FromTicks(SelectedItem.RunTimeTicks.Value);

                    Log.Info("Playing {0} [{1}] ({2})", SelectedItem.Type, SelectedItem.Name, SelectedItem.Id);
                    break;
                case PlayerSourceType.Recording:
                    //query = CreateVideoStreamOptions(RecordingItem.Id, _startPositionTicks);
                    streamInfo = CreateVideoStream(RecordingItem.Id, _startPositionTicks);

                    if (RecordingItem.RunTimeTicks.HasValue)
                        EndTime = TimeSpan.FromTicks(RecordingItem.RunTimeTicks.Value);

                    Log.Info("Playing {0} [{1}] ({2})", RecordingItem.Type, RecordingItem.Name, RecordingItem.Id);
                    break;
                case PlayerSourceType.Programme:
                    //query = CreateVideoStreamOptions(ProgrammeItem.ChannelId, _startPositionTicks, true);
                    try
                    {
                        var channel = await ApiClient.GetItemAsync(ProgrammeItem.ChannelId, AuthenticationService.Current.LoggedInUserId);
                        streamInfo = CreateVideoStream(ProgrammeItem.ChannelId, _startPositionTicks, channel.MediaSources, useHls: true);
                    }
                    catch (HttpException ex)
                    {
                        Utils.HandleHttpException(ex, "GetVideoChannel", NavigationService, Log);
                        NavigationService.GoBack();
                        return;
                    }

                    if (ProgrammeItem.RunTimeTicks.HasValue)
                        EndTime = TimeSpan.FromTicks(ProgrammeItem.RunTimeTicks.Value);

                    Log.Info("Playing {0} [{1}] ({2})", ProgrammeItem.Type, ProgrammeItem.Name, ProgrammeItem.Id);
                    break;
            }

            if (subtitleIndex.HasValue)
            {
                streamInfo.SubtitleStreamIndex = subtitleIndex.Value;
            }

            var url = streamInfo.ToUrl(ApiClient.GetApiUrl("/"), ApiClient.AccessToken);
            _streamInfo = streamInfo;
            //var url = PlayerSourceType == PlayerSourceType.Programme ? ApiClient.GetHlsVideoStreamUrl(query) : ApiClient.GetVideoStreamUrl(query);
            //Captions = GetSubtitles(SelectedItem);

            if (EndTime.Ticks > 0 && !IsDirectStream)
            {
                EndTime = TimeSpan.FromTicks(EndTime.Ticks - _startPositionTicks);
            }

            StopAudioPlayback();

            if (_isResume && IsDirectStream)
            {
                _startFrom = TimeSpan.FromTicks(_startPositionTicks);
            }

            RaisePropertyChanged(() => IsDirectStream);

            VideoUrl = url;
            Debug.WriteLine(VideoUrl);            

            Log.Debug(VideoUrl);

            try
            {
                Log.Info("Sending playback started message to the server.");

                _itemId = streamInfo.ItemId;

                var info = new PlaybackStartInfo
                {
                    ItemId = _itemId,
                    CanSeek = false,
                    QueueableMediaTypes = new List<string>()
                };

                await ApiClient.ReportPlaybackStartAsync(info);
            }
            catch (HttpException ex)
            {
                Utils.HandleHttpException("VideoPageLoaded", ex, NavigationService, Log);
            }
        }
        /// <summary>
        /// Handles the MediaChanged event of the _mediaPlayer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="MediaChangeEventArgs"/> instance containing the event data.</param>
        async void _mediaPlayer_MediaChanged(object sender, MediaChangeEventArgs e)
        {
            if (e.PreviousMedia != null)
            {
                var info = new PlaybackStopInfo
                {
                    ItemId = e.PreviousMedia.Id,
                    UserId = _apiClient.CurrentUserId,
                    PositionTicks = e.EndingPositionTicks
                };

                try
                {
                    await _apiClient.ReportPlaybackStoppedAsync(info);
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error sending playback stopped checking for {0}", ex, e.PreviousMedia.Name);
                }
            }

            if (e.NewMedia != null)
            {
                try
                {
                    var queueTypes = _mediaPlayer.CanQueue
                                ? new List<string> { e.NewMedia.MediaType }
                                : new List<string> { };

                    var info = new PlaybackStartInfo
                    {
                        ItemId = e.NewMedia.Id,
                        UserId = _apiClient.CurrentUserId,
                        IsSeekable = _mediaPlayer.CanSeek,
                        QueueableMediaTypes = queueTypes.ToArray()
                    };

                    await _apiClient.ReportPlaybackStartAsync(info);
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error sending playback start checking for {0}", ex, e.NewMedia.Name);
                }
            }
        }
        /// <summary>
        /// Handles the MediaChanged event of the _mediaPlayer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="MediaChangeEventArgs"/> instance containing the event data.</param>
        async void _mediaPlayer_MediaChanged(object sender, MediaChangeEventArgs e)
        {
            if (e.PreviousMedia != null)
            {
                var info = new PlaybackStopInfo
                {
                    ItemId = e.PreviousMedia.Id,
                    PositionTicks = e.EndingPositionTicks
                };

                var apiClient = _connectionManager.GetApiClient(e.PreviousMedia);

                try
                {
                    await apiClient.ReportPlaybackStoppedAsync(info);
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error sending playback stopped checking for {0}", ex, e.PreviousMedia.Name);
                }
            }

            if (e.NewMedia != null)
            {
                try
                {
                    var queueTypes = _mediaPlayer.CanQueue
                                ? new List<string> { e.NewMedia.MediaType }
                                : new List<string> { };

                    var info = new PlaybackStartInfo
                    {
                        ItemId = e.NewMedia.Id,

                        CanSeek = _mediaPlayer.CanSeek,
                        QueueableMediaTypes = queueTypes.ToList(),

                        // TODO: Remove this hardcoding
                        PlayMethod = PlayMethod.DirectPlay
                    };

                    var apiClient = _connectionManager.GetApiClient(e.NewMedia);

                    await apiClient.ReportPlaybackStartAsync(info);
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error sending playback start checking for {0}", ex, e.NewMedia.Name);
                }
            }
        }
        /// <summary>
        /// Handles the MediaChanged event of the _mediaPlayer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="eventArgs">The <see cref="MediaChangeEventArgs"/> instance containing the event data.</param>
        async void _mediaPlayer_MediaChanged(object sender, MediaChangeEventArgs eventArgs)
        {
            if (eventArgs.PreviousMedia != null)
            {
                var apiClient = _connectionManager.GetApiClient(eventArgs.PreviousMedia);

                var stopInfo = new PlaybackStopInfo
                {
                    ItemId = eventArgs.PreviousMedia.Id,
                    PositionTicks = eventArgs.EndingPositionTicks
                };

                // Have to test this for null because external players are currently not supplying this
                // Also some players will play in contexts not currently supported by common playback managers, e.g. direct play of folder rips, and iso-mounted media
                // Remove when implemented
                if (eventArgs.PreviousStreamInfo != null)
                {
                    await _apiPlaybackManager.ReportPlaybackStopped(stopInfo, eventArgs.PreviousStreamInfo, eventArgs.PreviousMedia.ServerId, apiClient.CurrentUserId, false, apiClient);
                }
                else
                {
                    await apiClient.ReportPlaybackStoppedAsync(stopInfo);
                }
            }

            if (eventArgs.NewMedia != null)
            {
                try
                {
                    var queueTypes = _mediaPlayer.CanQueue
                                ? new List<string> { eventArgs.NewMedia.MediaType }
                                : new List<string> { };

                    var info = new PlaybackStartInfo
                    {
                        ItemId = eventArgs.NewMedia.Id,

                        CanSeek = _mediaPlayer.CanSeek,
                        QueueableMediaTypes = queueTypes.ToList(),

                        // TODO: Remove this hardcoding
                        PlayMethod = PlayMethod.DirectPlay
                    };

                    var apiClient = _connectionManager.GetApiClient(eventArgs.NewMedia);

                    await apiClient.ReportPlaybackStartAsync(info);
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error sending internalPlaybackManager start checking for {0}", ex, eventArgs.NewMedia.Name);
                }
            }
        }
 /// <summary>
 /// Reports playback start
 /// </summary>
 /// <param name="info">The information.</param>
 /// <param name="isOffline">if set to <c>true</c> [is offline].</param>
 /// <param name="apiClient">The current apiClient. It can be null if offline</param>
 /// <returns>Task.</returns>
 public async Task ReportPlaybackStart(PlaybackStartInfo info, bool isOffline, IApiClient apiClient)
 {
     if (!isOffline)
     {
         await apiClient.ReportPlaybackStartAsync(info).ConfigureAwait(false);
     }
 }
        private async Task InformOfPlayingTrack()
        {
            if (_apiClient == null)
            {
                return;
            }

            try
            {
                var track = BackgroundAudioPlayer.Instance.Track;
                if (track != null)
                {
                    var info = new PlaybackStartInfo
                    {
                        CanSeek = false,
                        ItemId = track.Tag,
                        QueueableMediaTypes = new List<string>(),
                    };
                    await _apiClient.ReportPlaybackStartAsync(info);
                }
            }
            catch (HttpException ex)
            {
                _logger.FatalException("InformOfPlayingTrack()", ex);
            }

            NotifyComplete();
        }