All of lore.kernel.org
 help / color / mirror / Atom feed
* hw pause in USB
@ 2005-12-13  1:43 Steve deRosier
  2005-12-13  9:16 ` Clemens Ladisch
  0 siblings, 1 reply; 7+ messages in thread
From: Steve deRosier @ 2005-12-13  1:43 UTC (permalink / raw)
  To: Alsa-Devel

All,

When I have a USB pcm device attached and I press pause in my application, I get a "burp" of audio out of device.  Un-pausing is fine, but then my MIDI and audio are no longer synced up.  This happens in several different players in our system.  This doesn't happen when using the on-board audio (but we're recommending USB audio devices to some customers since the on-board audio may be somewhat noisy for certain configurations).  BTW, this happens on 6 different USB audio devices from different manufacturers.

When running my player via commandline and pressing pause, I get the following error message out of ALSA lib:

ALSA lib pcm_hw.c:535:(snd_pcm_hw_pause) SNDRV_PCM_IOCTL_PAUSE failed: Function not implemented

I'm guessing that the USB driver doesn't implement pause.

My program implements pause by calling snd_pcm_pause( hPCM, 1 );.

For drill:
# cat /proc/asound/cards
0 [rev50          ]: VIA686A - VIA 82C686A/B rev50
                     VIA 82C686A/B rev50 at 0xdc00, irq 10
1 [Opus7          ]: Serial - Serial midi (uart16550A)
                     Serial midi (uart16550A) at 0x3f8, irq 4 speed 115200 div 1 outs 3 ins 3 adaptor Generic droponfull 1
2 [AN1            ]: USB-Audio - HiFi Link AN1
                     XITEL HiFi Link AN1 at usb-0000:00:07.2-1, full speed
# cat /proc/asound/version
Advanced Linux Sound Architecture Driver Version 1.0.4 (Mon May 17 14:31:44 2004 UTC).
Compiled on Jun 23 2004 for kernel 2.6.7.

So, the questions:
* Is there a better way to implement pause in my client program?  
* Is the USB driver broken?  
* Does a more current USB driver fix this issue?  Yes, I know there are more current alsa releases; I ask this because upgrading and qualifying a new kernel and alsa lib on our device is not a trivial undertaking and if a more current USB driver doesn't absolutely fix it then I've got a serious time issue on my hands.
* Can anybody suggest any other workarounds?

Thanks,
- Steve


-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: hw pause in USB
  2005-12-13  1:43 hw pause in USB Steve deRosier
@ 2005-12-13  9:16 ` Clemens Ladisch
  2005-12-13 11:14   ` Takashi Iwai
  0 siblings, 1 reply; 7+ messages in thread
From: Clemens Ladisch @ 2005-12-13  9:16 UTC (permalink / raw)
  To: Steve deRosier; +Cc: Alsa-Devel

Steve deRosier wrote:
> When running my player via commandline and pressing pause, I get the 
> following error message out of ALSA lib:
> 
> ALSA lib pcm_hw.c:535:(snd_pcm_hw_pause) SNDRV_PCM_IOCTL_PAUSE failed: 
> Function not implemented
> 
> I'm guessing that the USB driver doesn't implement pause.

Yes.

> My program implements pause by calling snd_pcm_pause( hPCM, 1 );.

You cannot call snd_pcm_pause() when the device doesn't support it
(it should have returned an error code).
See snd_pcm_hw_params_can_pause().

> * Is there a better way to implement pause in my client program?  

snd_pcm_stop()


HTH
Clemens


-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: hw pause in USB
  2005-12-13  9:16 ` Clemens Ladisch
@ 2005-12-13 11:14   ` Takashi Iwai
  2005-12-13 17:31     ` Steve deRosier
  0 siblings, 1 reply; 7+ messages in thread
From: Takashi Iwai @ 2005-12-13 11:14 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: Steve deRosier, Alsa-Devel

At Tue, 13 Dec 2005 10:16:51 +0100,
Clemens Ladisch wrote:
> 
> Steve deRosier wrote:
> > When running my player via commandline and pressing pause, I get the 
> > following error message out of ALSA lib:
> > 
> > ALSA lib pcm_hw.c:535:(snd_pcm_hw_pause) SNDRV_PCM_IOCTL_PAUSE failed: 
> > Function not implemented
> > 
> > I'm guessing that the USB driver doesn't implement pause.
> 
> Yes.
> 
> > My program implements pause by calling snd_pcm_pause( hPCM, 1 );.
> 
> You cannot call snd_pcm_pause() when the device doesn't support it
> (it should have returned an error code).
> See snd_pcm_hw_params_can_pause().
> 
> > * Is there a better way to implement pause in my client program?  
> 
> snd_pcm_stop()

