Ethernet audio library ready to beta test

Status
Not open for further replies.
More data..

I have narrowed the issue down to these two lines in control_sgtl5000.cpp enable()

Code:
	write(CHIP_ANA_POWER, 0x40FF); // power up: lineout, hp, adc, dac					// fixed "broken" teensy by downloading, but didnt survive reboot
	write(CHIP_DIG_POWER, 0x0073); // power up all digital stuff						// fixed reboot issue with previous line

I'm reasonably sure if you can run these two lines in control_ethernet::enable(), then the issue will be resolved. I feel like there should be a way to do this with inheritance but I just don't know enough about the structure of the classes.

I see that AudioControlSGTL5000 extends AudioControl. So I thougth I could just replace AudioControl with AudioControlSGTL5000 in control_ethernet but it didn't quite work the way I was expecting...

I'll leave the fix up to smarter people than I.
 
Thanks for the diagnostic, it's good to know exactly where the pain is. It doesn't immediately indicate what the issue is, unless these are the first write register commands in SGTL...enable().

Your proposed solution isn't the best way to approach the issue. BTW each of the two child classes inherits AucioControl in a different way, so Ether inheriting SGTL isn't going to be a good idea. It also ties SGTL and Ethernet together, which is not appropriate (i.e. they should be able to be used independently).

I'll dig a bit more. I have a suspicion that all the pins are somehow being messed up while they are being sorted out: SGTL - clocks, TX/RX, enable and I2C and Ether - SPI, enable.
 
It also ties SGTL and Ethernet together, which is not appropriate (i.e. they should be able to be used independently).

Oh. Hmm. I hadn't thought of that. I assumed I had to use one or the other. Kinda makes more sense now. lol. So now I see why trying to play with inheritance was moot.

So If I wanted to use, say, a net in and and an I2S out the Audio shield, I would just have one AudioControlEtherNet control AND a AudioControlSGTL5000 control and then patch as necessary? Sometimes I wonder how I got this far in life.lol.

I guess I'm confused because audio in and out the SGTL works using the AudioEthernet library.

I would assume that all those things that get done in the AudioControlSGTL5000::enable() are probably important, and they won't get done if you don't create an AudioControlSGTL5000 instance. That's why I was confused how AudioControlSGTL5000 fits in...I didn't see how that library would do anything without instantiating an instance or inheriting it.

In my testing I added an instance of AudioControlSGTL5000 (in addition to the AudioControlEtherNet instance) which fixed the issue. So I guess technically there really isn't an issue, I was just using it wrong. :eek:


Thank you for all your help on this. I got audio coming in the Audio shield on one and out the Audio shield on the other and I'm very surprised and how low the latency is. Barely perceptible. Now lets see what happens when there are 8 streams.. well that will have to wait until I buy 6 more Teensys. If this all works out we'll be making 50+ of these...
 
Every piece of hardware has a single Control object - so yes an AudioControlEtherNet control AND a AudioControlSGTL5000.

Audio input and output for the SGTL is handled by input_i2s / output_i2s and input_net / output_net.

