/// <summary> /// Tries to retrieve the next available ALAC frame /// </summary> /// <param name="frame">Will be set to the retrieved frame if successful</param> /// <returns>True if successful, False if waiting for next frame and null if the audio buffer has been stopped</returns> public bool?GetNextFrame(out byte[] frame, out uint timeStamp) { frame = null; timeStamp = 0; if (bufferStopped) { return(null); } lock (syncRoot) { if (bufferStopped) { return(null); } if (!bufferInit || actualBufferSize < 1 || !synced) { if (synced && actualBufferSize < 1) { //Buffer underrun Logger.Warn("Audio Buffer: Underrun"); } // Signal we're waiting and wait for next packet Logger.Debug("Audio Buffer: Waiting for new packet"); decoderStopped = true; Monitor.Wait(syncRoot); if (bufferStopped) { return(null); } Logger.Debug("Audio Buffer: New packet received"); decoderStopped = false; OnBufferRestart(); } // Overrunning. Restart at a sane distance if (actualBufferSize >= maxBufferFrames) { Logger.Debug("Buffer overrun"); readIndex = (ushort)(writeIndex - startFill); } for (int i = 16; i < (startFill / 2); i = i * 2) { int next = readIndex + i; if (!audioBuffer[next % maxBufferFrames].Ready) { OnMissingPackets(new MissingPacketEventArgs(next, next + 1)); } } AudioData buffer = audioBuffer[readIndex % maxBufferFrames]; bool ready = buffer.Ready; if (ready) { timeStamp = buffer.TimeStamp; frame = ProcessNextPacket(buffer.Data); buffer.Ready = false; } else { //Logger.Warn("Audio Buffer: Missing packet {0}", readIndex); } readIndex++; actualBufferSize = (ushort)(writeIndex - readIndex); OnPacketTaken(); return(ready); } }
/// <summary> /// Decrypts and adds the audio data to the buffer /// </summary> /// <param name="seqno">The sequence number of the packet</param> /// <param name="timestamp">The timestamp of the packet</param> /// <param name="data">The encrypted audio packet</param> public void PutPacketInBuffer(ushort seqno, uint timestamp, byte[] data) { if (bufferStopped) { return; } bool fireStarted = false; bool fireReady = false; lock (syncRoot) { if (bufferStopped) { return; } if (!synced) { writeIndex = seqno; readIndex = seqno; synced = true; } AudioData buffer = audioBuffer[seqno % maxBufferFrames]; if (seqno == writeIndex) { //Packet we expected buffer.Data = data; buffer.TimeStamp = timestamp; buffer.Ready = true; writeIndex++; } else if (isSequence(writeIndex, seqno)) { //Too early, missed packets between writeIndex and seqno //Logger.Debug("Audio Buffer: Received packet early. Expected: {0}, Received: {1}", writeIndex, seqno); //OnMissingPackets(new MissingPacketEventArgs(writeIndex, seqno)); //ask to resend buffer.Data = data; buffer.TimeStamp = timestamp; buffer.Ready = true; //jump to new seq no. writeIndex = (ushort)(seqno + 1); } else if (isSequence(readIndex, seqno)) { //Less than write index but greater than read so not yet played, insert //Logger.Debug("Audio Buffer: Received packet late but still in time to play. Expected: {0}, Received: {1}", writeIndex, seqno); buffer.Data = data; buffer.TimeStamp = timestamp; buffer.Ready = true; return; } else { //Already played Logger.Warn("Audio Buffer: Received packet late. Expected: {0}, Received: {1}", writeIndex, seqno); return; } // The number of packets in buffer actualBufferSize = (ushort)(writeIndex - readIndex); if (!bufferStarted && actualBufferSize > 0) { bufferStarted = true; fireStarted = true; } if (actualBufferSize > startFill) { if (!bufferInit) { bufferInit = true; fireReady = true; Monitor.PulseAll(syncRoot); } else if (decoderStopped) { Monitor.PulseAll(syncRoot); } } } if (fireStarted) { OnBufferStarted(); } if (fireReady) { OnBufferReady(); } }