Beispiel #1
0
        public bool InitStream(string identifier, string clientDescription, MediaSource source, int timeout)
        {
            if (!source.Exists)
            {
                Log.Warn("Tried to start stream for non-existing file {0}", source.GetDebugName());
                return(false);
            }

            ActiveStream stream = new ActiveStream();

            stream.Identifier            = identifier;
            stream.ClientDescription     = clientDescription;
            stream.StartTime             = DateTime.Now;
            stream.Timeout               = timeout;
            stream.LastActivity          = DateTime.Now;
            stream.UseActivityForTimeout = false;
            stream.Context               = new StreamContext();
            stream.Context.Source        = source;
            stream.Context.IsTv          = source.MediaType == WebMediaType.TV;

            // Some clients such as WebMP proxy the streams before relying it to the client. We should give these clients the option to
            // forward the real IP address, so that we can show that one in the configurator too. However, to avoid abuse, we should show
            // the real IP of the client too, so make up some nice text string.
            string realIp = WCFUtil.GetHeaderValue("forwardedFor", "X-Forwarded-For");

            stream.ClientIP = realIp == null?WCFUtil.GetClientIPAddress() : String.Format("{0} (via {1})", realIp, WCFUtil.GetClientIPAddress());

            Streams[identifier] = stream;
            return(true);
        }
Beispiel #2
0
        /// <summary>
        ///
        /// </summary>
        private void CloseStreamsWithStall(string Dir)
        {
            Logger.Log(LogLevel.Info, LogCategory.IO, "Stalling for directory close: '{0}'", Dir);

            lock (ActiveStreams)
            {
                for (int i = 0; i < ActiveStreams.Count; i++)
                {
                    ActiveStream Stm = ActiveStreams[i];
                    if (Stm.Path.StartsWith(Dir))
                    {
                        Logger.Log(LogLevel.Verbose, LogCategory.IO, "Closing stream for directory close: '{0}'", Stm.Path);

                        // This is not ideal, we should remove this if practical, it wastes processing time.
                        while (Stm.ActiveOperations > 0)
                        {
                            Thread.Sleep(0);
                        }

                        Stm.Stream.Close();
                        ActiveStreams.Remove(Stm);
                        ActiveStreamsByPath.Remove(Stm.Path);

                        i--;
                    }
                }
            }

            Logger.Log(LogLevel.Info, LogCategory.IO, "Finished closing directory: '{0}'", Dir);
        }
Beispiel #3
0
        /// <summary>
        /// Reads data from the remote client asynchronously and with the given timeout.
        /// </summary>
        /// <param name="timeout">The timeout.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A byte array containing the results of encoding the specified set of characters.</returns>
        /// <exception cref="InvalidOperationException">Read methods have been disabled because continuous reading is enabled.</exception>
        /// <exception cref="TimeoutException">Reading data from {ActiveStream} timed out in {timeout.TotalMilliseconds} m.</exception>
        public async Task <byte[]> ReadDataAsync(TimeSpan timeout, CancellationToken cancellationToken = default)
        {
            if (IsContinuousReadingEnabled)
            {
                throw new InvalidOperationException(
                          "Read methods have been disabled because continuous reading is enabled.");
            }

            if (RemoteClient == null)
            {
                throw new InvalidOperationException("An open connection is required");
            }

            var receiveBuffer  = new byte[RemoteClient.ReceiveBufferSize * 2];
            var receiveBuilder = new List <byte>(receiveBuffer.Length);

            try
            {
                var startTime = DateTime.UtcNow;

                while (receiveBuilder.Count <= 0)
                {
                    if (DateTime.UtcNow.Subtract(startTime) >= timeout)
                    {
                        throw new TimeoutException(
                                  $"Reading data from {ActiveStream} timed out in {timeout.TotalMilliseconds} ms");
                    }

                    if (_readTask == null)
                    {
                        _readTask = ActiveStream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken);
                    }

                    if (_readTask.Wait(_continuousReadingInterval))
                    {
                        var bytesReceivedCount = _readTask.Result;
                        if (bytesReceivedCount > 0)
                        {
                            DataReceivedLastTimeUtc = DateTime.UtcNow;
                            var buffer = new byte[bytesReceivedCount];
                            Array.Copy(receiveBuffer, 0, buffer, 0, bytesReceivedCount);
                            receiveBuilder.AddRange(buffer);
                        }

                        _readTask = null;
                    }
                    else
                    {
                        await Task.Delay(_continuousReadingInterval, cancellationToken).ConfigureAwait(false);
                    }
                }
            }
            catch (Exception ex)
            {
                ex.Error(typeof(Connection).FullName, "Error while reading network stream data asynchronously.");
                throw;
            }

            return(receiveBuilder.ToArray());
        }
 public void Close()
 {
     ActiveClient.Client.NoDelay = true;
     ActiveClient.Client.Disconnect(false);
     ActiveStream.Close();
     ActiveClient.Close();
 }
