Improve stream management and synchronization

This commit is contained in:
Serif 2025-11-17 11:22:39 +01:00 committed by serifpersia
parent 0cd2e5d732
commit fd32af5022
6 changed files with 51 additions and 46 deletions

0
build_and_install.sh Executable file → Normal file
View File

0
tascam_controls/build_appimage.sh Executable file → Normal file
View File

View File

@ -258,21 +258,7 @@ error:
return -ENOMEM;
}
void tascam_stop_work_handler(struct work_struct *work)
{
struct tascam_card *tascam =
container_of(work, struct tascam_card, stop_work);
if (!atomic_read(&tascam->playback_active)) {
usb_kill_anchored_urbs(&tascam->playback_anchor);
usb_kill_anchored_urbs(&tascam->feedback_anchor);
}
if (!atomic_read(&tascam->capture_active))
usb_kill_anchored_urbs(&tascam->capture_anchor);
if (!atomic_read(&tascam->playback_active) && !atomic_read(&tascam->capture_active))
atomic_set(&tascam->active_urbs, 0);
}
/**
* tascam_card_private_free() - Frees private data associated with the sound
@ -316,7 +302,6 @@ static int tascam_suspend(struct usb_interface *intf, pm_message_t message)
snd_pcm_suspend_all(tascam->pcm);
cancel_work_sync(&tascam->stop_work);
cancel_work_sync(&tascam->capture_work);
cancel_work_sync(&tascam->midi_in_work);
cancel_work_sync(&tascam->midi_out_work);
@ -498,8 +483,10 @@ static int tascam_probe(struct usb_interface *intf,
tascam->capture_34_source = 1;
spin_lock_init(&tascam->lock);
spin_lock_init(&tascam->trigger_lock);
spin_lock_init(&tascam->midi_in_lock);
spin_lock_init(&tascam->midi_out_lock);
atomic_set(&tascam->stream_active, 0);
init_usb_anchor(&tascam->playback_anchor);
init_usb_anchor(&tascam->capture_anchor);
init_usb_anchor(&tascam->feedback_anchor);
@ -508,7 +495,6 @@ static int tascam_probe(struct usb_interface *intf,
timer_setup(&tascam->error_timer, tascam_error_timer, 0);
INIT_WORK(&tascam->stop_work, tascam_stop_work_handler);
INIT_WORK(&tascam->stop_pcm_work, tascam_stop_pcm_work_handler);
INIT_WORK(&tascam->capture_work, tascam_capture_work_handler);
init_completion(&tascam->midi_out_drain_completion);
@ -588,7 +574,6 @@ static void tascam_disconnect(struct usb_interface *intf)
if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
/* Ensure all deferred work is complete before freeing resources */
snd_card_disconnect(tascam->card);
cancel_work_sync(&tascam->stop_work);
cancel_work_sync(&tascam->capture_work);
cancel_work_sync(&tascam->midi_in_work);
cancel_work_sync(&tascam->midi_out_work);

View File

@ -229,8 +229,10 @@ struct tascam_card {
/* --- Stream State --- */
spinlock_t lock;
spinlock_t trigger_lock;
atomic_t playback_active;
atomic_t capture_active;
atomic_t stream_active;
atomic_t active_urbs;
int current_rate;
@ -273,7 +275,6 @@ struct tascam_card {
struct us144mkii_frame_pattern_observer fpo;
/* --- Workqueues --- */
struct work_struct stop_work;
struct work_struct stop_pcm_work;
struct work_struct capture_work;
struct work_struct midi_in_work;
@ -308,14 +309,7 @@ void tascam_free_urbs(struct tascam_card *tascam);
*/
int tascam_alloc_urbs(struct tascam_card *tascam);
/**
* tascam_stop_work_handler() - Work handler to stop all active streams.
* @work: Pointer to the work_struct.
*
* This function is scheduled to stop all active URBs (playback, feedback,
* capture) and reset the active_urbs counter.
*/
void tascam_stop_work_handler(struct work_struct *work);
/* us144mkii_pcm.h */
#include "us144mkii_pcm.h"

View File

@ -282,12 +282,30 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
int err = 0;
int i;
unsigned long flags;
spin_lock_irqsave(&tascam->trigger_lock, flags);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (atomic_xchg(&tascam->playback_active, 1) == 0) {
if (atomic_fetch_inc(&tascam->stream_active) == 0) {
for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
usb_get_urb(tascam->feedback_urbs[i]);
usb_anchor_urb(tascam->feedback_urbs[i], &tascam->feedback_anchor);
err = usb_submit_urb(tascam->feedback_urbs[i], GFP_ATOMIC);
if (err < 0) {
usb_unanchor_urb(tascam->feedback_urbs[i]);
usb_put_urb(tascam->feedback_urbs[i]);
atomic_dec(&tascam->active_urbs);
break;
}
atomic_inc(&tascam->active_urbs);
}
}
for (i = 0; i < NUM_PLAYBACK_URBS; i++) {
usb_get_urb(tascam->playback_urbs[i]);
usb_anchor_urb(tascam->playback_urbs[i], &tascam->playback_anchor);
@ -299,23 +317,24 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
atomic_inc(&tascam->active_urbs);
}
for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
usb_get_urb(tascam->feedback_urbs[i]);
usb_anchor_urb(tascam->feedback_urbs[i],
&tascam->feedback_anchor);
err = usb_submit_urb(tascam->feedback_urbs[i],
GFP_ATOMIC);
if (err < 0) {
usb_unanchor_urb(tascam->feedback_urbs[i]);
usb_put_urb(tascam->feedback_urbs[i]);
atomic_dec(&tascam->active_urbs);
break;
}
atomic_inc(&tascam->active_urbs);
}
}
} else {
if (atomic_xchg(&tascam->capture_active, 1) == 0) {
if (atomic_fetch_inc(&tascam->stream_active) == 0) {
for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
usb_get_urb(tascam->feedback_urbs[i]);
usb_anchor_urb(tascam->feedback_urbs[i], &tascam->feedback_anchor);
err = usb_submit_urb(tascam->feedback_urbs[i], GFP_ATOMIC);
if (err < 0) {
usb_unanchor_urb(tascam->feedback_urbs[i]);
usb_put_urb(tascam->feedback_urbs[i]);
atomic_dec(&tascam->active_urbs);
break;
}
atomic_inc(&tascam->active_urbs);
}
}
for (i = 0; i < NUM_CAPTURE_URBS; i++) {
usb_get_urb(tascam->capture_urbs[i]);
usb_anchor_urb(tascam->capture_urbs[i], &tascam->capture_anchor);
@ -335,14 +354,19 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (atomic_xchg(&tascam->playback_active, 0) == 1) {
usb_kill_anchored_urbs(&tascam->playback_anchor);
usb_kill_anchored_urbs(&tascam->feedback_anchor);
schedule_work(&tascam->stop_work);
if (atomic_dec_and_test(&tascam->stream_active))
usb_unlink_anchored_urbs(&tascam->feedback_anchor);
usb_unlink_anchored_urbs(&tascam->playback_anchor);
}
} else {
if (atomic_xchg(&tascam->capture_active, 0) == 1) {
usb_kill_anchored_urbs(&tascam->capture_anchor);
schedule_work(&tascam->stop_work);
if (atomic_dec_and_test(&tascam->stream_active))
usb_unlink_anchored_urbs(&tascam->feedback_anchor);
usb_unlink_anchored_urbs(&tascam->capture_anchor);
}
}
break;
@ -351,6 +375,8 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
break;
}
spin_unlock_irqrestore(&tascam->trigger_lock, flags);
return err;
}
int tascam_init_pcm(struct snd_pcm *pcm)

View File

@ -276,7 +276,7 @@ void feedback_urb_complete(struct urb *urb)
}
goto out;
}
if (!tascam || !atomic_read(&tascam->playback_active))
if (!tascam || !atomic_read(&tascam->stream_active))
goto out;
playback_ss = tascam->playback_substream;