sle118 / squeezelite-esp32

ESP32 Music streaming based on Squeezelite, with support for multi-room sync, AirPlay, Bluetooth, Hardware buttons, display and more
1.27k stars 114 forks source link

Add support for Line input on SqueezeAMP / ESP32-Audio-kit and others #227

Open nagyrobi opened 1 year ago

nagyrobi commented 1 year ago

Follow up from https://github.com/sle118/squeezelite-esp32/discussions/164, seconding @FHFS and @jamesmyatt I'm chiming in for an option to use the Line Input on the Audiokit. Or just use the SPDIF on SqueezeAMP's GPIO as input? Or some I2C SPDIF input modules?

The use case is very simple - use the squeezelite system to route local sound (from a TV connected to LINEIN) to the speakers (just like it would be Bluetooth). The reason for using direct cable connection is zero delay introduced in the sound which is important due to lipsync with the TV picture.

One could use the board to place it between the TV and the speakers, and this way when not watching TV, all the LMS/SqueezeLite stuff can be enjoyed on the same speakers.

It's important to have the LINEIN feature published towards LMS, so the input can be selected through the server too (eg. using an automation related to powering ON/OFF the TV set and the speakers). Logitech Transporter has two digital inputs which can be activated from LMS.

Of course volume control would be good to have through this LINE-IN -> LINE-OUT loop. Don't know if that's possible.

FHFS commented 1 year ago

I do like this option. I would love the option to add my speakers to my TV, or connect to my laptop docking station. If someone could point me in the right direction maybe I could figure it out and create a pull request for it.

sle118 commented 1 year ago

This feature is on the list to be implemented at some point, initial support will be for the new board I am creating, the SqueezeIO

Screenshot_20230111_125819

Which has the following features:

The CODEC chip I'm using on the board supports Digital-In as well so I might include SPDIF/Toslink in at some point, although I think for most usecases, the analog in should be sufficient. Outputting to all the audio ports and digitizing an analog signal is only possible thanks to the CS4265 codec I'm using, which does the heavy lifting of creating the high frequency bitstream required to encode the digital out for SPDIF and Toslink. When generating SPDIF from the bare ESP32, we are abusing the i2s to output a massive amount of data and this demanding enough that we can't output to other i2s codecs onboard.

This also a good reason for not being to use a standard GPIO to read SPDIF data; we would likely be using the max bandwidth for i2s and there wouldn't be sufficient resources left to allow local playback. There again, the CS4265 will play a major role because it will take the high frequency digital signal and convert it to an i2s bitstream that can be handled by the ESP32.

Note: The sharing of the SPI bus between Ethernet, display and IO expander were confirmed to be working already in the software

nagyrobi commented 1 year ago

Wow. Please put me on the list, I'd be the first to buy and test your prototypes. I need at least 2 or 3 pieces in my home. This new board emphasises on everything which important, especially the Ethernet connection.

May I add an extra argument in favour of Toslink input: TV sets these days don't offer an analog output anymore. Not even 3.5mm jacks for headphones. What they do offer is optical output via Toslink and HDMI ARC (Audio Return Channel) on one of the HDMI input connectors. No way to use any analog source.

If we had Toslink input, we could design our own open source soundbar replacement with this board!

I see you added a combo SPDIF/Toslink connector to the board. If you don't want to re-design the whole thing you could go hybrid and just wire them separately to the codec (if they are not terminated on the same pin inside the connector). We could then choose to use for example Toslink as input and SPDIF as output or vice-versa in the config. That should fit almost everyone, having the same signal duplicated on two connectors is usually redundant, at least this way we would also have a choice to select which one to be used for what.

sle118 commented 1 year ago

It's not possible to wire the board's output to the input side because on the driving transformer on the RCA as well as the fact that the combo has an optical output driver, which is not pin compatible with the optical input combo of the same product family.

I'll consider including digital input for the next revision of the prototype, as the codec supports it

nagyrobi commented 1 year ago

Like described in https://github.com/sle118/squeezelite-esp32/issues/228#issuecomment-1478183653 perhaps this could be implemented in software rather easily, by just watching for the command corresponding to playlist play source:toslink from LMS, to replicate exactly the functionality of the Logitech Transporter.

sle118 commented 1 year ago

Like described in #228 (comment) perhaps this could be implemented in software rather easily, by just watching for the command corresponding to playlist play source:toslink from LMS, to replicate exactly the functionality of the Logitech Transporter.

This is achieved via a plugin designed for the transporter. I will discuss this with @philippe44 in more details, as we might be able to derive something from the existing plugin which would allow choosing Analog-In or Digital-In (which I will probably include in my next hardware design iteration). That would have to be implemented in the Squeezelite-ESP32 plugin that Philippe has been maintaining.

That being said, changing to digital in or analog in doesn't resolve all the challenges. In addition to switching the input internally, we also want to take the I2S bitstream coming out of the DAC/ADC chip and funnel it through a network connection (e.g. http streaming link) and tell the server to make it available for other players to source from. I am not sure if the existing plugin was already taking care of this or not.

nagyrobi commented 1 year ago

we also want to take the I2S bitstream coming out of the DAC/ADC chip and funnel it through a network connection (e.g. http streaming link) and tell the server to make it available for other players to source from. I am not sure if the existing plugin was already taking care of this or not.

That should be a different topic.

For the use case mentioned above, this wouldn't be beneficial, as it would likely introduce a considerable amount of delay in the sound stream which would make it out of sync with the TV picture.

As a first step, I think it would be just enough to route the selected input to the output within the codec, and just take care of the statuses within the ESP.

When the live input needs to be also routed through the ESP, that should be a separate feature.

sle118 commented 1 year ago

For the use case mentioned above, this wouldn't be beneficial, as it would likely introduce a considerable amount of delay in the sound stream which would make it out of sync with the TV picture.

I see your point and I agree that input selection is a feature of its own. Exposing a stream is, at least for me, a direct extension to this. There will be delays, yes, however, these delays would likely be acceptable when synchronizing to players that aren't in the same room. For instance, you might be watching a cool live jazz performance in a room with some guests while other guests are in a different room and not watching. Streaming to other devices would allow others to also listen to the stream and the delay between picture/audio playback wouldn't cause a significant issue in the end.

nagyrobi commented 1 year ago

Raspiaudio Muse Luxe, AI-Thinker ESP32-A1S Audio Kit and Espressif LyraT v4.3 are quite popular and they all contain the ES8388 DAC.

This also is a great DAC! Because it has a built-in mixer and multiple outputs too:

ESP32 Audio Kit with the ESP32-A1S module is a wonderful board because:

This DAC could solve alone the whole task of input handling, switching, mixing.

According to ES8388 documentation it's very versatile:

Since the mixer passes audio through there's no delay in the process, which is beneficial to keep lipsync with the TV picture if used as a soundbar. ESP32 Audio Kit could do this out of the box.

Afaik this DAC can also digitize the input signal so yes, it could also be usable to generate a stream for the network.

philippe44 commented 1 year ago

As said, the only part where there is an embryo of code is for controlling the jack from the LMS UI, because it's a feature of the Boom product line to have it as an output or an input and use the built in amp.

Streaming up is another thing as we would have to activate an encoder and putting encoded audio in a ring buffer and send what we have (I don't recommend streaming pcm). Having an http server is fine

nagyrobi commented 1 year ago

As said, the only part where there is an embryo of code is for controlling the jack from the LMS UI, because it's a feature of the Boom product line to have it as an output or an input and use the built in amp.

Yes, that's exactly why I opened this feature request!

wizmo2 commented 1 year ago

@sle118 , have you or @philippe44 made any progress on your SqueezeIO project and in particular i2s rx/line-in?

I'm thinking of having a look into this as my S3 project has stereo mics built-in (with a separate ES7210 DAC). There has been a couple of request for streaming audio data out, mostly driven by HA users (like myself) for voice control (see #336, #252). I personally am not a fan (don't have the patience for a half-deaf assistant!), but it would be an interesting project and the line-in capabilities could be useful.

ESPHome code is actually pretty simple. It configures/initiates the ADC, reads the raw data and then streams the raw data though an IP socket to HA. I would think that LMS could potentially use the same stream (although this is probably / most-definitely beyond my capabilities).

I'm going to have a play around, but do either of you have an existing framework?

philippe44 commented 1 year ago

No I don't and it's potentially a bit disruptive for many other aspects of the code (side effects of programming the DACs) if you want to do that properly, including LMS integration, and if we do this, I really want it to be clean, not a quick hack job that we'll regret in a year or so, looking at it and wondering WTF were we trying to do ๐Ÿ˜„. That project is still alive and not a total mess because we tried to apply a sane level of rigor and quality (nothing compare to a professional project of course). For the sake of clarity, I'm not implying that this is what you do ๐Ÿ˜„ but I just want to clarify something that matters for me. This is the reason why I'm picky sometimes on some PR (which does not mean that what I'm doing is flawless, far from that to say the least).

wizmo2 commented 1 year ago

Been using LMS/Slim stuff since the early days, and what you have put together here is immense! I'm just a tinkerer who like to help out were I can.

Let me play in my S3 fork and see what comes out. At this stage, I want to get a better understanding of how your existing architecture is structured, and was checking to see if you had already put some thoughts into how any ADC modules "should" be integrated.

Re, PR validation: it's important, that you as developers, keep a handle on the project. If you feel any of my Pulls are overstepping then let me know or just close them. I'm not easily offended ๐Ÿ˜‰.

sle118 commented 1 year ago

@wizmo2 I'm doing an attempt at refactoring the platform config stuff and I'll need some help there. I think I can do better than the initial implementation in terms of design and efficiency, but I still have lots to do before I get a satisfactory clean compile. My goal is to reduce the memory footprint as well as the flash storage that the config system takes, while centralizing access to configuration options

philippe44 commented 1 year ago

I think we should be careful with too many changes in // because we are not so many... people. This project is still up and running because we have been able to keep a pretty good ratio of stability vs features, i.e. it's not cranking a new thingy every other week at the expense of the result rebooting every other hour.

I've seen many projects looking great on the features list and never "converging" (being stable), thus remaining a big bucket of spaghetti code. Our code is very far from perfect, but it's not spaghetti ๐Ÿ˜„ and AFAIK, it's essential to keep it under control because once you've started that, it's a slippery slope and we all know that the "I'll do that quick hack today to make it work for now and fix it later" never works. You never fix it later, move to the next shiny object and keep piling up junk till you have to give up (well, they'll call it refactor...)

Anyway, long message to say that my opinion is that we should now concentrate on @sle118 work to refactor the config which needs it but put the rest on hold for now until we have something that is stable and clean.

This also means that we should create a new branch and keep the current one only for bug fixes for now.

wizmo2 commented 1 year ago

@sle118, let me know how I can be of assistance.

sle118 commented 1 year ago

@sle118, let me know how I can be of assistance.

As soon as I have a solid foundation, I'll commit the code back to a new branch. When it hits that branch, the code will pretty much have been stripped from all the NVS references (with will have been commented out). At this point of time, I will need help to re-attach all the settings relevant code to the new settings module. So your help will definitely be appreciated!

alidaf commented 10 months ago

@sle118 I really like the look of the SqueezeIO but I'd like to request some considerations after designing cases for various Squeezelite devices that would make it much more accessible and easier to create custom cases for it.

Please could you consider making duplicate connectors (screw terminals or JST etc) or alternative mounting options for all of the inputs/outputs, e.g. power supply, RCA, IR, SPDIF, speaker output, etc., so that panel mounted versions can be designed into the case. I've been really handicapped by PCB mounted socketry because everything has to be made as a pass-through or daisy chain and the existing PCB mounted stuff just takes up additional space.

Also consider make the mounting holes a decent size (at least M2.5) with adequate clearance underneath for a decent mount and spaced adequately for rigidity, i.e. sufficient to allow inserting/removing plugs without stressing the board. The M1.4 screws I had to use for the SqueezeAMP caused a lot of problems.

IR pass-through would also be handy!

sle118 commented 10 months ago

@sle118 I really like the look of the SqueezeIO but I'd like to request some considerations after designing cases for various Squeezelite devices that would make it much more accessible and easier to create custom cases for it.

Please could you consider making duplicate connectors (screw terminals or JST etc) or alternative mounting options for all of the inputs/outputs, e.g. power supply, RCA, IR, SPDIF, speaker output, etc., so that panel mounted versions can be designed into the case. I've been really handicapped by PCB mounted socketry because everything has to be made as a pass-through or daisy chain and the existing PCB mounted stuff just takes up additional space.

Also consider make the mounting holes a decent size (at least M2.5) with adequate clearance underneath for a decent mount and spaced adequately for rigidity, i.e. sufficient to allow inserting/removing plugs without stressing the board. The M1.4 screws I had to use for the SqueezeAMP caused a lot of problems.

