Re: [alsa-devel] hardware not asking for more data using asyn call back
Hi,
Thanks Stan, for your response - Instead of copying pcm data from a wav file, i decided to copy all the data to a master buffer first and then see if the circular buffer implementation works -
so now instead of copying from the wave file, i m copying data from the master buffer to the circular buffer.. however, as per your suggestion, if i copy the data in the while loop in main, then, it might not always be copied between 2 consecutive callbacks, but maybe more, as the callbacks are asynchronous.
however, the hardware still does not ask for more data after executing the callback function about twice -- is there a way to flush the hardware buffer before beginning playback? I have pasted my code below
Regards, Ashlesha.
/* Reading wav file into a buffer and then trying to play it */
#include <stdio.h> #include </usr/include/alsa/asoundlib.h> #include </usr/include/alsa/pcm.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h>
#define SIZE 128 //mpos is the position in the master buffer to write from short int *buffer, *mbuf, *mpos; int ind=10, fd1, length; static snd_pcm_t *handle; static char *device = "default"; /* playback device */ snd_output_t *output = NULL; static short int *wto, *rfrom, buflen;
void MyCallback(snd_async_handler_t *pcm_callback);
int main() { int i,j,n,count,a,err,k=0; char c; snd_pcm_sframes_t frames; snd_async_handler_t *pcm_callback;
if((fd1=open("SA2.WAV",O_RDONLY,0))==-1) printf("error opening wav file\n"); count=0; while(count++<40) a=read(fd1,&c,sizeof(char)); a=read(fd1,&length,sizeof(int)); n=length/SIZE; printf("length = %d\n",length); mbuf = (short int *) malloc (length * sizeof(short int)); mpos = &mbuf[0]; buflen = 4*SIZE; buffer = (short int *) malloc (buflen*sizeof(short int)); wto = NULL; rfrom = &buffer[0]; /* reading to master buffer */ count=0; a=1; while(count<length && a>0) a=read(fd1,&mbuf[count++],sizeof(short int)); if(a<0){ printf("error in reading from wav file\n"); exit(1); } close (fd1); for(count =0; count < buflen; count++) { buffer[count]=mbuf[count]; } /******************************/ /*ALSA DEV INIT*/ if((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) <
{ printf("error opening device: %s\n",snd_strerror(err)); return -1; }
if((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 16000, 1, 1000)) < 0) { /* 2 sec */ printf("Playback open error: %s\n", snd_strerror(err)); return -2; } /*****************************/
printf("n=%d\n",n); for (i=0; i<50; i++) { printf("i=%d\n",i); frames = snd_pcm_writei(handle, rfrom, SIZE); if(frames < 0) // underrun { printf("underrun recovery\n"); frames = snd_pcm_recover(handle, frames,0); if(frames < 0){ printf("error in recovery\n"); return -3; } } if(frames >0 && frames < SIZE) printf("expected to write %d, wrote %d\n",SIZE,frames);
printf("distance between ptrs before reinit is %d\n",rfrom - wto); if(rfrom < &buffer[buflen-1]) { wto = rfrom; rfrom = rfrom + SIZE; } if(rfrom >= &buffer[buflen-1]) { printf("rfm at the end, rfrom -buffer[buflen-1]
=%d\n",(*rfrom - buffer[buflen-1])); //wto = rfrom; rfrom = &buffer[0]; }
if((a = writetobuf())<0) printf("error in reading from wav file k = %d\n"); printf("buffer[i*SIZE] - rfrom = %d\n",(buffer[(i+1)*SIZE] -
*rfrom));
} /* Async Handler */ err = snd_async_add_pcm_handler(&pcm_callback,handle,MyCallback,NULL); if(err<0) printf("add pcm handler error = %d\n%s\n",err,snd_strerror(err)); err = snd_pcm_start(handle); if(err<0) printf("error in starting snd pcm start err
:%s\n",snd_strerror(err)); /******************************/
while (1) {
if(wto == NULL) break; // redundancy -- already checking for this
condition in MyCallback printf("infinite loop\n"); sleep(1); }
err = snd_pcm_close(handle); if(err<0) printf("error in closing pcm device: %s\n",snd_strerror(err)); return 0;
}
void MyCallback(snd_async_handler_t *pcm_callback) {
snd_pcm_t *pcm_handle = snd_async_handler_get_pcm(pcm_callback); snd_pcm_sframes_t avail; int count,a; snd_pcm_uframes_t period_size = 64; snd_pcm_sframes_t frames; if((avail=snd_pcm_avail_update(pcm_handle)) >= period_size) { printf("available frames = %d\n",avail); frames = snd_pcm_writei(pcm_handle, rfrom, SIZE); if(frames < 0) // underrun { printf("underrun recovery\n"); frames = snd_pcm_prepare(pcm_handle); printf("error from snd_pcm_prepare is: %d\n",frames); if(frames < 0){ printf("error in recovery\n"); } } if(frames >0 && frames < SIZE) printf("expected to write %d, wrote %d\n",SIZE,frames); if(rfrom < &buffer[buflen-1]) { wto = rfrom; rfrom = rfrom + SIZE; } if(rfrom >= &buffer[buflen-1]) {
// wto = rfrom; rfrom = &buffer[0]; } //location of where to start writing from next
if(writetobuf()<0){ wto=NULL; exit(0); // returns 0 to the operating system -- so it
ends the program! } ++ind; }
printf("going out of callback, ind = %d\n",ind);
}
/*Function to copy data from master buffer (mbuf) to circular buffer (buffer)*/ int writetobuf() { int count=-1;
while((++count < SIZE) && (mpos < &mbuf[length])) *(mpos++) = *(wto+count); if(mpos >= &mbuf[length-1]) return -1; else return 0;
}
On Tue, 29 May 2007 15:19:12 -0400 "Ashlesha Shintre" ashlesha.shintre@gmail.com wrote:
Hi,
Thanks Stan, for your response - Instead of copying pcm data from a wav file, i decided to copy all the data to a master buffer first and then see if the circular buffer implementation works -
Not really necessary to use an intermediate buffer, but won't hurt. I'm not sure why you are using a circular buffer, though it shouldn't hurt either.
so now instead of copying from the wave file, i m copying data from the master buffer to the circular buffer.. however, as per your suggestion, if i copy the data in the while loop in main, then, it might not always be copied between 2 consecutive callbacks, but maybe more, as the callbacks are asynchronous.
Well, your computer is creating the data that the callback function is going to send to alsa. If the callback function can fill the buffer and send it to alsa and keep up with the play rate, then if you fill the buffer in your main routine it will work even better. Your program is sleeping instead of doing anything. You can put in place some kind of interprocess communication so that they don't tread on each other in the buffer. With any modern processor that isn't heavily loaded, I don't think this will matter anyway.
however, the hardware still does not ask for more data after executing the callback function about twice -- is there a way to flush the hardware buffer before beginning playback? I have pasted my code below
The program output would still be helpful. I implemented this a few years ago. I'll go look at the code and see how it differs from yours. I seem to recall that there was a sample of exactly this on the alsa website, www.alsa-project.org. You could look at that and it might trigger an Aha! moment.
Regards, Ashlesha.
Not really necessary to use an intermediate buffer, but won't hurt. I'm not sure why you are using a circular buffer, though it shouldn't hurt either.
I wrote another code sometime back, to asychcronously playback data from a wav file, where I copied the contents of the wav file to a master buffer (like in this code) and then pumped data to the callback till the end of the buffer was reached. This code works fine -- I m trying to get the circular buffer to work now as part of an application I am writing that will allow realtime communication over the network between two hosts.
A circular buffer thus seems like a good idea, as in the case of real time communication I wont really know how much data is going to come through the network.
so now instead of copying from the wave file, i m copying data from
the master buffer to the circular buffer.. however, as per your suggestion, if i copy the data in the while loop in main, then, it might not always be copied between 2 consecutive callbacks, but maybe more, as the callbacks are asynchronous.
Well, your computer is creating the data that the callback function is going to send to alsa. If the callback function can fill the buffer and send it to alsa and keep up with the play rate, then if you fill the buffer in your main routine it will work even better. Your program is sleeping instead of doing anything. You can put in place some kind of interprocess communication so that they don't tread on each other in the buffer. With any modern processor that isn't heavily loaded, I don't think this will matter anyway.
One question I had about this interprocess communication was whether we can pass more data to the callback function apart from the pcm handler. From what I can see in the ALSA libraries, the snd_async_add_pcm_handler function only allows you to pass one parameter in the form of void * private_data.
however, the hardware still does not ask for more data after
executing the callback function about twice -- is there a way to flush the hardware buffer before beginning playback? I have pasted my code below
The program output would still be helpful. I implemented this a few years ago. I'll go look at the code and see how it differs from yours. I seem to recall that there was a sample of exactly this on the alsa website, www.alsa-project.org. You could look at that and it might trigger an Aha! moment.
I think you re talking about the pcm.c which implements asynchronous playback which in my case works -- but it doesnt implement a circular buffer. Another query that I have regarding this is that I get a "Bad File Descriptor" error from the snd_pcm_start function, but my asynchronous playback code works despite this error -- I dont think thats the reason for this code failing, but its a mystry all the same!
Here is the output of my program:
i=49
error in starting snd pcm start err :File descriptor in bad state infinite loop inside callback, available frames = 364 going out of callback, ind = 1 infinite loop inside callback, available frames = 577 going out of callback, ind = 2 infinite loop inside callback, available frames = 790 underrun recovery error from snd_pcm_prepare is: 0 going out of callback, ind = 3 infinite loop infinite loop infinite loop
Regards,
Ashlesha.
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
participants (2)
-
Ashlesha Shintre
-
stan