summaryrefslogtreecommitdiff
path: root/drivers/dahdi/wctc4xxp
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
commit7d7e521e8e2a8d625a45f0c2c1bba9617166f90b (patch)
treef05931f57acb45fdf335065e46ff596f27458ca9 /drivers/dahdi/wctc4xxp
parent9e2d1674748e7dc28d9de7cd62e1dedeaebcba75 (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/dahdi/wctc4xxp')
-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. */