avantrec / soco-cli

Command Line Interface to Control Sonos Sound Systems
Apache License 2.0
224 stars 12 forks source link

Play local mp3 files from Linux file system #3

Closed martinpeg26 closed 3 years ago

martinpeg26 commented 3 years ago

Hi Avantrec, thank you for the soco-cli software. Unfortunately I can't see how to add local linux file system mp3 files to either favourites or queues so I can then set them to play.

Can you tell me how this might be done please?

Kind regards Martin

pwt commented 3 years ago

Hi Martin:

SoCo-CLI only knows how to control playback of audio sources that Sonos knows about -- i.e., it acts like a Sonos controller app, which is effectively a software remote control for Sonos, and doesn't actually send it any audio.

So, the standard way to play local MP3 files is by adding them to Sonos as a Music Library. There's an overview on the Sonos Website. For files on a Linux system, you'd need to create a share using Samba (you will need to enable the older SMB v1 protocol), then add the relevant share to Sonos. Once this is done, the files in the Music Library will be available to SoCo-CLI, and to all other Sonos controller apps.

However, you have given me an idea for adding a simpler way of playing local audio files directly using SoCo-CLI, by setting up a temporary local web server to serve each local file to Sonos. I'll try that out when I get some time to work on it.

Hope this helps for now. -- Peter

martinpeg26 commented 3 years ago

Hi Peter, thanks 4 the quick and detailed reply.

I understand now, just a bit of a shame that I’d hav 2 drop the SMB 2 v1, had 2 do the same on a server I set up 4 my brother so his scanner could send images 2 it.

It’s only open 2 the home LAN though so can’t c it bein an issue.

  I hav had RPis since v1 and currently hav 2 x 4s and 2 x 3s doin home automation running Domoticz as the main controller.