In the Net case, as many input_net / output_net objects are created as necessary to talk to other hosts or multiply the number of channels (I'll create input_4net / output_4net sometime soon to handle quad traffic, 8 channels takes us over the 1500 byte ethernet MTU limit). So stack up a few objects and try it out.

At 100Mbits, the theoretical max is limited by the SPI rate (you need to increase this to 30Mb/s in W5100.h if you haven't done so already, as there's lots of SPI chatting with the WIZ going on other than data transmission) and the max W5500 ethernet rate (15Mb/s) over a 100Mb/s link. This equates to about 16 channels each way, total. I've only tried 2+2 each way so far, and had zero dropouts on an isolated network.
 
I'll create input_4net / output_4net sometime soon to handle quad traffic
Me being greedy... I'm only interested in mono streams. No idea what is involved with that. I would assume that would halve the bandwidth and reduce the processing power needed to process (?)


For my situation, each unit will only generate one mono network stream, but may be subscribed to 1 or several (possibly up to 8 but normally 1-3) incoming (broadcast) streams.

Also I see that it seems once an output stream is enabled, that it turns on the ethernet faucet. With broadcast traffic, I'm guessing this will increase workloads of all units on the network, even if they aren't subscribed (?) as they still need to see if that packet is for them. Or is this overhead small?

Is there a possibility to not send packets if there is no audio? (Assuming it makes sense to do so)
 
A small gain in processing power, and yes it nearly halves the bandwidth (each packet has an overhead).

It's in my longer ToDo list - it is not difficult, but involves a lot of fiddly work, creating a pair of extra in/out objects and a new packet type to support them. When I do it, it will be something like the new multi channel I2S routines, with a common core of code and just the differentiated code in each specific file.

In all, unless you're using a whole lot of the two channel objects (8 or more), you shouldn't get close to WIZ limits, and the T4 has an abundance of processing power, with audio buffer handling consuming a very small proportion of that.
 
I'm having all kinds of pain running the Audio Shield with Ethernet at the moment (T4, rev D Audio Shield). Ethernet's working on its own with the AudioShield in place and un-enabled; as is the AudioShield with ethernet SPI connected but not enabled. As soon as I enable the AudioShield after the Ethernet, everything stops.

Can you flick across your working code for your
I got audio coming in the Audio shield on one and out the Audio shield on the other.

Both libraries and sketch would be useful, so that I can see where I've introduced the error into the library?

BTW, which Teensys are you using?
 
I'm away on business this week so I'm away from the hardware.

I am using the 3.6 so not sure how much this will help, but I have two 4s and 2 more audioshields coming by the weekend.

This is a long shot of a guess but I've found similar issues if I do not include this line in the setup, I don't understand why:
Code:
AudioConnection          patchCord(net_in1, 0, net_out1, 1);
If I don't do this, the code stops before it gets even to the setup(). As soon as I add it, everything works normally even though I'm not using that output channel.

Here's my working 2 way, the modified library, and my current pinout.
View attachment 2way test.zip

One thing to note, this code relies on having a 2 or 3 written to address 0x00 in the EEPROM to determine the setup.

Note, one additional (unrelated) change I made to the library is added a overloaded AudioPlaySerialflashRaw::lengthMillis(const char *filename) that allows you to get the length of a file without actually playing it first which is useful for scheduling a string of audio clips together.
 
Last edited:
Thanks for the files and explanations.

I'll dig through my code and yours and see if I can find the bug(s). It may not be the same thing causing both issues - despite them having similar symptoms (dying at setup() ).

I've now tested the code on both a T3.2 / Rev C board and a T4 / Rev D board with the same fault appearing, so my guess is that the T3.6 will behave pretty much the same as the T3.2 in this case.

No problems with your updated (and quite neat) way of storing the HostID and IP - it saves changing code for each chip programmed. I'll have a look at adding it to the code base, and maybe adding a simple Serial Monitor command parser to set the values remotely.

BTW in V2 of the code, I'm pulling enable() out of the AudioControlEtherNet constructor, as it doesn't make sense to auto-run it before the SPI pins and IP/MAC are established.
 
Any update on the library?


Have you ever used the SD Card (either the one on the Teensy, or the one on the Audioboard) along with this EthAudio library?

If so, what SD library did you use?

I use the "CopyFromSD" to copy files from the SD card to the Serial Flash chip on the audio board. But when I try to just connect to the SD card in my existing project that uses the EthAudio library, it hangs.

I dug deep into the SD library and found it hanging while trying to send a CRC byte. Gets caught in that never ending while loop.

Code:
/** SPI send a byte */
static void spiSend(uint8_t b) {
  SPI0_MCR |= SPI_MCR_CLR_RXF;
  SPI0_SR = SPI_SR_TCF;
  SPI0_PUSHR = b;
  while (!(SPI0_SR & SPI_SR_TCF)) {}
}

The call stack is something like SD.begin(10) -> card.init(SPI_HALF_SPEED, csPin) -> Sd2Card::SD_init -> cardAcmd -> cardCommand -> spiSend(crc)

It sends a couple commands prior to the one that fails. It fails on this one in SD_init when cardAcmd is called:

Code:
// initialize card and send host supports SDHC if SD2
  arg = (type_ == SD_CARD_TYPE_SD2) ? 0X40000000 : 0;
  	
  while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
    // check for timeout
    unsigned int d = millis() - t0;
    if (d > SD_INIT_TIMEOUT) {
      goto fail; // SD_CARD_ERROR_ACMD41
    }
  }