Beispiel #5
0
        private void PerformContinuousReading(object threadContext)
        {
            _continuousReadingThread = Thread.CurrentThread;

            // Check if the RemoteClient is still there
            if (RemoteClient == null)
            {
                return;
            }

            var receiveBuffer = new byte[RemoteClient.ReceiveBufferSize * 2];

            while (IsConnected && _disconnectCalls <= 0)
            {
                var doThreadSleep = false;

                try
                {
                    if (_readTask == null)
                    {
                        _readTask = ActiveStream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length);
                    }

                    if (_readTask.Wait(_continuousReadingInterval))
                    {
                        var bytesReceivedCount = _readTask.Result;
                        if (bytesReceivedCount > 0)
                        {
                            DataReceivedLastTimeUtc = DateTime.UtcNow;
                            var buffer = new byte[bytesReceivedCount];
                            Array.Copy(receiveBuffer, 0, buffer, 0, bytesReceivedCount);
                            RaiseReceiveBufferEvents(buffer);
                        }

                        _readTask = null;
                    }
                    else
                    {
                        doThreadSleep = _disconnectCalls <= 0;
                    }
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    ex.Log(nameof(PerformContinuousReading), "Continuous Read operation errored");
                }
                finally
                {
                    if (doThreadSleep)
                    {
                        Thread.Sleep(_continuousReadingInterval);
                    }
                }
            }
        }
Beispiel #6
0
 private void StopAndCloseStream()
 {
     if (activeStream != null)
     {
         inputStream.Close();
         inputStream = null;
         ActiveStream.Close();
         ActiveStream = null;
     }
 }
        private void processActiveStream()
        {
            int pos = (int)ActiveStream.Position;
            int len = (int)ActiveStream.Length;

            byte[] path     = new byte[len];
            byte[] waveData = null;

            ActiveStream.Read(path, 0, len);
            ActiveStream.Position = pos;

            WaveFormat waveFormat = (WaveFormat)ActiveStream.WaveFormat;

            SetWaveHeader(ref path, waveFormat, out waveData);
            GenerateWaveformData(waveData, null, waveFormat);
        }
Beispiel #8
0
 private void StopAndCloseStream()
 {
     waveOutDevice?.Stop();
     if (activeStream != null)
     {
         inputStream.Close();
         inputStream = null;
         ActiveStream.Close();
         ActiveStream = null;
     }
     if (waveOutDevice != null)
     {
         waveOutDevice.Dispose();
         waveOutDevice = null;
     }
 }
 private void StopAndCloseStream()
 {
     IsPlaying = false;
     if (directSoundOut != null)
     {
         directSoundOut.Stop();
     }
     if (ActiveStream != null)//Check object hoiding resources(pcm or MP3Reader)
     {
         ActiveStream.Close();
         ActiveStream = null;
     }
     if (directSoundOut != null)
     {
         directSoundOut.Dispose();
         directSoundOut = null;
     }
 }
        private void StopAndCloseStream()
        {
            if (waveOutDevice != null)
            {
                waveOutDevice.Stop();
            }

            if (activeStream != null)
            {
                _streamToPlay.Close();
                _streamToPlay = null;
                ActiveStream.Close();
                ActiveStream = null;
            }
            if (waveOutDevice != null)
            {
                waveOutDevice.Dispose();
                waveOutDevice = null;
            }
        }
Beispiel #11
0
        /// <summary>
        /// Writes data asynchronously.
        /// </summary>
        /// <param name="buffer">The buffer.</param>
        /// <param name="forceFlush">if set to <c>true</c> [force flush].</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task that represents the asynchronous write operation.</returns>
        public async Task WriteDataAsync(byte[] buffer, bool forceFlush, CancellationToken cancellationToken = default)
        {
            try
            {
                _writeDone.WaitOne();
                _writeDone.Reset();
                await ActiveStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);

                if (forceFlush)
                {
                    await ActiveStream.FlushAsync(cancellationToken).ConfigureAwait(false);
                }

                DataSentLastTimeUtc = DateTime.UtcNow;
            }
            finally
            {
                _writeDone.Set();
            }
        }
