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
|
* @freq_q16: current frequency for the playback PLL in Q16.16 format
|
||||||
* @feedback_synced: flag indicating if feedback is synced
|
* @feedback_synced: flag indicating if feedback is synced
|
||||||
* @feedback_urb_skip_count: number of feedback URBs to skip at startup
|
* @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_work: work struct for stopping all streams
|
||||||
* @stop_pcm_work: work struct for stopping PCM streams
|
* @stop_pcm_work: work struct for stopping PCM streams
|
||||||
*/
|
*/
|
||||||
|
|
@ -183,6 +184,7 @@ struct tascam_card {
|
||||||
u32 freq_q16;
|
u32 freq_q16;
|
||||||
bool feedback_synced;
|
bool feedback_synced;
|
||||||
unsigned int feedback_urb_skip_count;
|
unsigned int feedback_urb_skip_count;
|
||||||
|
bool running_ghost_playback;
|
||||||
|
|
||||||
struct work_struct stop_work;
|
struct work_struct stop_work;
|
||||||
struct work_struct stop_pcm_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)
|
static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
{
|
{
|
||||||
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
||||||
int i, ret = 0;
|
int i, u, ret = 0;
|
||||||
bool start = false;
|
bool start = false;
|
||||||
bool stop = false;
|
bool stop = false;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
@ -105,6 +105,20 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
if (tascam->capture_urbs[i])
|
if (tascam->capture_urbs[i])
|
||||||
usb_unlink_urb(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) {
|
if (start) {
|
||||||
|
|
@ -121,6 +135,54 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
}
|
}
|
||||||
atomic_inc(&tascam->active_urbs);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ static int tascam_playback_prepare(struct snd_pcm_substream *substream)
|
||||||
tascam->playback_frames_consumed = 0;
|
tascam->playback_frames_consumed = 0;
|
||||||
tascam->last_pb_period_pos = 0;
|
tascam->last_pb_period_pos = 0;
|
||||||
tascam->feedback_synced = false;
|
tascam->feedback_synced = false;
|
||||||
|
tascam->running_ghost_playback = false;
|
||||||
|
|
||||||
tascam->feedback_urb_skip_count = 4;
|
tascam->feedback_urb_skip_count = 4;
|
||||||
|
|
||||||
|
|
@ -204,7 +205,6 @@ void playback_urb_complete(struct urb *urb)
|
||||||
goto exit_clear;
|
goto exit_clear;
|
||||||
|
|
||||||
substream = tascam->playback_substream;
|
substream = tascam->playback_substream;
|
||||||
runtime = substream->runtime;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
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;
|
urb->transfer_buffer_length = total_bytes_for_urb;
|
||||||
|
|
||||||
if (total_bytes_for_urb > 0) {
|
if (total_bytes_for_urb > 0) {
|
||||||
u8 *dst_buf = urb->transfer_buffer;
|
if (substream) {
|
||||||
size_t ptr_bytes = frames_to_bytes(runtime, tascam->driver_playback_pos);
|
runtime = substream->runtime;
|
||||||
frames_to_copy = bytes_to_frames(runtime, total_bytes_for_urb);
|
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) {
|
if (tascam->driver_playback_pos + frames_to_copy > runtime->buffer_size) {
|
||||||
size_t part1 = runtime->buffer_size - tascam->driver_playback_pos;
|
size_t part1 = runtime->buffer_size - tascam->driver_playback_pos;
|
||||||
size_t part1_bytes = frames_to_bytes(runtime, part1);
|
size_t part1_bytes = frames_to_bytes(runtime, part1);
|
||||||
|
|
||||||
memcpy(dst_buf, runtime->dma_area + ptr_bytes, 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);
|
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 {
|
} else {
|
||||||
memcpy(dst_buf, runtime->dma_area + ptr_bytes, total_bytes_for_urb);
|
memset(urb->transfer_buffer, 0, 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||||
|
|
||||||
if (need_period_elapsed)
|
if (need_period_elapsed && substream)
|
||||||
snd_pcm_period_elapsed(substream);
|
snd_pcm_period_elapsed(substream);
|
||||||
|
|
||||||
usb_anchor_urb(urb, &tascam->playback_anchor);
|
usb_anchor_urb(urb, &tascam->playback_anchor);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue