コード例 #1
0
        public virtual void Dispose()
        {
            _runThread = false;
            _threadEvent.Set();
            if (_thread.IsStarted)
            {
                _thread.Join();
            }

            //ncrunch: no coverage start
            if (_diagnosticOutputRecorder != null)
            {
                _diagnosticOutputRecorder.Dispose();
                _diagnosticOutputRecorder = null;
            }
            //ncrunch: no coverage end

            using (var subscriptions = _micSubscriptions.Lock())
                while (subscriptions.Value.Count > 0)
                {
                    Unsubscribe(subscriptions.Value[0]);
                }

            using (var subscriptions = _vadSubscriptions.Lock())
                while (subscriptions.Value.Count > 0)
                {
                    Unsubscribe(subscriptions.Value[0]);
                }

            Log.Debug("Disposed pipeline");
        }
コード例 #2
0
ファイル: EncoderPipeline.cs プロジェクト: KarmaPenny/Hanabi
        public void ReceiveMicrophoneData(ArraySegment <float> inputSamples, [NotNull] WaveFormat format)
        {
            if (format == null)
            {
                throw new ArgumentNullException("format");
            }
            if (!format.Equals(_inputFormat))
            {
                throw new ArgumentException(string.Format("Samples expected in format {0}, but supplied with format {1}", _inputFormat, format), "format");
            }

            using (var encoderLock = _encoder.Lock())
            {
                var encoder = encoderLock.Value;

                //Early exit if we have been disposed on the main thread
                if (_disposed)
                {
                    return;
                }

                //Early exit if we've sent the last frame of this stream
                if (_stopped)
                {
                    return;
                }

                //Propogate the loss value on to the encoder
                encoder.PacketLoss = TransmissionPacketLoss;

                //Write samples to the pipeline (keep a running total of how many we have sent)
                //Keep sending until we've sent all of these samples
                var offset = 0;
                while (offset != inputSamples.Count)
                {
                    // ReSharper disable once AssignNullToNotNullAttribute (Justification: Array segment cannot be null)
                    offset += _input.Write(new ArraySegment <float>(inputSamples.Array, inputSamples.Offset + offset, inputSamples.Count - offset));

                    //Drain some of those samples just written, encode them and send them off
                    //If we're shutting down send a maximum of 1 packet
                    var encodedFrames = EncodeFrames(encoder, _stopping ? 1 : int.MaxValue);

                    //Don't encode any more frames if we've sent the one final frame
                    if (encodedFrames > 0 && _stopping)
                    {
                        _stopped = true;
                        Log.Debug("Encoder stopped");
                        break;
                    }
                }
            }
        }
コード例 #3
0
        public bool Read(ArraySegment <float> frame)
        {
            VoicePacket?encoded;
            var         lastFrame = _buffer.Read(out encoded);

            int decodedCount;

            if (encoded != null)
            {
                Log.Trace("Decoding frame {0}", encoded.Value.SequenceNumber);
                decodedCount = _decoder.Decode(encoded.Value.EncodedAudioFrame, frame);

                //Expose the playback options for this packet
                using (var l = _options.Lock())
                    l.Value = encoded.Value.PlaybackOptions;

                //Expose the channel list for this packet (if it's null just assume the previous value is still correct)
                if (encoded.Value.Channels != null)
                {
                    using (var l = _channels.Lock())
                    {
                        _approxChannelCount = encoded.Value.Channels.Count;
                        l.Value.Clear();
                        l.Value.AddRange(encoded.Value.Channels);
                    }
                }

                _recycleFrame(encoded.Value);
            }
            else
            {
                Log.Trace("Running decoder PLC");
                decodedCount = _decoder.Decode(null, frame);
            }

            //Sanity check that decoding got correct number of samples
            if (decodedCount != _frameSize)
            {
                throw new InvalidOperationException(string.Format("Decoding a frame of audio got {0} samples, but should have decoded {1} samples", decodedCount, _frameSize));
            }

            if (_diagnosticOutput != null)
            {
                _diagnosticOutput.WriteSamples(frame);
            }

            return(lastFrame);
        }
コード例 #4
0
        private void ExtractChannels(VoicePacket encoded)
        {
            //Expose the channel list for this packet (if it's null just assume the previous value is still correct)
            if (encoded.Channels != null)
            {
                using (var l = _channels.Lock())
                {
                    _approxChannelCount = encoded.Channels.Count;

                    l.Value.Clear();
                    l.Value.AddRange(encoded.Channels);
                }

                _receivedFirstPacket = true;
            }
        }
コード例 #5
0
 private static int Drop <T>([NotNull] ReadonlyLockedValue <List <T> > l)
 {
     using (var ll = l.Lock())
     {
         var dropped = ll.Value.Count;
         ll.Value.Clear();
         return(dropped);
     }
 }
コード例 #6
0
        /// <summary>
        /// Return an item to the pool
        /// </summary>
        /// <param name="item"></param>
        public void Put([NotNull] T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            using (_putter.Lock())
            {
                _items.TryWrite(item);
            }
        }
コード例 #7
0
 /// <summary>
 /// Get an item from this pool
 /// </summary>
 /// <returns></returns>
 [NotNull] public T Get()
 {
     using (_getter.Lock())
     {
         T item;
         if (_items.Read(out item) && !ReferenceEquals(item, null))
         {
             return(item);
         }
         else
         {
             return(_factory());
         }
     }
 }
コード例 #8
0
        public void Stop()
        {
            //Stop listening for channel events
            _playerChannels.OpenedChannel -= OpenPlayerChannel;
            _playerChannels.ClosedChannel -= ClosePlayerChannel;
            _roomChannels.OpenedChannel   -= OpenRoomChannel;
            _roomChannels.ClosedChannel   -= CloseRoomChannel;

            //Stop listening for player events
            _events.PlayerJoined -= OnPlayerJoined;
            _events.PlayerLeft   -= OnPlayerLeft;

            //Discard all open channels
            using (var openChannels = _openChannels.Lock())
                openChannels.Value.Clear();
        }
コード例 #9
0
        public void Update()
        {
            //Reliable traffic to server
            using (var locker = _serverReliableQueue.Lock())
            {
                var q = locker.Value;
                for (var i = 0; i < q.Count; i++)
                {
                    var item = q[i];
                    _client.SendReliable(item);
                    _tmpRecycleQueue.Add(item.Array);
                }

                q.Clear();
            }

            //Unreliable traffic to server
            using (var locker = _serverUnreliableQueue.Lock())
            {
                var q = locker.Value;
                for (var i = 0; i < q.Count; i++)
                {
                    var item = q[i];
                    _client.SendUnreliable(item);
                    _tmpRecycleQueue.Add(item.Array);
                }

                q.Clear();
            }

            //P2P reliable traffic
            using (var locker = _reliableP2PQueue.Lock())
            {
                var q = locker.Value;
                for (var i = 0; i < q.Count; i++)
                {
                    var item = q[i];

                    //Send it
                    _client.SendReliableP2P(item.Key, item.Value);

                    //Recycle
                    _tmpRecycleQueue.Add(item.Value.Array);
                    item.Key.Clear();
                    _listPool.Put(item.Key);
                }

                q.Clear();
            }

            //P2P reliable traffic
            using (var locker = _unreliableP2PQueue.Lock())
            {
                var q = locker.Value;
                for (var i = 0; i < q.Count; i++)
                {
                    var item = q[i];

                    //Send it
                    _client.SendUnreliableP2P(item.Key, item.Value);

                    //Recycle
                    _tmpRecycleQueue.Add(item.Value.Array);
                    item.Key.Clear();
                    _listPool.Put(item.Key);
                }

                q.Clear();
            }

            //Recycle all the buffers
            using (var locker = _sendBufferPool.Lock())
            {
                for (var i = 0; i < _tmpRecycleQueue.Count; i++)
                {
                    var v = _tmpRecycleQueue[i];
                    if (v != null)
                    {
                        locker.Value.Put(v);
                    }
                }
            }
            _tmpRecycleQueue.Clear();
        }
コード例 #10
0
        /// <summary>
        /// Dispatch all events waiting in the queue to event handlers
        /// </summary>
        /// <remarks>Returns true if any invocation caused an error</remarks>
        public bool DispatchEvents(DateTime?utcNow = null)
        {
            PreDispatchLog(utcNow ?? DateTime.UtcNow);

            var error = false;

            using (var events = _queuedEvents.Lock())
            {
                var queuedEvents = events.Value;

                for (var i = 0; i < queuedEvents.Count; i++)
                {
                    var e = queuedEvents[i];

                    switch (e.Type)
                    {
                    case EventType.PlayerJoined:
                        error |= InvokeEvent(e.PlayerName, e.CodecSettings, PlayerJoined);
                        break;

                    case EventType.PlayerLeft:
                        error |= InvokeEvent(e.PlayerName, PlayerLeft);
                        break;

                    case EventType.PlayerStartedSpeaking:
                        error |= InvokeEvent(e.PlayerName, PlayerStartedSpeaking);
                        break;

                    case EventType.PlayerStoppedSpeaking:
                        error |= InvokeEvent(e.PlayerName, PlayerStoppedSpeaking);
                        break;

                    case EventType.VoiceData:
                        error |= InvokeEvent(e.VoicePacket, VoicePacketReceived);
                        _pendingVoicePackets--;

                        // Recycle channel buffer
                        if (e.VoicePacket.Channels != null)
                        {
                            e.VoicePacket.Channels.Clear();
                            _channelsListPool.Recycle(e.VoicePacket.Channels);
                        }

                        // Recycle voice data buffer
                        var arr = e.VoicePacket.EncodedAudioFrame.Array;
                        if (arr != null)
                        {
                            using (var locker = _byteArrayPool.Lock())
                                locker.Value.Put(arr);
                        }

                        break;

                    case EventType.TextMessage:
                        error |= InvokeEvent(e.TextMessage, TextMessageReceived);
                        break;

                    case EventType.PlayerEnteredRoom:
                        var evtEnter = CreateRoomEvent(e, true);
                        error |= InvokeEvent(evtEnter, PlayerEnteredRoom);
                        break;

                    case EventType.PlayerExitedRoom:
                        var evtExit = CreateRoomEvent(e, false);
                        error |= InvokeEvent(evtExit, PlayerExitedRoom);
                        break;

                    //ncrunch: no coverage start (Justification: It's a sanity check, we shouldn't ever hit this line)
                    default:
                        throw new ArgumentOutOfRangeException();
                        //ncrunch: no coverage end
                    }
                }

                queuedEvents.Clear();

                return(error);
            }
        }
コード例 #11
0
        /// <summary>
        /// Dispatch all events waiting in the queue to event handlers
        /// </summary>
        /// <remarks>Returns true if any invocation caused an error</remarks>
        public bool DispatchEvents()
        {
            var error = false;

            using (var events = _queuedEvents.Lock())
            {
                var queuedEvents = events.Value;

                for (var i = 0; i < queuedEvents.Count; i++)
                {
                    var e = queuedEvents[i];

                    switch (e.Type)
                    {
                    case EventType.PlayerJoined:
                        error |= InvokeEvent(e.PlayerName, PlayerJoined);
                        break;

                    case EventType.PlayerLeft:
                        error |= InvokeEvent(e.PlayerName, PlayerLeft);
                        break;

                    case EventType.PlayerStartedSpeaking:
                        error |= InvokeEvent(e.PlayerName, PlayerStartedSpeaking);
                        break;

                    case EventType.PlayerStoppedSpeaking:
                        error |= InvokeEvent(e.PlayerName, PlayerStoppedSpeaking);
                        break;

                    case EventType.VoiceData:
                        error |= InvokeEvent(e.VoicePacket, VoicePacketReceived);

                        //The voice packet event is special. It has some components which need to be recycled. Do that here
                        if (e.VoicePacket.Channels != null)
                        {
                            e.VoicePacket.Channels.Clear();
                            _channelsListPool.Recycle(e.VoicePacket.Channels);
                        }
                        _byteArrayPool.Recycle(e.VoicePacket.EncodedAudioFrame.Array);
                        break;

                    case EventType.TextMessage:
                        error |= InvokeEvent(e.TextMessage, TextMessageReceived);
                        break;

                    case EventType.PlayerEnteredRoom:
                        var evtEnter = CreateRoomEvent(e, true);
                        error |= InvokeEvent(evtEnter, PlayerEnteredRoom);
                        break;

                    case EventType.PlayerExitedRoom:
                        var evtExit = CreateRoomEvent(e, false);
                        error |= InvokeEvent(evtExit, PlayerExitedRoom);
                        break;

                    //ncrunch: no coverage start (Justification: It's a sanity check, we shouldn't ever hit this line)
                    default:
                        throw new ArgumentOutOfRangeException();
                        //ncrunch: no coverage end
                    }
                }

                queuedEvents.Clear();

                return(error);
            }
        }