Beispiel #12
0
        /// <summary>
        /// Calls <see cref="TorrentManager.StopAsync()"/> on <see cref="Manager"/> and unregisters
        /// it from the <see cref="ClientEngine"/>. This will dispose the stream returned by the
        /// most recent invocation of <see cref="CreateHttpStreamAsync(ITorrentFileInfo)"/> or
        /// <see cref="CreateStreamAsync(ITorrentFileInfo)"/>.
        /// </summary>
        /// <returns></returns>
        public async Task StopAsync()
        {
            if (!Active)
            {
                throw new InvalidOperationException("The StreamProvider can only be stopped if it is Active");
            }

            if (Manager.State == TorrentState.Stopped)
            {
                throw new InvalidOperationException(
                          "The TorrentManager associated with this StreamProvider has already been stopped. " +
                          "It is an error to directly call StopAsync, PauseAsync or StartAsync on the TorrentManager.");
            }

            Cancellation.Cancel();
            await Manager.StopAsync();

            await Engine.Unregister(Manager);

            ActiveStream.SafeDispose();
            Active = false;
        }
            /// <summary>
            /// Delete a live Twitch stream.
            /// </summary>
            /// <param name="username">Username of the stream.</param>
            /// <returns>DateTime of when stream went live, null if not deleted or error.</returns>
            public static DateTime?Delete(string username)
            {
                try {
                    using DatabaseContext database = new DatabaseContext();

                    if (database.ActiveStreams.AsNoTracking().Any(x => x.Username == username))
                    {
                        ActiveStream stream = database.ActiveStreams.AsNoTracking().Where(x => x.Username == username).FirstOrDefault();
                        database.ActiveStreams.Remove(stream);

                        database.SaveChanges();

                        return(stream.StartedAt);
                    }
                    else
                    {
                        return(null);
                    }
                } catch (Exception ex) {
                    LoggingManager.Log.Error(ex);
                    return(null);
                }
            }
Beispiel #14
0
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: dispose managed state (managed objects).
                }

                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                if (DisplayInfo != null)
                {
                    DisplayInfo.Dispose();
                    DisplayInfo = null;
                }
                if (waveOutDevice != null)
                {
                    waveOutDevice.Stop();
                }
                if (activeStream != null)
                {
                    inputStream.Close();
                    inputStream = null;
                    ActiveStream.Close();
                    ActiveStream = null;
                }
                if (waveOutDevice != null)
                {
                    waveOutDevice.Dispose();
                    waveOutDevice = null;
                }

                // TODO: set large fields to null.

                disposedValue = true;
            }
        }
Beispiel #15
0
        public bool InitStream(string identifier, string clientDescription, MediaSource source)
        {
            if (!source.Exists)
            {
                Log.Warn("Tried to start stream for non-existing file {0}", source.GetDebugName());
                return(false);
            }

            ActiveStream stream = new ActiveStream();

            stream.Identifier        = identifier;
            stream.ClientDescription = clientDescription;
            stream.ClientIP          = WCFUtil.GetClientIPAddress();
            stream.StartTime         = DateTime.Now;
            stream.Context           = new StreamContext();
            stream.Context.Source    = source;
            stream.Context.IsTv      = source.MediaType == WebStreamMediaType.TV;

            lock (Streams)
            {
                Streams[identifier] = stream;
            }
            return(true);
        }
Beispiel #16
0
        /// <summary>
        /// </summary>
        private void CloseOldStreams()
        {
            ulong CurrentTicks = TimeUtils.Ticks;

            lock (ActiveStreams)
            {
                for (int i = 0; i < ActiveStreams.Count; i++)
                {
                    ActiveStream Stm = ActiveStreams[i];

                    ulong Elapsed = CurrentTicks - Stm.LastAccessed;
                    if (Elapsed > MaxStreamAge && Stm.ActiveOperations == 0)
                    {
                        Logger.Log(LogLevel.Verbose, LogCategory.IO, "Closing stream for async queue: {0}", Stm.Path);

                        Stm.Stream.Close();

                        ActiveStreams.RemoveAt(i);
                        ActiveStreamsByPath.Remove(Stm.Path);
                        i--;
                    }
                }
            }
        }