IR pass-through would also be handy!

I will definitely consider this on the next iteration, as the current one was a increment that was done to prove myself I could design a working PHY for Ethernet, which requires great care in laying down the PCB traces.

That being said, I can definitely make mounting holes better; there's room on the board. Also, I believe the spdif/RCA combo connector I'm using has a mounting screw, which would contribute to increasing strength.

But I'm not sure I understand what you mean by pass through or daisy chain.

Additionally, I can generate a 3D model of the board with connectors, something that might help with the case design effort. I was also thinking of making my board wider to fit the usb connector on the back.

20240201_091602

alidaf commented 10 months ago

But I'm not sure I understand what you mean by pass through or daisy chain.

A pass through would be when using a panel mounted (on the back of the case) pass-through connector, e.g. spdif that basically connects an optical cable to another optical cable on the inside of the case (optical to optical), that then connects to the optical connector on the board. A daisy chain is similar but in this case it is a panel mounted socket, e.g. power that is then wired to a plug that then plugs into the same type of socket on the board.

Have a look at the what I mean in the image below!

Rather than do this, I would rather be able to wire the panel mounted sockets to JST plugs (or similar) that can plug into sockets on the board, bypassing the connector (SPDIF, headphone, power, speaker, etc) sockets on the board. Oh, and not those tiny 1.25mm Molex Microlock 2 connectors! They are so difficult to source pre-crimped cables for.

DSC_1703

sle118 commented 9 months ago

Ok I see what you mean. I'm guessing a ribbon connector could be used to hook up a daughter board for most of the components of my board, but I'm not sure how I would be able to offload the Ethernet connector. Maybe mount the entire PHY layer with the Ethernet controller on the daughter board could be an option, but I don't know how EMF might interfere with stability or worst noise percolating towards the analog stage.

My design already has a generous gpio header with dedicated display connector, so at least the front panel can be separated easily.

As for the back panel, it would probably be easier to space out the connectors and provide room to screw some brackets. From there, only the back panel would require an adapter design and since the SqueezeIO doesn't have screw in terminals, there wouldn't be a challenge with having the screws exposed.

alidaf commented 9 months ago

Yes, I see the difficulty for some components and the desire to have a comprehensive feature set. I know TOSlink / SPDIF transmitters need a capacitor connected across the terminals within a short range but I guess that, and ethernet would be up to the hobbyist (case designer) to implement or workaround. Plus, as much as modularity may sound like a great idea, I don't think many people bought Google's modular phone in the end!

Itโ€™s your baby at the end of the day and I donโ€™t wish to dictate but any extra extra flexibility would really help.

m1ke02 commented 8 months ago

Raspiaudio Muse Luxe, AI-Thinker ESP32-A1S Audio Kit and Espressif LyraT v4.3 are quite popular and they all contain the ES8388 DAC.

This also is a great DAC! Because it has a built-in mixer and multiple outputs too:

  • has two analog stereo inputs (one L/R pair with a switchable microphone preamp)
  • has implicitly an I2S DAC
  • has two analog outputs
  • the inputs can be mixed with the DAC signal to the outputs

ESP32 Audio Kit with the ESP32-A1S module is a wonderful board because:

  • it has small onboard microphones ready on one of the stereo input pair
  • it has a stereo jack line input on the other pair
  • has a 2x3W onboard amp on one of the output pair
  • has a stereo jack headphone on the other output pair
  • has a GPIO connected to the headphone jack for plug detection

This DAC could solve alone the whole task of input handling, switching, mixing.

According to ES8388 documentation it's very versatile:

  • it has separate gain control on the inputs (independently on L/R channels, registers 39, 42)
  • DAC-only volume (registers 26, 27) and mute (register 29) on L/R
  • it has separate volume control for the sum (mixed) outputs (registers 46-49)

Since the mixer passes audio through there's no delay in the process, which is beneficial to keep lipsync with the TV picture if used as a soundbar. ESP32 Audio Kit could do this out of the box.

Afaik this DAC can also digitize the input signal so yes, it could also be usable to generate a stream for the network.

Line input passthrough on ES8388 can be achieved by the following: dac_controlset {"init": [{"reg":39, "val":208}, {"reg":42, "val":208}, {"reg":38, "val":9}]} But the input signal is turned into crap with a lot of noise and glitches, even if powered by battery