/// <summary> /// Cancel the Series Timer /// </summary> /// <param name="timerId">The Timer Id</param> /// <param name="cancellationToken">The CancellationToken</param> /// <returns></returns> public async Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken) { ensureConnection(); int timeOut = await WaitForInitialLoadTask(cancellationToken); if (timeOut == -1 || cancellationToken.IsCancellationRequested) { _logger.Info("[TVHclient] CancelSeriesTimerAsync, call canceled or timed out."); return; } HTSMessage deleteAutorecMessage = new HTSMessage(); deleteAutorecMessage.Method = "deleteAutorecEntry"; deleteAutorecMessage.putField("id", timerId); //HTSMessage deleteAutorecResponse = await Task.Factory.StartNew<HTSMessage>(() => //{ // LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); // _htsConnection.sendMessage(deleteAutorecMessage, lbrh); // return lbrh.getResponse(); //}); TaskWithTimeoutRunner<HTSMessage> twtr = new TaskWithTimeoutRunner<HTSMessage>(TIMEOUT); TaskWithTimeoutResult<HTSMessage> twtRes = await twtr.RunWithTimeout(Task.Factory.StartNew<HTSMessage>(() => { LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); _htsConnection.sendMessage(deleteAutorecMessage, lbrh); return lbrh.getResponse(); })); if (twtRes.HasTimeout) { _logger.Error("[TVHclient] Can't delete recording because of timeout"); } else { HTSMessage deleteAutorecResponse = twtRes.Result; Boolean success = deleteAutorecResponse.getInt("success", 0) == 1; if (!success) { _logger.Error("[TVHclient] Can't cancel timer: '" + deleteAutorecResponse.getString("error") + "'"); } } }
public async Task<MediaSourceInfo> GetRecordingStream(string recordingId, string mediaSourceId, CancellationToken cancellationToken) { ensureConnection(); HTSMessage getTicketMessage = new HTSMessage(); getTicketMessage.Method = "getTicket"; getTicketMessage.putField("dvrId", recordingId); //HTSMessage getTicketResponse = await Task.Factory.StartNew<HTSMessage>(() => //{ // LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); // _htsConnection.sendMessage(getTicketMessage, lbrh); // return lbrh.getResponse(); //}); TaskWithTimeoutRunner<HTSMessage> twtr = new TaskWithTimeoutRunner<HTSMessage>(TIMEOUT); TaskWithTimeoutResult<HTSMessage> twtRes = await twtr.RunWithTimeout(Task.Factory.StartNew<HTSMessage>(() => { LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); _htsConnection.sendMessage(getTicketMessage, lbrh); return lbrh.getResponse(); })); if (twtRes.HasTimeout) { _logger.Error("[TVHclient] Can't delete recording because of timeout"); } else { HTSMessage getTicketResponse = twtRes.Result; if (_subscriptionId == int.MaxValue) { _subscriptionId = 0; } int currSubscriptionId = _subscriptionId++; return new MediaSourceInfo { Id = "" + currSubscriptionId, Path = _httpBaseUrl + getTicketResponse.getString("path") + "?ticket=" + getTicketResponse.getString("ticket"), Protocol = MediaProtocol.Http, MediaStreams = new List<MediaStream> { new MediaStream { Type = MediaStreamType.Video, // Set the index to -1 because we don't know the exact index of the video stream within the container Index = -1, // Set to true if unknown to enable deinterlacing IsInterlaced = true }, new MediaStream { Type = MediaStreamType.Audio, // Set the index to -1 because we don't know the exact index of the audio stream within the container Index = -1 } } }; } throw new TimeoutException(); }
/// <summary> /// Update a single Timer /// </summary> /// <param name="info">The program info</param> /// <param name="cancellationToken">The CancellationToken</param> /// <returns></returns> public async Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken) { ensureConnection(); int timeOut = await WaitForInitialLoadTask(cancellationToken); if (timeOut == -1 || cancellationToken.IsCancellationRequested) { _logger.Info("[TVHclient] UpdateTimerAsync, call canceled or timed out."); return; } HTSMessage updateTimerMessage = new HTSMessage(); updateTimerMessage.Method = "updateDvrEntry"; updateTimerMessage.putField("id", info.Id); updateTimerMessage.putField("startExtra", (long)(info.PrePaddingSeconds / 60)); updateTimerMessage.putField("stopExtra", (long)(info.PostPaddingSeconds / 60)); //HTSMessage updateTimerResponse = await Task.Factory.StartNew<HTSMessage>(() => //{ // LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); // _htsConnection.sendMessage(updateTimerMessage, lbrh); // return lbrh.getResponse(); //}); TaskWithTimeoutRunner<HTSMessage> twtr = new TaskWithTimeoutRunner<HTSMessage>(TIMEOUT); TaskWithTimeoutResult<HTSMessage> twtRes = await twtr.RunWithTimeout(Task.Factory.StartNew<HTSMessage>(() => { LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); _htsConnection.sendMessage(updateTimerMessage, lbrh); return lbrh.getResponse(); })); if (twtRes.HasTimeout) { _logger.Error("[TVHclient] Can't update timer because of timeout"); } else { HTSMessage updateTimerResponse = twtRes.Result; Boolean success = updateTimerResponse.getInt("success", 0) == 1; if (!success) { _logger.Error("[TVHclient] Can't update timer: '" + updateTimerResponse.getString("error") + "'"); } } }
/// <summary> /// Create a new recording /// </summary> /// <param name="info">The TimerInfo</param> /// <param name="cancellationToken">The cancellationToken</param> /// <returns></returns> public async Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken) { ensureConnection(); int timeOut = await WaitForInitialLoadTask(cancellationToken); if (timeOut == -1 || cancellationToken.IsCancellationRequested) { _logger.Info("[TVHclient] CreateTimerAsync, call canceled or timed out."); return; } HTSMessage createTimerMessage = new HTSMessage(); createTimerMessage.Method = "addDvrEntry"; createTimerMessage.putField("channelId", info.ChannelId); createTimerMessage.putField("start", DateTimeHelper.getUnixUTCTimeFromUtcDateTime(info.StartDate)); createTimerMessage.putField("stop", DateTimeHelper.getUnixUTCTimeFromUtcDateTime(info.EndDate)); createTimerMessage.putField("startExtra", (long)(info.PrePaddingSeconds / 60)); createTimerMessage.putField("stopExtra", (long)(info.PostPaddingSeconds / 60)); createTimerMessage.putField("priority", _priority); // info.Priority delivers always 0 - no GUI createTimerMessage.putField("configName", _profile); createTimerMessage.putField("description", info.Overview); createTimerMessage.putField("title", info.Name); createTimerMessage.putField("creator", Plugin.Instance.Configuration.Username); //HTSMessage createTimerResponse = await Task.Factory.StartNew<HTSMessage>(() => //{ // LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); // _htsConnection.sendMessage(createTimerMessage, lbrh); // return lbrh.getResponse(); //}); TaskWithTimeoutRunner<HTSMessage> twtr = new TaskWithTimeoutRunner<HTSMessage>(TIMEOUT); TaskWithTimeoutResult<HTSMessage> twtRes = await twtr.RunWithTimeout(Task.Factory.StartNew<HTSMessage>(() => { LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); _htsConnection.sendMessage(createTimerMessage, lbrh); return lbrh.getResponse(); })); if (twtRes.HasTimeout) { _logger.Error("[TVHclient] Can't create timer because of timeout"); } else { HTSMessage createTimerResponse = twtRes.Result; Boolean success = createTimerResponse.getInt("success", 0) == 1; if (!success) { _logger.Error("[TVHclient] Can't create timer: '" + createTimerResponse.getString("error") + "'"); } } }
public Boolean authenticate(String username, String password) { _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: start"); HTSMessage helloMessage = new HTSMessage(); helloMessage.Method = "hello"; helloMessage.putField("clientname", _clientName); helloMessage.putField("clientversion", _clientVersion); helloMessage.putField("htspversion", HTSMessage.HTSP_VERSION); helloMessage.putField("username", username); LoopBackResponseHandler loopBackResponseHandler = new LoopBackResponseHandler(); sendMessage(helloMessage, loopBackResponseHandler); HTSMessage helloResponse = loopBackResponseHandler.getResponse(); if (helloResponse != null) { if (helloResponse.containsField("htspversion")) { _serverProtocolVersion = helloResponse.getInt("htspversion"); } else { _serverProtocolVersion = -1; _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: hello don't deliver required field 'htspversion' - htsp wrong implemented on tvheadend side."); } if (helloResponse.containsField("servername")) { _servername = helloResponse.getString("servername"); } else { _servername = "n/a"; _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: hello don't deliver required field 'servername' - htsp wrong implemented on tvheadend side."); } if (helloResponse.containsField("serverversion")) { _serverversion = helloResponse.getString("serverversion"); } else { _serverversion = "n/a"; _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: hello don't deliver required field 'serverversion' - htsp wrong implemented on tvheadend side."); } byte[] salt = null; if (helloResponse.containsField("challenge")) { salt = helloResponse.getByteArray("challenge"); } else { salt = new byte[0]; _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: hello don't deliver required field 'challenge' - htsp wrong implemented on tvheadend side."); } byte[] digest = SHA1helper.GenerateSaltedSHA1(password, salt); HTSMessage authMessage = new HTSMessage(); authMessage.Method = "authenticate"; authMessage.putField("username", username); authMessage.putField("digest", digest); sendMessage(authMessage, loopBackResponseHandler); HTSMessage authResponse = loopBackResponseHandler.getResponse(); if (authResponse != null) { Boolean auth = authResponse.getInt("noaccess", 0) != 1; if (auth) { HTSMessage getDiskSpaceMessage = new HTSMessage(); getDiskSpaceMessage.Method = "getDiskSpace"; sendMessage(getDiskSpaceMessage, loopBackResponseHandler); HTSMessage diskSpaceResponse = loopBackResponseHandler.getResponse(); if (diskSpaceResponse != null) { long freeDiskSpace = -1; long totalDiskSpace = -1; if (diskSpaceResponse.containsField("freediskspace")) { freeDiskSpace = diskSpaceResponse.getLong("freediskspace") / BytesPerGiga; } else { _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: getDiskSpace don't deliver required field 'freediskspace' - htsp wrong implemented on tvheadend side."); } if (diskSpaceResponse.containsField("totaldiskspace")) { totalDiskSpace = diskSpaceResponse.getLong("totaldiskspace") / BytesPerGiga; } else { _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: getDiskSpace don't deliver required field 'totaldiskspace' - htsp wrong implemented on tvheadend side."); } _diskSpace = freeDiskSpace + "GB / " + totalDiskSpace + "GB"; } HTSMessage enableAsyncMetadataMessage = new HTSMessage(); enableAsyncMetadataMessage.Method = "enableAsyncMetadata"; sendMessage(enableAsyncMetadataMessage, null); } _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: authenticated = " + auth); return auth; } } _logger.Error("[TVHclient] HTSConnectionAsync.authenticate: no hello response"); return false; }
public async Task<MediaSourceInfo> GetRecordingStream(string recordingId, string mediaSourceId, CancellationToken cancellationToken) { HTSMessage getTicketMessage = new HTSMessage(); getTicketMessage.Method = "getTicket"; getTicketMessage.putField("dvrId", recordingId); TaskWithTimeoutRunner<HTSMessage> twtr = new TaskWithTimeoutRunner<HTSMessage>(TIMEOUT); TaskWithTimeoutResult<HTSMessage> twtRes = await twtr.RunWithTimeout(Task.Factory.StartNew<HTSMessage>(() => { LoopBackResponseHandler lbrh = new LoopBackResponseHandler(); _htsConnectionHandler.SendMessage(getTicketMessage, lbrh); return lbrh.getResponse(); })); if (twtRes.HasTimeout) { _logger.Error("[TVHclient] Timeout obtaining playback authentication ticket from TVH"); } else { HTSMessage getTicketResponse = twtRes.Result; if (_subscriptionId == int.MaxValue) { _subscriptionId = 0; } int currSubscriptionId = _subscriptionId++; if (_htsConnectionHandler.GetEnableSubsMaudios()) { _logger.Info("[TVHclient] Support for live TV subtitles and multiple audio tracks is enabled."); MediaSourceInfo recordingasset = new MediaSourceInfo(); recordingasset.Id = "" + currSubscriptionId; // Use HTTP basic auth instead of TVH ticketing system for authentication to allow the users to switch subs or audio tracks at any time recordingasset.Path = _htsConnectionHandler.GetHttpBaseUrl() + getTicketResponse.getString("path"); recordingasset.Protocol = MediaProtocol.Http; // Set asset source and type for stream probing and logging string recordingasset_probeUrl = "" + recordingasset.Path; string recordingasset_source = "Recording"; // Probe the asset stream to determine available sub-streams await ProbeStream(recordingasset, recordingasset_probeUrl, recordingasset_source, cancellationToken); // If enabled, force video deinterlacing for recordings if (_htsConnectionHandler.GetForceDeinterlace()) { _logger.Info("[TVHclient] Force video deinterlacing for all channels and recordings is enabled."); foreach (MediaStream i in recordingasset.MediaStreams) { if (i.Type == MediaStreamType.Video && i.IsInterlaced == false) { i.IsInterlaced = true; } } } return recordingasset; } else { return new MediaSourceInfo { Id = "" + currSubscriptionId, Path = _htsConnectionHandler.GetHttpBaseUrl() + getTicketResponse.getString("path") + "?ticket=" + getTicketResponse.getString("ticket"), Protocol = MediaProtocol.Http, MediaStreams = new List<MediaStream> { new MediaStream { Type = MediaStreamType.Video, // Set the index to -1 because we don't know the exact index of the video stream within the container Index = -1, // Set to true if unknown to enable deinterlacing IsInterlaced = true }, new MediaStream { Type = MediaStreamType.Audio, // Set the index to -1 because we don't know the exact index of the audio stream within the container Index = -1 } } }; } } throw new TimeoutException(); }
public Boolean authenticate(String username, String password) { _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: start"); HTSMessage helloMessage = new HTSMessage(); helloMessage.Method = "hello"; helloMessage.putField("clientname", _clientName); helloMessage.putField("clientversion", _clientVersion); helloMessage.putField("htspversion", HTSMessage.HTSP_VERSION); helloMessage.putField("username", username); LoopBackResponseHandler loopBackResponseHandler = new LoopBackResponseHandler(); sendMessage(helloMessage, loopBackResponseHandler); HTSMessage helloResponse = loopBackResponseHandler.getResponse(); if (helloResponse != null) { _serverProtocolVersion = helloResponse.getInt("htspversion"); _servername = helloResponse.getString("servername"); _serverversion = helloResponse.getString("serverversion"); byte[] salt = helloResponse.getByteArray("challenge"); byte[] digest = SHA1helper.GenerateSaltedSHA1(password, salt); HTSMessage authMessage = new HTSMessage(); authMessage.Method = "authenticate"; authMessage.putField("username", username); authMessage.putField("digest", digest); sendMessage(authMessage, loopBackResponseHandler); HTSMessage authResponse = loopBackResponseHandler.getResponse(); if (authResponse != null) { Boolean auth = authResponse.getInt("noaccess", 0) != 1; if (auth) { HTSMessage getDiskSpaceMessage = new HTSMessage(); getDiskSpaceMessage.Method = "getDiskSpace"; sendMessage(getDiskSpaceMessage, loopBackResponseHandler); HTSMessage diskSpaceResponse = loopBackResponseHandler.getResponse(); if (diskSpaceResponse != null) { _diskSpace = (diskSpaceResponse.getLong("freediskspace") / BytesPerGiga) + "GB / " + (diskSpaceResponse.getLong("totaldiskspace") / BytesPerGiga) + "GB"; } HTSMessage enableAsyncMetadataMessage = new HTSMessage(); enableAsyncMetadataMessage.Method = "enableAsyncMetadata"; sendMessage(enableAsyncMetadataMessage, null); } _logger.Info("[TVHclient] HTSConnectionAsync.authenticate: authenticated = " + auth); return auth; } } _logger.Error("[TVHclient] HTSConnectionAsync.authenticate: no hello response"); return false; }