Beispiel #17
0
        /// <summary>
        /// </summary>
        /// <returns></returns>
        private ActiveStream GetActiveStream(string Path, bool AllowPermissionFixes = true, bool RequireWrite = true)
        {
            ulong CurrentTicks = TimeUtils.Ticks;

            lock (ActiveStreams)
            {
                ActiveStream ExistingStream = null;
                if (ActiveStreamsByPath.ContainsKey(Path))
                {
                    ExistingStream = ActiveStreamsByPath[Path];

                    // If we need to write to this file and we are only open for read, drain event queue and reopen.
                    if (!ExistingStream.CanWrite && RequireWrite)
                    {
                        Logger.Log(LogLevel.Info, LogCategory.IO, "Stalling while draining read queue and reopening for write: '{0}'", Path);

                        // This is not ideal, we should remove this if practical, it wastes processing time.
                        while (ExistingStream.ActiveOperations > 0)
                        {
                            Thread.Sleep(0);
                        }

                        ExistingStream.Stream.Close();
                        ActiveStreams.Remove(ExistingStream);
                        ActiveStreamsByPath.Remove(ExistingStream.Path);
                    }
                    else
                    {
                        ExistingStream.LastAccessed = CurrentTicks;
                        return(ExistingStream);
                    }
                }

                // We need to remove one stream to max space.
                while (ActiveStreams.Count >= MaxStreams)
                {
                    ActiveStream OldestStream = null;

                    // Find oldest thats not doing anything.
                    foreach (ActiveStream Stm in ActiveStreams)
                    {
                        if (Stm.ActiveOperations == 0)
                        {
                            if (OldestStream == null || Stm.LastAccessed < OldestStream.LastAccessed)
                            {
                                OldestStream = Stm;
                            }
                        }
                    }

                    if (OldestStream == null)
                    {
                        Thread.Sleep(0);
                    }
                    else
                    {
                        Logger.Log(LogLevel.Verbose, LogCategory.IO, "Closing stream for async queue (as we have reached maximum stream count): {0}", OldestStream.Path);

                        OldestStream.Stream.Close();

                        ActiveStreams.Remove(OldestStream);
                        ActiveStreamsByPath.Remove(OldestStream.Path);
                    }
                }

                try
                {
                    Logger.Log(LogLevel.Verbose, LogCategory.IO, "Opening stream for async queue (can write = {0}): {1}", RequireWrite, Path);

                    string DirPath = System.IO.Path.GetDirectoryName(Path);
                    if (!Directory.Exists(DirPath))
                    {
                        Directory.CreateDirectory(DirPath);
                    }

                    ActiveStream NewStm = new ActiveStream();
                    NewStm.LastAccessed = CurrentTicks;
                    NewStm.Path         = Path;
                    NewStm.CanWrite     = RequireWrite;
#if DISABLE_IO_BUFFERING
                    FileOptions FileFlagNoBuffering = (FileOptions)0x20000000;
                    NewStm.Stream = new FileStream(Path, FileMode.OpenOrCreate, RequireWrite ? FileAccess.ReadWrite : FileAccess.Read, FileShare.ReadWrite, StreamBufferSize, FileOptions.Asynchronous | FileOptions.WriteThrough | FileFlagNoBuffering);
#else
                    NewStm.Stream = new FileStream(Path, FileMode.OpenOrCreate, RequireWrite ? FileAccess.ReadWrite : FileAccess.Read, FileShare.ReadWrite, StreamBufferSize, FileOptions.Asynchronous);
#endif
                    ActiveStreams.Add(NewStm);
                    ActiveStreamsByPath.Add(NewStm.Path, NewStm);

                    return(NewStm);
                }
                catch (Exception Ex)
                {
                    Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to open stream '{0}' with error {1}", Path, Ex.Message);

                    if (AllowPermissionFixes && TryFixFileAttributes(Path))
                    {
                        return(GetActiveStream(Path, false, RequireWrite));
                    }
                }
            }

            return(null);
        }
Beispiel #18
0
        /// <summary>
        /// </summary>
        /// <param name="Stm"></param>
        /// <param name="Work"></param>
        /// <param name="Offset"></param>
        /// <param name="Size"></param>
        private void ReadWithOffset(ActiveStream Stm, Task Work, int Offset)
        {
            lock (Stm)
            {
                try
                {
                    Stm.Stream.Seek(Work.Offset + Offset, SeekOrigin.Begin);
                    Stm.Stream.BeginRead(
                        Work.Data, (int)Work.DataOffset + Offset, (int)Work.Size - Offset, Result =>
                    {
                        try
                        {
                            int BytesRead = Stm.Stream.EndRead(Result);
                            if (BytesRead == 0)
                            {
                                Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to read file {0} at offset {1} size {2}. Encountered end of file.", Stm.Path, Work.Offset + Offset, Work.Size - Offset);
                                Work.Callback?.Invoke(false);
                            }
                            else
                            {
                                GlobalBandwidthStats.Out(BytesRead);

                                if (BytesRead < Work.Size)
                                {
                                    ReadWithOffset(Stm, Work, Offset + BytesRead);
                                    return;
                                }

                                ulong ElapsedTime = TimeUtils.Ticks - Work.QueueTime;
                                OutLatency.Add(ElapsedTime);

                                Work.Callback?.Invoke(true);
                            }
                        }
                        catch (Exception Ex)
                        {
                            Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to read file {0} with error: {1}", Stm.Path, Ex.Message);

                            Work.Callback?.Invoke(false);
                        }
                        finally
                        {
                            Interlocked.Add(ref GlobalQueuedOut, -Work.Size);
                            Interlocked.Decrement(ref Stm.ActiveOperations);

                            WakeThread();
                        }
                    }, null
                        );
                }
                catch (Exception Ex)
                {
                    Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to read to file {0} with error: {1}", Stm.Path, Ex.Message);

                    Work.Callback?.Invoke(false);
                    Interlocked.Add(ref GlobalQueuedOut, -Work.Size);
                    Interlocked.Decrement(ref Stm.ActiveOperations);

                    WakeThread();
                }
            }
        }
