Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Many Questions: Which ESP, Wiring Diagram, MAX98357A Compatibility, and Expandability #1

Closed
bai-yi-bai opened this issue May 2, 2024 · 22 comments

Comments

@bai-yi-bai
Copy link

bai-yi-bai commented May 2, 2024

Hi! I saw you posted on a hackernews a few days ago. I've wanted to try this out because I have been using thin clients with Snapcast which cost a lot more and take up a lot more space. I've been waiting for a project like this.

I have a lot of questions.

  1. Could you provide a wiring diagram? Even a simple photo would help. I am a novice at Rust and didn't know it was possible to compile rust to ESP32s, so I cannot figure out the pinout from the source code.
  2. Related to the first question, I picked up an I2S mono amp a while back, based on the MAX98357A, looks like a knockoff of an Adafruit I2S 3W Class D Amplifier Breakout - MAX98357A. Since it's I2S, it should simply be compatible, right?
  3. I have an ESP development kit which I got a few years ago with an ESP32-WROOM-32, would this be compatible? Or do I need an ESP32S? I'm confused by the statement on the product page and the linked aliexpress product.
  4. This one is a long shot... I have some Marshall bluetooth speakers which turn off after a few minutes of inactivity. I wrote a bash script to play some low frequency noise. Using Systemd to Keep Speakers with Automatic Sleep Function Alive, I wonder if it would be possible to expand this project to play back this noise when snapcast is not playing back audio to prevent them from turning off.

Again, awesome project! This really drops the cost down of having a multi-speaker audio system.

@DavidVentura
Copy link
Owner

DavidVentura commented May 2, 2024

Hey

  1. For the pins, I picked (now edited to match the new layout)
ESP I2s board
D21 WSEL
D19 DIN
D18 BCLK
GND GND
3v3 VIN

The specific pinout is not required, you only need pins that can output, are not bootstrap pins, and do not output garbage on boot.

I also have a pull down resistor on WSEL (>20k, going from WSEL -> GND) to limit some noise (pops, cracks), but that may be unnecessary with your adapter.

  1. For the mono amp, it should just work if it uses the same sample format (which most likely it will)

  2. The WROOM-32 will work, that's the one I'm using, though you end up limited to ~700ms of buffer, which will cause small silences if you have some network/wifi issues; I've been seeing about 1-2 drops/day. If you buy a model with more RAM, you can buffer longer
    I. do keep in mind that a long buffer is frustrating as a user, when you hit "next" on your playlist, you will not hear the new song until the entire buffer length is played out (this does not affect volume control)

  3. It shouldn't be too complicated to play a default sample if there's no audio data for a while, but the sample itself will require some tuning, as it's not clear what some speakers will consider "silence"

@bai-yi-bai
Copy link
Author

bai-yi-bai commented May 2, 2024

Excellent, your reply motivated me to try, but I fell a little short.
As a true newbie, I am stumbling through documentation to figure out how to build an image and get it working.
I've surmounted several errors and toolchain setup issues, but I'm a bit stumped.

Here's what I've done so far, I really am not sure which commands I should be running.

  1. I installed Rust according to the instructions at https://docs.esp-rs.org/book/installation/rust.html.
  2. I cloned both esp-snapcast and snapcast-client.
  3. I installed apt-get install -y libudev-dev.
  4. I installed cargo install ldproxy.
  5. I installed cargo install espflash.
  6. I tried make and that took a few minutes to build.
  7. Once, I got an error that the SSID and PASS variables were not defined, so I const SSID: &str = env!("SSID"); with simply const SSID: &str = "the_name_of_my_network". I did the same for the password.
  8. I copied partitions.csv to /target/xtensa-esp32-espidf/release/, navigated to the folder, and executed this command:
espflash flash esp-snapcast -p /dev/ttyUSB0 -f 40mhz --partition-table partitions.csv
[2024-05-02T16:50:56Z INFO ] Serial port: '/dev/ttyUSB0'
[2024-05-02T16:50:56Z INFO ] Connecting...
[2024-05-02T16:50:56Z INFO ] Using flash stub
Chip type:         esp32 (revision v1.0)
Crystal frequency: 40 MHz
Flash size:        4MB
Features:          WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC address:      <redacted>
Partition table:   partitions.csv
App/part. size:    1,105,216/3,145,728 bytes, 35.13%

