-
Notifications
You must be signed in to change notification settings - Fork 176
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
Clarify snd_pcm_hw_params_set_drain_silence documentation #378
Comments
For Also note that caller may check if hw support "perfect" drain |
Yes, I understood so far. But the default setting is And the sw_params silence params documentation only states that these influence the underrun behavior - unless you count draining as a kind of underrun, shouldn't that be orthogonal then? PS: Side question, I came up with a potentially easier method of preventing glitches after drain manually: fill the whole hardware buffer with silence with a blocking write (which should only be able to return once the last bit of actual audio was played back) and then just do |
That's the goal for the default settings. Most applications don't care and calls
It's basically same and not. It depends on view. Silence just add requested number of samples. The drain is just a special case and it depends on the application settings, if this silence length is enough (period + something) for all hardware variants. With
You will get extra buffer length latency at the end. Usually, the drain latency is up to one period. |
Ok, thanks. I suppose that means if I get glitches with that option enabled, I can report it as a bug. I suspect there may be one, where rewound samples are not properly zero'ed out, but I'll have to investigate more before I can really say.
Afaiu from the documentation, silence is only added when an underrun is closer than Or are you talking about the "special case" setting of
What you say makes sense if I'd drain the whole hw buffer of silence, but I did rather mean dropping once one knows the hardware has played back all "real" samples. |
When 0 < silence_threshold < buffer_size, then the driver ensures that there is always a number of silence samples ahead of the appl_ptr in the buffer, so that if the DAC reads past the appl_ptr (for example with imperfect drain, or when stop_threshold > buffer_size) then it reads silence, rather than replaying samples left over from the previous iteration of the buffer. I agree that the documentation reference to inderrun for silence_threshold/size parameters is confusing. That is because the pcm will still stop when the xrun point is reached, so that the inserted silence samples never actually get played, unless the stop_threshold is also set appropriately (or when draining and the driver does not stop until the end of the period) . However I do not have any better ways of expressing the behavior of these parameters. Perhaps instead of "xrun" an expression such as "end of application samples" or similar might be clearer, or would that be even more confusing? |
Uhh, I'm even more confused now. What you described I kind of though was the silence_size parameter, not the silence_threshold. So coming from the documentation, I believed that when an underrun is less than silence_threshold frames away, the driver will write silence_size frames of silence after the appl_ptr. That is not correct? And out of curiosity, is it also the driver's job to clear the samples when doing a rewind (since rewinding moves the appl_ptr back before previously written frames)? Edit: Also, when the hardware does not have perfect drain, shouldn't one assume that an underrun will also not perfectly stop at the appl_ptr position but likely will overshoot that, making some silence frames at the end good for that? |
Actually it writes a maximum of silence_size frames. It may write less than that it reaches the hw_ptr first, because it does not want to overwrite unplayed frames.
No. It is the appl_ptr which is rewound, so the xrun point is made earlier (subject to the stop_threshold setting of course). The next write from the application will then overwrite frames from its last write. For use when draining, the idea is that the application pads with silence to ensure that the last period is complete, but the rewinds to the start of that padding. This means that drivers with perfect drain will stop at the (rewound) application pointer, never playing the silence padding; whereas those without perfect drain will run past the appl_ptr, playing the silence padding until the end of the period.
Hmm, I hadn't thought of that, but yes I think you are right, the silence threshold/silence size parameters would also be useful in that situation. |
Awesome, very useful info. Thanks! I believe that should be added to the documentation of rewind, will do that soon.
It is strange that you say that. The documentation of silence threshold/silence size only talks about the underrun situation, and does not mention draining at all. You primarily seem to consider them relevant for the draining case? But only when |
Yes, as I said, that is confusing because they are useful in other situations. When used in combination with the stop_threshold they can give an application more options on how to determine when a pcm should be stopped, allowing ii to go beyond the normal underrun point. Having said that, I don't know of any application that uses this - the only example I could find is the dmix plugin within alsa-lib itself. |
I kind of question the usefulness of the drain state/operation in general, as one seemingly could always just as well simply intentionally wait for the underrun when one is done writing. With it we must now document how the different drain silence and sw silence parameter all interact with each other for the different sitautions (drain vs underrun)... Anyway, just to re-confirm, do I understand correctly that when |
The internal implementation details should not be in documentation IMHO. The overriding is hidden (silence sw_params from the caller are returned back when drain is finished).
Yes. |
The documentation should be clear about what alsa will take care for you and what the app developer needs to do themselves, right? I think what I want to do should be the most common use case: I simply want that glitchy old samples are never played back, neither when draining, nor when an underrun happens (of course I try to avoid underruns as much as possible, but since they still can happen, at least they shouldn't be glitchy). From the current documentation it is not clear how to archive this. Given this discussion so far:
|
I meant that we should describe the expected API behavior not the internal implementation. For rewind: I just checked the kernel and it seems that the silencing code is not called immediately when caller asks for it. It smells like a bug (omitted implementation) rather than an intended behavior. Possible kernel fix:
@tiwai: FYI
It's implementable and it may give a hint to drivers to handle this extra silencing. On the other side, the current silencing is not a perfect solution without a smooth sample value change to zero implementation. So it does not omit pops completely, if the last played sample is too far from the middle. |
Indeed, but playing silence is still better than random old samples from the last iteration. I am in fact currently developing and will soon release an audio player engine library and application that tries extra hard to avoid any audio glitches under any circumstance; For pausing I use rewind to apply a short fade-out before stopping, and I try to do that as well shortly before an underrun as a "soft underrun" mechanism to avoid the pops you mentioned. |
With my patch about the silence param interaction merged now, I am wondering if it is worth it to amend the I think it would be good to track the rewind thing in another task. If you decide to merge your kernel-side fix, then I guess the documentation doesn't need to be updated. Otherwise the And potentially adding a new |
The API documentation states that drain silence is enabled by default. But since this is a hardware parameter, is it possible that some hardware does not support this? Or is this always available (and will cause alsa-lib internal software workarounds for hardware that doesn't have perfect drain)?
Also, the documentation mentions the sw_params silencing mechanism as usable for a manual emulation of this, but the documentation of the sw_params silence_size/silence_threshold imply they only affect the silencing behavior in case of underrun, not in case of draining.
I can create a patch for the documentation if you'd like, as soon as I get the needed info.
The text was updated successfully, but these errors were encountered: