playback optimizations

This commit is contained in:
serifpersia 2025-07-15 11:12:13 +02:00
parent 57fd9e18c9
commit a61ad1d1e9
1 changed files with 20 additions and 21 deletions

View File

@ -727,6 +727,8 @@ static void playback_urb_complete(struct urb *urb)
unsigned long flags; unsigned long flags;
char *src_buf, *dst_buf; char *src_buf, *dst_buf;
size_t total_bytes_for_urb = 0; size_t total_bytes_for_urb = 0;
snd_pcm_uframes_t offset_frames;
snd_pcm_uframes_t frames_to_copy;
int ret, i; int ret, i;
if (urb->status) if (urb->status)
@ -740,7 +742,7 @@ static void playback_urb_complete(struct urb *urb)
spin_lock_irqsave(&tascam->lock, flags); spin_lock_irqsave(&tascam->lock, flags);
/* Phase 1: Populate the isochronous frame descriptors and calculate total size. */ /* Phase 1: Populate the isochronous frame descriptors from the accumulator. */
for (i = 0; i < urb->number_of_packets; i++) { for (i = 0; i < urb->number_of_packets; i++) {
unsigned int frames_for_packet; unsigned int frames_for_packet;
size_t bytes_for_packet; size_t bytes_for_packet;
@ -759,13 +761,19 @@ static void playback_urb_complete(struct urb *urb)
} }
urb->transfer_buffer_length = total_bytes_for_urb; urb->transfer_buffer_length = total_bytes_for_urb;
/* Phase 2: Copy and format audio data from ALSA buffer to URB buffer. */ /* Phase 2: Atomically update the driver's position. */
offset_frames = tascam->driver_playback_pos;
frames_to_copy = bytes_to_frames(runtime, total_bytes_for_urb);
tascam->driver_playback_pos = (offset_frames + frames_to_copy) % runtime->buffer_size;
/* --- End of Critical Section --- */
spin_unlock_irqrestore(&tascam->lock, flags);
/* Phase 3: Perform the data copy OUTSIDE the lock. */
if (total_bytes_for_urb > 0) {
int f;
src_buf = runtime->dma_area; src_buf = runtime->dma_area;
dst_buf = urb->transfer_buffer; dst_buf = urb->transfer_buffer;
if (total_bytes_for_urb > 0) {
snd_pcm_uframes_t offset_frames = tascam->driver_playback_pos;
snd_pcm_uframes_t frames_to_copy = bytes_to_frames(runtime, total_bytes_for_urb);
int f;
for (f = 0; f < frames_to_copy; ++f) { for (f = 0; f < frames_to_copy; ++f) {
snd_pcm_uframes_t current_frame_pos = (offset_frames + f) % runtime->buffer_size; snd_pcm_uframes_t current_frame_pos = (offset_frames + f) % runtime->buffer_size;
@ -774,29 +782,20 @@ static void playback_urb_complete(struct urb *urb)
switch (tascam->playback_routing) { switch (tascam->playback_routing) {
case 0: /* Stereo to All */ case 0: /* Stereo to All */
*(u32 *)dst_frame = *(u32 *)src_frame; memcpy(dst_frame, src_frame, 6); /* Copy L/R to Out 1/2 */
*(u32 *)(dst_frame + 3) = *(u32 *)(src_frame + 3); memcpy(dst_frame + 6, src_frame, 6); /* Copy L/R to Out 3/4 */
*(u32 *)(dst_frame + 6) = *(u32 *)src_frame;
*(u32 *)(dst_frame + 9) = *(u32 *)(src_frame + 3);
break; break;
case 1: /* Swapped */ case 1: /* Swapped */
*(u32 *)dst_frame = *(u32 *)(src_frame + 6); memcpy(dst_frame, src_frame + 6, 6); /* Copy 3/4 to Out 1/2 */
*(u32 *)(dst_frame + 3) = *(u32 *)(src_frame + 9); memcpy(dst_frame + 6, src_frame, 6); /* Copy 1/2 to Out 3/4 */
*(u32 *)(dst_frame + 6) = *(u32 *)src_frame;
*(u32 *)(dst_frame + 9) = *(u32 *)(src_frame + 3);
break; break;
case 2: /* Digital In to All */ case 2: /* Digital In to All */
*(u32 *)dst_frame = *(u32 *)(src_frame + 6); memcpy(dst_frame, src_frame + 6, 6); /* Copy 3/4 to Out 1/2 */
*(u32 *)(dst_frame + 3) = *(u32 *)(src_frame + 9); memcpy(dst_frame + 6, src_frame + 6, 6); /* Copy 3/4 to Out 3/4 */
*(u32 *)(dst_frame + 6) = *(u32 *)(src_frame + 6);
*(u32 *)(dst_frame + 9) = *(u32 *)(src_frame + 9);
break; break;
} }
} }
} }
tascam->driver_playback_pos = (tascam->driver_playback_pos + bytes_to_frames(runtime, total_bytes_for_urb)) % runtime->buffer_size;
spin_unlock_irqrestore(&tascam->lock, flags);
urb->dev = tascam->dev; urb->dev = tascam->dev;
ret = usb_submit_urb(urb, GFP_ATOMIC); ret = usb_submit_urb(urb, GFP_ATOMIC);