[00:00:01] [========================================]      17/17      0x1000
[00:00:00] [========================================]       1/1       0x8000
[00:01:10] [========================================]     711/711     0x10000 
[2024-05-02T16:52:12Z INFO ] Flashing has completed!
  1. I stopped my snapserver and launched it manually to observe the log.
  2. I then used espflash monitor and in another terminal confirmed the ESP32 did connect to my network by pinging it.
 (5136) esp_netif_handlers: sta ip: 192.168.1.135, mask: 255.255.255.0, gw: 192.168.1.1
I (5138) esp_snapcast::wifi: IP config: IpInfo { ip: 192.168.1.135, subnet: Subnet { gateway: 192.168.1.1, mask: Mask(24) }, dns: Some(192.168.1.1), secondary_dns: Some(0.0.0.0) }
I (5151) esp_snapcast: Syncing time via SNTP
I (5156) esp_idf_svc::sntp: Initializing
I (5161) esp_idf_svc::sntp: Initialization complete
I (6978) esp_snapcast: Time sync 1714667804.518844s
I (25231) esp_idf_svc::sntp: Dropped
Error: Software caused connection abort (os error 113)
I (25232) main_task: Returned from app_main()

There was no activity on the snapserver output from 192.168.1.135 which is the ESP32 snapclient.

During one try, I got this error:

***ERROR*** A stack overflow in task IDLE0 has been detected.

Backtrace: 0x40082de6:0x3ffba5a0 0x40088e59:0x3ffba5c0 0x4008b77a:0x3ffba5e0 0x4008a14d:0x3ffba660 0x4008b8c4:0x3ffba690 0x4008b876:0x00000300 |<-CORRUPTED

At this point, I had not wired up the MAX98357A. I thought this might be causing a problem. I tried it again with these pins connected:
D21 BCLK
D19 DIN
GND GND
3v3 VIN

I left all the other pins, including LRC disconnected, but it made no difference.

I realize, I didn't define a name of this ESP32 snapcast client anywhere.

I feel like I'm very close. Any ideas?

@DavidVentura
Copy link
Owner

Ah, so close! for the SSID/Pss you can set the environment variables when building -- export SSID=<your ssid>

This log

I (25231) esp_idf_svc::sntp: Dropped
Error: Software caused connection abort (os error 113)
I (25232) main_task: Returned from app_main()

Is saying that the tcp connection to the server got refused, so the ESP returned from main, causing it to drop its wifi connectivity.

This is because I've not gotten around to implementing mDNS so the server IP is hardcoded 😞

If you update this line with your server's IP, it should connect
https://github.com/DavidVentura/esp-snapcast/blob/master/src/main.rs#L177

@bai-yi-bai
Copy link
Author

Wow, I was really close!
With your help, that did the trick and it appeared to connect. Unfortunately, I need to find the speaker I had intended to use so I cannot listen to the audio yet. I will purchase a UDA1334A module since it's only a few dollars.

Also, I did run into an error with flac, which makes me think my compile settings were wrong.

2024-05-03 08-48-54.995 [Error] (StreamSessionTCP) Error in socket shutdown: Transport endpoint is not connected
2024-05-03 08-48-55.004 [Notice] (StreamServer) StreamServer::NewConnection: 192.168.1.135
2024-05-03 08-48-55.014 [Info] (Server) Hello from <redacted>, host: esp32, v0.17.1, ClientName: CoolClient, OS: espidf, Arch: xtensa, Protocol version: 2
2024-05-03 08-48-55.058 [Error] (StreamSessionTCP) Error reading message header of length 0: Connection reset by peer
I (16834) esp_snapcast: Starting a new connection
I (16835) esp_snapcast: [setup done] heap low water mark: 199316
I (17157) esp_snapcast: Initializing player with: CodecHeader { codec: "flac", metadata: Flac(FlacMetadata { sample_rate: 44100, bit_depth: 16, channel_count: 2 }) }
E (17166) esp_snapcast: Connection dropped: Err(Flac disabled at build time)

Up to this point I had been using flac, but I switched over to pcm and was able to control the volume from the snapserver:1708 interface.