The SD card I'm using is the same one I've used many times with the CopyFromSD example. So I'm not sure what is different other than I have the EthAudio library loaded.
 
So I've been able to get a partial file read. So it would seem something is right, but it's super unstable. Every reboot it may or may not hang at different spots in the communications.
 
Try the files in my development repo

https://github.com/palmerr23/audio

They have some updates that make them behave better with certain other modules (SGTL5000 and CS2448 specifically), but are not fully tested in other ways yet.

I've been working on the CS42448 board recently and haven't had a chance to update the main repo.

As for the SD card compatibility, you'll need to sort out the CS pins, as I used the same one as the Teensy Audio Board uses for the SD card. I don't use SD cards, so this was probably a poor default choice - able to be sorted out with the long form Ethernet constructor:

MyEthernet.begin(short csPin, short sckPin, short mosiPin, short misoPin);

Also, as the Ethernet library is not interrupt driven, SD card transfers may clash with the SPI transfers to the WIZ chip if the SD library is interrupt-driven. Things should be OK for program-driven SD IO where the code uses the transaction semaphores (i.e. SPI.beginTransaction()...).

As SPI traffic is pretty heavy on the Ethernet side, it would be better to use a totally separate SPI channel for SD transfers - sadly there's not a second one easily available. They are mapped to the pogo pins / FFC connector on the T4.0 and smaller T3's. The T4.1 (and T3.5/6) have a more accessible second SPI port, that should avoid SPI clashes.

Hope this helps!
 
Thanks for the info.

I spent all day on this yesterday testing the various SD libraries as well as trying both the card slot on the audio board and the one on the 3.6..

After reading up, I was under the impression the slot on the 3.6 was already on its own SPI bus. But seems no matter what I did it would fail at a random point which would support the idea that there's some clashing going on.

Guess I have more reading to do.

Thanks!
 
So either I'm a moron, or...... I'm a moron.

Got up this morning and got it working within 10 minutes of sitting down using the slot on the 3.6.

Onward!
 
In what way? The core of the 4.1 is identical to the 4.0, so the basic code should be OK.

If you wish to use the extra SPI pins - SPI remapping is already in place.

Are there other features that you can see might need porting?

When Paul has completed the planned Ethernet implementation I'll definitely take a look at that, as the Wiznet 5500s are a key constraint to throughput and flexibility.