Beispiel #19
0
        /// <summary>
        /// </summary>
        /// <param name="Work"></param>
        private bool RunTask(Task Work)
        {
            ActiveStream Stm = null;

            if (Work.Type == TaskType.Write || Work.Type == TaskType.Read)
            {
                Stm = GetActiveStream(Work.Path, true, Work.Type == TaskType.Write);
                if (Stm == null)
                {
                    Work.Callback?.Invoke(false);
                    return(true);
                }
            }

            // Limit number of ops per stream.
            if (Stm != null && Stm.ActiveOperations >= StreamMaxConcurrentOps)
            {
                return(false);
            }

            // Should this be a failure or a deferal? Going to
            // go with failure now as the only thing we use path locking for is deleting files.
            if (IsPathLocked(Work.Path))
            {
                Work.Callback?.Invoke(false);
                return(true);
            }

            if (Work.Type == TaskType.Write)
            {
                Interlocked.Increment(ref Stm.ActiveOperations);
                lock (Stm)
                {
#if EMULATE_IO
                    GlobalBandwidthStats.In(Work.Size);

                    Work.Callback?.Invoke(true);
                    Interlocked.Add(ref GlobalQueuedIn, -Work.Size);
                    Interlocked.Decrement(ref Stm.ActiveOperations);
#else
                    try
                    {
                        //Console.WriteLine("####### WRITING[offset={0} size={1}, stream={2}] {3}", Work.Offset, Work.Size, Stm.Stream.ToString(), Work.Path);

                        // TODO: Lock?
                        Stm.Stream.Seek(Work.Offset, SeekOrigin.Begin);
                        Stm.Stream.BeginWrite(
                            Work.Data, (int)Work.DataOffset, (int)Work.Size, Result =>
                        {
                            try
                            {
                                GlobalBandwidthStats.In(Work.Size);

                                Stm.Stream.EndWrite(Result);

                                ulong ElapsedTime = TimeUtils.Ticks - Work.QueueTime;
                                InLatency.Add(ElapsedTime);

                                Work.Callback?.Invoke(true);
                            }
                            catch (Exception Ex)
                            {
                                Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to write to file {0} with error: {1}", Stm.Path, Ex.Message);
                                Work.Callback?.Invoke(false);
                            }
                            finally
                            {
                                Interlocked.Add(ref GlobalQueuedIn, -Work.Size);
                                Interlocked.Decrement(ref Stm.ActiveOperations);

                                WakeThread();
                            }
                        }, null
                            );
                    }
                    catch (Exception Ex)
                    {
                        Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to write to file {0} with error: {1}", Stm.Path, Ex.Message);

                        Work.Callback?.Invoke(false);
                        Interlocked.Add(ref GlobalQueuedIn, -Work.Size);
                        Interlocked.Decrement(ref Stm.ActiveOperations);
                    }
#endif
                }
            }
            else if (Work.Type == TaskType.Read)
            {
                Interlocked.Increment(ref Stm.ActiveOperations);

                //Logger.Log(LogLevel.Info, LogCategory.IO, "Reading: offset={0} length={1} path={2}", Work.Offset, Work.Size, Work.Path);

#if EMULATE_IO
                GlobalBandwidthStats.Out(Work.Size);

                Work.Callback?.Invoke(true);
                Interlocked.Add(ref GlobalQueuedOut, -Work.Size);
                Interlocked.Decrement(ref Stm.ActiveOperations);
#else
                ReadWithOffset(Stm, Work, 0);
#endif
            }
            else if (Work.Type == TaskType.DeleteDir)
            {
                try
                {
                    CloseStreamsWithStall(Work.Path);

                    LockPath(Work.Path);

                    // Shifted into its own thread as it can take forever for large folders.
                    System.Threading.Tasks.Task.Run(
                        () =>
                    {
                        try
                        {
                            FileUtils.DeleteDirectory(Work.Path);
                            Work.Callback?.Invoke(true);
                        }
                        catch (Exception Ex)
                        {
                            Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to delete directory {0} with error: {1}", Work.Path, Ex.Message);
                            Work.Callback?.Invoke(false);
                        }
                        finally
                        {
                            UnlockPath(Work.Path);
                        }
                    }
                        );
                }
                catch (Exception Ex)
                {
                    Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to delete directory {0} with error: {1}", Work.Path, Ex.Message);
                    Work.Callback?.Invoke(false);
                }
            }
            else if (Work.Type == TaskType.CloseStreamsInDir)
            {
                try
                {
                    CloseStreamsWithStall(Work.Path);
                    Work.Callback?.Invoke(true);
                }
                catch (Exception Ex)
                {
                    Logger.Log(LogLevel.Error, LogCategory.IO, "Failed to close streams in directory {0} with error: {1}", Work.Path, Ex.Message);
                    Work.Callback?.Invoke(false);
                }
            }

            return(true);
        }
Beispiel #20
0
        public string StartStream(string identifier, TranscoderProfile profile, long position = 0, int audioId = STREAM_DEFAULT, int subtitleId = STREAM_DEFAULT)
        {
            // there's a theoretical race condition here between the insert in InitStream() and this, but the client should really, really
            // always have a positive result from InitStream() before continuing, so their bad that the stream failed.
            if (!Streams.ContainsKey(identifier) || Streams[identifier] == null)
            {
                Log.Warn("Stream requested for invalid identifier {0}", identifier);
                return(null);
            }

            if (profile == null)
            {
                StreamLog.Warn(identifier, "Stream requested for non-existent profile");
                return(null);
            }

            try
            {
                lock (Streams[identifier])
                {
                    StreamLog.Debug(identifier, "StartStream for file {0}", Streams[identifier].Context.Source.GetDebugName());

                    // initialize stream and context
                    ActiveStream stream = Streams[identifier];
                    stream.Context.StartPosition = position;
                    stream.Context.Profile       = profile;
                    stream.UseActivityForTimeout = profile.Transport == "httplive";
                    stream.Context.MediaInfo     = MediaInfoHelper.LoadMediaInfoOrSurrogate(stream.Context.Source);
                    stream.Context.OutputSize    = CalculateSize(stream.Context);
                    StreamLog.Debug(identifier, "Using {0} as output size for stream {1}", stream.Context.OutputSize, identifier);
                    Reference <WebTranscodingInfo> infoRef = new Reference <WebTranscodingInfo>(() => stream.Context.TranscodingInfo, x => { stream.Context.TranscodingInfo = x; });
                    sharing.StartStream(stream.Context, infoRef);

                    // get transcoder
                    stream.Transcoder            = (ITranscoder)Activator.CreateInstance(Type.GetType(profile.Transcoder));
                    stream.Transcoder.Identifier = identifier;
                    stream.Transcoder.Context    = stream.Context;

                    // get audio and subtitle id
                    if (stream.Context.MediaInfo.AudioStreams.Any(x => x.ID == audioId))
                    {
                        stream.Context.AudioTrackId = stream.Context.MediaInfo.AudioStreams.First(x => x.ID == audioId).ID;
                    }
                    else if (audioId == STREAM_DEFAULT)
                    {
                        string preferredLanguage = Configuration.Streaming.DefaultAudioStream;
                        if (stream.Context.MediaInfo.AudioStreams.Any(x => x.Language == preferredLanguage))
                        {
                            stream.Context.AudioTrackId = stream.Context.MediaInfo.AudioStreams.First(x => x.Language == preferredLanguage).ID;
                        }
                        else if (preferredLanguage != "none" && stream.Context.MediaInfo.AudioStreams.Any())
                        {
                            stream.Context.AudioTrackId = stream.Context.MediaInfo.AudioStreams.First().ID;
                        }
                    }

                    if (stream.Context.MediaInfo.SubtitleStreams.Any(x => x.ID == subtitleId))
                    {
                        stream.Context.SubtitleTrackId = stream.Context.MediaInfo.SubtitleStreams.First(x => x.ID == subtitleId).ID;
                    }
                    else if (subtitleId == STREAM_DEFAULT)
                    {
                        string preferredLanguage = Configuration.Streaming.DefaultSubtitleStream;
                        if (stream.Context.MediaInfo.SubtitleStreams.Any(x => x.Language == preferredLanguage))
                        {
                            stream.Context.SubtitleTrackId = stream.Context.MediaInfo.SubtitleStreams.First(x => x.Language == preferredLanguage).ID;
                        }
                        else if (preferredLanguage == "external" && stream.Context.MediaInfo.SubtitleStreams.Any(x => x.Filename != null))
                        {
                            stream.Context.SubtitleTrackId = stream.Context.MediaInfo.SubtitleStreams.First(x => x.Filename != null).ID;
                        }
                        else if (preferredLanguage == "first" && stream.Context.MediaInfo.SubtitleStreams.Any())
                        {
                            stream.Context.SubtitleTrackId = stream.Context.MediaInfo.SubtitleStreams.First().ID;
                        }
                    }
                    StreamLog.Debug(identifier, "Final stream selection: audioId={0}, subtitleId={1}", stream.Context.AudioTrackId, stream.Context.SubtitleTrackId);

                    // build the pipeline
                    stream.Context.Pipeline        = new Pipeline(identifier);
                    stream.Context.TranscodingInfo = new WebTranscodingInfo();
                    stream.Transcoder.BuildPipeline();

                    // start the pipeline, but imm
                    bool assembleResult = stream.Context.Pipeline.Assemble();
                    bool startResult    = assembleResult ? stream.Context.Pipeline.Start() : true;
                    if (!assembleResult || !startResult)
                    {
                        StreamLog.Warn(identifier, "Starting pipeline failed");
                        return(null);
                    }

                    // get the final stream and return it
                    Stream finalStream = Streams[identifier].Context.Pipeline.GetFinalStream();
                    if (finalStream != null)
                    {
                        Streams[identifier].OutputStream = new ReadTrackingStreamWrapper(finalStream);
                    }

                    StreamLog.Info(identifier, "Started stream");
                    Streams[identifier].LastActivity = DateTime.Now;
                    return(stream.Transcoder.GetStreamURL());
                }
            }
            catch (Exception ex)
            {
                StreamLog.Error(identifier, "Failed to start stream", ex);
                return(null);
            }
        }
