fix recording while using different playback device
This commit is contained in:
parent
7f10e1254e
commit
2f53fd05bc
|
|
@ -128,6 +128,7 @@ enum tascam_register {
|
|||
* @freq_q16: current frequency for the playback PLL in Q16.16 format
|
||||
* @feedback_synced: flag indicating if feedback is synced
|
||||
* @feedback_urb_skip_count: number of feedback URBs to skip at startup
|
||||
* @running_ghost_playback: flag indicating if implicit playback is running
|
||||
* @stop_work: work struct for stopping all streams
|
||||
* @stop_pcm_work: work struct for stopping PCM streams
|
||||
*/
|
||||
|
|
@ -183,6 +184,7 @@ struct tascam_card {
|
|||
u32 freq_q16;
|
||||
bool feedback_synced;
|
||||
unsigned int feedback_urb_skip_count;
|
||||
bool running_ghost_playback;
|
||||
|
||||
struct work_struct stop_work;
|
||||
struct work_struct stop_pcm_work;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ static snd_pcm_uframes_t tascam_capture_pointer(struct snd_pcm_substream *substr
|
|||
static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
||||
int i, ret = 0;
|
||||
int i, u, ret = 0;
|
||||
bool start = false;
|
||||
bool stop = false;
|
||||
unsigned long flags;
|
||||
|
|
@ -105,6 +105,20 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
if (tascam->capture_urbs[i])
|
||||
usb_unlink_urb(tascam->capture_urbs[i]);
|
||||
}
|
||||
|
||||
if (tascam->running_ghost_playback) {
|
||||
atomic_set(&tascam->playback_active, 0);
|
||||
tascam->running_ghost_playback = false;
|
||||
|
||||
for (i = 0; i < NUM_PLAYBACK_URBS; i++) {
|
||||
if (tascam->playback_urbs[i])
|
||||
usb_unlink_urb(tascam->playback_urbs[i]);
|
||||
}
|
||||
for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
|
||||
if (tascam->feedback_urbs[i])
|
||||
usb_unlink_urb(tascam->feedback_urbs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start) {
|
||||
|
|
@ -121,6 +135,54 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
}
|
||||
atomic_inc(&tascam->active_urbs);
|
||||
}
|
||||
|
||||
if (!atomic_read(&tascam->playback_active)) {
|
||||
atomic_set(&tascam->playback_active, 1);
|
||||
tascam->running_ghost_playback = true;
|
||||
tascam->phase_accum = 0;
|
||||
tascam->freq_q16 = div_u64(((u64)tascam->current_rate << 16), 8000);
|
||||
tascam->feedback_urb_skip_count = 4;
|
||||
tascam->feedback_synced = false;
|
||||
|
||||
for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
|
||||
struct urb *f_urb = tascam->feedback_urbs[i];
|
||||
f_urb->number_of_packets = FEEDBACK_URB_PACKETS;
|
||||
f_urb->transfer_buffer_length = FEEDBACK_URB_PACKETS * FEEDBACK_PACKET_SIZE;
|
||||
for (u = 0; u < FEEDBACK_URB_PACKETS; u++) {
|
||||
f_urb->iso_frame_desc[u].offset = u * FEEDBACK_PACKET_SIZE;
|
||||
f_urb->iso_frame_desc[u].length = FEEDBACK_PACKET_SIZE;
|
||||
}
|
||||
usb_anchor_urb(f_urb, &tascam->feedback_anchor);
|
||||
if (usb_submit_urb(f_urb, GFP_ATOMIC) < 0) {
|
||||
usb_unanchor_urb(f_urb);
|
||||
atomic_dec(&tascam->active_urbs);
|
||||
} else {
|
||||
atomic_inc(&tascam->active_urbs);
|
||||
}
|
||||
}
|
||||
|
||||
size_t nominal_bytes = (tascam->current_rate / 8000) * PLAYBACK_FRAME_SIZE;
|
||||
for (u = 0; u < NUM_PLAYBACK_URBS; u++) {
|
||||
struct urb *urb = tascam->playback_urbs[u];
|
||||
size_t total_bytes = 0;
|
||||
urb->number_of_packets = PLAYBACK_URB_PACKETS;
|
||||
for (i = 0; i < PLAYBACK_URB_PACKETS; i++) {
|
||||
urb->iso_frame_desc[i].offset = i * nominal_bytes;
|
||||
urb->iso_frame_desc[i].length = nominal_bytes;
|
||||
total_bytes += nominal_bytes;
|
||||
}
|
||||
urb->transfer_buffer_length = total_bytes;
|
||||
memset(urb->transfer_buffer, 0, total_bytes);
|
||||
|
||||
usb_anchor_urb(urb, &tascam->playback_anchor);
|
||||
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
|
||||
usb_unanchor_urb(urb);
|
||||
atomic_dec(&tascam->active_urbs);
|
||||
} else {
|
||||
atomic_inc(&tascam->active_urbs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ static int tascam_playback_prepare(struct snd_pcm_substream *substream)
|
|||
tascam->playback_frames_consumed = 0;
|
||||
tascam->last_pb_period_pos = 0;
|
||||
tascam->feedback_synced = false;
|
||||
tascam->running_ghost_playback = false;
|
||||
|
||||
tascam->feedback_urb_skip_count = 4;
|
||||
|
||||
|
|
@ -204,7 +205,6 @@ void playback_urb_complete(struct urb *urb)
|
|||
goto exit_clear;
|
||||
|
||||
substream = tascam->playback_substream;
|
||||
runtime = substream->runtime;
|
||||
|
||||
spin_lock_irqsave(&tascam->lock, flags);
|
||||
|
||||
|
|
@ -225,34 +225,39 @@ void playback_urb_complete(struct urb *urb)
|
|||
urb->transfer_buffer_length = total_bytes_for_urb;
|
||||
|
||||
if (total_bytes_for_urb > 0) {
|
||||
u8 *dst_buf = urb->transfer_buffer;
|
||||
size_t ptr_bytes = frames_to_bytes(runtime, tascam->driver_playback_pos);
|
||||
frames_to_copy = bytes_to_frames(runtime, total_bytes_for_urb);
|
||||
if (substream) {
|
||||
runtime = substream->runtime;
|
||||
u8 *dst_buf = urb->transfer_buffer;
|
||||
size_t ptr_bytes = frames_to_bytes(runtime, tascam->driver_playback_pos);
|
||||
frames_to_copy = bytes_to_frames(runtime, total_bytes_for_urb);
|
||||
|
||||
if (tascam->driver_playback_pos + frames_to_copy > runtime->buffer_size) {
|
||||
size_t part1 = runtime->buffer_size - tascam->driver_playback_pos;
|
||||
size_t part1_bytes = frames_to_bytes(runtime, part1);
|
||||
if (tascam->driver_playback_pos + frames_to_copy > runtime->buffer_size) {
|
||||
size_t part1 = runtime->buffer_size - tascam->driver_playback_pos;
|
||||
size_t part1_bytes = frames_to_bytes(runtime, part1);
|
||||
|
||||
memcpy(dst_buf, runtime->dma_area + ptr_bytes, part1_bytes);
|
||||
memcpy(dst_buf + part1_bytes, runtime->dma_area, total_bytes_for_urb - part1_bytes);
|
||||
memcpy(dst_buf, runtime->dma_area + ptr_bytes, part1_bytes);
|
||||
memcpy(dst_buf + part1_bytes, runtime->dma_area, total_bytes_for_urb - part1_bytes);
|
||||
} else {
|
||||
memcpy(dst_buf, runtime->dma_area + ptr_bytes, total_bytes_for_urb);
|
||||
}
|
||||
|
||||
tascam->driver_playback_pos += frames_to_copy;
|
||||
if (tascam->driver_playback_pos >= runtime->buffer_size)
|
||||
tascam->driver_playback_pos -= runtime->buffer_size;
|
||||
|
||||
tascam->playback_frames_consumed += frames_to_copy;
|
||||
|
||||
if (div_u64(tascam->playback_frames_consumed, runtime->period_size) > tascam->last_pb_period_pos) {
|
||||
tascam->last_pb_period_pos = div_u64(tascam->playback_frames_consumed, runtime->period_size);
|
||||
need_period_elapsed = true;
|
||||
}
|
||||
} else {
|
||||
memcpy(dst_buf, runtime->dma_area + ptr_bytes, total_bytes_for_urb);
|
||||
}
|
||||
|
||||
tascam->driver_playback_pos += frames_to_copy;
|
||||
if (tascam->driver_playback_pos >= runtime->buffer_size)
|
||||
tascam->driver_playback_pos -= runtime->buffer_size;
|
||||
|
||||
tascam->playback_frames_consumed += frames_to_copy;
|
||||
|
||||
if (div_u64(tascam->playback_frames_consumed, runtime->period_size) > tascam->last_pb_period_pos) {
|
||||
tascam->last_pb_period_pos = div_u64(tascam->playback_frames_consumed, runtime->period_size);
|
||||
need_period_elapsed = true;
|
||||
memset(urb->transfer_buffer, 0, total_bytes_for_urb);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||
|
||||
if (need_period_elapsed)
|
||||
if (need_period_elapsed && substream)
|
||||
snd_pcm_period_elapsed(substream);
|
||||
|
||||
usb_anchor_urb(urb, &tascam->playback_anchor);
|
||||
|
|
|
|||
Loading…
Reference in New Issue