janbar / noson-app

The essential to control music from your SONOS devices on Linux platforms
GNU General Public License v3.0
341 stars 28 forks source link

ability to stream output of a linux desktop to Sonos #60

Closed lsmith77 closed 5 years ago

lsmith77 commented 5 years ago

I would like to stream the audio on my linux laptop to Sonos when I am watching a movie in place of the laptops speakers. is this within the scope of this app?

janbar commented 5 years ago

The scope of this app is to control your Sonos devices. It cannot stream or share local resource to any devices. With it you could control the Sonos device to play an audio signal connected to an audio input (analog/coax/fiber).

lsmith77 commented 5 years ago

ok. I guess what would be within the scope is being able to set a stream URL?

at any rate, I managed to achieve more or less what I wanted using mkchromecast + soco .. however the delay was ~8.6s while watching a video in VLC which makes this somewhat unpractical, at least for that purpose.

janbar commented 5 years ago

Yes you can set a stream to play, but sure it won't be sync with an other renderer. In my opinion the only way is to connect the audio input.

sandsmark commented 5 years ago

I thought about opening a PR adding a simple pulseaudio sink that is streamed to the sonos, but as you already noticed the lag is quite considerable, and the only way (that I can think of) to really get around it is to use the mic to determine the latency. Which sounds fun, but a bit out of scope of noson, I guess.

janbar commented 5 years ago

Yep for instance it is out of the scope for the app because I haven't make code to stream to the Sonos. It could be fun to try that. Let me know if you have any idea to do it and some time to make a try. I guess Sonos uses the standard api to read stream from an upnp media server. And maybe it will need to use wireshark to know how Sonos works for that. The official desktop app (on OSX) doesn't provide this feature, but as I remember the android app do it. So running it in an android VM could help.

janbar commented 5 years ago

I've done some checking and the only way to stream local audio files is by using a streamer as icecast. Seems Sonos allows only mp3 or aac streams. I fails to play any stream ogg or flac. So the feature should require to embed a "mini" streamer and a mp3 encoder to support audio formats like ogg, flac or wav. That isn't impossible... libmp3lame is gpl and coding a simple http streamer isn't so complex.

sandsmark commented 5 years ago

Found this: https://github.com/masmu/pulseaudio-dlna

Very hackish, though, launching ffmpeg by itself, and the pulseaudio integration is way too complex.

And yeah, a very simple HTTP-ish server implementation to just hand out transcoded (if necessary) audio to any clients that connect, and point the Sonos at the local IP and right port. To stream any audio (i. e. from pulseaudio) and not just local files it's basically 10 lines of code if we use the pa_simple API.

It's probably simpler to just use ffmpeg, though, instead of using libmp3lame and libflac/libvorbis/etc. But then again; the ffmpeg API is anything but stable and there aren't that many sound formats people use for music (and the APIs for libmp3lame, libvorbis, libflac, etc. are easier to handle than ffmpeg ime).

sandsmark commented 5 years ago

oh, and doing this is what I meant was out of scope: https://github.com/alopatindev/sync-audio-tracks

needs to take into account the delay of the transcoding as well, though.

janbar commented 5 years ago

I pushed few commits (in branch streaming) to enable the request broker for others request than the upnp notifies. So now we can handle any GET/HEAD request from remote, do some work and reply to send a chunked stream. Also now I able to stream a flac file to my sonos. I tested it with noson-cli, where I transfer a flac stream to any remote requesting at http://host:1400/music/track.flac. So no need any more to use a losswith encoder. I had already designed a FLAC encoder wrapped within a QIODevice. Finally reading your previous comments I searched an easy way to read the stream from pulse and I found that: https://www.freedesktop.org/software/pulseaudio/doxygen/parec-simple_8c-example.html . Really simple and it should do the job.

janbar commented 5 years ago

yep, reading the pulse stream we cannot read ahead the audio. So imo to resolve any sync issue the user should setup the delay for the video instead.

janbar commented 5 years ago

Some news, Trying to stream the monitor source from the pulse server works pretty well here. I read the LPCM bytes flow to push it into a FLAC encoder and finally send chunked data in the http response . But the latency is near 4 ~ 5 sec !!!

sandsmark commented 5 years ago

awesome stuff!

but yeah, the latency is bad. in theory it is possible to automatically calculate the latency and tell whatever is playing about it, but I couldn't find that in the pulseaudio api (only how to ask for the latency).

but for just playing music from e. g. youtube in the background this approach works fine.

janbar commented 5 years ago

@sandsmark, also the sonos device takes some time for buffering. Often around 1 second. But yes this works great to play youtube or any other music app. Playing youtube it could stop after the end of a show if the blank period is longer than 5 seconds. The sonos seems to trigger the stop when frame data are "zero" for some time. It is tricky to resolve that, the only way imo is to update pcm data with inaudible sound during the blank period. For a first feature release it could be okay. For instance the feature will be available for Linux or BSD desktop with a pulseserver. Later when I will have more free time I will try to make it working on osx and android using the qt audiirecorder. The branch streaming should work if you want to test it with the cli as below:

janbar commented 5 years ago

This feature will be merged within the next release (3.8.0). Not too much work to finalze the required stuff. I will add an other request broker to share images and finally providing the pulseaudio logo and the favicon. About osx and android the feature has been killed. For those platforms we cannot monitor the sound output because firstly a "copyright" issue, and secondly for security issue. Only the streaming of stored files could be available.

janbar commented 5 years ago

The feature is merged into master

janbar commented 5 years ago

It is ready to use with the release 3.10.4. I fixed the blank issue by designing a blank killer that injects an inaudible sound: one wave 20khz with a level of 0.0007 for each blanked millisecond. Under the hood Noson create a dedicated PA sink with the name 'noson'. Then it read the stream data from the associated PA source monitor 'noson.monitor'. Once you stop to stream or you close the app, the sink is removed. In the app to pulse your stream you have to open the sound parameters and then clic "PulseAudio". Enjoy with youtube...

lsmith77 commented 5 years ago

thank you!

k-s-dean commented 5 years ago

@janbar I just wanna say thank you. Seriously one of my pet hates about sonos was the inability to stream things to this piece of s***, especially from youtube. made my day :) :+1:

expl0ratory commented 2 years ago

Just found this after railing against youtube music forever. Thank you!

javorekm commented 1 year ago

Maybe I did not understand this super cool feature well. I just did

./noson-latest-ubuntu-bionic-x86_64.AppImage --cli --deviceurl=http://192.168.1.158:1400
Noson CLI using libnoson 2.10.0, Copyright (C) 2018 Jean-Luc Barriere
Connecting to http://192.168.1.158:1400... Succeeded
Found player 'Living Room' with UUID 'RINCON_XXXXXXXXXXXXX'
Found zone 'Living Room' with coordinator 'Living Room'
>>> connect Living Room
Connected to zone Living Room
Living Room >>> playpulse
Succeeded
Living Room >>> 

and then I expected I will see a new pulseaudio sink in my desktop linux system which I can use to play through. But I cannot see any new sink (noson or something like this) in pavucontrol or anywhere else. I was looking for some more info for command "playpulse" but I did not find any.

Noson app: 5.4.0 (appimage)

Thanks a lot for some info how to use it.

javorekm commented 1 year ago

Mea culpa! I opened the android app and there was a stream to my computer - unable to play as firewall was active. When I changed firewall settings and play stream in app, noson sink appeared and I can play through.