BTW: My current priorities are:

  1. Crossing the divide between the Teensy and the desktop (e.g. DAWs) with more than 2 channels (particularly all 8 inputs/outputs from my CS42448 board!)
  2. Creating 4 channel input and output objects. (Maybe 8 channel objects too, but 8 channels is bigger than a single UDP packet's maximum size, so implementation could be messy.)
  3. Testing the MIDI transmission features.

Re 1:

Commercial protocols (e.g. Dante) are too expensive to consider, but I quite like the VBAN proposal by VoiceMeeter. It's quite similar in concept to mine, so re-implementation won't be onerous.
https://www.vb-audio.com/Voicemeeter/vban.htm

Changing packet structure won't affect the Teensy Audio side in any significant way, as it's mostly about the UDP packet construction. Their protocol can handle MIDI and text packets which are also on my to-do list.

Their virtual mixer products are donation-ware for non-commercial use and the Banana mixer has quite a good channel matrix implementation, but sadly only for Windows.
 
Thanks for the heads up.

I'm keeping to things that are in the core of the Teensyduino library at the moment, but will watch the FNTE/Native Ethernet developments with interest and definitely provide that option when it moves to mainstream.

It will be particularly nice if the library is interrupt driven at the TCP/UDP packet layer.

I'll need to split the queue/stream management and device management parts of the Ethernet control, but that's in the pipeline anyway.
 
Thanks for the heads up.

I'm keeping to things that are in the core of the Teensyduino library at the moment, but will watch the FNTE/Native Ethernet developments with interest and definitely provide that option when it moves to mainstream.

It will be particularly nice if the library is interrupt driven at the TCP/UDP packet layer.

I'll need to split the queue/stream management and device management parts of the Ethernet control, but that's in the pipeline anyway.

That is good to know. Was wondering about that.
 
It is interrupt driven to a certain extent, average response times are pretty low, with the NativeEthernet wrapper library it should already work with this library as long as you didn’t make any calls to w5100.h. If you wanted response times to be even lower you would have to use FNET directly which has a bit of a learning curve since there isn’t much documentation out there. I would recommend just trying it with the wrapper library first and see if you are satisfied with the speeds though.
 
I am investigating options for making a matrix intercom system, based on Teensy 4.1. The Ethernet Audio library seems to be a very good starting point for this.
I'm assuming that for a 16 station setup, i could potentially use a broadcasting structure, where each station broadcasts it's audio frames, and will receive the frames from all other stations.
The actual mixing for each station is then also done locally (only using the desired station data for listening). A simple control structure could be build to indicate talking to a station etc.
This method should not use more network bandwidth (1 broadcast per station) than using a central server for the matrix mixing (1 up / 1 down audio stream per station).
I might want to modify the audio frames to support mono (1 channel) transmission.

Does this make sense, or am i overlooking some basic constraints?

To reduce required bandwith i am also looking at using the OPUS codec, but that's for a later stage. I think that my initial approach in using Mumble as a server makes less sense since this merely routes the indiviual audio streams and leaves the mixing to the clients anyhow.
 
While each station would be able to network broadcast it's own audio, each station would have to set up a listening socket for each of the other 15 stations...you'd run out of sockets.

But I suspect you could use the control channel instead to signal which station wants to talk. Then all the other stations could set up a listening socket for that broadcast.

If you want them to all be able to talk/listen simultaneously, I don't think that's going to be possible unless there's something new in 4.1 that's not available in 3.6.
 
You might be right, but i do not know all the details for UDP broadcasts.
Do i really need a separate listening sockect for the individual incoming streams?
They all arrive at the same port, so i assumed they will be received anyhow. The only drawback might be, that i cannot associate each incoming stream packet to the correct originator. (this could be prevented by adding the StreamID into the audio packet)
Potentially also the NativeEthernet behaves different in this aspect than the WizNet modules....

Hopefully this does not go too much off-topic.
 
I’m not sure of the behavior with WizNet vs NativeEthernet, but I do know you can’t use the same port more than once. You also aren’t really limited in the number of sockets you can have once you add a user config option to FNET that changes it from the default max of 12.
 
Firstly, I haven't tested my code with native ethernet on a 4.1 yet. It's on my to do list, but not quite yet. Others will be more knowledgeable than I on this. No reason why it shouldn't work on a 4.1, if the calls to UDP behave in the same way.

turbo2ltr has it almost correct, you can use a single port on the Wiznet to pick up all the broadcast packets. The issue will be decoding them - what you will need to do is set up audio objects to receive all of the streams individually. I wrote the code thinking of a star configuration 8 channel "hub" (using my reworked version of the 8in 8out - yes, the updated version has 8 inputs) with 2 channel (Paul's audio board) slave channels.

The input subscribeStream() function allows you to subscribe to any one of the streams (and source) you like on each individual input object, and the control ethernet getActiveStreams() code provides a list of them.

Talk and listen simultaneously is not an issue - the input and output streams are totally independent at the audio library level. Removing sidetone (speaker into microphone) can be done in code, though I haven't tried it.

With 16 input streams you'll be pushing the boundaries of a Wiznet 5500 (particularly as each stream has 2 channels). The key issue is SPI throughput (40Mbits including handshaking and commands), which runs out of puff somewhat before the theoretical 100 Mb ethernet limit.

You might need to increase the maximum number of queue slots in the library, particularly if it starts dropping packets. (audio_net.h) You need two for every active in or out channel. But then, there's a danger of running out of audiomem completely if the max is still 40 (?)
#define MAX_AUDIO_QUEUE 32 // number of slots in the audio queue

You should have enough stream handles...
#define MAX_TCP_STREAMS_IN 32 // all available streams for this host
#define MAX_TCP_STREAMS_OUT 8 // published streams from this host

I hope this helps.
 
Status
Not open for further replies.
Back
Top