diff options
author | Shaun Ruffell <sruffell@digium.com> | 2010-07-28 15:30:47 +0000 |
---|---|---|
committer | Shaun Ruffell <sruffell@digium.com> | 2010-07-28 15:30:47 +0000 |
commit | 7d7e521e8e2a8d625a45f0c2c1bba9617166f90b (patch) | |
tree | f05931f57acb45fdf335065e46ff596f27458ca9 /drivers/dahdi/wctc4xxp | |
parent | 9e2d1674748e7dc28d9de7cd62e1dedeaebcba75 (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.c | 80 |
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. */ |