summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/class/audio/audio_host.c36
-rw-r--r--src/class/audio/audio_host.h6
2 files changed, 21 insertions, 21 deletions
diff --git a/src/class/audio/audio_host.c b/src/class/audio/audio_host.c
index 8918ca86e..b682d2d8a 100644
--- a/src/class/audio/audio_host.c
+++ b/src/class/audio/audio_host.c
@@ -311,15 +311,12 @@ static tuh_audio_stream_t *audioh_find_stream(uint8_t dev_addr, uint8_t ep_addr)
//--------------------------------------------------------------------+
// Re-arm the capture endpoint: request one full packet (the device sends at
-// most its max packet size per poll interval). Only submit while the whole
-// packet fits into the FIFO — otherwise the frame is lost anyway and the
-// transfer would be wasted; the stream resumes when tuh_audio_read() frees
-// FIFO space.
+// most its max packet size per poll interval). The overwritable FIFO retains
+// the newest capture frames when the application cannot drain it in time.
static void audioh_stream_capture_xfer(tuh_audio_stream_t *s) {
TU_VERIFY(s->state == STREAM_STATE_READY && s->running, );
const audioh_stream_map_t *map = &s->map[s->active_config];
- TU_VERIFY(tu_fifo_remaining(&s->edpt.ff) >= map->ep_size, );
TU_VERIFY(usbh_edpt_claim(s->daddr, map->ep_addr), ); // one transfer in flight
// ep_size is guaranteed <= CFG_TUH_AUDIO_EPIN_BUFSIZE by enumeration
@@ -347,13 +344,13 @@ static void audioh_stream_playback_xfer(tuh_audio_stream_t *s) {
bytes_64 <= CFG_TUH_AUDIO_STREAM_BUFSIZE, );
const uint16_t bytes = (uint16_t)bytes_64;
if (tu_fifo_count(&s->edpt.ff) < bytes) {
- // Wait until one complete poll interval is queued. This is required when
- // bInterval is greater than one frame and also avoids short audio packets.
- usbh_edpt_release(s->daddr, map->ep_addr);
- return;
+ // Keep the isochronous stream active without consuming a partial frame.
+ // The queued audio is sent once a complete poll interval is available.
+ tu_memclr(s->edpt.ep_buf, bytes);
+ } else {
+ tu_fifo_read_n(&s->edpt.ff, s->edpt.ep_buf, bytes);
}
- tu_fifo_read_n(&s->edpt.ff, s->edpt.ep_buf, bytes);
TU_ASSERT(usbh_edpt_xfer(s->daddr, map->ep_addr, s->edpt.ep_buf, bytes), );
s->rem_acc = next_rem_acc;
}
@@ -506,7 +503,7 @@ bool audioh_init(void) {
out->dir = TUSB_DIR_OUT;
// Bind FIFO buffer and transfer buffer (see tu_edpt_stream_init)
- TU_VERIFY(tu_edpt_stream_init(&in->edpt, true, false, false, in->ff_buf, CFG_TUH_AUDIO_STREAM_BUFSIZE,
+ TU_VERIFY(tu_edpt_stream_init(&in->edpt, true, false, true, in->ff_buf, CFG_TUH_AUDIO_STREAM_BUFSIZE,
_audioh_epbuf[idx].epin));
TU_VERIFY(tu_edpt_stream_init(&out->edpt, true, true, false, out->ff_buf, CFG_TUH_AUDIO_STREAM_BUFSIZE,
_audioh_epbuf[idx].epout));
@@ -883,8 +880,8 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface
uint8_t usb_input_terminal_id = 0;
uint8_t usb_output_source_id = 0;
// A Feature Unit may precede the USB terminal that identifies its stream.
- uint8_t pending_fu_id = 0;
- uint8_t pending_fu_source_id = 0;
+ uint8_t pending_fu_id = 0;
+ uint8_t pending_fu_source_id = 0;
bool have_header = false;
p_desc = tu_desc_next(p_desc);
@@ -1159,6 +1156,12 @@ bool tuh_audio_configure(uint8_t dev_idx, uint8_t stream_idx, uint8_t config_idx
s->complete_cb = complete_cb;
s->user_data = user_data;
s->state = STREAM_STATE_CONFIG;
+ if (s->dir == TUSB_DIR_IN) {
+ // A byte FIFO can overwrite only complete audio frames when its depth is
+ // an exact multiple of the configured frame size.
+ const uint16_t fifo_depth = CFG_TUH_AUDIO_STREAM_BUFSIZE - (CFG_TUH_AUDIO_STREAM_BUFSIZE % s->frame_bytes);
+ TU_VERIFY(tu_fifo_config(&s->edpt.ff, s->ff_buf, fifo_depth, true), false);
+ }
TU_LOG_DRV(" AUDIO configure %s stream %u: itf %u alt %u ep %02x\r\n",
(s->dir == TUSB_DIR_IN) ? "capture" : "playback", s->stream_idx, map->itf_num, map->alt_setting,
@@ -1187,7 +1190,7 @@ static void audioh_stream_start_complete(tuh_xfer_t *xfer) {
if (s->dir == TUSB_DIR_IN) {
audioh_stream_capture_xfer(s); // feed the capture endpoint
} else {
- audioh_stream_playback_xfer(s); // flush queued frames, if any
+ audioh_stream_playback_xfer(s); // start the continuous playback transfer chain
}
}
@@ -1261,10 +1264,6 @@ uint32_t tuh_audio_write(uint8_t dev_idx, uint8_t stream_idx, const void *buffer
}
tu_fifo_write_n(&s->edpt.ff, buffer, (uint16_t)(frames * s->frame_bytes));
- // Flush a packet when the FIFO holds at least one; the scheduler drains
- // the rest on completion
- audioh_stream_playback_xfer(s);
-
return frames;
}
@@ -1283,7 +1282,6 @@ uint32_t tuh_audio_read(uint8_t dev_idx, uint8_t stream_idx, void *buffer, uint3
const uint32_t frames = TU_MIN(frame_count, tu_fifo_count(&s->edpt.ff) / s->frame_bytes);
if (frames > 0) {
tu_fifo_read_n(&s->edpt.ff, buffer, (uint16_t)(frames * s->frame_bytes));
- audioh_stream_capture_xfer(s); // re-arm: the FIFO has room again
}
return frames;
}
diff --git a/src/class/audio/audio_host.h b/src/class/audio/audio_host.h
index 74dfdcdb6..9fcbe2577 100644
--- a/src/class/audio/audio_host.h
+++ b/src/class/audio/audio_host.h
@@ -45,7 +45,8 @@ extern "C" {
// Depth in bytes of the per-stream data FIFO. The FIFO decouples the
// application's read/write calls from the endpoint's isochronous polling cadence
-// and absorbs rate differences. 1024 bytes hold 4 default (256 B) packets.
+// and absorbs rate differences. Capture overwrites the oldest frames when full.
+// 1024 bytes hold 4 default (256 B) packets.
#ifndef CFG_TUH_AUDIO_STREAM_BUFSIZE
#define CFG_TUH_AUDIO_STREAM_BUFSIZE 1024
#endif
@@ -240,7 +241,8 @@ void tuh_audio_umount_cb(uint8_t idx);
void tuh_audio_capture_cb(uint8_t idx, uint8_t stream_idx, uint16_t xferred_bytes);
// Invoked when an isochronous OUT transfer completes successfully: the
-// next queued packet is submitted from the stream's playback FIFO.
+// next playback packet is submitted from the stream FIFO, or as silence when
+// a complete packet is not queued.
void tuh_audio_playback_cb(uint8_t idx, uint8_t stream_idx, uint16_t xferred_bytes);
// Invoked when an isochronous transfer fails. The stream is stopped