summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2010-07-28 15:30:47 +0000
committerShaun Ruffell <sruffell@digium.com>2010-07-28 15:30:47 +0000
commit6c577bce6fdb7e7e620ce7f8fbdc0af52568f090 (patch)
treef05931f57acb45fdf335065e46ff596f27458ca9 /drivers
parentac377557b23f9c62382ce8799f3843654153a59b (diff)
wctc4xxp: Allow read to return more than one packet of data.
As of this writing codec_dahdi (Asterisk module) will not call 'read' on a transcoder channel more often than it calls 'write'. When a translation path is setup that will transcode from g723 to g729, write is called every 30ms and each 'read' returns only 20ms of data. The end result is audio that slowly becomes increasing delayed. Since codec_dahdi calls the system read function with a buffer large enough to hold more than one packet this can prevents packets from backing up on the channel. DAHDI-582 git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9034 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dahdi/wctc4xxp/base.c80
1 files changed, 49 insertions, 31 deletions
diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 1f250be..03eda38 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1,7 +1,7 @@
/*
* Wildcard TC400B Driver
*
- * Copyright (C) 2006-2009, Digium, Inc.
+ * Copyright (C) 2006-2010, Digium, Inc.
*
* All rights reserved.
*
@@ -2038,6 +2038,8 @@ wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos)
struct tcb *cmd;
struct rtp_packet *packet;
ssize_t payload_bytes;
+ ssize_t returned_bytes = 0;
+ unsigned long flags;
BUG_ON(!dtc);
BUG_ON(!cpvt);
@@ -2050,48 +2052,64 @@ wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos)
cmd = get_ready_cmd(dtc);
if (!cmd) {
- if (file->f_flags & O_NONBLOCK) {
+ if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- } else {
- ret = wait_event_interruptible(dtc->ready,
+ ret = wait_event_interruptible(dtc->ready,
dahdi_tc_is_data_waiting(dtc));
- if (-ERESTARTSYS == ret) {
- /* Signal interrupted the wait */
- return -EINTR;
- } else {
- /* List went not empty. */
- cmd = get_ready_cmd(dtc);
- }
- }
+ if (-ERESTARTSYS == ret)
+ return -EINTR;
+ /* List went not empty. */
+ cmd = get_ready_cmd(dtc);
}
- BUG_ON(!cmd);
- packet = cmd->data;
+ do {
+ BUG_ON(!cmd);
+ packet = cmd->data;
+
+ payload_bytes = be16_to_cpu(packet->udphdr.len) -
+ sizeof(struct rtphdr) -
+ sizeof(struct udphdr);
+
+ if (count < (payload_bytes + returned_bytes)) {
+ if (returned_bytes) {
+ /* If we have already returned at least one
+ * packets worth of data, we'll add this next
+ * packet to the head of the receive queue so
+ * it will be picked up next time. */
+ spin_lock_irqsave(&cpvt->lock, flags);
+ list_add(&cmd->node, &cpvt->rx_queue);
+ dahdi_tc_set_data_waiting(dtc);
+ spin_unlock_irqrestore(&cpvt->lock, flags);
+ return returned_bytes;
+ }
+
+ if (printk_ratelimit()) {
+ DTE_PRINTK(ERR,
+ "Cannot copy %zd bytes into %zd byte user " \
+ "buffer.\n", payload_bytes, count);
+ }
+ free_cmd(cmd);
+ return -EFBIG;
+ }
- payload_bytes = be16_to_cpu(packet->udphdr.len) -
- sizeof(struct rtphdr) - sizeof(struct udphdr);
+ atomic_inc(&cpvt->stats.packets_received);
- if (count < payload_bytes) {
- if (printk_ratelimit()) {
- DTE_PRINTK(ERR,
- "Cannot copy %zd bytes into %zd byte user " \
- "buffer.\n", payload_bytes, count);
+ ret = copy_to_user(&frame[returned_bytes],
+ &packet->payload[0], payload_bytes);
+ if (unlikely(ret)) {
+ DTE_PRINTK(ERR, "Failed to copy data in %s\n",
+ __func__);
+ free_cmd(cmd);
+ return -EFAULT;
}
- free_cmd(cmd);
- return -EFBIG;
- }
- atomic_inc(&cpvt->stats.packets_received);
+ returned_bytes += payload_bytes;
- if (unlikely(copy_to_user(frame, &packet->payload[0], payload_bytes))) {
- DTE_PRINTK(ERR, "Failed to copy data in %s\n", __func__);
free_cmd(cmd);
- return -EFAULT;
- }
- free_cmd(cmd);
+ } while ((cmd = get_ready_cmd(dtc)));
- return payload_bytes;
+ return returned_bytes;
}
/* Called with a frame in the srcfmt to be transcoded into the dstfmt. */