Heh, it's snd_pcm_drop() in alsa-lib :)

snd_pcm_drop() will stop DMA and abandon the whole data on the ring
buffer.  To restart the stream, you have to call snd_pcm_prepare()
and fill the rest data again (and start with snd_pcm_start() if
necessary).

So, obviously, this procedure isn't "better" than snd_pcm_pause(),
but works with all devices as a fallback.


Takashi


-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: hw pause in USB
  2005-12-13 11:14   ` Takashi Iwai
@ 2005-12-13 17:31     ` Steve deRosier
  2005-12-13 18:20       ` Takashi Iwai
  0 siblings, 1 reply; 7+ messages in thread
From: Steve deRosier @ 2005-12-13 17:31 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Clemens Ladisch, Alsa-Devel

Takashi Iwai wrote:
> At Tue, 13 Dec 2005 10:16:51 +0100,
> Clemens Ladisch wrote:
> 
>>Steve deRosier wrote:
>>
>>>When running my player via commandline and pressing pause, I get the 
>>>following error message out of ALSA lib:
>>>
>>>ALSA lib pcm_hw.c:535:(snd_pcm_hw_pause) SNDRV_PCM_IOCTL_PAUSE failed: 
>>>Function not implemented
>>>
>>>I'm guessing that the USB driver doesn't implement pause.
>>
>>Yes.
>>

Perhaps it should?!?

>>
>>>My program implements pause by calling snd_pcm_pause( hPCM, 1 );.
>>
>>You cannot call snd_pcm_pause() when the device doesn't support it
>>(it should have returned an error code).
>>See snd_pcm_hw_params_can_pause().
>>
>>
>>>* Is there a better way to implement pause in my client program?  
>>
>>snd_pcm_stop()
> 
> 
> Heh, it's snd_pcm_drop() in alsa-lib :)
> 
> snd_pcm_drop() will stop DMA and abandon the whole data on the ring
> buffer.  To restart the stream, you have to call snd_pcm_prepare()
> and fill the rest data again (and start with snd_pcm_start() if
> necessary).
> 
> So, obviously, this procedure isn't "better" than snd_pcm_pause(),
> but works with all devices as a fallback.
> 

So, do I use snd_pcm_stop() or snd_pcm_drop()?  Also, if snd_pcm_drop() will abandon the data in the ringbuffer, how do I know what it abandoned so I can put the right data back to restart?  And what is the maximum amount of data it might discard?  After sending the samples to Alsa, my program doesn't normally keep track of that data so I'll need to know how much to buffer as a "pause undo" buffer.

On a design note, shouldn't the library hide this issue from the user?  I understand the point of alsa is to provide a powerful library for advanced apps, but most applications aren't going to care HOW pause is implemented and exposing the fact that some devices implement it and some don't really defeat the purpose of having a library API in the first place.  Don't take my criticism wrong, I think Alsa is great. But, having to put this sort of hardware based check in my code hurts.  And frankly also hurts my reputation around here since I didn't realize that snd_pcm_pause() actually should be titled snd_pcm_pause_if_device_supports_pause_else_burp() and I let a release out the door with this broken (my responsibility, I should've tested pause with USB devices; but man, who would've thunk it would've been an issue).

Seems to me that the library should take device differences into account and just Do The Right Thing, or that all the drivers must support such basic functionality in decent way, even if the driver has to simulate in software a feature the hardware can't support (if that is indeed the case here).

Again, don't take me to be too harsh.  I'm just trying to stimulate positive discussion so we can improve alsa if warranted in this case.  I'll even help w/ the patches if: 1. we can agree on what needs to be done and 2. if someone can point me to where (file/function) it needs to be fixed.

In the mean time I'll settle with getting my app to work right.

- Steve


-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: hw pause in USB
  2005-12-13 17:31     ` Steve deRosier
@ 2005-12-13 18:20       ` Takashi Iwai
  0 siblings, 0 replies; 7+ messages in thread
From: Takashi Iwai @ 2005-12-13 18:20 UTC (permalink / raw)
  To: Steve deRosier; +Cc: Clemens Ladisch, Alsa-Devel

At Tue, 13 Dec 2005 09:31:57 -0800,
Steve deRosier wrote:
> 
> Takashi Iwai wrote:
> > At Tue, 13 Dec 2005 10:16:51 +0100,
> > Clemens Ladisch wrote:
> > 
> >>Steve deRosier wrote:
> >>
> >>>When running my player via commandline and pressing pause, I get the 
> >>>following error message out of ALSA lib:
> >>>
> >>>ALSA lib pcm_hw.c:535:(snd_pcm_hw_pause) SNDRV_PCM_IOCTL_PAUSE failed: 
> >>>Function not implemented
> >>>
> >>>I'm guessing that the USB driver doesn't implement pause.
> >>
> >>Yes.
> >>
> 
> Perhaps it should?!?

Patches are always welcome :)

> >>
> >>>My program implements pause by calling snd_pcm_pause( hPCM, 1 );.
> >>
> >>You cannot call snd_pcm_pause() when the device doesn't support it
> >>(it should have returned an error code).
> >>See snd_pcm_hw_params_can_pause().
> >>
> >>
> >>>* Is there a better way to implement pause in my client program?  
> >>
> >>snd_pcm_stop()
> > 
> > 
> > Heh, it's snd_pcm_drop() in alsa-lib :)
> > 
> > snd_pcm_drop() will stop DMA and abandon the whole data on the ring
> > buffer.  To restart the stream, you have to call snd_pcm_prepare()
> > and fill the rest data again (and start with snd_pcm_start() if
> > necessary).
> > 
> > So, obviously, this procedure isn't "better" than snd_pcm_pause(),
> > but works with all devices as a fallback.
> > 
> 
> So, do I use snd_pcm_stop() or snd_pcm_drop()?

There is no snd_pcm_stop().

>  Also, if
> snd_pcm_drop() will abandon the data in the ringbuffer, how do I
> know what it abandoned so I can put the right data back to restart?

You need to track the data position.  Count the data you sent and
check the value of snd_pcm_delay() just before snd_pcm_drop().

> And what is the maximum amount of data it might discard?

The size of the ring buffer.  Can't be more, of course.

>  After
> sending the samples to Alsa, my program doesn't normally keep track
> of that data so I'll need to know how much to buffer as a "pause
> undo" buffer. 

You need a manual track.

> On a design note, shouldn't the library hide this issue from the
> user?  I understand the point of alsa is to provide a powerful
> library for advanced apps, but most applications aren't going to
> care HOW pause is implemented and exposing the fact that some
> devices implement it and some don't really defeat the purpose of
> having a library API in the first place.  Don't take my criticism
> wrong, I think Alsa is great. But, having to put this sort of
> hardware based check in my code hurts.  And frankly also hurts my
> reputation around here since I didn't realize that snd_pcm_pause()
> actually should be titled
> snd_pcm_pause_if_device_supports_pause_else_burp() and I let a
> release out the door with this broken (my responsibility, I
> should've tested pause with USB devices; but man, who would've thunk
> it would've been an issue). 

Yes, it's a better name.  But too late to change.

> Seems to me that the library should take device differences into
> account and just Do The Right Thing, or that all the drivers must
> support such basic functionality in decent way, even if the driver
> has to simulate in software a feature the hardware can't support (if
> that is indeed the case here). 

The problem behind the pause is that many hardware doesn't support the
pause function indeed.  You can stop the stream, but not restart from
the exact position.  Hence, the driver needs to set up the whole data
again.

Now if the library does it secretly, it will cause an inconsistency
between the actual data on the driver and the application side.  The
app still holds the old data while the actual position was reset to
zero by the restart.  So, it's not always good to hide everyhing in
alsa-lib.

> Again, don't take me to be too harsh.  I'm just trying to stimulate
> positive discussion so we can improve alsa if warranted in this
> case.  I'll even help w/ the patches if: 1. we can agree on what
> needs to be done and 2. if someone can point me to where
> (file/function) it needs to be fixed. 

Well, as I mentioned many times, I don't recommend to use alsa-lib
directly with audio apps at all.  Rather, I see it as a lowlevel
backend like X11 library (do you remember different visual models on
X?)  What we need is a nice and portable library for simplistic
usages to cover different hardwares for a specific purpose.  Of
course, it could be a part of alsa-lib, but it's not necessary to be,
too.

Though, I guess it's still doable without too much hustle to make
snd_pcm_pause() emulation in alsa-lib.  But, enabling it
unconditionally looks too much to me.


Takashi


-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: hw pause in USB
  2005-12-28 23:37 Steve DeRosier
@ 2006-01-04  0:19 ` Steve deRosier
  0 siblings, 0 replies; 7+ messages in thread
