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"); }
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; } } } }
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); }
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; } }
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); } }
/// <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); } }
/// <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()); } } }
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(); }
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(); }
/// <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); } }
/// <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); } }