version 1.67, 2011/10/12 07:20:04 |
version 1.68, 2011/11/15 08:05:22 |
|
|
* finished draining), then the device |
* finished draining), then the device |
* automatically switches to INIT or CLOSED |
* automatically switches to INIT or CLOSED |
*/ |
*/ |
/* |
|
* TODO: |
|
* |
|
* priming buffer is not ok, because it will insert silence and |
|
* break synchronization to other programs. |
|
* |
|
* priming buffer in server mode is required, because f->bufsz may |
|
* be smaller than the server buffer and may cause underrun in the |
|
* dev_bufsz part of the buffer, in turn causing apps to break. It |
|
* doesn't hurt because we care only in synchronization between |
|
* clients. |
|
* |
|
* Priming is not required in non-server mode, because streams |
|
* actually start when they are in the READY state, and their |
|
* buffer is large enough to never cause underruns of dev_bufsz. |
|
* |
|
* Fix sock.c to allocate dev_bufsz, but to use only appbufsz -- |
|
* or whatever -- but to avoid underruns in dev_bufsz. Then remove |
|
* this ugly hack. |
|
* |
|
*/ |
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
int devctl_open(struct dev *, struct devctl *); |
int devctl_open(struct dev *, struct devctl *); |
|
|
struct dev *dev_list = NULL; |
struct dev *dev_list = NULL; |
|
unsigned dev_sndnum = 0, dev_thrnum = 0; |
|
|
|
#ifdef DEBUG |
|
void |
|
dev_dbg(struct dev *d) |
|
{ |
|
if (d->num >= DEV_NMAX) { |
|
dbg_puts("thr"); |
|
dbg_putu(d->num - DEV_NMAX); |
|
} else { |
|
dbg_puts("snd"); |
|
dbg_putu(d->num); |
|
} |
|
} |
|
#endif |
|
|
/* |
/* |
* Create a sndio device |
* Create a sndio device |
*/ |
*/ |
|
|
unsigned bufsz, unsigned round, unsigned hold, unsigned autovol) |
unsigned bufsz, unsigned round, unsigned hold, unsigned autovol) |
{ |
{ |
struct dev *d; |
struct dev *d; |
|
unsigned *pnum; |
|
|
d = malloc(sizeof(struct dev)); |
d = malloc(sizeof(struct dev)); |
if (d == NULL) { |
if (d == NULL) { |
perror("malloc"); |
perror("malloc"); |
exit(1); |
exit(1); |
} |
} |
|
pnum = (mode & MODE_THRU) ? &dev_thrnum : &dev_sndnum; |
|
if (*pnum == DEV_NMAX) { |
|
#ifdef DEBUG |
|
if (debug_level >= 1) |
|
dbg_puts("too many devices\n"); |
|
#endif |
|
return NULL; |
|
} |
|
d->num = (*pnum)++; |
|
if (mode & MODE_THRU) |
|
d->num += DEV_NMAX; |
d->ctl_list = NULL; |
d->ctl_list = NULL; |
d->path = path; |
d->path = path; |
d->reqmode = mode; |
d->reqmode = mode; |
|
|
d->autostart = 0; |
d->autostart = 0; |
d->pstate = DEV_CLOSED; |
d->pstate = DEV_CLOSED; |
d->next = dev_list; |
d->next = dev_list; |
dev_list = d; |
dev_list = d; |
return d; |
return d; |
} |
} |
|
|
|
|
{ |
{ |
if ((d->reqmode & (MODE_AUDIOMASK | MODE_MIDIMASK)) == 0) { |
if ((d->reqmode & (MODE_AUDIOMASK | MODE_MIDIMASK)) == 0) { |
#ifdef DEBUG |
#ifdef DEBUG |
dbg_puts(d->path); |
dev_dbg(d); |
dbg_puts(": has no streams, skipped\n"); |
dbg_puts(": has no streams, skipped\n"); |
#endif |
#endif |
return 1; |
return 1; |
|
|
* Add a MIDI port to the device |
* Add a MIDI port to the device |
*/ |
*/ |
int |
int |
devctl_add(struct dev *d, char *name, unsigned mode) |
devctl_add(struct dev *d, char *path, unsigned mode) |
{ |
{ |
struct devctl *c; |
struct devctl *c; |
|
|
|
|
perror("malloc"); |
perror("malloc"); |
exit(1); |
exit(1); |
} |
} |
c->path = name; |
c->path = path; |
c->mode = mode; |
c->mode = mode; |
c->next = d->ctl_list; |
c->next = d->ctl_list; |
d->ctl_list = c; |
d->ctl_list = c; |
|
|
if (f == NULL) { |
if (f == NULL) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
|
dev_dbg(d); |
|
dbg_puts(": "); |
dbg_puts(d->path); |
dbg_puts(d->path); |
dbg_puts(": failed to open audio device\n"); |
dbg_puts(": failed to open audio device\n"); |
} |
} |
|
|
if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) { |
if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
dbg_puts(d->path); |
dev_dbg(d); |
dbg_puts(": mode not supported by device\n"); |
dbg_puts(": mode not supported by device\n"); |
} |
} |
#endif |
#endif |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
if (d->mode & MODE_REC) { |
if (d->mode & MODE_REC) { |
dbg_puts(d->path); |
dev_dbg(d); |
dbg_puts(": recording "); |
dbg_puts(": recording "); |
aparams_dbg(&d->ipar); |
aparams_dbg(&d->ipar); |
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
if (d->mode & MODE_PLAY) { |
if (d->mode & MODE_PLAY) { |
dbg_puts(d->path); |
dev_dbg(d); |
dbg_puts(": playing "); |
dbg_puts(": playing "); |
aparams_dbg(&d->opar); |
aparams_dbg(&d->opar); |
dbg_puts("\n"); |
dbg_puts("\n"); |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
if (d->mode & (MODE_PLAY | MODE_RECMASK)) { |
if (d->mode & (MODE_PLAY | MODE_RECMASK)) { |
dbg_puts(d->path); |
dev_dbg(d); |
dbg_puts(": block size is "); |
dbg_puts(": block size is "); |
dbg_putu(d->round); |
dbg_putu(d->round); |
dbg_puts(" frames, using "); |
dbg_puts(" frames, using "); |