I (5039) esp_idf_svc::sntp: Initialization complete
I (9072) esp_snapcast: Time sync 1714698072.347591s
E (9097) snapcast_client::client: Failed to set nodelay on connection: Os { code: 109, kind: Uncategorized, message: "Protocol not available" }
I (9105) esp_snapcast: Starting a new connection
I (9106) esp_snapcast: [setup done] heap low water mark: 199036
I (9120) esp_snapcast: Initializing player with: CodecHeader { codec: "pcm", metadata: Pcm(PcmMetadata { channel_count: 2, audio_rate: 44100, _bit_depth: 16 }) }
I (9131) esp_snapcast::player: vol is now 5/128
I (9133) esp_snapcast::player: vol is now 17/128
I (14438) esp_snapcast::player: vol is now 41/128
I (21448) esp_snapcast::player: vol is now 60/128
I (22813) esp_snapcast::player: vol is now 75/128
I (51874) esp_snapcast: heap low water mark: 174012
I (52515) esp_snapcast: heap low water mark: 68148
I (54465) esp_snapcast: heap low water mark: 67572
I (54945) esp_snapcast: heap low water mark: 66592
W (56793) esp_snapcast::util: Calling send buf to queue took 1.334ms
W (64473) esp_snapcast::util: Calling send buf to queue took 1.402ms
I (68173) esp_snapcast: heap low water mark: 64780
W (74405) esp_snapcast::util: Calling send buf to queue took 1.162ms
W (75327) esp_snapcast::util: Calling send buf to queue took 1.36ms

After a while, I did start seeing resync messages on the espflash monitor. I expect this is normal, but I did see a task_wdt error

aud_at = t_c TimeVal { sec: 139, usec: 825663 } + buf_ms TimeVal { sec: 0, usec: 690000 } - local_lat TimeVal { sec: 0, usec: 0 }
wc.ts TimeVal { sec: 3579509, usec: 387320 } - lat TimeVal { sec: 3579369, usec: 561657 }
tb 141.152716s - last_tval TimeVal { sec: 3579509, usec: 357320 }
negative ts from net. cmp TimeVal { sec: -1, usec: 383058 } (norm TimeVal { sec: -1, usec: 383058 }) = aud_at TimeVal { sec:E (150301) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:
E (150301) task_wdt:  - IDLE0 (CPU 0)
E (150301) task_wdt: Tasks currently running:
E (150301) task_wdt: CPU 0: main
E (150301) task_wdt: CPU 1: IDLE1
E (150301) task_wdt: Print CPU 0 (current core) backtrace

@bai-yi-bai
Copy link
Author

Ha, I cannibalized an old Xiaomi bluetooth speaker and got it working.
The MAX98357A is incredibly loud, I tried using a 100k resistor between gain and vin to reduce it to 3db, but I don't think it helped. It's hard to tell how in-sync/out-of sync the playback is.

@DavidVentura
Copy link
Owner

To use flac you can build with --features flac, and for testing sync I've been using a phone with the snapcast app

Make sure to reduce the default buffer on snapserver, if unset it will default to 1 second

@bai-yi-bai
Copy link
Author

What's the command to recompile?

cargo build --release --features flac

feature `default` includes `flac` which is neither a dependency nor another feature

or

error: none of the selected packages contains these features: flac, did you mean: alloc?

@DavidVentura
Copy link
Owner

Oops, that's for the snapcast-client crate, in this crate you'd configure it here:
https://github.com/DavidVentura/esp-snapcast/blob/master/Cargo.toml#L29

But I've just pushed a change, adding flac as a default feature, so if you git pull you should be able to build with flac support

@bai-yi-bai
Copy link
Author

Thanks.
Small issue here:
https://github.com/DavidVentura/snapcast-client/blob/cf402c4a17d1e9afda4c1d3525760f458669c630/Cargo.toml#L28

I tried cloning https://github.com/ruuda/claxon one directory higher. Did you use a specific version?

arning: claxon (lib) generated 128 warnings (run cargo fix --lib -p claxon to apply 1 suggestion)
error[E0308]: mismatched types

error[E0412]: cannot find type ServerSettings in this scope
--> /snapcast-client/src/client.rs:15:20

@DavidVentura
Copy link
Owner

I did use a specific version! I just pushed an updated Cargo.toml pointing to this branch

@bai-yi-bai
Copy link
Author

Awesome. I got flac working with those fixes.
Absolutely incredible work.

I'll keep testing this.
If the UDA133A is a better DAC, I will likely buy a bunch of these because they should be much lower power to run than x86 thin clients.

@DavidVentura
Copy link
Owner

DavidVentura commented May 3, 2024

I bought the UDA133A because it looked like it'd be better with those caps, along with having stereo and pre-soldered headphone jack. I don't know if it's better.

If you want to use mono speakers, you probably do not want the UDA133A, as it won't merge L+R into a single channel, like the MAX98357A does

@DavidVentura
Copy link
Owner

I've just pushed support to emit low-volume audio if there is no data coming from the snapserver for a while

@bai-yi-bai
Copy link
Author

Interesting, I didn't think you'd actually do it!

I ran into some trouble again.
This time I used the bash variables for the SSID and PASS.
I only overwrote the hard-coded snapcast server with my own.
I tried flashing with both make flashm and espflash flash esp-snapcast -p /dev/ttyUSB0 -f 40mhz --partition-table partitions.csv

It seemed to stop after this:

(4976) esp_netif_handlers: sta ip: x.x.x.x mask: 255.255.255.0, gw: x.x.x.x
I (4978) esp_snapcast::wifi: IP config: IpInfo { ip: x.x.x.x, subnet: Subnet { gateway: x.x.x.x, mask: Mask(24) }, dns: Some(x.x.x.x), secondary_dns: Some(0.0.0.0) }
I (4991) esp_snapcast: Syncing time via SNTP
I (4996) esp_idf_svc::sntp: Initializing
I (5001) esp_idf_svc::sntp: Initialization complete

I could still ping it, but there was no activity on the snapcast server.

@DavidVentura
Copy link
Owner

I have the same issue 😬 I ended up disabling SNTP syncing on my devices for now, but I'll look into it soon

@DavidVentura
Copy link
Owner

I just pushed an update which fixes this, when addressing some clippy warnings I replaced a default usage, but there was some magic inside the default initializer for SNTP.

I also changed the WSEL and BCLK pins around, as they line up more easily that way with my board 😞 I'll figure out a way to make the pins configurable

@bai-yi-bai
Copy link
Author

Excellent.
Thank you for confirming the issue.
It compiles and loads just fine now :)

024-05-12 12-04-06.246 [Notice] (StreamServer) StreamServer::NewConnection: x.x.x.x
2024-05-12 12-04-06.267 [Info] (Server) Hello from MAC, host: esp32, v0.17.1, ClientName: CoolClient, OS: espidf, Arch: xtensa, Protocol version: 2

The only trouble left is on my end:

  • I have not gotten around to purchasing a UDA133A.
  • Therefore, the sound output I have is quite terrible.
  • I cannot confirm that the white noise works with my other speaker.

I do have a question about the volume settings. Perhaps I mentioned before that I trying to figure out how to run Spotify in Home Assistant as the "player" and not have to use either a desktop player or mobile player. Typically I leave the volume at 100% in the player, and use Snapcast to adjust the individual volume, using Home Assistant, however even through the terribly noisy output on my ESP+MAX98357A, I can tell that the Spotify player volume is influencing the output volume. I suppose my question is, is this intended?

Also, I see rumblings that Spotify might also finally release "High Definition" audio... do you think this will be beyond the capabilities of the ESP32?

Again, I'm glad I am on this journey with you.

@DavidVentura
Copy link
Owner

DavidVentura commented May 12, 2024

I cannot confirm that the white noise works with my other speaker.

Do you mean that it does not work? If so, you can change the volume of the sample that is played to be louder; Change this 8 to a lower number, and you should be able to hear the sound. Probably that'll be enough to keep the device alive.
If that's not it, then it's not just about "max loudness over time" but "minimum activity level", if that's the case, then you can change this 5 to a 1 how to generate more frequent samples and let me know.

On the sound quality, you mean that it's choppy/popping/scratchy, even with the snapcast volume at 100%?

I suppose my question is, is this intended?

Not entirely sure what you mean here?

Also, I see rumblings that Spotify might also finally release "High Definition" audio... do you think this will be beyond the capabilities of the ESP32?

Should be fine -- I doubt the will go above FLAC at 48kHz which is already supported.

