Closed ao-il closed 4 years ago
The performance over Wi-Fi seems very poor, but the case is different with a wired connection (100Mb/s). What is the minimum bandwidth requirement?
That depends on the routers. I had problems before with an old router. That of course may not be your problem.
Also, the latency slightly improves when other devices are disconnected from the network. Another issue is that it seems to need a restart when no media is streamed for a while.
I am aware of this. If you don't stream anything for a while, you need to restart. Now, in that case I am not sure if it is the Google cast device that goes to sleep because nothing is playing.
Regarding latency, there must be some algorithm to fix this, something like buffering and/or using smaller packets (I'm no expert), since streaming with other mobile apps is without this issue.
Try the --chuck-size
flag:
--chunk-size CHUNK_SIZE
Set the chunk size for streaming in the Flask server. Default to 1024. This
python mkchromecast.py --encoder-backend ffmpeg -c ogg -b 128 --chunk-size 2048
python mkchromecast.py --encoder-backend avconv -c ogg -b 128 --chunk-size 512
Let me know if it improves the lag.
Thanks for your reply.
I can assure you that it is not my router that makes it not to work on Wi-Fi, as I can stream flawlessly from other mobile devices. The problem is that the playback keeps getting interrupted, making it impossible to play anything.
I have doubled the chunk-size but it has not improved. Should I use something higher than 2048? I have also noticed that it (sometimes) plays some cached chunk a few minutes afters it has stopped.
May I ask if you are employing some standard streaming protocol? Or maybe there isn't such thing.
Shouldn't I be reducing the chunk size instead? Anyway, I have used both, still the same. It now plays some chunk after it has stopped.
I can assure you that it is not my router that makes it not to work on Wi-Fi, as I can stream flawlessly from other mobile devices. The problem is that the playback keeps getting interrupted, making it impossible to play anything.
Can you elaborate on how those devices do the streaming?. You are not talking about Spotify or something like that, isn't it?.
I have doubled the chunk-size but it has not improved. Should I use something higher than 2048? I have also noticed that it (sometimes) plays some cached chunk a few minutes afters it has stopped.
The size of the chunk had to be decreased as you said. I put the option because of the problems with my old router, but it didn't help too much.
May I ask if you are employing some standard streaming protocol? Or maybe there isn't such thing.
What I can tell you is that in Linux using ffmpeg
implies different layers to stream to the google cast. Let me explain. First I create the sink (pulseaudio being a layer on top of ALSA), and ffmpeg
reads from it and dumps to /dev/stdout
. Then, python-flask
creates a local HTTP server that takes as input the ffmpeg
stdout
. I think that all of that adds up making the lag occur.
I think that the problem could be in the flask side, maybe that is not the best way of doing the streaming. I am thinking to provide a node
server and verify if this helps. Do you know something about programming in node.js
?.
I have used different chromecast apps (pulsar for example) from play store, even the Google's play music app for android, with no noticeable lag.
Yes, I think the issue is with the transport protocol not the encoder. Http is connection-oriented and reliable, but slow. Udp is connectionless and fast, but unreliable. Maybe if you move the packets over the latter, that would solve the problem. I think I read somewhere people advocating a packet size of 1500 bytes and that large packet size would cause fragmentation (which explains the extra chunk being played after stopping the playback). Have you heard about gstreamer? Not really sure how it works but read somewhere that it is fast and without latency. There are many protocols out there for steaming. I also read that ffmpeg can work with ffserver. I'm just mentioning, I have no idea.
You mentioned using pulseaudio, I thought I was using ALSA directly? I am not sure I know about the node server, but I am familiar with little javascript.
I have used different chromecast apps (pulsar for example) from play store, even the Google's play music app for android, with no noticeable lag.
Google play music app sends directly the streaming from google servers (like spotify does when you use the app in the phone), therefore, in that case, your phone is just a remote control and nothing else. I don't know if pulsar plays local files and if it does, then the streaming server is doing the difference here.
Yes, I think the issue is with the transport protocol not the encoder. Http is connection-oriented and reliable, but slow. Udp is connectionless and fast, but unreliable. Maybe if you move the packets over the latter, that would solve the problem. I think I read somewhere people advocating a packet size of 1500 bytes and that large packet size would cause fragmentation (which explains the extra chunk being played after stopping the playback).
I also think the problem is related to python-flask not been adequate for this task. Sadly, Google cast devices cannot read from UDP streams... I have tried it. It has to be a http://something
.
Have you heard about gstreamer? Not really sure how it works but read somewhere that it is fast and without latency. There are many protocols out there for steaming. I also read that ffmpeg can work with ffserver. I'm just mentioning, I have no idea.
Yes, I am working on that. I think it is operational in the devel
branch, but gstreamer is just being used to capture audio. I cannot use the UDP stream pipeline because google cast does not read them (could you confirm this?).
You mentioned using pulseaudio, I thought I was using ALSA directly? I am not sure I know about the node server, but I am familiar with little javascript.
If you are not using the --alsa-device
and the .asoundrc
file then you are a pulseaudio user. I really don't remember if you were the one who reported adding ALSA support before.
I have been playing local files and not from Google servers. Using normal http must result in some lag because of the "ceremonies" involved. Udp is not good for audio because we want all the bits to arrive. So, we must need some enhancement to make http work. This will probably involve transmitting smaller packets (progressive download) to reduce latency. What about ffmpeg with ffserver? I think it uses rtp.
I use the .asoundrc, so I am not using pulseaudio.
You mean to check whether the cca supports udp?
I just want to ask, are you using http headers? I have read somewhere where they passed arguments with url instead.
I have been playing local files and not from Google servers. Using normal http must result in some lag because of the "ceremonies" involved. Udp is not good for audio because we want all the bits to arrive. So, we must need some enhancement to make http work. This will probably involve transmitting smaller packets (progressive download) to reduce latency. What about ffmpeg with ffserver? I think it uses rtp.
That's why I added a chunk
option. But it does not work as expected. I thought about ffmpeg + ffserver but rtp is not supported either :(.
I use the .asoundrc, so I am not using pulseaudio.
You are right. Sorry for the mistake.
You mean to check whether the cca supports udp?
Yes. But I think it does not.
I just want to ask, are you using http headers? I have read somewhere where they passed arguments with url instead.
The local http server is contained in these functions: https://github.com/muammar/mkchromecast/blob/master/mkchromecast/audio.py#L478. And the Google Cast is instructed to point to that local server here: https://github.com/muammar/mkchromecast/blob/master/mkchromecast/cast.py#L305. So basically, when the chromecast knows what's the IP of the local server in your laptop, it requests the headers and the flask server send them back and the stream starts.
What it would make a difference is if the data dumped to stdout
be segmented?. Maybe that's lacking in the ffmpeg command.
I think it should improve if you get the stream in a progressive approach. Eg:
Get 0-4 3 min Get 4-8 3 min ...
@ao-il I have added segmented audio in the ffmpeg command: https://github.com/muammar/mkchromecast/commit/9677ba2536089b9f413c45bbcb3cdb8d1ab36cc4#diff-890309d9973a3076001e4163695a23ba. Could you please test it, and tell me if it improves anything?
Use the ffmpeg
backend and the ogg
codec. I was able to see audio starting in two seconds, which is the segmented time I chose.
Slightly better, but still with up to 20s lag. Still playing old chunk of previous audio on resume/track change. I have removed the chunk-size argument so it uses default, but still the same. Shouldn't it suffice to have at least 2mb/s? I have 65 on Wi-Fi and 100 on wired connection. If you are using something much higher, you may not notice the flaws.
Slightly better, but still with up to 20s lag. Still playing old chunk of previous audio on resume/track change. I have removed the chunk-size argument so it uses default, but still the same.
Summarizing: problem is when stopping/resuming track while casting. Another possible way to fix this would be to monitor when silence is being streamed and stop ffmpeg, and resume again(?). But it sounds complicated.
Shouldn't it suffice to have at least 2mb/s? I have 65 on Wi-Fi and 100 on wired connection. If you are using something much higher, you may not notice the flaws.
2mb/s should suffice. I will keep thinking of this. Thanks for testing, and sorry that the problem is not solved yet.
I think the problem is already solved. Let's not try to reinvent the wheel. There are apps out there that already can stream (over http) without latency problems (gave some examples of some android platform apps), but the question is how is/was it done. I haven't found time myself to research, but there must be some algorithm to handle latency problems, as it is even possible to stream loseless audio. There is also a pulseaudio-dlna (linux) tool that can stream to chromecast, haven't tried it since I'm not a pulseaudio fan, but I believe it does it flawlessly. Thank you too for your efforts.
I have tried pulseaudio-dlna. It works well (I maintain it in Debian), but quality of sound is not the best in my opinion. That's why I decided to do my own :). The difference is that the author of that application did his own implementation of a http server, if I understand correctly. I am using modules already available in Python to do this plus ffmpeg or avconv. I strongly believe that having so many layers also is a possible trigger to all of these latency problems.
I agree with you that the problem is already solved somewhere else. I haven't had either the time to look more into details (started my postdoc 3 weeks ago, ;S).
I believe so too that having many layers/modules involved contributes to latency. I wish you all the best with your postdoc.
You probably already know, but there is castnow commandline tool for casting to CC. It is based on node.js which you had in mind earlier. Haven't tried it myself, but it seems to be working for those who have. So maybe replacing python flask with node.js will be the solution?
You probably already know, but there is castnow commandline tool for casting to CC. It is based on node.js which you had in mind earlier. Haven't tried it myself, but it seems to be working for those who have. So maybe replacing python flask with node.js will be the solution?
Yes, I know about them. I don't know how to program using node.js. But mkchromecast for macOS, the mp3 streaming is done with nodejs (I used some packages from node), and it works better (no lag at all). We could try this: https://github.com/fluent-ffmpeg/node-fluent-ffmpeg. I have it in my mind, to give a nodejs option because it is supposed to be better for these things. So yes, that would be a solution for the problem in the case that flask is not working well.
I am testing nodejs to cast video, and the process is smoother.
Good. Does it work for cc audio as well? Unfortunately, I have replaced my chromecast with a soundcard instead, as I have discovered that the sound output/quality is not identical with the source. Bass and midrange are weak. Maybe ok for casual listening but not for audiophiles. This is probably because it requires faster internet connection, like 250+. I have tried wiring both the chromecast and my computer on my network but it didn't improve. Is it the same with you and how fast is your internet?
Good. Does it work for cc audio as well?
Not yet. But now I am starting to understand node :).
Unfortunately, I have replaced my chromecast with a soundcard instead, as I have discovered that the sound output/quality is not identical with the source. Bass and midrange are weak. Maybe ok for casual listening but not for audiophiles. This is probably because it requires a faster internet connection, like 250+. I have tried wiring both the chromecast and my computer on my network but it didn't improve. Is it the same with you and how fast is your internet?
Oh. Well, when using wav I think that quality is fine. Right now I don't have speakers I had to sell them because I moved out from France to the US.
In France my internet was 50Mbps/20Mbps. I don't think the streaming happens through internet, everything is done withing the local network. I have just tested in the following way: with internet (that is needed to talk to the chromecast, yes, shitty) I started a casting session, and then I disconnected the cable that is coming from my ONT, and the casting process keeps working. I am right now with Verizon Fios which is a symmetric connection of 100/100. But this router is superior to the one I had before and I don't experience any troubles.
That was what I thought initially, that the sound was crispy, until I compared with a usb sound card. Have you compared the source with the output? My router is netgear CG3100, maybe that needs to be upgraded.
That was what I thought initially, that the sound was crispy, until I compared with a usb sound card. Have you compared the source with the output? My router is netgear CG3100, maybe that needs to be upgraded.
Yes, one looses some quality a would say. I remember I did a test before where I connected directly my computer to my speakers. However, I don't know if it was something related to the sampling rate. I've got issue #40, and OP is using Tidal and he reported back after some exchanges that s/he was getting a decent quality. I don't know if it would apply to your case.
Sampling should not be the issue, since Google fix that? I learnt that the cc audio and the other devices should be at most 4 meters apart for optimal quality. In my case, I had the cc audio very close to my router and my computer wired 2 meters from the router. I suspect that it's python flask that is responsible, as I could not even stream over Wi-Fi.
I got the cc audio again and I discovered that ffmpeg was using 24 bit format for wav in the argument list, but I changed it in audio.py and now the sound is better except that the bass is bit thinner than with the USB soundcard. Could this be the nature of the DAC in cc audio or is the signal still not full?
I got the cc audio again and I discovered that FFmpeg was using 24-bit format for wav in the argument list, but I changed it in audio.py and now the sound is better except that the bass is bit thinner than with the USB soundcard.
Good catch. I think that if your audio card is set to have a depth of 16 bit then casting at 24 bit may not be a good idea. I can try to fix that (detect it on Linux). In macOS the history is different because SoundFlower set the audio to 32-bit and sampling down is not an issue.
Could this be the nature of the DAC in cc audio or is the signal still not full?
I can dare to say that it is maybe the nature of the DAS in CC audio, because WAV should be lossless in theory.
I just discovered a similar tool stream2chromecast, but it seems to have the same problems, which I think are caused by ffmpeg processes. I have tried this:
ffmpeg -f alsa -ac 2 -ar 44100 -i hw:1,1 -acodec copy -f wav pipe:1 | stream2chromecast.py -transcodeopts '-acodec copy -f wav' -transcode /dev/stdin
and this:
ffmpeg -f alsa -ac 2 -ar 44100 -i hw:1,1 -acodec pcm_s16le -f nut pipe:1 | stream2chromecast.py -transcodeopts '-acodec copy -f wav' -transcode /dev/stdin
Works only with wired connection but hacking on Wi-Fi. Am I doing anything wrong? I have also specified buffer with -transcodebufsize which did not help.
Ok.. Mystery solved! Tested my throughput and discovered it was much lower than the specs, so I updated the driver of my wireless card, installed some packages, disabled ipv6 (preferred ipv4), and now I can stream on Wi-Fi. In my new setup, the cc device is wired to the router, and with my computer on Wi-Fi, I can stream wav losslessly using stream2chromecast, which I adapted to work without re-encoding the audio. Have not yet tried with mkchromecast, but since it is basically the same processes, it should work too.
Ok.. Mystery solved! Tested my throughput and discovered it was much lower than the specs, so I updated the driver of my wireless card, installed some packages, disabled ipv6 (preferred ipv4), and now I can stream on Wi-Fi. In my new setup, the cc device is wired to the router, and with my computer on Wi-Fi, I can stream wav losslessly using stream2chromecast, which I adapted to work without re-encoding the audio. Have not yet tried with mkchromecast, but since it is basically the same processes, it should work too.
Sorry for the late reply. Yes, it should work with mkchromecast as well. If you can try and let me know, that would be great. That seems to make sense, not reencoding to avoid audio delay. I will tray it later. If you can provide a patch for having such an option, it will be more than welcome :).
No problem. Yes, it does work with mkchromecast too. For copying the stream, you use 'copy' instead of codec, for ouput. I am not sure how to patch that. Don't understand much of python. However, there is about 3 s delay with copy. Maybe it's because I'm using wav. Copy is basically to ensure lossless audio. You could try to see if it improves for your ogg.
@ao-il thanks for testing!. I will proceed to close this report, and i will implement this option using copy
.
@ao-il I remembered you today. I have now a Sonos speaker, and the delay is very short in these ones compared to the chromecasts.
Thanks for that. But did you do it with mkchromecast or Sonos app? Now, I am working on removing redundancies from the procedure. Firstly, I discovered I didn't need ffmpeg when no transcoding is required. Secondly, with ALSA file device I could just pipe the audio to the python server and then to chromecast (no need for loopback device). This is much better in that I don't need to hardcode the sampling and bit depth parameters i.e bit perfect rendering depending on the playback application. Audacious music player can automatically set bit depth, but it sets 32 for everything and sample rate as is, which to my surprise is accepted by cc audio, which according to specs should only support up to 24/96. I suspect that guy is downsampling the audio, or may it supports 32 and only uses the low bytes up to 3?
Thanks for that. But did you do it with mkchromecast or Sonos app?
With mkchromecast. Delay is < 2 sec.
Now, I am working on removing redundancies from the procedure. Firstly, I discovered I didn't need ffmpeg when no transcoding is required.
You are correct in this. I hadn't thought it on that way.
Secondly, with ALSA file device I could just pipe the audio to the python server and then to chromecast (no need for loopback device). This is much better in that I don't need to hardcode the sampling and bit depth parameters i.e bit perfect rendering depending on the playback application.
How can you do that?.
Audacious music player can automatically set bit depth, but it sets 32 for everything and sample rate as is, which to my surprise is accepted by cc audio, which according to specs should only support up to 24/96. I suspect that guy is downsampling the audio, or may it supports 32 and only uses the low bytes up to 3?
These are the specs of sonos https://sonos.custhelp.com/app/answers/detail/a_id/80/~/supported-audio-formats.
Thanks for sharing all of this information. I think I need to improve these things to reduce delay. I will reopen so that I remember.
I think Sonos wireless antenna is better than the cc audio's? As regards how to pipe from ALSA file device, that's easy, see the following example:
pcm.!default {
type plug
slave.pcm filedev
}
pcm.filedev {
type file
format "raw" # or wav in my case
slave.pcm "hw:0,0" # your card
file '| stream2chromecast.py -stop && stream2chromecast.py -"
}
then in python server read stdin
def write_response_stdin(self):
for line in sys.stdin:
self.write(chunk_size)
self.write(...)
...
One problem with this approach is that the write buffer underruns due to sampling deviation, thus, the buffer gets reset too quickly before the audio finishes at CC's. My current solution is to pad the audio with silence(-39dB), that would not be removed by silence removal (-40dB) plugin in audacious, and still maintain gapless playback. You may not notice when the sampling parameters are constant, and without gapless playback. To see what is happening in the terminal, use $ tail -f /proc/<python-pid>/fd/1
Hi, I found this thread, as I was interested in the latency of sending video (BTW, it looks awesome - so very good work). I get about 5 seconds.
It looks like ffmpeg can serve http itself
https://trac.ffmpeg.org/wiki/ffserver#Connectingyourinputsources
So you might not need flask at all for that bit.
I've got a little bit of experience using python for video based apps, and it is one area where the speed really adds up if it's possible to swap out the ffmpeg->stdout->flask http step and just have ffmpeg handle it, it's got to help a bit.
Hey there, Muammar. First of all, thanks for the terrific Mkchromecast. After installing it (along with ffmpeg and soundflower) I finally got to stream 24/96 FLAC files from my Mac to the CCA without any distortion. I set the Mkchromecast preferences to WAV and 96khz and everything looks and sounds fine. My only doubt would be: can I be certain that the files are actually playing at the correct bit & sample rate? Or could there be some downsampling in the process? Unfortunately I have no way to find out in my system (CCA is connected directly to a tube amp). They sure sound good, but it's hard to tell the difference between 44 and 96khz using just my ears. (I know: then why do I care? Well, as you know these forums are full of OCDs...)
Hey there, Muammar. First of all, thanks for the terrific Mkchromecast.
Thanks!
After installing it (along with ffmpeg and soundflower) I finally got to stream 24/96 FLAC files from my Mac to the CCA without any distortion. I set the Mkchromecast preferences to WAV and 96khz and everything looks and sounds fine. My only doubt would be: can I be certain that the files are actually playing at the correct bit & sample rate? Or could there be some downsampling in the process? Unfortunately I have no way to find out in my system (CCA is connected directly to a tube amp). They sure sound good, but it's hard to tell the difference between 44 and 96khz using just my ears. (I know: then why do I care? Well, as you know these forums are full of OCDs...)
Did you read https://github.com/muammar/mkchromecast/issues/40? We were able to make the output from ffmpeg
to respect the bitrate and sample rate. I don't know how to check what the chromecast is playing tough. I set the mtype
according to the codec that is being used and the raw output from ffmpeg is piped to the webserver. Then, the chromecast is reading that stream.
The performance over Wi-Fi seems very poor, but the case is different with a wired connection (100Mb/s). What is the minimum bandwidth requirement? Also, the latency slightly improves when other devices are disconnected from the network. Another issue is that it seems to need a restart when no media is streamed for a while. Regarding latency, there must be some algorithm to fix this, something like buffering and/or using smaller packets (I'm no expert), since streaming with other mobile apps is without this issue.