From: Steve deRosier @ 2006-01-04  0:19 UTC (permalink / raw)
  To: Alsa-Devel; +Cc: Takashi Iwai, Clemens Ladisch

We've got it licked.  The most recent issue was a thread synchronization issue, where our pcm writing thread was putting data into the pcm AFTER we "paused" it and corrupting both the pcm and our "save" ring buffer.  After inserting a mutex all was well.

Thanks for your help in figuring out how to implement a software emulated pause.  

Now all I need is that time to write that high-level basic sound library. :)

- Steve



-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: hw pause in USB
@ 2005-12-28 23:37 Steve DeRosier
  2006-01-04  0:19 ` Steve deRosier
  0 siblings, 1 reply; 7+ messages in thread
From: Steve DeRosier @ 2005-12-28 23:37 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Clemens Ladisch, Alsa-Devel

Ok, still on the hw pause issue.  I've got it so the "burp" doesn't happen any more. But upon unpause I'm still out of sync.  At first I just figured that my calculations based on delay were off, but at this point I think I'm right.

Here's the code:

            if( device.CanPause )
            {
              snd_pcm_pause(device.pcmhandle, 1);
            }
            else
            {
              /* more complex if we can't do hardware pause. */
              
              /* First step: get our count */
              device.PauseFrames = 0;
              err = snd_pcm_delay( device.pcmhandle, &device.PauseFrames );
              if( err )
                printf( "snd_pcm_delay error: %i\n", err );  
                  
              /* Second, drop the pcm data: */
              err = snd_pcm_drop( device.pcmhandle );
              if( err )
                printf( "snd_pcm_drop error: %i", err );  
              
            }
        
            all_notes_off();
            while (device.pause.status) {
              usleep(250000);
              start_time = time(NULL);
              update_status();
            }
            
            if( device.CanPause )
            {
              snd_pcm_pause(device.pcmhandle, 0);
            }
            else
            {
              /* More difficult to do a "software pause" */
              
              /* Get the data from our ring buffer */
              ogg_int16_t Buff[ RingBuff_Size( device.PauseBuff ) ];
              
              int PauseRet = RingBuff_GetBuff( device.PauseBuff, Buff, device.PauseFrames *2 );
              
              if( PauseRet < device.PauseFrames*2 )
                printf( "DSP Unpause: Frames stored != frames returned.\n" );
              
               err = snd_pcm_prepare( device.pcmhandle );
               if( err )
                 printf( "DSP Unpause: snd_pcm_prepare return error: %i.\n", err );
              
              err = snd_pcm_writei( device.pcmhandle, Buff, device.PauseFrames );
              
              /* since the buffer should be empty, should never overrun. */
              if( (err == -EAGAIN) )
              {
                printf( "DSP Unpause: snd_pcm_writei return -EAGAIN when buffer should be empty.\n" );
              }
              else if( err < 0 )
              {
                printf( "DSP Unpause: snd_pcm_writei return < 0: %i\n", err );
              }

Note, RingBuff_* has been tested to work and returns what I'm asking of it. It handles 16bit words, and since a frame (in this config anyway) is two 16 bit words I'm having to mult frame counts by 2 when I work with it.  When I do my snd_pcm_writei() calls earlier, I always then put the same data into the ring buffer so it is always full of the most current data I did via snd_pcm_writei().

Any sugestions?    

Thanks,
- Steve



-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_idv37&alloc_id\x16865&op=click

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2006-01-04  0:19 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-12-13  1:43 hw pause in USB Steve deRosier
2005-12-13  9:16 ` Clemens Ladisch
2005-12-13 11:14   ` Takashi Iwai
2005-12-13 17:31     ` Steve deRosier
2005-12-13 18:20       ` Takashi Iwai
2005-12-28 23:37 Steve DeRosier
2006-01-04  0:19 ` Steve deRosier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.