@bai-yi-bai
Copy link
Author

I apologize for my late response. I ordered a bunch of UDA1334A boards and they just arrived. The difference between the UDA1334A and MAX98357A is night and day. I didn't want to upload a sample of how bad the output I was getting was, because it is really terrible and not worth your time debugging.

I will experiment with the volume settings, but now this is irrelevant because I am able to plug directly into a speaker with a built-in amplifier. The output sounded fine on a headphone as well.

I will test the keep-alive audio in the next day or so. I need to solder on some pin headers; it seems my first attempt didn't work, so on my second attempt I tried a different board and kept pressure on by hand.

I think the next step for me is to design a 3d-printable case to sandwich the boards together so that D18, D19, and D21 go straight down to the UDA1334A's BLCK, DIN, and WSEL pins, and then just run some jump wires from 3V3t to VIN and GND to GND.

@bai-yi-bai
Copy link
Author

I've had more time to test the UDA1334A boards. I'm even more convinced how awesome your work is.

  • Volume control is working as expected, please disregard.
  • I'm testing white noise and will reply with my results.

A question:

  • This should work with a ESP32-WROOM-U, right? I ordered one because it has a u.FL connector for an external antenna. I have location which is behind two 13 cm thick brick walls. I might rig up a directional antenna and point it at my access point.

One more idea:

  • Would it be possible to use a GPIO on these boards to indicate buffer or synchronization health? For example, it should be possible to set GPIO02, which is the blue LED on these dev boards, to ON/High when it is healthy, and Off when it falls below a set threshold. This might help give some feedback when deploying these devices to figure out what the optimal antenna orientation and position is.

@bai-yi-bai
Copy link
Author

White Noise test

  • Control Test: I powered on my blue tooth speaker and placed it in AUX mode with the audio cable detached and let it sit for 20 minutes. Then I attached cable and no audio came out. I had to manually manipulate the volume knob to get audio to come out.
  • White Noise Test: I powered on my blue tooth speaker and placed it in AUX mode with the audio cable attached to the ESP snapcast, played some music, paused the music, and then let it sit for 20 minutes. I then came back and unpaused/played music. I had to manually manipulate the volume knob to get audio to come out.
  • I should note that I do not hear the white noise.
  • I'm sorry, I don't understand how to adjust the code to try different settings. I suspect there is some sort of filter on the speaker. Would using numbers larger than "128" on this line increase the amplitude, making the sound more audible?
    if (i % 128) == 0 {

@bai-yi-bai
Copy link
Author

@DavidVentura this project is fantastic. Do you have a tip jar?

I have some additional feedback.

  • ESP-Snapcast is working very well, I was really excited to switch out all the clients I had and dreamed up new places to put speakers. However, it has been a long time since I dealt with the limitations of 2.4 GHz 802.11n, now rebranded as "Wi-Fi 4", and I was reminded of the headaches they caused us. I attempted to connect multiple ESP32's loaded with ESP-Snapcast to the same access point and SSID, and through a trial and error, I discovered that my Xiaomi AX3200 / Redmi AX6S access points are not up to the task. This is likely because they have minimal 2.4 GHz radio hardware, and do not support 2.4 GHz 802.11ax, known as "Wi-Fi 6". For my tests, I disabled my IoT SSID and created a 2.4 GHz SSID for the ESP32s running ESP-Snapcast. Whenever I connected more than one ESP32, I immediately experienced skipping due to the buffer running out or time-sync failures. I tried dozens of adjustments to the settings in the snapserver.conf file, but the result was always the same: unacceptable performance. And for the coup de gras, I connected an Android device to the same 2.4 GHz network and ran a few iterations of download tests from speedtest.net. This upset the ESPs so much that they cried, esp_snapcast: Connection dropped: Err(cannot read pkt and rebooted. Wi-Fi issues like these are a well known issue from the past 804. Therefore, I won't be replacing all my hardware with ESP-Snapcast clients, but I will install three clients, each on its own unique 2.4 GHz SSID on a dedicated access point.
  • Feel remove all the white noise code; I'm going to try to implement a server-side solution badaix/snapcast - Help With Trying to Use GStreamer to Play a Flac/Wav File #1247 or I will stick with one wired client running my shell scripts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants