/// <summary> /// Decoded data into the buffer /// </summary> /// <returns></returns> private bool FillBuffer() { var packet = GetNextEncodedData(); if (!packet.HasValue) { //Debug.Log("empty"); return(false); } // Don't make the decoder unless we know that we'll have to if (_decoder == null) { _decoder = new OpusDecoder(_outputSampleRate, _outputChannelCount); } if (_decodedBuffer[_nextBufferToDecodeInto] == null) { _decodedBuffer[_nextBufferToDecodeInto] = new float[SubBufferSize]; } //Debug.Log("decoding " + packet.Value.Sequence + " expected=" + _nextSequenceToDecode + " last=" + _lastReceivedSequence + " len=" + packet.Value.Data.Length); if (_nextSequenceToDecode != 0) { long seqDiff = packet.Value.Sequence - _nextSequenceToDecode; // If new packet is VERY late, then the sequence number has probably reset if (seqDiff < -MaxMissingPackets) { Debug.Log("Sequence has possibly reset diff = " + seqDiff); _decoder.ResetState(); } // If the packet came before we were expecting it to, but after the last packet, the sampling has probably changed // unless the packet is a last packet (in which case the sequence may have only increased by 1) else if (packet.Value.Sequence > _lastReceivedSequence && seqDiff < 0 && !packet.Value.IsLast) { Debug.Log("Mumble sample rate may have changed"); } // If the sequence number changes abruptly (which happens with push to talk) else if (seqDiff > MaxMissingPackets) { Debug.Log("Mumble packet sequence changed abruptly pkt: " + packet.Value.Sequence + " last: " + _lastReceivedSequence); } // If the packet is a bit late, drop it else if (seqDiff < 0 && !packet.Value.IsLast) { Debug.LogWarning("Received old packet " + packet.Value.Sequence + " expecting " + _nextSequenceToDecode); return(false); } // If we missed a packet, add a null packet to tell the decoder what happened else if (seqDiff > 0) { //Debug.LogWarning("dropped packet, recv: " + packet.Value.Sequence + ", expected " + _nextSequenceToDecode); NumPacketsLost += packet.Value.Sequence - _nextSequenceToDecode; int emptySampleNumRead = _decoder.Decode(null, _decodedBuffer[_nextBufferToDecodeInto]); _decodedCount += emptySampleNumRead; _numSamplesInBuffer[_nextBufferToDecodeInto] = emptySampleNumRead; _readOffsetInBuffer[_nextBufferToDecodeInto] = 0; _nextSequenceToDecode = packet.Value.Sequence + emptySampleNumRead / ((_outputSampleRate / 100) * _outputChannelCount); _nextBufferToDecodeInto++; //Make sure we don't go over our max number of buffers if (_nextBufferToDecodeInto == NumDecodedSubBuffers) { _nextBufferToDecodeInto = 0; } if (_decodedBuffer[_nextBufferToDecodeInto] == null) { _decodedBuffer[_nextBufferToDecodeInto] = new float[SubBufferSize]; } //Debug.Log("Null read returned: " + emptySampleNumRead + " samples"); } } int numRead = 0; if (packet.Value.Data.Length != 0) { numRead = _decoder.Decode(packet.Value.Data, _decodedBuffer[_nextBufferToDecodeInto]); } else { Debug.LogError("empty packet data?"); } if (numRead < 0) { Debug.Log("num read is < 0"); return(false); } _decodedCount += numRead; _numSamplesInBuffer[_nextBufferToDecodeInto] = numRead; _readOffsetInBuffer[_nextBufferToDecodeInto] = 0; //Debug.Log("numRead = " + numRead); _lastReceivedSequence = packet.Value.Sequence; if (!packet.Value.IsLast) { _nextSequenceToDecode = packet.Value.Sequence + numRead / ((_outputSampleRate / 100) * _outputChannelCount); } else { //Debug.Log("Resetting decoder"); _nextSequenceToDecode = 0; HasFilledInitialBuffer = false; _decoder.ResetState(); } if (numRead > 0) { _nextBufferToDecodeInto++; } //Make sure we don't go over our max number of buffers if (_nextBufferToDecodeInto == NumDecodedSubBuffers) { _nextBufferToDecodeInto = 0; } return(true); }
private void DecodeThread() { while (!_isDisposing) { _waitHandle.WaitOne(); // Keep looping until either disposed // or the message queue is depleted while (!_isDisposing) { try { MessageData messageData; lock (_messageQueue) { if (_messageQueue.Count == 0) { break; } messageData = _messageQueue.Dequeue(); } OpusDecoder decoder = null; DecoderState decoderState; switch (messageData.TypeOfMessage) { case MessageType.AllocDecoderState: // If we receive an alloc decoder state message // then we just need make an entry for it in // current decoders. We don't bother assigning // an actual opus decoder until we get data // this is because there may be lots of users // in current decoders, but only a few of them // actually are sending audio _currentDecoders[messageData.Session] = new DecoderState(); //Debug.Log("Alloc'd DecoderState for session: " + messageData.Session); break; case MessageType.FreeDecoder: if (_currentDecoders.TryGetValue(messageData.Session, out decoderState)) { // Return the OpusDecoder if (decoderState.Decoder != null) { _unusedDecoders.Enqueue(decoderState.Decoder); } _currentDecoders.Remove(messageData.Session); //Debug.Log("Removing DecoderState for session: " + messageData.Session); } else { Debug.Log("Failed to remove decoder for session: " + messageData.Session); } break; case MessageType.DecompressData: // Drop this audio, if there's no assigned decoder ready to receive it if (!_currentDecoders.TryGetValue(messageData.Session, out decoderState)) { Debug.LogWarning("No DecoderState for session: " + messageData.Session); break; } // Make an OpusDecoder if there isn't one if (decoderState.Decoder == null) { if (_unusedDecoders.Count > 0) { decoder = _unusedDecoders.Dequeue(); decoder.ResetState(); } else { decoder = new OpusDecoder(_outputSampleRate, _outputChannelCount); } //Debug.Log("Added OpusDecoder for DecoderState session: " + messageData.Session); decoderState.Decoder = decoder; } DecodeAudio(messageData.Session, decoderState, messageData.CompressedAudio, messageData.PosData, messageData.Sequence, messageData.IsLast); break; default: Debug.LogError("Message type not implemented:" + messageData.TypeOfMessage); break; } }catch (Exception e) { Debug.LogError("Exception in decode thread: " + e.ToString()); } } } }