At Sat, 8 Jul 2006 18:14:15 +0200, Stefano D'Angelo wrote: > > Excuse me if I'm repeatedly asking the same things, but I still can't understand how > some stuff works probably. > I have these lines of code: > > static snd_pcm_hardware_t snd_line6_tp_ux1_playback_hw = { > .info = SNDRV_PCM_INFO_INTERLEAVED | > SNDRV_PCM_INFO_BLOCK_TRANSFER, > .formats = SNDRV_PCM_FMTBIT_S16_LE, > .rates = SNDRV_PCM_RATE_48000, > .rate_min = 48000, > .rate_max = 48000, > .channels_min = 2, > .channels_max = 2, > /* double buffering */ > .buffer_bytes_max = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2 * 2, > .period_bytes_min = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, > .period_bytes_max = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, > .periods_min = 1, > .periods_max = 2 > }; > > and then also: > > static snd_pcm_uframes_t snd_line6_tp_ux1_pcm_pointer ( > snd_pcm_substream_t* substream) > { > struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream); > > printk ("pos: %d\n", chip->playback_pos); > return chip->playback_pos; > } > > static int snd_line6_tp_ux1_playback_copy (snd_pcm_substream_t *substream, > int channel, snd_pcm_uframes_t pos, > void *src, snd_pcm_uframes_t count) > { > struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream); > snd_pcm_runtime_t *runtime = substream->runtime; > static struct urb* urb; > > int i = 0; > static int j = 0; > > urb = usb_alloc_urb (2, GFP_ATOMIC); > urb->dev = chip->dev; > urb->pipe = usb_sndisocpipe (urb->dev, 1); > urb->complete = snd_line6_tp_ux1_complete_playback_transfer; > urb->context = substream; > urb->transfer_buffer = kmalloc (LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, > GFP_ATOMIC); > urb->transfer_buffer_length = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2; > urb->transfer_flags = URB_ISO_ASAP; > > memcpy (urb->transfer_buffer, src, count * 2 * 2); > > for (; i < LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT; i++) { > printk ("%d\n", ((s16*)urb->transfer_buffer)[i]); > } > printk ("---------\n"); > > urb->interval = 1; > urb->number_of_packets = 2; > urb->iso_frame_desc[0].offset = 0; > urb->iso_frame_desc[0].length = urb->iso_frame_desc[1].offset = > urb->iso_frame_desc[1].length = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT; > if (chip->playback_pos) > chip->playback_pos = 0; > else > chip->playback_pos = count; > j++; > printk (":: %d %d %d\n", j, chip->playback_pos, runtime->buffer_size); > snd_pcm_period_elapsed (substream); > usb_submit_urb (urb, GFP_KERNEL); > > return count; > } > > Don't care about printk()s and codying style, count in the copy callback is always 96, > which is the # of frames of a period, so everytime the copy callback is called, a > period is elapsed. Since the buffer is long 2 periods, the playback position pointer > should be either 0 or 96, I think (beginning or half of the buffer). > Now, instead of working as expected, the copy callback just works twice, for the first > two periods (one buffer length). Then the pointer becomes 0 and I can't understand why > the playback stops. > Please help! I have some people who keep on asking me about the driver, and it's a > pity that I can't overcome such simple problems and let them use their sound card! Calling snd_pcm_period_elapsed() in copy callback doesn't make sense. The copy callback is called when the PCM core requires something to copy. In general, all PCM driver callbacks are passive. They need to do only what they are requested. The role of copy callback is to copy the given user-space data to the hardware buffer. The role of pointer callback is to return the current (DMA) transfer position in the ring buffer. The role of trigger callback is to start or stop the PCM stream... In the ALSA PCM model, there are some assumptions: 1. You have a ring buffer containing PCM data. 2. DMA is running at constant rate, transferring the data in background and updating the position. Usually, the DMA controller issues an interrupt when a given size of data ("period" in ALSA term) is processed. The driver calls snd_pcm_period_elapsed() in the interrupt handler, then. However, in the case of USB devices, it's a bit tricky, because the transfer is done via non-continuous packets. To overcome this, snd-usb-audio allocates a ring-buffer via vmalloc() in hw_params callback. The PCM core copies the user-space data to the ring-buffer, and the driver copies the data from the ring-buffer to each urb appropriately. The first trigger-start callback prepares the urbs (with data copy from ring-buffer) and submit them. When urb-complete callback is called, the driver updates the current position, then *here* calls snd_pcm_period_elapsed() if the pre-given period size was already processed. Then, copy the data to urb, and re-submit it. Takashi ------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.sourceforge.net/lists/listinfo/alsa-devel