Skip to content

Instantly share code, notes, and snippets.

@hatchjaw
Last active March 22, 2023 11:14
Show Gist options
  • Save hatchjaw/689a3833af2e79f779bd17deb0805e72 to your computer and use it in GitHub Desktop.
Save hatchjaw/689a3833af2e79f779bd17deb0805e72 to your computer and use it in GitHub Desktop.
Teensy Audio + QNEthernet multicast example
#include <Audio.h>
#include "MulticastNode.h"
AudioControlSGTL5000 audioShield;
AudioOutputI2S out;
MulticastNode node{true, false}; // flags to receive and send respectively.
AudioConnection patchCord1(node, 0, out, 0);
AudioConnection patchCord2(node, 1, out, 1);
AudioConnection patchCord3(node, 0, node, 0);
AudioConnection patchCord4(node, 1, node, 1);
void setup() {
while (!Serial);
node.begin();
AudioMemory(16);
audioShield.enable();
}
void loop() {
Serial.println("In loop()"); // Eventually stops being called...
delay(1000);
}
#include "MulticastNode.h"
MulticastNode::MulticastNode(bool receive, bool send) : AudioStream(kNumChannels, new audio_block_t *[kNumChannels]),
rx{receive}, tx{send} {
}
void MulticastNode::begin() {
Ethernet.onLinkState([this](bool state) {
Serial.printf("[Ethernet] Link %s\n", state ? "ON" : "OFF");
if (state) {
Serial.print("IP is ");
Serial.println(Ethernet.localIP());
ready = udp.beginMulticast(multicastIP, localPort);
while (!ready) {
Serial.println("Failed to set up network connection.");
yield();
}
Serial.println("Network connection established.");
}
});
Ethernet.begin(localIP, netmask, gatewayIP);
}
void MulticastNode::update(void) {
if (rx) receive();
audioOut();
if (tx) send();
}
void MulticastNode::receive() {
if (!ready) return;
int size;
while ((size = udp.parsePacket()) > 0) {
udp.read(buffer, size);
++received;
Serial.printf("Packet received (#%d), From ", received);
Serial.print(udp.remoteIP());
Serial.printf(":%d, Length %d, Data: ", udp.remotePort(), size);
// Serial.write(buffer, size);
Serial.println();
}
}
void MulticastNode::audioOut() {
audio_block_t *outBlock[kNumChannels];
audio_block_t *inBlock[kNumChannels];
auto channelFrameSize{AUDIO_BLOCK_SAMPLES * sizeof(int16_t)};
for (int ch = 0; ch < kNumChannels; ++ch) {
inBlock[ch] = receiveReadOnly(ch);
outBlock[ch] = allocate();
if (outBlock[ch] && inBlock[ch]) {
memcpy(outBlock[ch]->data, inBlock[ch], channelFrameSize);
memcpy(buffer + ch * channelFrameSize, inBlock[ch], channelFrameSize);
transmit(outBlock[ch], ch);
release(outBlock[ch]);
release(inBlock[ch]);
}
}
}
void MulticastNode::send() {
if (!ready) return;
auto size{kNumChannels * AUDIO_BLOCK_SAMPLES * sizeof(int16_t)};
Serial.print("Sending packet, to: ");
Serial.print(multicastIP);
Serial.printf(":%d, Length: %d, Data:", remotePort, size);
// Serial.write(buffer, size);
Serial.println();
auto err{udp.send(multicastIP, remotePort, buffer, size)};
Serial.println(err);
if (err == ERR_OK) {
++sent;
Serial.println("Packet sent successfully.");
}
}
#ifndef QNETHERNET_MINIMAL_MULTICASTNODE_H
#define QNETHERNET_MINIMAL_MULTICASTNODE_H
#include <Audio.h>
#include <QNEthernet.h>
using namespace qindesign::network;
class MulticastNode : public AudioStream {
public:
MulticastNode(bool receive, bool send);
void begin();
private:
static constexpr int kNumChannels{2};
void update(void) override;
void receive();
void audioOut();
void send();
EthernetUDP udp{64};
uint8_t buffer[EthernetClass::mtu() - 20 - 8];
bool ready{false};
const IPAddress multicastIP{226, 6, 38, 226},
gatewayIP{192, 168, 10, 1}, localIP{192, 168, 10, 66}, netmask{255, 255, 255, 0};
const uint16_t localPort{41814}, remotePort{41814};
int received{0}, sent{0};
bool rx, tx;
};
#endif //QNETHERNET_MINIMAL_MULTICASTNODE_H
@hatchjaw
Copy link
Author

hatchjaw commented Mar 21, 2023

receive() works for up to several thousand incoming 32-sample packets, but Teensy always locks up. send() doesn't work at all.

Specifying different packet-queue lengths doesn't appear to help, nor does switching to a while condition in MulticastNode::receive

Tested with QNEthernet 0.18.0 and 0.19.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment