[BACK]Return to abuf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

Diff for /src/usr.bin/aucat/abuf.c between version 1.25 and 1.26

version 1.25, 2013/11/18 17:37:45 version 1.26, 2015/01/21 08:43:55
Line 1 
Line 1 
 /*      $OpenBSD$       */  /*      $OpenBSD$       */
 /*  /*
  * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>   * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 15 
Line 15 
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */   */
 /*  /*
  * Simple byte fifo. It has one reader and one writer. The abuf   * Simple byte fifo.
  * structure is used to interconnect audio processing units (aproc  
  * structures).  
  *   *
  * The abuf data is split in two parts: (1) valid data available to the reader   * The abuf data is split in two parts: (1) valid data available to the reader
  * (2) space available to the writer, which is not necessarily unused. It works   * (2) space available to the writer, which is not necessarily unused. It works
  * as follows: the write starts filling at offset (start + used), once the data   * as follows: the write starts filling at offset (start + used), once the data
  * is ready, the writer adds to used the count of bytes available.   * is ready, the writer adds to used the count of bytes available.
  */   */
 /*  
  * TODO  
  *  
  *      use blocks instead of frames for WOK and ROK macros. If necessary  
  *      (unlikely) define reader block size and writer blocks size to  
  *      ease pipe/socket implementation  
  */  
 #include <err.h>  
 #include <stdarg.h>  
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
   
 #include "abuf.h"  #include "abuf.h"
 #include "aparams.h"  #include "utils.h"
 #include "aproc.h"  
 #include "conf.h"  
 #ifdef DEBUG  
 #include "dbg.h"  
 #endif  
   
 void abuf_dump(struct abuf *);  
 int abuf_flush_do(struct abuf *);  
 int abuf_fill_do(struct abuf *);  
 void abuf_eof_do(struct abuf *);  
 void abuf_hup_do(struct abuf *);  
   
 #ifdef DEBUG  #ifdef DEBUG
 void  void
 abuf_dbg(struct abuf *buf)  abuf_log(struct abuf *buf)
 {  {
         if (buf->wproc) {          log_putu(buf->start);
                 aproc_dbg(buf->wproc);          log_puts("+");
         } else {          log_putu(buf->used);
                 dbg_puts("none");          log_puts("/");
         }          log_putu(buf->len);
         dbg_puts(buf->inuse ? "=>" : "->");  
         if (buf->rproc) {  
                 aproc_dbg(buf->rproc);  
         } else {  
                 dbg_puts("none");  
         }  
 }  }
   #endif
   
 void  void
 abuf_dump(struct abuf *buf)  abuf_init(struct abuf *buf, unsigned int len)
 {  {
         abuf_dbg(buf);          buf->data = xmalloc(len);
         dbg_puts(": used = ");          buf->len = len;
         dbg_putu(buf->used);  
         dbg_puts("/");  
         dbg_putu(buf->len);  
         dbg_puts(" start = ");  
         dbg_putu(buf->start);  
         dbg_puts("\n");  
 }  
 #endif  
   
 struct abuf *  
 abuf_new(unsigned int nfr, struct aparams *par)  
 {  
         struct abuf *buf;  
         unsigned int len, bpf;  
   
         bpf = aparams_bpf(par);  
         len = nfr * bpf;  
         buf = malloc(sizeof(struct abuf) + len);  
         if (buf == NULL) {  
 #ifdef DEBUG  
                 dbg_puts("couldn't allocate abuf of ");  
                 dbg_putu(nfr);  
                 dbg_puts("fr * ");  
                 dbg_putu(bpf);  
                 dbg_puts("bpf\n");  
                 dbg_panic();  
 #else  
                 err(1, "malloc");  
 #endif  
         }  
         buf->bpf = bpf;  
         buf->cmin = par->cmin;  
         buf->cmax = par->cmax;  
         buf->inuse = 0;  
   
         /*  
          * fill fifo pointers  
          */  
         buf->len = nfr;  
         buf->used = 0;          buf->used = 0;
         buf->start = 0;          buf->start = 0;
         buf->rproc = NULL;  
         buf->wproc = NULL;  
         buf->duplex = NULL;  
         return buf;  
 }  }
   
 void  void
 abuf_del(struct abuf *buf)  abuf_done(struct abuf *buf)
 {  {
         if (buf->duplex)  #ifdef DEBUG
                 buf->duplex->duplex = NULL;          if (buf->used > 0) {
 #ifdef DEBUG                  if (log_level >= 3) {
         if (buf->rproc || buf->wproc) {                          log_puts("deleting non-empty buffer, used = ");
                 abuf_dbg(buf);                          log_putu(buf->used);
                 dbg_puts(": can't delete referenced buffer\n");                          log_puts("\n");
                 dbg_panic();  
         }  
         if (ABUF_ROK(buf)) {  
                 /*  
                  * XXX: we should call abort(), here.  
                  * However, poll() doesn't seem to return POLLHUP,  
                  * so the reader is never destroyed; instead it appears  
                  * as blocked. Fix file_poll(), if fixable, and add  
                  * a call to abord() here.  
                  */  
                 if (debug_level >= 3) {  
                         abuf_dbg(buf);  
                         dbg_puts(": deleting non-empty buffer, used = ");  
                         dbg_putu(buf->used);  
                         dbg_puts("\n");  
                 }                  }
         }          }
 #endif  #endif
         free(buf);          xfree(buf->data);
           buf->data = (void *)0xdeadbeef;
 }  }
   
 /*  /*
  * Clear buffer contents.   * return the reader pointer and the number of bytes available
  */   */
 void  
 abuf_clear(struct abuf *buf)  
 {  
 #ifdef DEBUG  
         if (debug_level >= 3) {  
                 abuf_dbg(buf);  
                 dbg_puts(": cleared\n");  
         }  
 #endif  
         buf->used = 0;  
         buf->start = 0;  
 }  
   
 /*  
  * Get a pointer to the readable block at the given offset.  
  */  
 unsigned char *  unsigned char *
 abuf_rgetblk(struct abuf *buf, unsigned int *rsize, unsigned int ofs)  abuf_rgetblk(struct abuf *buf, int *rsize)
 {  {
         unsigned int count, start, used;          int count;
   
         start = buf->start + ofs;          count = buf->len - buf->start;
         used = buf->used - ofs;          if (count > buf->used)
         if (start >= buf->len)                  count = buf->used;
                 start -= buf->len;  
 #ifdef DEBUG  
         if (start >= buf->len || used > buf->used) {  
                 abuf_dump(buf);  
                 dbg_puts(": rgetblk: bad ofs = ");  
                 dbg_putu(ofs);  
                 dbg_puts("\n");  
                 dbg_panic();  
         }  
 #endif  
         count = buf->len - start;  
         if (count > used)  
                 count = used;  
         *rsize = count;          *rsize = count;
         return (unsigned char *)buf + sizeof(struct abuf) + start * buf->bpf;          return buf->data + buf->start;
 }  }
   
 /*  /*
  * Discard the block at the start postion.   * discard "count" bytes at the start postion.
  */   */
 void  void
 abuf_rdiscard(struct abuf *buf, unsigned int count)  abuf_rdiscard(struct abuf *buf, int count)
 {  {
 #ifdef DEBUG  #ifdef DEBUG
         if (count > buf->used) {          if (count < 0 || count > buf->used) {
                 abuf_dump(buf);                  log_puts("abuf_rdiscard: bad count = ");
                 dbg_puts(": rdiscard: bad count = ");                  log_putu(count);
                 dbg_putu(count);                  log_puts("\n");
                 dbg_puts("\n");                  panic();
                 dbg_panic();  
         }          }
         if (debug_level >= 4) {  
                 abuf_dbg(buf);  
                 dbg_puts(": discard(");  
                 dbg_putu(count);  
                 dbg_puts(")\n");  
         }  
 #endif  #endif
         buf->used -= count;          buf->used -= count;
         buf->start += count;          buf->start += count;
Line 222 
Line 102 
 }  }
   
 /*  /*
  * Commit the data written at the end postion.   * advance the writer pointer by "count" bytes
  */   */
 void  void
 abuf_wcommit(struct abuf *buf, unsigned int count)  abuf_wcommit(struct abuf *buf, int count)
 {  {
 #ifdef DEBUG  #ifdef DEBUG
         if (count > (buf->len - buf->used)) {          if (count < 0 || count > (buf->len - buf->used)) {
                 abuf_dump(buf);                  log_puts("abuf_wcommit: bad count = ");
                 dbg_puts(": rdiscard: bad count = ");                  log_putu(count);
                 dbg_putu(count);                  log_puts("\n");
                 dbg_puts("\n");                  panic();
                 dbg_panic();  
         }          }
         if (debug_level >= 4) {  
                 abuf_dbg(buf);  
                 dbg_puts(": commit(");  
                 dbg_putu(count);  
                 dbg_puts(")\n");  
         }  
 #endif  #endif
         buf->used += count;          buf->used += count;
 }  }
   
 /*  /*
  * Get a pointer to the writable block at offset ofs.   * get writer pointer and the number of bytes writable
  */   */
 unsigned char *  unsigned char *
 abuf_wgetblk(struct abuf *buf, unsigned int *rsize, unsigned int ofs)  abuf_wgetblk(struct abuf *buf, int *rsize)
 {  {
         unsigned int end, avail, count;          int end, avail, count;
   
           end = buf->start + buf->used;
         end = buf->start + buf->used + ofs;  
         if (end >= buf->len)          if (end >= buf->len)
                 end -= buf->len;                  end -= buf->len;
 #ifdef DEBUG          avail = buf->len - buf->used;
         if (end >= buf->len) {  
                 abuf_dump(buf);  
                 dbg_puts(": wgetblk: bad ofs = ");  
                 dbg_putu(ofs);  
                 dbg_puts("\n");  
                 dbg_panic();  
         }  
 #endif  
         avail = buf->len - (buf->used + ofs);  
         count = buf->len - end;          count = buf->len - end;
         if (count > avail)          if (count > avail)
                         count = avail;                  count = avail;
         *rsize = count;          *rsize = count;
         return (unsigned char *)buf + sizeof(struct abuf) + end * buf->bpf;          return buf->data + end;
 }  
   
 /*  
  * Flush buffer either by dropping samples or by calling the aproc  
  * call-back to consume data. Return 0 if blocked, 1 otherwise.  
  */  
 int  
 abuf_flush_do(struct abuf *buf)  
 {  
         struct aproc *p;  
   
         p = buf->rproc;  
         if (!p)  
                 return 0;  
 #ifdef DEBUG  
         if (debug_level >= 4) {  
                 aproc_dbg(p);  
                 dbg_puts(": in\n");  
         }  
 #endif  
         return p->ops->in(p, buf);  
 }  
   
 /*  
  * Fill the buffer either by generating silence or by calling the aproc  
  * call-back to provide data. Return 0 if blocked, 1 otherwise.  
  */  
 int  
 abuf_fill_do(struct abuf *buf)  
 {  
         struct aproc *p;  
   
         p = buf->wproc;  
         if (!p)  
                 return 0;  
 #ifdef DEBUG  
         if (debug_level >= 4) {  
                 aproc_dbg(p);  
                 dbg_puts(": out\n");  
         }  
 #endif  
         return p->ops->out(p, buf);  
 }  
   
 /*  
  * Notify the reader that there will be no more input (producer  
  * disappeared) and destroy the buffer.  
  */  
 void  
 abuf_eof_do(struct abuf *buf)  
 {  
         struct aproc *p;  
   
         p = buf->rproc;  
         if (p) {  
                 buf->rproc = NULL;  
                 LIST_REMOVE(buf, ient);  
                 buf->inuse++;  
 #ifdef DEBUG  
                 if (debug_level >= 4) {  
                         aproc_dbg(p);  
                         dbg_puts(": eof\n");  
                 }  
 #endif  
                 p->ops->eof(p, buf);  
                 buf->inuse--;  
         }  
         abuf_del(buf);  
 }  
   
 /*  
  * Notify the writer that the buffer has no more consumer,  
  * and destroy the buffer.  
  */  
 void  
 abuf_hup_do(struct abuf *buf)  
 {  
         struct aproc *p;  
   
         if (ABUF_ROK(buf)) {  
 #ifdef DEBUG  
                 if (debug_level >= 3) {  
                         abuf_dbg(buf);  
                         dbg_puts(": hup: lost ");  
                         dbg_putu(buf->used);  
                         dbg_puts(" bytes\n");  
                 }  
 #endif  
                 buf->used = 0;  
         }  
         p = buf->wproc;  
         if (p != NULL) {  
                 buf->wproc = NULL;  
                 LIST_REMOVE(buf, oent);  
                 buf->inuse++;  
 #ifdef DEBUG  
                 if (debug_level >= 3) {  
                         aproc_dbg(p);  
                         dbg_puts(": hup\n");  
                 }  
 #endif  
                 p->ops->hup(p, buf);  
                 buf->inuse--;  
         }  
         abuf_del(buf);  
 }  
   
 /*  
  * Notify the read end of the buffer that there is input available  
  * and that data can be processed again.  
  */  
 int  
 abuf_flush(struct abuf *buf)  
 {  
         if (buf->inuse) {  
 #ifdef DEBUG  
                 if (debug_level >= 4) {  
                         abuf_dbg(buf);  
                         dbg_puts(": flush blocked (inuse)\n");  
                 }  
 #endif  
         } else {  
                 buf->inuse++;  
                 for (;;) {  
                         if (!abuf_flush_do(buf))  
                                 break;  
                 }  
                 buf->inuse--;  
                 if (ABUF_HUP(buf)) {  
                         abuf_hup_do(buf);  
                         return 0;  
                 }  
         }  
         return 1;  
 }  
   
 /*  
  * Notify the write end of the buffer that there is room and data can be  
  * written again. This routine can only be called from the out()  
  * call-back of the reader.  
  *  
  * Return 1 if the buffer was filled, and 0 if eof condition occured. The  
  * reader must detach the buffer on EOF condition, since its aproc->eof()  
  * call-back will never be called.  
  */  
 int  
 abuf_fill(struct abuf *buf)  
 {  
         if (buf->inuse) {  
 #ifdef DEBUG  
                 if (debug_level >= 4) {  
                         abuf_dbg(buf);  
                         dbg_puts(": fill blocked (inuse)\n");  
                 }  
 #endif  
         } else {  
                 buf->inuse++;  
                 for (;;) {  
                         if (!abuf_fill_do(buf))  
                                 break;  
                 }  
                 buf->inuse--;  
                 if (ABUF_EOF(buf)) {  
                         abuf_eof_do(buf);  
                         return 0;  
                 }  
         }  
         return 1;  
 }  
   
 /*  
  * Run a read/write loop on the buffer until either the reader or the  
  * writer blocks, or until the buffer reaches eofs. We can not get hup here,  
  * since hup() is only called from terminal nodes, from the main loop.  
  *  
  * NOTE: The buffer may disappear (ie. be free()ed) if eof is reached, so  
  * do not keep references to the buffer or to its writer or reader.  
  */  
 void  
 abuf_run(struct abuf *buf)  
 {  
         int canfill = 1, canflush = 1;  
   
         if (buf->inuse) {  
 #ifdef DEBUG  
                 if (debug_level >= 4) {  
                         abuf_dbg(buf);  
                         dbg_puts(": run blocked (inuse)\n");  
                 }  
 #endif  
                 return;  
         }  
         buf->inuse++;  
         for (;;) {  
                 if (canfill) {  
                         if (!abuf_fill_do(buf))  
                                 canfill = 0;  
                         else  
                                 canflush = 1;  
                 } else if (canflush) {  
                         if (!abuf_flush_do(buf))  
                                 canflush = 0;  
                         else  
                                 canfill = 1;  
                 } else  
                         break;  
         }  
         buf->inuse--;  
         if (ABUF_EOF(buf)) {  
                 abuf_eof_do(buf);  
                 return;  
         }  
         if (ABUF_HUP(buf)) {  
                 abuf_hup_do(buf);  
                 return;  
         }  
 }  
   
 /*  
  * Notify the reader that there will be no more input (producer  
  * disappeared). The buffer is flushed and eof() is called only if all  
  * data is flushed.  
  */  
 void  
 abuf_eof(struct abuf *buf)  
 {  
 #ifdef DEBUG  
         if (debug_level >= 3) {  
                 abuf_dbg(buf);  
                 dbg_puts(": eof requested\n");  
         }  
         if (buf->wproc == NULL) {  
                 abuf_dbg(buf);  
                 dbg_puts(": eof, no writer\n");  
                 dbg_panic();  
         }  
 #endif  
         LIST_REMOVE(buf, oent);  
         buf->wproc = NULL;  
         if (buf->rproc != NULL) {  
                 if (!abuf_flush(buf))  
                         return;  
                 if (ABUF_ROK(buf)) {  
                         /*  
                          * Could not flush everything, the reader will  
                          * have a chance to delete the abuf later.  
                          */  
 #ifdef DEBUG  
                         if (debug_level >= 3) {  
                                 abuf_dbg(buf);  
                                 dbg_puts(": eof, blocked (drain)\n");  
                         }  
 #endif  
                         return;  
                 }  
         }  
         if (buf->inuse) {  
 #ifdef DEBUG  
                 if (debug_level >= 3) {  
                         abuf_dbg(buf);  
                         dbg_puts(": eof, blocked (inuse)\n");  
                 }  
 #endif  
                 return;  
         }  
         abuf_eof_do(buf);  
 }  
   
 /*  
  * Notify the writer that the buffer has no more consumer,  
  * and that no more data will accepted.  
  */  
 void  
 abuf_hup(struct abuf *buf)  
 {  
 #ifdef DEBUG  
         if (debug_level >= 3) {  
                 abuf_dbg(buf);  
                 dbg_puts(": hup requested\n");  
         }  
         if (buf->rproc == NULL) {  
                 abuf_dbg(buf);  
                 dbg_puts(": hup, no reader\n");  
                 dbg_panic();  
         }  
 #endif  
         buf->rproc = NULL;  
         LIST_REMOVE(buf, ient);  
         if (buf->wproc != NULL) {  
                 if (buf->inuse) {  
 #ifdef DEBUG  
                         if (debug_level >= 3) {  
                                 abuf_dbg(buf);  
                                 dbg_puts(": eof, blocked (inuse)\n");  
                         }  
 #endif  
                         return;  
                 }  
         }  
         abuf_hup_do(buf);  
 }  
   
 /*  
  * Notify the reader of the change of its real-time position  
  */  
 void  
 abuf_ipos(struct abuf *buf, int delta)  
 {  
         struct aproc *p = buf->rproc;  
   
         if (p && p->ops->ipos) {  
                 buf->inuse++;  
 #ifdef DEBUG  
                 if (debug_level >= 4) {  
                         aproc_dbg(p);  
                         dbg_puts(": ipos delta = ");  
                         dbg_puti(delta);  
                         dbg_puts("\n");  
                 }  
 #endif  
                 p->ops->ipos(p, buf, delta);  
                 buf->inuse--;  
         }  
         if (ABUF_HUP(buf))  
                 abuf_hup_do(buf);  
 }  
   
 /*  
  * Notify the writer of the change of its real-time position  
  */  
 void  
 abuf_opos(struct abuf *buf, int delta)  
 {  
         struct aproc *p = buf->wproc;  
   
         if (p && p->ops->opos) {  
                 buf->inuse++;  
 #ifdef DEBUG  
                 if (debug_level >= 4) {  
                         aproc_dbg(p);  
                         dbg_puts(": opos delta = ");  
                         dbg_puti(delta);  
                         dbg_puts("\n");  
                 }  
 #endif  
                 p->ops->opos(p, buf, delta);  
                 buf->inuse--;  
         }  
         if (ABUF_HUP(buf))  
                 abuf_hup_do(buf);  
 }  }

Legend:
Removed from v.1.25  
changed lines
  Added in v.1.26