<p><br>
2016-4-9 上午2:23於 "Georg Chini" <<a href="mailto:georg@chini.tk">georg@chini.tk</a>>寫道:<br>
><br>
> On 08.04.2016 18:01, Tanu Kaskinen wrote:<br>
><br>
>>>>>><br>
>>>>>> I can't follow that line of reasoning. In the beginning the ring buffer<br>
>>>>>> is filled to max, and once you call snd_pcm_start(), data starts to<br>
>>>>>> move from the ring buffer to other buffers (I'll call the other buffers<br>
>>>>>> the "not-ring-buffer"). Apparently the driver "sees" the not-ring-<br>
>>>>>> buffer only partially, since it reports a larger latency than just the<br>
>>>>>> ring buffer fill level, but it still doesn't report the full latency.<br>
>>>>>> The time between snd_pcm_start() and the point where the reported delay<br>
>>>>>> does not any more equal the written amount tells the size of the<br>
>>>>>> visible part of the not-ring-buffer - it's the time it took for the<br>
>>>>>> first sample to travel from the ring buffer to the invisible part of<br>
>>>>>> the not-ring-buffer. I don't understand how the time could say anything<br>
>>>>>> about the size of the invisible part of the not-ring-buffer. Your logic<br>
>>>>>> "works" only if the visible and invisible parts happen to be of the<br>
>>>>>> same size.<br>
>>>>>><br>
>>>>>> You should get the same results by calculating<br>
>>>>>><br>
>>>>>>      adjusted delay = ring buffer fill level + 2 * (reported delay - ring buffer fill level)<br>
>>>>>><br>
>>>>>> That formula doesn't make sense, but that's how I understand your logic<br>
>>>>>> works, with the difference that your fix is based on one measurement<br>
>>>>>> only, so it's constant over time, while my formula recalculates the<br>
>>>>>> adjustment every time the delay is queried, so the adjustment size<br>
>>>>>> varies somewhat depending on the granularity at which audio moves to<br>
>>>>>> and from the visible part of the not-ring-buffer.<br>
>>>>>><br>
>>>>>> In any case, even if your logic actually makes sense and I'm just<br>
>>>>>> misunderstanding something, I don't see why the correction should be<br>
>>>>>> done in pulseaudio instead of the alsa driver.<br>
>>>>><br>
>>>>>   Well, now I don't understand what you mean. The logic is very simple:<br>
>>>>> If there is a not reported delay between the time snd_pcm_start() is<br>
>>>>> called and the time when the first sample is delivered to the DAC, then<br>
>>>>> this delay will persist and become part of the continuous latency.<br>
>>>>> That's all, what causes the delay is completely irrelevant.<br>
>>>><br>
>>>>   The code can't know when the first sample hits the DAC. The delay<br>
>>>> reported by alsa is supposed to tell that, but if the reported delay is<br>
>>>> wrong, I don't think you have any way to know the real delay.<br>
>>><br>
>>>   Yes, the code can know when the first sample hits the DAC. I explained it<br>
>>> already. Before the first sample hits the DAC, the delay is growing and<br>
>>> larger or equal than the number of samples you have written to the<br>
>>> buffer.<br>
>>> At the moment the delay is smaller than the write count, you can be<br>
>>> sure that at least some audio has been delivered. Since the delay is<br>
>>> decreased by the amount of audio that has been delivered to the DAC,<br>
>>> you can work back in time to the moment when the first sample has been<br>
>>> played.<br>
>><br>
>> Yes, you explained that already, but you didn't give a convincing<br>
>> explanation of why the point in time when the delay stops growing would<br>
>> indicate the point when the first sample hit the DAC.<br>
><br>
><br>
> See below. The precondition for my thoughts naturally is that no<br>
> samples vanish from the latency reports, maybe that is where<br>
> we are thinking differently.<br>
><br>
><br>
>><br>
>>>>> Maybe what I said above was not complete. At the point in time when<br>
>>>>> the first audio is played, there are two delays: First the one that is<br>
>>>>> reported<br>
>>>>> by alsa and the other is the difference between the time stamps minus<br>
>>>>> the played audio. If these two delays don't match, then there is an<br>
>>>>> "extra delay" that has to be taken into account.<br>
>>>><br>
>>>>   The difference between the time stamps is not related to how big the<br>
>>>> invisible part of the buffer is. I'll try to illustrate:<br>
>>>><br>
>>>> In the beginning, pulseaudio has written 10 ms of audio to the ring<br>
>>>> buffer, and snd_pcm_start() hasn't been called:<br>
>>>><br>
>>>> DAC <- ssssssssss|sss|dddddddddd <- pulseaudio<br>
>>>><br>
>>>> Here "ssssssssss|sss|ddddddddd" is the whole buffer between the DAC and<br>
>>>> pulseaudio. It's divided into three parts; the pipe characters separate<br>
>>>> the different parts. Each letter represents 1 ms of data. "s" stands<br>
>>>> for silence and "d" stands for data. The first part of the buffer is<br>
>>>> the invisible part that is not included in the delay reports. I've put<br>
>>>> 10 ms of data there, but it's unknown to the driver how big the<br>
>>>> invisible part is. The middle part of the buffer is the "send buffer"<br>
>>>> that the driver maintains, its size is 3 ms in this example. It's<br>
>>>> filled with silence in the beginning. The third part is the ring<br>
>>>> buffer, containing 10 ms of data from pulseaudio.<br>
>>>><br>
>>>> At this point the driver reports 10 ms latency. It knows it has 3 ms of<br>
>>>> silence buffered too, which it should include in its latency report,<br>
>>>> but it's stupid, so it only reports the data in the ring buffer. The<br>
>>>> driver has no idea how big the invisible part is, so it doesn't include<br>
>>>> it in the report.<br>
>>>><br>
>>>> Now pulseaudio calls snd_pcm_start(), which causes data to start moving<br>
>>>> from the ring buffer to the send buffer. After 1 ms the situation looks<br>
>>>> like this:<br>
>>>><br>
>>>> DAC <- ssssssssss|ssd|ddddddddd  <- pulseaudio<br>
>>>><br>
>>>> There's 2 ms of silence in the send buffer and 1 ms of data. The driver<br>
>>>> again ignores the silence in the send buffer, and reports that the<br>
>>>> delay is 10 ms, which consists of 1 ms of data in the send buffer and 9<br>
>>>> ms of data in the ring buffer.<br>
>>>><br>
>>>> After 2 ms:<br>
>>>><br>
>>>> DAC <- ssssssssss|sdd|dddddddd   <- pulseaudio<br>
>>>><br>
>>>> Reported delay: 10 ms<br>
>>>><br>
>>>> After 3 ms:<br>
>>>><br>
>>>> DAC <- ssssssssss|ddd|ddddddd    <- pulseaudio<br>
>>>><br>
>>>> Reported delay: 10 ms<br>
>>>><br>
>>>> Let's say pulseaudio refills the ring buffer now.<br>
>>>><br>
>>>> DAC <- ssssssssss|ddd|dddddddddd <- pulseaudio<br>
>>>><br>
>>>> Reported delay: 13 ms<br>
>>>><br>
>>>> After 4 ms:<br>
>>>><br>
>>>> DAC <- sssssssssd|ddd|ddddddddd  <- pulseaudio<br>
>>>><br>
>>>> The first data chunk has now entered the invisible part of the buffer,<br>
>>>> but it will still take 9 ms before it hits the DAC. At this point<br>
>>>> pulseaudio has written 13 ms of audio, and the reported delay is 12 ms.<br>
>>>> According to your logic, the adjusted delay is 12 + (4 - 1) = 15 ms,<br>
>>>> while in reality the latency is 22 ms.<br>
>>><br>
>>>   At this point, no audio has been played yet. You still have silence in the<br>
>>> buffer, so alsa would not report back, that samples have been played.<br>
>><br>
>> But the reported delay stopped growing! That's the point where you<br>
>> claim the first sample hits the DAC, but as my example illustrates,<br>
>> that doesn't seem to be true.<br>
><br>
><br>
> In your example it is not true, that's right. But for the USB devices it is.<br>
> They only start decreasing the delay when real audio has been played,<br>
> and they would increase the delay when you write to the buffer,<br>
> I have checked that in the code.<br>
> And I think any driver that makes samples vanish is so severely screwed,<br>
> that we can't do anything about it. If the driver reports complete moonshine<br>
> numbers, you can't fix it, I agree with you in that respect.<br>
><br>
> But that is not the case with USB. There is only some missing latency<br>
> that is not reported - call it transport delay or whatever and I suspect a<br>
> similar delay can be found in other alsa drivers. There is no need to figure<br>
> out the reason for it, it just takes some time after snd_pcm_start() was<br>
> called until the first sample is played - without making samples vanish.<br>
> And in that case the delay can be detected and used by the code.<br>
><br>
><br>
>><br>
>>> I choose the point where the first d hits the DAC and that is reported<br>
>>> back by alsa. (see above) I've tried put it all together in a document.<br>
>>> I hope I can finish the part that deals with the smoother code today.<br>
>>> If so, I will send it to you privately because the part about<br>
>>> module-loopback<br>
>>> is still missing.<br>
>>> Anyway, even if you think it is wrong I am still measuring the correct<br>
>>> end-to-end latency with my code, so something I am doing must be<br>
>>> right ...<br>
>><br>
>> >From what I can tell, that's a coincidence.<br>
><br>
><br>
> No, it definitely isn't. If you accept the precondition, that samples<br>
> not simply vanish from the latency reports, it's physics.<br>
> I would tend to agree that I have overlooked something, if the "extra<br>
> delay" would be the same every time and if I could not write down<br>
> the math for it.<br>
> But it isn't completely constant (just in the same range) and I can<br>
> write down the math and it matches my measurements. So I am<br>
> fairly sure that I am right. Did you have a look at my document?<br>
><br>
><br>
>><br>
>>>> I don't know how well this model reflects the reality of how the usb<br>
>>>> audio driver works, but this model seems like a plausible explanation<br>
>>>> for why the driver reports delays equalling the amount of written data<br>
>>>> in the beginning, and why the real latency is higher than the reported<br>
>>>> latency at later times.<br>
>>>><br>
>>>> I hope this also clarifies why I don't buy your argument that the time<br>
>>>> stamp difference is somehow related to the unreported latency.<br>
>>><br>
>>>   No, in fact it doesn't.<br>
>>><br>
>>>>> Trying to fix up that delay on every iteration does not make any sense<br>
>>>>> at all, it is there from the start and it is constant.<br>
>>>><br>
>>>>   Commenting on "it is constant": The playback latency is the sum of data<br>
>>>> in various buffers. The DAC consumes one sample at a time from the very<br>
>>>> last buffer, but I presume that all other places move data in bigger<br>
>>>> chunks than one sample. The unreported delay can only be constant if<br>
>>>> data moves to the invisible part of the buffering in one sample chunks.<br>
>>>> Otherwise the latency goes down every time the DAC reads a sample, and<br>
>>>> then when the buffer is refilled at the other end, the latency jumps up<br>
>>>> by the refill amount.<br>
>>><br>
>>>   I only said the "extra latency" is constant, not the latency as such.<br>
>>> See your own example above that your argument is wrong. Even<br>
>>> if the audio is moved in chunks through your invisible buffer part,<br>
>>> that part still has the same length all the time. When one "d" is<br>
>>> moved forward another one will replace it.<br>
>><br>
>> No, the invisible part is not constant, even though my presentation<br>
>> didn't show the variance. The DAC consumes data from the invisible<br>
>> buffer one sample at a time, and each time it does that, the extra<br>
>> latency decreases by one sample. Data moves from the visible part of<br>
>> the buffer to the invisible part in bigger chunks. I didn't specify the<br>
>> chunk size, but if we assume 1 ms chunks, the extra latency grows by 1<br>
>> ms every time a chunk is transferred from the visible part to the<br>
>> invisible part.<br>
><br>
><br>
> Then take any part of the buffer but the last or the first bit. All the<br>
> chunks are always full, so it's constant. The moving bit is dealt with<br>
> elsewhere, (in the smoother) but there is a lot of buffer that is always<br>
> full.<br>
> And when you take USB, the driver sees only chunks. The sample<br>
> by sample consuming of the DAC is never seen by the driver, it gets<br>
> the notification from USB that a chunk has been played.<br>
> I'm not sure how it is with HDA, but probably similar.<br>
><br>
>><br>
>>>>> This is not a negative delay reported by alsa, but my "extra latency"<br>
>>>>> is getting negative, which means playback must have started<br>
>>>>> before snd_pcm_start().<br>
>>>>> According to Raymond Yau playback seems in fact to be started<br>
>>>>> before snd_pcm_start() for HDA devices, at least if I read his last<br>
>>>>> mail on that topic right. Then the negative delays would even make<br>
>>>>> sense, since data is written to the buffer before snd_pcm_start().<br>
>>>><br>
>>>>   I had a look at the code to verify the claim that we configure alsa to<br>
>>>> start playback already before we call snd_pcm_start(). If we really do<br>
>>>> that intentionally, then it doesn't make sense to call snd_pcm_start()<br>
>>>> explicitly.<br>
>>>><br>
>>>> This is what we do:<br>
>>>> snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)<br>
>>>><br>
>>>> Note the casting of -1 to an unsigned integer. It seems that the<br>
>>>> intention is to set as high threshold as possible to avoid automatic<br>
>>>> starting. However, alsa-lib casts the threshold back to a signed value<br>
>>>> when it's used, and I believe the end result is indeed that playback<br>
>>>> starts immediately after the first write. I don't know if that matters,<br>
>>>> since we do the manual snd_pcm_start() call immediately after the first<br>
>>>> write anyway, but it seems like a bug in any case.<br>
>><br>
>> Not very important, but I'll clarify one thing: I had another look, and<br>
>> I'm not any more sure that the code where I saw the casting back to a<br>
>> signed integer is actually used by pulseaudio. The function<br>
>> is snd_pcm_write_areas(), but pulseaudio doesn't call that at least<br>
>> directly, and I did some searching in alsa-lib too, and I didn't find a<br>
>> call path that would cause snd_pcm_write_areas() to be used by<br>
>> pulseaudio. Even if snd_pcm_write_areas() isn't used, though, it's<br>
>> entirely possible that there's some other code that does a similar<br>
>> cast. I don't know the code is that triggers the snd_pcm_start() call<br>
>> when the ring buffer fill level exceeds the configured threshold. It<br>
>> might be in the kernel.<br>
>><br>
>>> OK, this it why I measure an "extra latency" of -60 to -20 usec.<br>
>>> So again, if I can measure it and even detect a bug that way,<br>
>>> don't you think there must be some truth in what I'm saying?<br>
>><br>
>> Do I understand correctly that your "extra latency" is affected by<br>
>> whether snd_pcm_start() is called implicitly in mmap_write() or<br>
>> explicitly after mmap_write()? The time when mmap_write() is called<br>
>> doesn't affect the latency in the long term.<br>
><br>
> It does. It isn't much, but if playback starts earlier, the delay<br>
> will be exactly that amount less even after 10 hours of playback.<br>
> Let's assume you have 10ms of audio to write to the buffer.<br>
> During the time, when you write, samples are coming in.<br>
> Let's say it takes 100 usec to write the buffer. If you start<br>
> playback after the write, this will be 100 usec additional delay.<br>
> 5 samples have accumulated.<br>
> If you start playback immediately after the first bit of data is<br>
> written this might take much less time, say 20 usec.<br>
> So your delay is four samples less and it will remain that way<br>
> until the sink is stopped. There is nothing that would take away<br>
> the delay.<br>
><br>
><br>
>> The smoother will produce<br>
>> wrong values if it's not started at the same time as snd_pcm_start() is<br>
>> called, but I presume the smoother is able to fix such inaccuracies<br>
>> over time, so it doesn't matter that much when the snd_pcm_start() is<br>
>> called. So isn't it a bad thing if your "extra latency" permanently<br>
>> includes something that doesn't have any real effect after some time?<br>
><br>
><br>
> Yes, it is affected by it and it should be, because the "extra delay"<br>
> is the time between snd_pcm_start() and the first sample being<br>
> played. So if the first samples are played before snd_pcm_start()<br>
> the "extra latency" will become negative. And as explained above,<br>
> it has permanent effect. Somehow you seem to be of the opinion<br>
> that all delays that are not controlled by the pulseaudio code<br>
> vanish magically, but they don't.<br>
><br>
> For the reported latency, it just means, that it will become slightly<br>
> smaller. As I said, the smoother does not use the "extra delay"<br>
> for anything, it is only calculated once when the origin for the<br>
> smoother is set and added later as an offset, when get_latency()<br>
> is called.<br>
></p>
<p>as your log had two "Starting Playback" message, can you call snd_pcm_dump after snd_pcm_start to find value of  appl_ptr,</p>
<p>  do pulseaudio prebuf mean minimum first write ?</p>
<p>Do loopback module stop the running pcm stream ? <br></p>
<p>Seem pulseaudio does not use snd_pcm_drop nor snd_pcm_drain,  how can the running pcm stream stop? <br>
</p>