Beispiel #21
0
        public bool InitStream(string identifier, string clientDescription, MediaSource source)
        {
            ActiveStream stream = new ActiveStream();
            stream.Identifier = identifier;
            stream.ClientDescription = clientDescription;
            stream.StartTime = DateTime.Now;
            stream.Context = new StreamContext();
            stream.Context.Source = source;
            stream.Context.IsTv = source.MediaType == WebStreamMediaType.TV;

            lock (Streams)
            {
                Streams[identifier] = stream;
            }
            return true;
        }
Beispiel #22
0
        public string StartStream(string identifier, TranscoderProfile profile, int position = 0, int audioId = STREAM_DEFAULT, int subtitleId = STREAM_DEFAULT)
        {
            // there's a theoretical race condition here between the insert in InitStream() and this, but the client should really, really
            // always have a positive result from InitStream() before continuing, so their bad that the stream failed.
            if (!Streams.ContainsKey(identifier) || Streams[identifier] == null)
            {
                Log.Warn("Stream requested for invalid identifier {0}", identifier);
                return(null);
            }

            if (profile == null)
            {
                Log.Warn("Stream requested for non-existent profile");
                return(null);
            }

            try
            {
                lock (Streams[identifier])
                {
                    Log.Trace("StartStream called with identifier {0}", identifier);

                    // initialize stream and context
                    ActiveStream stream = Streams[identifier];
                    stream.Context.StartPosition = position;
                    stream.Context.Profile       = profile;
                    stream.Context.MediaInfo     = MediaInfoHelper.LoadMediaInfoOrSurrogate(stream.Context.Source);
                    stream.Context.OutputSize    = CalculateSize(stream.Context);
                    Reference <WebTranscodingInfo> infoRef = new Reference <WebTranscodingInfo>(() => stream.Context.TranscodingInfo, x => { stream.Context.TranscodingInfo = x; });
                    Log.Trace("Using {0} as output size for stream {1}", stream.Context.OutputSize, identifier);
                    sharing.StartStream(stream.Context, infoRef);

                    // get transcoder
                    stream.Transcoder            = profile.GetTranscoder();
                    stream.Transcoder.Identifier = identifier;

                    // get audio and subtitle id
                    if (stream.Context.MediaInfo.AudioStreams.Where(x => x.ID == audioId).Count() > 0)
                    {
                        stream.Context.AudioTrackId = stream.Context.MediaInfo.AudioStreams.Where(x => x.ID == audioId).First().ID;
                    }
                    else if (audioId == STREAM_DEFAULT)
                    {
                        string preferredLanguage = Configuration.Streaming.DefaultAudioStream;
                        if (stream.Context.MediaInfo.AudioStreams.Count(x => x.Language == preferredLanguage) > 0)
                        {
                            stream.Context.AudioTrackId = stream.Context.MediaInfo.AudioStreams.First(x => x.Language == preferredLanguage).ID;
                        }
                        else if (preferredLanguage != "none" && stream.Context.MediaInfo.AudioStreams.Count() > 0)
                        {
                            stream.Context.AudioTrackId = stream.Context.MediaInfo.AudioStreams.First().ID;
                        }
                    }

                    if (stream.Context.MediaInfo.SubtitleStreams.Where(x => x.ID == subtitleId).Count() > 0)
                    {
                        stream.Context.SubtitleTrackId = stream.Context.MediaInfo.SubtitleStreams.Where(x => x.ID == subtitleId).First().ID;
                    }
                    else if (subtitleId == STREAM_DEFAULT)
                    {
                        string preferredLanguage = Configuration.Streaming.DefaultSubtitleStream;
                        if (stream.Context.MediaInfo.SubtitleStreams.Count(x => x.Language == preferredLanguage) > 0)
                        {
                            stream.Context.SubtitleTrackId = stream.Context.MediaInfo.SubtitleStreams.First(x => x.Language == preferredLanguage).ID;
                        }
                        else if (preferredLanguage == "external" && stream.Context.MediaInfo.SubtitleStreams.Count(x => x.Filename != null) > 0)
                        {
                            stream.Context.SubtitleTrackId = stream.Context.MediaInfo.SubtitleStreams.First(x => x.Filename != null).ID;
                        }
                        else if (preferredLanguage == "first" && stream.Context.MediaInfo.SubtitleStreams.Count() > 0)
                        {
                            stream.Context.SubtitleTrackId = stream.Context.MediaInfo.SubtitleStreams.First().ID;
                        }
                    }
                    Log.Debug("Final stream selection: audioId={0}, subtitleId={1}", stream.Context.AudioTrackId, stream.Context.SubtitleTrackId);

                    // build the pipeline
                    stream.Context.Pipeline        = new Pipeline();
                    stream.Context.TranscodingInfo = new WebTranscodingInfo();
                    stream.Transcoder.BuildPipeline(stream.Context);

                    // start the processes and retrieve output stream
                    stream.Context.Pipeline.Assemble();
                    stream.Context.Pipeline.Start();

                    Stream finalStream = Streams[identifier].Context.Pipeline.GetFinalStream();
                    if (finalStream != null)
                    {
                        Streams[identifier].OutputStream = new ReadTrackingStreamWrapper(finalStream);
                    }

                    Log.Info("Started stream with identifier " + identifier);
                    return(stream.Transcoder.GetStreamURL());
                }
            }
            catch (Exception ex)
            {
                Log.Error("Failed to start stream " + identifier, ex);
                return(null);
            }
        }
Beispiel #23
0
 public void Close()
 {
     ActiveClient.Close();
     ActiveStream.Close();
 }
Beispiel #24
0
        public bool InitStream(string identifier, string clientDescription, MediaSource source, int timeout)
        {
            if (!source.Exists)
            {
                StreamLog.Warn(identifier, "Tried to start stream for non-existing file {0}", source.GetDebugName());
                return false;
            }

            ActiveStream stream = new ActiveStream();
            stream.Identifier = identifier;
            stream.ClientDescription = clientDescription;
            stream.StartTime = DateTime.Now;
            stream.Timeout = timeout;
            stream.LastActivity = DateTime.Now;
            stream.UseActivityForTimeout = false;
            stream.Context = new StreamContext();
            stream.Context.Identifier = identifier;
            stream.Context.Source = source;
            stream.Context.IsTv = source.MediaType == WebMediaType.TV;

            // Some clients such as WebMP proxy the streams before relying it to the client. We should give these clients the option to
            // forward the real IP address, so that we can show that one in the configurator too. However, to avoid abuse, we should show
            // the real IP of the client too, so make up some nice text string.
            string realIp = WCFUtil.GetHeaderValue("forwardedFor", "X-Forwarded-For");
            stream.ClientIP = realIp == null ? WCFUtil.GetClientIPAddress() : String.Format("{0} (via {1})", realIp, WCFUtil.GetClientIPAddress());

            Streams[identifier] = stream;
            return true;
        }
Beispiel #25
0
        public bool InitStream(string identifier, string clientDescription, MediaSource source)
        {
            if (!source.Exists)
            {
                Log.Warn("Tried to start stream for non-existing file {0}", source.GetDebugName());
                return false;
            }

            ActiveStream stream = new ActiveStream();
            stream.Identifier = identifier;
            stream.ClientDescription = clientDescription;
            stream.ClientIP = WCFUtil.GetClientIPAddress();
            stream.StartTime = DateTime.Now;
            stream.Context = new StreamContext();
            stream.Context.Source = source;
            stream.Context.IsTv = source.MediaType == WebStreamMediaType.TV;

            lock (Streams)
            {
                Streams[identifier] = stream;
            }
            return true;
        }