private void InterpretLine(string line) { if (!line.StartsWith("S") && !line.StartsWith("P")) { Debug.WriteLine("Whirligig: " + line); } if (_timeSource.CheckAccess()) { if (line.StartsWith("S")) { _timeSource.Pause(); } else if (line.StartsWith("C")) { string file = line.Substring(2).Trim('\t', ' ', '\"'); Debug.WriteLine($"Whirligig opened '{file}'"); OnFileOpened(file); } else if (line.StartsWith("P")) { string timeStamp = line.Substring(2).Trim(); double seconds = ParseWhirligigTimestap(timeStamp); TimeSpan position = TimeSpan.FromSeconds(seconds); _timeSource.Play(); if (position == _lastReceivedTimestamp) { return; } _lastReceivedTimestamp = position; _timeSource.SetPosition(position); } else if (line.StartsWith("dometype")) { } else if (line.StartsWith("duration")) { string timeStamp = line.Substring(10).Trim(); double seconds = ParseWhirligigTimestap(timeStamp); _timeSource.SetDuration(TimeSpan.FromSeconds(seconds)); } else { Debug.WriteLine("Unknown Parameter: " + line); } //Unknown Parameter: dometype = 6180 //Unknown Parameter: duration = 1389.141 } else { _timeSource.Dispatcher.Invoke(() => InterpretLine(line)); } }
private void InterpretStatus(string statusXml) { if (!_timeSource.CheckAccess()) { try { _timeSource.Dispatcher.Invoke(() => InterpretStatus(statusXml)); } catch (Exception e) { Debug.WriteLine("Exception in McpTimeSource.InterpretStatus: " + e.Message); } return; } try { MpcStatus newStatus = new MpcStatus(statusXml); if (newStatus.IsValid) { if (!_previousStatus.IsValid || _previousStatus.FilePath != newStatus.FilePath) { OnFileOpened(newStatus.FilePath); } if (!_previousStatus.IsValid || _previousStatus.State != newStatus.State) { if (newStatus.State == MpcPlaybackState.Playing) { _timeSource.Play(); } else { _timeSource.Pause(); } } if (!_previousStatus.IsValid || _previousStatus.Duration != newStatus.Duration) { _timeSource.SetDuration(TimeSpan.FromMilliseconds(newStatus.Duration)); } if (!_previousStatus.IsValid || _previousStatus.Position != newStatus.Position) { _timeSource.SetPosition(TimeSpan.FromMilliseconds(newStatus.Position)); } } _previousStatus = newStatus; } catch (Exception exception) { Debug.WriteLine("Couldn't interpret MPC Status: " + exception.Message); } }
private void InterpretData(DeoVrApiData data) { if (data == null) { return; } if (!_timeSource.CheckAccess()) { _timeSource.Dispatcher.Invoke(() => InterpretData(data)); return; } if (!string.IsNullOrEmpty(data.Path)) { if (!String.Equals(data.Path, _previousData?.Path, StringComparison.InvariantCultureIgnoreCase)) { OnFileOpened(data.Path); } } if (data.PlaybackSpeed != null) { _timeSource.PlaybackRate = (float)data.PlaybackSpeed; } if (data.Duration != null) { _timeSource.SetDuration(TimeSpan.FromSeconds((float)data.Duration)); } if (data.CurrentTime != null) { _timeSource.SetPosition(TimeSpan.FromSeconds((float)data.CurrentTime)); } if (data.PlayerState != null) { bool isPlaying = (data.PlayerState == DeoVrPlayerState.Play); if (_timeSource.IsPlaying != isPlaying) { if (isPlaying) { _timeSource.Play(); } else { _timeSource.Pause(); } } } }
private void InterpretLine(string line) { if (_timeSource.CheckAccess()) { Debug.WriteLine(line); ZoomPlayerMessageCodes commandCode = (ZoomPlayerMessageCodes)int.Parse(line.Substring(0, 4)); string parameter = line.Substring(4).Trim(); switch (commandCode) { case ZoomPlayerMessageCodes.StateChanged: ZoomPlayerPlaybackStates state = (ZoomPlayerPlaybackStates)int.Parse(parameter); if (state == ZoomPlayerPlaybackStates.Playing) { _timeSource.Play(); } else { _timeSource.Pause(); } break; case ZoomPlayerMessageCodes.PositionUpdate: string[] parts = parameter.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()).ToArray(); string[] timeFormats = { "hh\\:mm\\:ss", "mm\\:ss" }; TimeSpan position = TimeSpan.ParseExact(parts[0], timeFormats, CultureInfo.InvariantCulture); TimeSpan duration = TimeSpan.ParseExact(parts[1], timeFormats, CultureInfo.InvariantCulture); _timeSource.SetDuration(duration); _timeSource.SetPosition(position); break; case ZoomPlayerMessageCodes.CurrentlyLoadedFile: if (!String.IsNullOrWhiteSpace(parameter)) { OnFileOpened(parameter); } break; } } else { _timeSource.Dispatcher.Invoke(() => InterpretLine(line)); } }
private void InterpretStatus(string statusXml) { if (!_timeSource.CheckAccess()) { _timeSource.Dispatcher.Invoke(() => InterpretStatus(statusXml)); return; } try { VlcStatus newStatus = new VlcStatus(statusXml); if (newStatus.IsValid) { if (!_previousStatus.IsValid || _previousStatus.Filename != newStatus.Filename) { FindFullFilename(newStatus.Filename); } if (!_previousStatus.IsValid || _previousStatus.PlaybackState != newStatus.PlaybackState) { if (newStatus.PlaybackState == VlcPlaybackState.Playing) { _timeSource.Play(); } else { _timeSource.Pause(); } } if (!_previousStatus.IsValid || _previousStatus.Duration != newStatus.Duration) { _timeSource.SetDuration(newStatus.Duration); } if (!_previousStatus.IsValid || _previousStatus.Progress != newStatus.Progress) { _timeSource.SetPosition(newStatus.Progress); } } _previousStatus = newStatus; } catch (Exception exception) { Debug.WriteLine("Couldn't interpret VLC Status: " + exception.Message); } }
private void InterpretKodiMsgNew(string json) { if (!_timeSource.CheckAccess()) { _timeSource.Dispatcher.Invoke(() => InterpretKodiMsgNew(json)); return; } JObject json_obj; try { json_obj = JObject.Parse(json); } catch (Exception) { return; } string method = json_obj["method"]?.ToString(); switch (method) { case "Player.OnAVStart": // only available since api v9 https://kodi.wiki/view/JSON-RPC_API/v9 // OnAVStart occurs when the first frame is drawn { Pause(); // pause because of all the synchronous http post requests and could get badly out of sync // always get the filepath via http json api string filepath = GetCurrentPlayingFile(); OnFileOpened(filepath); TimeSpan current_duration = GetCurrentDuration(); _timeSource.SetDuration(current_duration); // for the times when the video was resumed TimeSpan current_time = GetCurrentTime(); // there doesn't seem to be a race condition in Kodi 18.1 like in Kodi 15 // needs to be tested on a slower device _timeSource.SetPosition(current_time); Play(); _timeSource.Play(); break; } case "Player.OnPause": { _timeSource.Pause(); break; } case "Player.OnResume": // also api v9+ lower apis will instead send OnPlay :/ { _timeSource.Play(); break; } case "Player.OnStop": { Console.WriteLine("stop playback"); _timeSource.Pause(); _timeSource.SetPosition(TimeSpan.Zero); break; } case "Player.OnSeek": { JObject time = (JObject)json_obj["params"]["data"]["player"]["time"]; if (time != null) { double hours, minutes, seconds, milliseconds; if (!double.TryParse(time["hours"]?.ToString(), out hours)) { return; } if (!double.TryParse(time["minutes"]?.ToString(), out minutes)) { return; } if (!double.TryParse(time["seconds"]?.ToString(), out seconds)) { return; } if (!double.TryParse(time["milliseconds"]?.ToString(), out milliseconds)) { return; } TimeSpan pos = TimeSpan.FromHours(hours); pos += TimeSpan.FromMinutes(minutes); pos += TimeSpan.FromSeconds(seconds); pos += TimeSpan.FromMilliseconds(milliseconds); Console.WriteLine("new pos:" + pos.ToString()); _timeSource.SetPosition(pos); } break; } case null: { Console.WriteLine("no method"); return; } default: { Console.WriteLine("Unhandled method: " + method); break; } } }
private void InterpretMessage(string message, IPEndPoint source) { if (!_timeSource.CheckAccess()) { _timeSource.Dispatcher.Invoke(() => InterpretMessage(message, source)); return; } JObject data = JObject.Parse(message); bool outputCommand = true; string command = data["cmd"].Value <string>(); switch (command) { case "pause": { _timeSource.Pause(); break; } case "play": { _timeSource.Play(); break; } case "stop": { // Not sure if this will be useful: // Format of local files: {"cmd":"stop", "data":"/storage/emulated/0/Download/my_video.mp4"} // string filename = data["data"].Value<string>().Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries).Last(); _timeSource.Pause(); _timeSource.SetPosition(TimeSpan.Zero); break; } case "load": { string title = data["data"]["title"].Value <string>(); string filename = title + ".mp4"; OnFileOpened(filename); _timeSource.Play(); break; } case "seekTo": { double miliseconds = data["data"].Value <double>(); TimeSpan position = TimeSpan.FromMilliseconds(miliseconds); if (position == _lastReceivedTimestamp) { return; } _lastReceivedTimestamp = position; _timeSource.SetPosition(position); break; } case "headpos2": { outputCommand = false; break; } } if (outputCommand) { Debug.WriteLine("Got '" + message + "' from " + source); } }