-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Fix Shoutcast live sending not to break stream #665
Conversation
- There is another thread that handles sending - Write only adds stuff to cache - Delay is kept minimal as possible (It can be made shorter but this is on the safe side)
@@ -455,6 +496,45 @@ bool EngineShoutcast::serverConnect() { | |||
|
|||
void EngineShoutcast::write(unsigned char *header, unsigned char *body, | |||
int headerLen, int bodyLen) { | |||
struct shoutcastCacheObject *l_SCacheObj = (struct shoutcastCacheObject *) malloc(sizeof(struct shoutcastCacheObject)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
malloc and free are potentially blocking system calls. We should not use them here regularly.
Can we preallocate the memory?
Nit: break long lines <= cloumn 80
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes if we can stand little bit over head and 1 MB pre-allocated memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should be no problem. But do we actually need that much? Can't we pass all data instantly to the server? In which case the buffer is required?
You cannot use shout_sync(), because the Mixxx engine runs at the master sound card Crystal and not at the shoutcast server clock. It is unlikely that the master sound card and the shoutcast server clocks are fully in sync. In the case the master sound card is faster, it will fill up your m_pShoutcastCache until the device is out of memory. This will not happen in the age of GB memory, but once you have removed the mallocs, m_pShoutcastCache will overflow, leading to a hear-able click. In the case the server is faster, it will empty the server cache until the stream drops. Workaround:
Advanced thoughts: Since the shoutcast stream is the "product", messing around with the samples it probably not desired. If is this is identified as a problem, we need to drop/add a frame from the master sound card stream. I am afraid this is hard with the current architecture, since this would made the Mixxx engine audio buffer non const. We can get around this by registering the Shoutcast server as master soundcard. I have no clue if this would be hard or easy. :-/ |
The documentation also says "Alternatively, the caller may use shout_delay to determine the number of milliseconds to wait and delay itself." Maybe this is a way we can track the current latency between sound card and stream? I think that if we do any correction to a stream, it should be to the shoutcast stream and not the master soundcard output. Broadcasters should expect pristine output from their own speakers, and if they are recording the stream they will also want that to be pristine (recording either inside mixxx or with an external device). Whereas, people listening to a stream are going to more tolerant of slight glitches and latency issues in the stream (which they already experience due to rebuffering and so forth). Also someone might be playing to a live audience while simulcasting to a streaming station. |
(This is the part I am disagreeing with in my previous comment, since the stream is already more unstable anyway and it's likely that the actual soundcard output will have listeners present) |
Yes thank you, shout_delay() should work better, since you do not have to deal with the compressed data. Sure the recording feature should be able to record a bit perfect stream in any case. (We have other bugs that prevent this) Once you pass the samples to the DAC from the master sound card it can't be bit perfect. But I agree, that using the master sound card as master Mixxx clock is a good band aid for 1.12 until someone does the effort to allow to use the shoutcast clock for the Mixxx engine. |
We may also still use shout shout_sync() and add/drop the frame if the m_pShoutcastCache level is moving out of reasonable regions. |
Actually I don't understand this at all. Problem ain't crystals or delays problem is about the way the things works with compressed audio (which is very different world than playing with soundcard). Soundcard is rather easy it just clocks you and you just feed asked amout of bytes but then this Icecast hustle breaks loose most times Icecast server can't estimate how much data you are about to send and how much PCM data it will generate. |
Sorry for my confusing mails, I was myself confused by the fact that we have to deal with compressed data. I just had a look at the libshout code. It uses internally the gettimeofday() to sync the stream. This is driven by the cmos wall clock crystal of the host machine and should be corrected by NTP servers, to be synced world wide. Clock changes by NTP are allowed by normalizing the time to the stream start time.
It can, since all streaming formats have a fixed data consume rate. Even if you broadcast with VBR.
Right, I was wrong in this. It reflects only the network buffer, which is somhow independent from the sample timing.
This is a problem of a slightly differ kind. I was talking about the clock crystal miss match which is stacking up during a long broadcast session. It looks like you experience here a audio buffer underflow of the main soundcard, which makes the issue worse, since this is stacked up much faster. This issue is also coverd by this bug https://bugs.launchpad.net/mixxx/+bug/1198306 since the audience also dislikes such behaviour because the track slows down by the extra buffer of silence and the dances bay fall out of rhythm.
We must not drop compressed packages. We have to add or drop frames (a single sample for each R/L channel) of uncompressed data. It is require once the sound card stream is ahead or bejond the uncompressed streaming stream. Possibles solution:
:-/ this sounds like a hacky band aid solution. but it will work for 1.12.
Our latest discussion clarifies a lot to me. I hope you feel the same. |
Yes.. this clears things and now everyone is talking same thing. It will be hacky even it done the way that I have done it. I think we have to rearrange engines little bit in 1.13 like you can just pop them from them list and every side engine is independent what mixxx does. |
I was re-reading QT QObject documentation and started to thing should this be fixed with Signals and slots? Then it can be get rid of Thread and other unwanted things if there would be 'write' signal which caches and send signal which send stuff to server when there is enough material. Only thing I didn't understand do signals block each other (are they real callbacks?) it they are not returned. |
I would not use signal and slots to pass audio data. This may involve locking and slow malloc / free calls- |
If you use moveToThread(), the thread runs its on main loop with a Qt message queue. I would prefer to control the cycle of the Shoutcast thread manually. |
Main problems are thread and malloc/free? Does making Qthread instace it free from mainloop? |
I am not sure if I understand your last comment but I will try to answer anyway. If you inherit from QThread, override the run() function and newer exit it, the thread has no other main loop that processes signals. If you move Qt Objects to such a thread, their slots are never processed. |
IMHO processing the event queue is the default run() implementation. Once it is overridden, it is gone. |
If malloc is considered as blocking is new the same? |
new calls malloc |
Gotta figure out some non blocking non malloc hack to get this working.. |
I'd really like all hands on deck for this bug -- this is the thing holding up the release right now. Who else is able to help make this bulletproof? @uklotzde ? |
There is problem also that it's not bulletproof that problem is libshout (which I highly hope). I can provide testing server for those how are willing to work on this (but you have to write me directly) because I currently lost my Windows dev enviroment. |
buildbot: test this please |
retest this please |
Now I updated some problems away and added signals for connected and disconnected. |
Thank you for the fixes. |
It seems so I missed this push.. but now there is signals |
How do you all feel about this? If it's pretty much done, I would like to merge this in, produce another beta build, and get this to testers. |
IMHO it is already much better than the 1.12 branch. Open, but no blocker:
@illuusio: Are you currently working on the reconnect feature? |
I would consider reconnect a nice-to-have. @illuusio if you think this is pretty good as is, we can merge. Then it's just up to me to get the build server to cooperate :( |
@daschuer Is it ok that we exit without all threads are dead? I think this wait() have caused that hang in microphone bug so it's real deadlock issue should we change it just some couple of sleep() and because disconnect should only take couple ms or it's not going to happen and we can just release socket our side and server will do so in a while also. |
IMHO we have to make sure the thread is gone at this point. Instead of healing the symptoms at wait(), lets analyses all places where the thread is waiting and add timeouts there.
This seams to be a working approach. However the solution I had in my mind was like that: Just reconnect from inside EngineShoutcast, if the connection was lost for any reason except the user has changed the "enable" CO.
|
This PR is already gigantic. Let's do reconnection in another PR |
Fix Shoutcast live sending not to break stream
It could help to make an announcement on the blog calling for Internet broadcast users to test this. |
first we have to fix the build server :( |
This PR fails to build on windows, please fix asap: http://builds.mixxx.org:8081/jenkins/job/1.12-release/architecture=i386,platform=windows/144/console /IC:\usr\include\taglib /Ilib\hidapi-0.8.0-pre\hidapi /Ilib\xwax /Ilib |
I will have a look |
I have just pushed a possible fix. |
There is no SIGPIPE under Windows. |
still failing: http://builds.mixxx.org:8081/jenkins/job/1.12-release/architecture=amd64,platform=windows/146/console C:\mixxx\environments\2.0-x64-Release\include\shout/shout.h(163) : error C2146: syntax error : missing ';' before identifier 'shout_send_raw' C:\mixxx\environments\2.0-x64-Release\include\shout/shout.h(167) : error C2086: 'int ssize_t' : redefinition Build step 'Execute Windows batch command' marked build as failure Recording test results ERROR: Publisher 'Publish JUnit test result report' failed: Test reports were found but none of them are new. Did tests run? SSH: Current build result is [FAILURE], not going to run. Finished: FAILURE |
It does not really make sense to fix it remote. Who can try this:
And make ignoreSigpipe() conditional by
|
I have just pushed dedcd27 |
#define WIN23Did you mean 32? |
Shoutcast streams are breaking heavily on Mixxx 1.12 beta (launchpad bug #1277274). Mainly the problem is that Mixxx is not using shout_sync() (and output can't block) function and this the reason why it gets out of the sync.
This one creates new thread inside Shoutcast engine that handles writing things from cache and so there is not big changes needed to Mixxx engine.