Re: [Alsa-devel] more on that return from poll(2) issue
On Wed, 28 Nov 2001, Jaroslav Kysela wrote: On Tue, 27 Nov 2001, Paul Davis wrote: enclosed below what happens when using ALSA, mmap mode and poll(2) on my trident card at 44100. the value of contiguous is the value returned by snd_pcm_mmap_begin() having been passed a value of 2048 as the upper limit. the period size is 2048 frames, the buffer size is 2 * period size. the figures shown are for the capture stream; both capture and playback are open at the same time and are both in active use. needless to say, this is basically unworkable as is. any suggestions as to why this happening? it happens much, much less frequently at 48kHz, and almost never on the Hammerfall. i tried it on the (admittedly known to be broken) tropez+ and it crashed my machine :) is this an application design problem, or an alsa low level driver implementation problem (i.e. with the hw pointer routines?) Can you send me output from 'snd_pcm_dump()', too? It might be caused by a wrong sw_params settings. I looked to this problem. The default sw_params should be ok - they set avail_min and xfer_align to period_size. The question is, if the direct access function - snd_pcm_mmap_begin - should take care about these values. Also, it would be problematic to include the test for non-continous transfers. The right loop, based on the period_size transfers, should be like this: poll(); if ((pfd-revents POLLIN) { while (1) { if (snd_pcm_avail_update(pcm) period_size) break; count = period_size; // transfer whole period (can be composed from more // non-continuous parts) while (avail 0) { frames = count; snd_pcm_mmap_begin(pcm, areas, offset, frames); snd_pcm_mmap_commit(pcm, offset, frames); count -= frames; } } } Jaroslav - Jaroslav Kysela [EMAIL PROTECTED] SuSE Linuxhttp://www.suse.com ALSA Project http://www.alsa-project.org ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
count = (avail / period_size) * period_size; count = avail - avail % period_size; is more efficient (at least on i386 and gcc). thanks for reminding me. alas, there is still a problem. could it just be a device-specific issue? its as if the snd_pcm_mmap_commit doesn't work on the playback stream on the trident ... source: --- http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/~checkout~/jackit/jack/alsa_driver.c?rev=1.5content-type=text/plain params: --- period_size = 64; buffer_size = 2 * period_size; `hw_avail' = values reported by snd_pcm_avail_update() on return from poll(2) for each stream `this_time' = the minimum of the two hw_avail values, processed via the mod expression above `contiguous' = smaller of the values returned by snd_pcm_mmap_begin() for the two streams, having been passed `this_time' as an upper limit this is the number passed to snd_pcm_mmap_commit() for each stream. behaviour on a hammerfall (correct): --- hw avail: c:64 p:64 this time = 64 contiguous = 64 hw avail: c:64 p:64 this time = 64 contiguous = 64 hw avail: c:64 p:64 this time = 64 contiguous = 64 hw avail: c:64 p:64 this time = 64 contiguous = 64 hw avail: c:64 p:64 etc. etc. etc. behaviour on a trident (problem) --- hw avail: c:64 p:65 this time = 64 contiguous = 64 hw avail: c:64 p:66 this time = 64 contiguous = 64 hw avail: c:0 p:65 this time = 0 hw avail: c:0 p:65 this time = 0 hw avail: c:65 p:65 this time = 64 contiguous = 64 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 hw avail: c:1 p:66 this time = 0 [ ... continues like this for quite some time ... then: ] hw avail: c:64 p:65 this time = 64 contiguous = 64 hw avail: c:64 p:66 this time = 64 contiguous = 64 hw avail: c:64 p:65 this time = 64 contiguous = 64 hw avail: c:0 p:66 this time = 0 ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
On Wed, 28 Nov 2001, Paul Davis wrote: non-continous transfers. The right loop, based on the period_size transfers, should be like this: poll(); if ((pfd-revents POLLIN) { while (1) { if (snd_pcm_avail_update(pcm) period_size) break; count = period_size; // transfer whole period (can be composed from more // non-continuous parts) right, i understand that on some hardware, this is true. but there is no reason i know of for the trident h/w (perhaps for any hardware) to have a whole period composed of 2 non-continuous parts of size 1 and (period_size-1) frames. i can't believe that its an honest reflection of the state of the hardware. There can be two reasons: 1) the interrupt acknowledge is a bit delayed 2) the task wakeup is a bit delayed It makes perfectly sense, that the stream is some frames ahead when task is woken up. the one complication that i can see that might cause this is the extent to which capture+playback hw pointers are in sync. what might be happening is that there really is a continuous period_size's worth of frames available on one stream, but in the other stream, the pointer doesn't quite reflect this, so we end up with the silly situation of having (period_size-1) + 1 frames. you'll note that in the code below, i poll only one descriptor. Yes, that's right. Some hardware has trouble to pass the same pointers when the streams are running in sync, but the difference should be only a few frames. do you think this is possible/likely? if it is, do you think that its the job of the low level driver(s) to handle this? otherwise, its hard for me to see how an application (or library) can handle this efficiently in any full-duplex situations. Yes, I think that only lowlevel driver code knows which streams are broken and we can have only one interrupt acknowledge source. i say this because even if we poll on both stream descriptors, if one of them is out-of-step by 1 (or lets just say some very small number of frames), we have to go back into poll immediately, which will return immediately, and we end up busy waiting, which is not good at all. i don't see any other way to handle that situation. do you? Nope. i'm going to add some debugging to check on the pointers-not-in-sync theory, and i'll let you know what i find. since very few programs do full duplex operation, this may be a rather hidden problem. while (avail 0) { Oops. There should be 'while (count 0) {'. frames = count; snd_pcm_mmap_begin(pcm, areas, offset, frames ); snd_pcm_mmap_commit(pcm, offset, frames); count -= frames; } } } is there any difference between that and the actual loop (a few non-essentials removed to make it clearer): Yes, there are differences: if (poll (driver-pfd, 1, 1000) 0) { error ... } if (driver-pfd.revents POLLERR) { error } if (driver-pfd.revents == 0) { ... timeout } if ((capture_avail = snd_pcm_avail_update (driver-capture_handle)) 0) { ... detect xruns ... } if ((playback_avail = snd_pcm_avail_update (driver-playback_handle)) 0) { ... detect xruns ... } ... handle xruns ... avail = capture_avail playback_avail ? capture_avail : playback_avail; while (avail) { You are trying to process all available frames. It's not bad, but you can assume (if poll returned a bit later) that there will be extra frames available in the ring buffer. It's your problem with the sigle extra frame, which started this discussion. /* driver-frames_per_cycle === period_size */ capture_avail = (avail driver-frames_per_cycle) ? driver-frames_per_cycle : avail; playback_avail = (avail driver-frames_per_cycle) ? driver-frames_per_cycle : avail; Note that my algorithm has two loops: One handles that only frames for the whole period will be processed, the second is for non-contiguous frames in one period. The second loop can be called maximally twice. /* THIS CALLS snd_pcm_mmap_begin() FOR BOTH STREAMS */ if (alsa_driver_get_channel_addresses (driver, (snd_pcm_uframes_t *) capture_avail, (snd_pcm_uframes_t *) playback_avail, capture_offset, playback_offset) 0) { return -1; } contiguous = capture_avail playback_avail ?
Re: [Alsa-devel] more on that return from poll(2) issue
true, except that we enforce this requirement at a different level. you can't get a synchronous engine to run correctly if the capture and playback streams are not usable in the same basic way. or can you? Yes, you can find the nearest transfer count for both streams. Sure, that would work but its not of much interest to me right now. Thats really just telling a user you asked for N frames per cycle, but we can only do 3*N, just to let you know. That may be completely wrong. The model in a synchronous system is that you specify the number of frames per cycle, and that number is honored. choosing a value thats not supported by both streams is obviously a mistake. if a user asks for N, but one of the streams can't support it, its arguably better to tell what will work, and let them try again. a similar issue arises with devices like the sbawe, which also cannot be used because the code requires that both streams be configurable with the same data format (the sbawe can't do this) But the alsa-lib can. well, JACK could too. it would be a small detail to add this to the code, probably no more than half and hour. its just not of much interest to anyone involved in it right now. its a hack to support broken h/w, and you all know how i feel about that :) --p ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
I think that you can easily solve the problem of missing frames from capture or playback simply calling poll a first time with both stream and a second time with the missing one. In this way you solve the problem without the busy loop. -- Abramo Bagnara mailto:[EMAIL PROTECTED] Opera Unica Phone: +39.546.656023 Via Emilia Interna, 140 48014 Castel Bolognese (RA) - Italy ALSA project http://www.alsa-project.org It sounds good! ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
I think that you can easily solve the problem of missing frames from capture or playback simply calling poll a first time with both stream and a second time with the missing one. In this way you solve the problem without the busy loop. thats true. however, as we've seen, that wasn't the nature of the problem, which was instead my code trying to process all frames rather than N*period_size frames. when this is fixed, that particular issue goes away. well, it does if other things are working as expected :) --p ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
Jaroslav, you wrote: avail = capture_avail playback_avail ? capture_avail : playback_avail; /* here is very bad assumption, that all drivers are able */ /* todo full duplex with same period sizes, it would be better * / /* to choose smaller value from playback-frames_per_cycle */ /* and capture-frames_per_cycle */ true, except that we enforce this requirement at a different level. you can't get a synchronous engine to run correctly if the capture and playback streams are not usable in the same basic way. or can you? a similar issue arises with devices like the sbawe, which also cannot be used because the code requires that both streams be configurable with the same data format (the sbawe can't do this) --p ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
On Wed, 28 Nov 2001, Paul Davis wrote: Jaroslav, you wrote: avail = capture_avail playback_avail ? capture_avail : playback_avail; /* here is very bad assumption, that all drivers are able */ /* todo full duplex with same period sizes, it would be better * / /* to choose smaller value from playback-frames_per_cycle */ /* and capture-frames_per_cycle */ true, except that we enforce this requirement at a different level. you can't get a synchronous engine to run correctly if the capture and playback streams are not usable in the same basic way. or can you? Yes, you can find the nearest transfer count for both streams. a similar issue arises with devices like the sbawe, which also cannot be used because the code requires that both streams be configurable with the same data format (the sbawe can't do this) But the alsa-lib can. Jaroslav - Jaroslav Kysela [EMAIL PROTECTED] SuSE Linuxhttp://www.suse.com ALSA Project http://www.alsa-project.org ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
On Wed, 28 Nov 2001, Abramo Bagnara wrote: I think that you can easily solve the problem of missing frames from capture or playback simply calling poll a first time with both stream and a second time with the missing one. In this way you solve the problem without the busy loop. That's right. I was writting exactly same answer. Jaroslav - Jaroslav Kysela [EMAIL PROTECTED] SuSE Linuxhttp://www.suse.com ALSA Project http://www.alsa-project.org ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
RE: [Alsa-devel] more on that return from poll(2) issue
I don't know all about mmap, but why does one need to poll. I would have thought that a callback with info on how many samples it wants would be a better way. Cheers James -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]On Behalf Of Paul Davis Sent: 28 November 2001 13:47 To: Jaroslav Kysela Cc: [EMAIL PROTECTED] Subject: Re: [Alsa-devel] more on that return from poll(2) issue non-continous transfers. The right loop, based on the period_size transfers, should be like this: poll(); if ((pfd-revents POLLIN) { while (1) { if (snd_pcm_avail_update(pcm) period_size) break; count = period_size; // transfer whole period (can be composed from more // non-continuous parts) right, i understand that on some hardware, this is true. but there is no reason i know of for the trident h/w (perhaps for any hardware) to have a whole period composed of 2 non-continuous parts of size 1 and (period_size-1) frames. i can't believe that its an honest reflection of the state of the hardware. the one complication that i can see that might cause this is the extent to which capture+playback hw pointers are in sync. what might be happening is that there really is a continuous period_size's worth of frames available on one stream, but in the other stream, the pointer doesn't quite reflect this, so we end up with the silly situation of having (period_size-1) + 1 frames. you'll note that in the code below, i poll only one descriptor. do you think this is possible/likely? if it is, do you think that its the job of the low level driver(s) to handle this? otherwise, its hard for me to see how an application (or library) can handle this efficiently in any full-duplex situations. i say this because even if we poll on both stream descriptors, if one of them is out-of-step by 1 (or lets just say some very small number of frames), we have to go back into poll immediately, which will return immediately, and we end up busy waiting, which is not good at all. i don't see any other way to handle that situation. do you? i'm going to add some debugging to check on the pointers-not-in-sync theory, and i'll let you know what i find. since very few programs do full duplex operation, this may be a rather hidden problem. while (avail 0) { frames = count; snd_pcm_mmap_begin(pcm, areas, offset, frames ); snd_pcm_mmap_commit(pcm, offset, frames); count -= frames; } } } is there any difference between that and the actual loop (a few non-essentials removed to make it clearer): if (poll (driver-pfd, 1, 1000) 0) { error ... } if (driver-pfd.revents POLLERR) { error } if (driver-pfd.revents == 0) { ... timeout } if ((capture_avail = snd_pcm_avail_update (driver-capture_handle)) 0) { ... detect xruns ... } if ((playback_avail = snd_pcm_avail_update (driver-playback_handle)) 0) { ... detect xruns ... } ... handle xruns ... avail = capture_avail playback_avail ? capture_avail : playback_avail; while (avail) { /* driver-frames_per_cycle === period_size */ capture_avail = (avail driver-frames_per_cycle) ? driver-frames_per_cycle : avail; playback_avail = (avail driver-frames_per_cycle) ? driver-frames_per_cycle : avail; /* THIS CALLS snd_pcm_mmap_begin() FOR BOTH STREAMS */ if (alsa_driver_get_channel_addresses (driver, (snd_pcm_uframes_t *) capture_avail, (snd_pcm_uframes_t *) playback_avail, capture_offset, playback_offset) 0) { return -1; } contiguous = capture_avail playback_avail ? capture_avail : playback_avail; do interesting stuff with `contiguous' frames ... snd_pcm_mmap_commit (driver-capture_handle, capture_offset, contiguous); snd_pcm_mmap_commit (driver-playback_handle, playback_offset, contiguous); avail -= contiguous; } ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel ___ Alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
after hacking both the kernel driver and alsa-lib, this is the view from user-space. each block between is single return from poll(2). i added code to print the values of the hw_ptr and appl_ptr from within alsa-lib. --- hwptr = 65 apptr = 0 hwptr = 128 apptr = 64 hw avail: c:64 p:66 this time = 64 hwptr = 128 apptr = 64 contiguous = 64 --- hwptr = 128 apptr = 64 hwptr = 193 apptr = 128 hw avail: c:65 p:65 this time = 64 hwptr = 193 apptr = 128 contiguous = 64 --- hwptr = 193 apptr = 128 hwptr = 193 apptr = 192=== THIS hw avail: c:1 p:66 this time = 0 the line marked THIS seems impossible to me. we've returned from poll(2), but only one hwptr has changed since the last time. i just don't understand how this can happen. unless its an xrun, but that seems unlikely given that the code run here takes about 2usec to execute, is mlocked and SCHED_FIFO'ed. any suggestions of how to study this some more? the appl_ptr is being updated correctly by snd_pcm_mmap_commit() (it moves forward 64 frames each time). i have a kernel space trace too, but it seems too hard to sync up the output from there with the userspace dump. needless to say, i don't see this on the hammerfall (not suprising since there is only one hw_ptr for both playback and capture). --p ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
On Wed, 28 Nov 2001, Paul Davis wrote: after hacking both the kernel driver and alsa-lib, this is the view from user-space. each block between is single return from poll(2). i added code to print the values of the hw_ptr and appl_ptr from within alsa-lib. --- hwptr = 65 apptr = 0 hwptr = 128 apptr = 64 hw avail: c:64 p:66 this time = 64 hwptr = 128 apptr = 64 contiguous = 64 --- hwptr = 128 apptr = 64 hwptr = 193 apptr = 128 hw avail: c:65 p:65 this time = 64 hwptr = 193 apptr = 128 contiguous = 64 --- hwptr = 193 apptr = 128 hwptr = 193 apptr = 192=== THIS hw avail: c:1 p:66 this time = 0 the line marked THIS seems impossible to me. we've returned from poll(2), but only one hwptr has changed since the last time. i just don't understand how this can happen. unless its an xrun, but that Note that IRQ acknowledge differs for playback and capture streams for the Trident hardware. So it is possible, that one stream is acknowledged before other and the hw pointer is updated only inside IRQ routine. Jaroslav - Jaroslav Kysela [EMAIL PROTECTED] SuSE Linuxhttp://www.suse.com ALSA Project http://www.alsa-project.org ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
From a recent thread I learned that my RME DIGI96 only allows period sizes of 2048 or 8192 bytes. No other choices, due to hardware design. So what if the applications asks for 256 bytes? If the applications insists on that, it won't run. If it asks for near, it'll get not what it expects, but at least something that works. I tried to run the ardour-package that Takashi Iwai provides on ftp://ftp.suse.com/pub/people/tiwai/alsa9-packages/7.3-src/ but it seems that exactly due to this it won't run. Too bad, ardour look very very promising on the web-pages! It should be possible to run applications with periods of 2048 bytes, shouldn't it? Well, latency would be bad, but for plain recording it should be ok, right? Wolfgang - Original Message - From: Paul Davis [EMAIL PROTECTED] To: Jaroslav Kysela [EMAIL PROTECTED] Cc: Abramo Bagnara [EMAIL PROTECTED]; [EMAIL PROTECTED] Sent: Wednesday, November 28, 2001 6:08 PM Subject: Re: [Alsa-devel] more on that return from poll(2) issue Yes, you can find the nearest transfer count for both streams. Sure, that would work but its not of much interest to me right now. Thats really just telling a user you asked for N frames per cycle, but we can only do 3*N, just to let you know. That may be completely wrong. The model in a synchronous system is that you specify the number of frames per cycle, and that number is honored. choosing a value thats not supported by both streams is obviously a mistake. if a user asks for N, but one of the streams can't support it, its arguably better to tell what will work, and let them try again. ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel
Re: [Alsa-devel] more on that return from poll(2) issue
I tried to run the ardour-package that Takashi Iwai provides on ftp://ftp.suse.com/pub/people/tiwai/alsa9-packages/7.3-src/ but it seems that exactly due to this it won't run. Too bad, ardour look very very promising on the web-pages! I respectfull request, with great vigor, that Takashi remove this package. It is not acceptable to distribute binary copies of ardour at this time. Absolutely not acceptable, and I am quite annoyed that this was done. Its the second report I've had on this package. It should be possible to run applications with periods of 2048 bytes, shouldn't it? Well, latency would be bad, but for plain recording it should be ok, right? ardour -f 2048 will ask the h/w for a period of size 2048. ardour --help will show all options. --p ___ Alsa-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-devel