If u want 2 pick my brains on anything Pi or automation related pls don’t hesitate and good luck with your Pi Sonos/AirPlay project.

  Thanks again from cold and grey Anglesey and keep safe.

  Martin

   From: pwt notifications@github.com Sent: 28 December 2020 18:13 To: avantrec/soco-cli soco-cli@noreply.github.com Cc: Martin Pegler martin.pegler@datase.co.uk; Author author@noreply.github.com Subject: Re: [avantrec/soco-cli] Play local mp3 files from Linux file system (#3)

  Hi Martin:

SoCo-CLI only knows how to control playback of audio sources that Sonos knows about -- i.e., it acts like a Sonos controller app, which is effectively a software remote control for Sonos, and doesn't actually send it any audio.

So, the standard way to play local MP3 files is by adding them to Sonos as a Music Library. There's an overview on the Sonos Website. For files on a Linux system, you'd need to create a share using Samba (you will need to enable the older SMB v1 protocol), then add the relevant share to Sonos. Once this is done, the files in the Music Library will be available to SoCo-CLI, and to all other Sonos controller apps.

However, you have given me an idea for adding a simpler way of playing local audio files directly using SoCo-CLI, by setting up a temporary local web server to serve each local file to Sonos. I'll try that out when I get some time to work on it.

Hope this helps for now. -- Peter

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

pwt commented 3 years ago

In SoCo-CLI v0.1.45 I've introduced experimental support for playing audio files on Sonos directly from the local filesystem. More details in the README file; please see:

This is working well for me on macOS and Linux, albeit with limited testing. My Windows test system is exhibiting issues, however, which I'll need to look into.

Do let me know how you get on with this -- feedback welcome!

martinpeg26 commented 3 years ago

Hi Peter, that’s unreal, thank you so much.

I’ll give it a test when I’ve finished migrating all my stuff to the Pi4 and will let u know.

  I only ever use Linux for the backend / server side, only use Windows because I run Ableton and can’t afford a Mac. Hehe. 

  Thank you again.

  Martin

  From: pwt notifications@github.com Sent: 29 December 2020 15:56 To: avantrec/soco-cli soco-cli@noreply.github.com Cc: Martin Pegler martin.pegler@datase.co.uk; Author author@noreply.github.com Subject: Re: [avantrec/soco-cli] Play local mp3 files from Linux file system (#3)

  In SoCo-CLI v0.1.45 I've introduced experimental support for playing audio files on Sonos directly from the local filesystem. More details in the README file; please see:

This is working well for me on macOS and Linux, albeit with limited testing. My Windows test system is exhibiting issues, however, which I'll need to look into.

Do let me know how you get on with this -- feedback welcome!

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

pwt commented 3 years ago

This is working well for me on macOS and Linux, albeit with limited testing. My Windows test system is exhibiting issues, however, which I'll need to look into.

Update: the issue is not with Windows, but with non-MP3 files (e.g., m4a). I'll work on this. Edit: Works for MP3, FLAC, OGG and WAV files currently. Research needed for m4a support.

martinpeg26 commented 3 years ago

Hi Peter, all works brilliantly for me with local MP3s, thank you so much. Martin :-)

martinpeg26 commented 3 years ago

Morning. I've just realised after trying to run the play_file on my main RPi4 that it doesn't work and I think it's probably because I already have apache2 running to host a few different apps. :(

To make it work your local and temporary web server would need to run on a different port and there'd have to be proxy in an apache2 virtual host to handle it.

I don't want to make more work for you as you're busy enough but if you wanted to go this route I'm happy to test.

Cheers Martin

pwt commented 3 years ago

Not sure what the problem is, but It's not that. The internal web server tries up to 100 ports in the dynamic range: 54000 to 54100.

Might be a firewall setting?

Could you try running with --log=info, and post the resulting output?

Thanks.

martinpeg26 commented 3 years ago

Was just looking at the same thing now as stopping apache made no difference. Using strace I could see " FUTEX_BITSET_MATCH_ANY) = -1 ETIMEDOUT (Connection timed out)"

I'll add a firewall rule now 2 allow the input on 54000.

martinpeg26 commented 3 years ago

That allowed the mp3 to play but the app doesn't close after playing the file, I have to CTRL+C it. This is the log output up to playing the mp3: 2020-12-30 10:28:19,454 sonos.py:159 - main() - Found 1 action sequence(s): [['192.168.10.130', 'play_file', './BackDoorBell.mp3']] 2020-12-30 10:28:19,454 utils.py:303 - get_speaker() - Using IP address instead of speaker name 2020-12-30 10:28:19,455 play_local_file.py:93 - play_local_file() - Using server IP address: 192.168.10.254 2020-12-30 10:28:19,455 play_local_file.py:54 - http_server() - Using 192.168.10.254:54000 for web server 2020-12-30 10:28:19,455 play_local_file.py:57 - http_server() - Web server started 2020-12-30 10:28:19,455 play_local_file.py:101 - play_local_file() - Playing file 'BackDoorBell.mp3' from directory '.' 2020-12-30 10:28:19,465 services.py:484 - send_command() - Sending GetZoneGroupState [] to 192.168.10.130 2020-12-30 10:28:19,471 services.py:492 - send_command() - Received status 200 from 192.168.10.130 2020-12-30 10:28:19,471 services.py:484 - send_command() - Sending SetAVTransportURI [('InstanceID', 0), ('CurrentURI', 'http://192.168.10.254:54000/BackDoorBell.mp3'), ('CurrentURIMetaData', '')] to 192.168.10.130 2020-12-30 10:28:19,478 services.py:492 - send_command() - Received status 200 from 192.168.10.130 2020-12-30 10:28:19,478 services.py:484 - send_command() - Sending Play [('InstanceID', 0), ('Speed', 1)] to 192.168.10.130 2020-12-30 10:28:19,484 services.py:492 - send_command() - Received status 200 from 192.168.10.130 2020-12-30 10:28:19,484 play_local_file.py:105 - play_local_file() - Setting flag to stop playback on signal 2020-12-30 10:28:19,484 play_local_file.py:110 - play_local_file() - Waiting for playback to stop 2020-12-30 10:28:19,484 events.py:152 - run() - Event listener running on ('192.168.10.254', 1400) 2020-12-30 10:28:19,485 events_base.py:312 - start() - Event Listener started 2020-12-30 10:28:19,486 play_local_file.py:22 - do_GET() - Get request received by HTTP server 2020-12-30 10:28:19,499 events_base.py:465 - success() - Subscribed to http://192.168.10.130:1400/MediaRenderer/AVTransport/Event, sid: uuid:RINCON_7828CA6E172601400_sub0000000142

And then it sits there until I CTRL+C and I get: ^C2020-12-30 10:28:25,596 utils.py:218 - sig_handler() - Caught signal, exiting. CTRL-C ... exiting. 2020-12-30 10:28:25,596 services.py:484 - send_command() - Sending GetZoneGroupState [] to 192.168.10.130 2020-12-30 10:28:25,603 services.py:492 - send_command() - Received status 200 from 192.168.10.130 2020-12-30 10:28:25,603 services.py:484 - send_command() - Sending Stop [('InstanceID', 0), ('Speed', 1)] to 192.168.10.130 2020-12-30 10:28:25,609 services.py:492 - send_command() - Received status 200 from 192.168.10.130 2020-12-30 10:28:25,611 events_base.py:321 - stop() - Event Listener stopped

martinpeg26 commented 3 years ago

Sorted, I had to also open 1400 for INPUT and now the app closes properly after playing the file. This is brilliant, thank you for your work and help Peter.

Martin

pwt commented 3 years ago

Sorted, I had to also open 1400 for INPUT and now the app closes properly after playing the file. This is brilliant, thank you for your work and help Peter.

Great!

Yes, well spotted, port 1400 is used for incoming events so that I know when the speaker has stopped playing, so I can shut things down. (Really, this should also use ports in the dynamic range, but I didn't write that code.)

Note that in both cases if a port is already in use, the subsequent ones will be tried until a free port is found, up to a limit. I.e., 1401, 1402, ... and 54001, 54002, ... Bear this in mind if you happen to run SoCo-CLI in parallel on the same host -- the single port firewall rules won't work.

I'll add some brief notes on required port ranges to the README.

Edit: Firewall rules are now described here.

martinpeg26 commented 3 years ago

Ok, understood. I have a custom bash script that adds INPUT and OUPUT rules for only the services that the server is running so anything new is blocked until I add the required rules.

pwt commented 3 years ago

Version 0.1.46 now supports the following file types: ["MP3", "M4A", "MP4", "FLAC", "OGG", "WAV"], and also allows seeking within track from Sonos controllers. So, I'm now going to close this issue.

The remaining Sonos supported file types, AAC and WMA, are still eluding playback. I'll create a new issue for these.

martinpeg26 commented 3 years ago

Ur a star and a genius Peter, thank you. From my side the firewall ports I needed 2 open are INPUT 1400, 3500 and 54000 and all TCP. I'm not sure what, if any, codecs are needed or supported by the Sonos speakers, that could be the issue the AAC and WMA playback?

Martin

pwt commented 3 years ago

Not sure why you'd need TCP/3500 open for soco-cli: it doesn't have anything listening on that port. Perhaps you have an RTMP server running on the same device?

The issue with AAC and WMA playback is something to do with how the simple internal Python web server handles interactions with Sonos (doesn't happen with NGINX, for example), so I 'just' need to figure out what's different.

martinpeg26 commented 3 years ago

Nope, only 'media' related service I hav runnin is minidlna and that already has 1900/UDP open. If I remove the 3500/TCP rule in the firewall the sonos app plays the audio but then doesn't close. I hav entries in a directory server (OpenLDAP) that define 'roles' and members of those roles are the servers I run by FQDN, the SonosPlay role has those 3 ports but without 3500 The Computer Says No.

More diagnosis!

pwt commented 3 years ago

If I remove the 3500/TCP rule in the firewall the sonos app plays the audio but then doesn't close. I hav entries in a directory server (OpenLDAP) that define 'roles' and members of those roles are the servers I run by FQDN, the SonosPlay role has those 3 ports but without 3500 The Computer Says No.

Odd.

As I'd expect, netstat tells me that soco-cli is only listening on one TCP/14xx port and one TCP/540xx port during playback. There's nothing in the code that listens on any other port(s):

(soco-cli) pwt@raspberrypi-4:~ $ sudo netstat -lntp | grep 2898
tcp        2      0 192.168.0.75:54000      0.0.0.0:*               LISTEN      2898/python3        
tcp        0      0 192.168.0.75:1404       0.0.0.0:*               LISTEN      2898/python3        
(soco-cli) pwt@raspberrypi-4:~ $

Also, if explicitly block inbound TCP/3500, I see no change in behaviour: soco-cli terminates normally as soon as playback stops.

(soco-cli) pwt@raspberrypi-4:~ $ sudo iptables -L |  grep 3500
DROP       tcp  --  anywhere             anywhere             tcp dpt:3500
(soco-cli) pwt@raspberrypi-4:~ $

However, if I block the relevant inbound TCP/14xx port, soco-cli does not terminate, also as I'd expect.

So, I can't explain the phenomenon you're reporting.

martinpeg26 commented 3 years ago

Hi, found it after getting back to the server in question. I had a node.js http sonos service still running, it works but it's not longer maintained and I wanted to switch to something that was command line based and scriptable, hence using your app. :-)

Once I stopped that process and removed the TCP/3500 port from the firewall all worked ok. My only thought was that somehow the Sonos Play:1 was still registered/connected back to the node.js service and only when I'd stopped it that released the connection.