private void onStatusReceived(IAsyncResult res) { if (!res.IsCompleted) { return; } if (udpStatus == null) { return; } IPEndPoint rmtEndpoint = new IPEndPoint(IPAddress.Any, 9001); byte[] data = udpStatus.EndReceive(res, ref rmtEndpoint); ampIPAddress = rmtEndpoint.Address; lastSeenTime = DateTime.Now; byte[] seqData = new byte[4]; // Convert big endian to little endian seqData[0] = data[3]; seqData[1] = data[2]; seqData[2] = data[1]; seqData[3] = data[0]; recvSequenceLast = recvSequence; recvSequence = BitConverter.ToUInt32(seqData, 0); byte[] windowData = new byte[4]; // Convert big endian to little endian windowData[0] = data[7]; windowData[1] = data[6]; windowData[2] = data[5]; windowData[3] = data[4]; recvWindowSize = BitConverter.ToUInt32(windowData, 0); byte[] statusData = new byte[4]; // Convert big endian to little endian statusData[0] = data[11]; statusData[1] = data[10]; statusData[2] = data[9]; statusData[3] = data[8]; statusBitmask = BitConverter.ToUInt32(statusData, 0); if (!didConnectSender) { IPEndPoint epSend = new IPEndPoint(ampIPAddress, 9000); udpSend.Connect(epSend); didConnectSender = true; try { if (AmplifierConnected != null) { AmplifierConnected(this); } } catch (Exception ex) { } } // This fails if a status update comes in too quickly... // the first set of packets will be dequeued before the real // ACK comes in. A work-around is in the send method above // where it waits for a litle bit after sending a reset command. lock (packetInProgress) { while (packetInProgress.Count > 0) { ulong recvSeqLong = recvSequence; PacketData pkt = packetInProgress.Peek(); // Handles the case where the amp's sequence has wrapped around if (pkt.seq > 0xFFF00000 && recvSeqLong < 0x00080000) { recvSeqLong += 0x100000000; } if (pkt.seq < recvSeqLong && (recvSeqLong - pkt.seq) >= 3 * ((ulong)pkt.data.Length - 8)) { packetInProgress.Dequeue(); } else { break; } } } try { udpStatus.BeginReceive(new AsyncCallback(onStatusReceived), null); } catch (Exception ex) { } try { if (StatusReceived != null) { StatusReceived(this, recvSequence, recvWindowSize); } } catch (Exception ex) { } }
public int sendAudioData(byte[] data, int dataLen, bool newAudioStream) { if (dataLen > data.Length) { throw new Exception("dataLen is greater than data.Length"); } if (dataLen % 6 != 0) { throw new Exception("Data must contain 2 channels of 24 bit samples, a multiple of 6 bytes per packet."); } if (dataLen > 21000) { throw new Exception("Amplifier can only accept up to 21,000 bytes per packet."); } if (!didConnectSender) { // Wait a little bit to see if it will come back... Thread.Sleep(2000); if (!didConnectSender) { throw new Exception("Have not received any status updates yet."); } } if ((statusBitmask & STATUS_CLOCK_WARNING) == STATUS_CLOCK_WARNING) { throw new Exception("The audio clock does not appear to be running."); } int START_RETRIES = 7; int retries = START_RETRIES; int packetInProgressCount; lock (packetInProgress) { packetInProgressCount = packetInProgress.Count; } while (retries > 0 && packetInProgressCount > 20) { Debug.WriteLine(String.Format("{0:HH:mm:ss:fff}: Retry {4}. Expected: {1:#,##0} but have {2:#,##0}, diff={3:#,##0}", DateTime.Now, sendSequence, recvSequence, (sendSequence - recvSequence), (START_RETRIES - retries + 1))); resendMissingPackets(); retries--; // Wait for next status to come in //Thread.Sleep(500); lock (packetInProgress) { packetInProgressCount = packetInProgress.Count; } } if (retries == 0) { throw new Exception("Retried packets too many times. Queue lenth = " + packetInProgressCount); } // Command will below will unpause automatically isPaused = false; byte[] pktBytes = new byte[dataLen + 8]; // Command pktBytes[0] = 0; pktBytes[1] = 0; pktBytes[2] = 0; pktBytes[3] = 0; // Always reset mute when starting a new stream if (newAudioStream) { isMute = false; } if (isMute) { pktBytes[3] |= 0x01; } if (newAudioStream) { sendSequence = 0; // Reset sequence to 0 and stop anything that is playing sendCommand(CMD_RESET_I2S | CMD_SET_SEQUENCE | CMD_MUTE, sendSequence); // Forget any pending audio data lock (packetInProgress) { packetInProgress.Clear(); } // Let any status messages be processed first Thread.Sleep(1000); } byte[] seqData = BitConverter.GetBytes(sendSequence); // Sequence pktBytes[4] = seqData[3]; pktBytes[5] = seqData[2]; pktBytes[6] = seqData[1]; pktBytes[7] = seqData[0]; Array.Copy(data, 0, pktBytes, 8, dataLen); PacketData pkt = new PacketData(); pkt.seq = sendSequence; pkt.data = pktBytes; lock (packetInProgress) { packetInProgress.Enqueue(pkt); } int retVal = udpSend.Send(pktBytes, pktBytes.Length); if (retVal == pktBytes.Length) { sendSequence += (uint)dataLen; } return(retVal); }