/* * Re-opens device with read-mode and starts recording (half-duplex). * Returns the DMA buffer size if successful. */ static int sndio_rec_start(int rate, int bits, int stereo) { sndio_save_bits = _sound_bits; sndio_save_stereo = _sound_stereo; sndio_save_freq = _sound_freq; _unix_bg_man->unregister_func(sndio_update); if (hdl != NULL) sio_close(hdl); hdl = NULL; _sound_bits = bits; _sound_stereo = stereo; _sound_freq = rate; if (open_sndio_device(1) != 0) return 0; sndio_volume = 127; sio_onvol(hdl, volcb, NULL); if (!sio_start(hdl)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not start sndio for recording")); sio_close(hdl); return 0; } return sndio_rec_bufsize; }
/* Stops recording and switches the device back to the original mode. */ static void sndio_rec_stop(void) { if (hdl != NULL) sio_close(hdl); hdl = NULL; _sound_bits = sndio_save_bits; _sound_stereo = sndio_save_stereo; _sound_freq = sndio_save_freq; if (open_sndio_device(0) != 0) return; sndio_realpos = sndio_playpos = 0; sio_onmove(hdl, movecb, NULL); sndio_volume = 127; sio_onvol(hdl, volcb, NULL); if (!sio_start(hdl)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not start sndio")); sio_close(hdl); return; } _unix_bg_man->register_func(sndio_update); }
int main(int argc, char **argv) { int ch; int tty; struct sio_hdl *hdl; struct termios tio; struct pollfd pfd[2]; char cmd; ssize_t n, len; /* * defaults parameters */ sio_initpar(&par); par.sig = 1; par.bits = 16; par.pchan = 2; par.rate = 44100; if (isatty(STDIN_FILENO)) { fprintf(stderr, "stdin can't be a tty\n"); exit(1); } tty = open("/dev/tty", O_RDWR); if (tty < 0) { perror("/dev/tty"); exit(1); } if (tcgetattr(tty, &tio) < 0) { perror("tcsetattr"); exit(1); } tio.c_lflag &= ~ICANON; tio.c_lflag &= ~ECHO; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (tcsetattr(tty, TCSAFLUSH, &tio) < 0) { perror("tcsetattr"); exit(1); } while ((ch = getopt(argc, argv, "r:c:e:b:x:")) != -1) { switch(ch) { case 'r': if (sscanf(optarg, "%u", &par.rate) != 1) { fprintf(stderr, "%s: bad rate\n", optarg); exit(1); } break; case 'c': if (sscanf(optarg, "%u", &par.pchan) != 1) { fprintf(stderr, "%s: bad channels\n", optarg); exit(1); } break; case 'e': if (!sio_strtoenc(&par, optarg)) { fprintf(stderr, "%s: bad encoding\n", optarg); exit(1); } break; default: usage(); exit(1); break; } } hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0); if (hdl == NULL) { fprintf(stderr, "sio_open() failed\n"); exit(1); } if (!sio_setpar(hdl, &par)) { fprintf(stderr, "sio_setpar() failed\n"); exit(1); } if (!sio_onvol(hdl, onvol, NULL)) fprintf(stderr, "warning: no volume knob on this device\n"); fprintf(stderr, "use ``+'' and ``-'' to adjust the volume\n"); if (!sio_start(hdl)) { fprintf(stderr, "sio_start() failed\n"); exit(1); } for (;;) { pfd[0].fd = tty; pfd[0].events = POLLIN; sio_pollfd(hdl, &pfd[1], POLLOUT); if (poll(pfd, 2, -1) < 0) { perror("poll"); exit(1); } if (pfd[0].revents & POLLIN) { if (read(tty, &cmd, 1) < 0) { perror("read(tty)"); exit(1); } switch (cmd) { case '+': if (vol < SIO_MAXVOL) { vol++; sio_setvol(hdl, vol); } break; case '-': if (vol > 0) { vol--; sio_setvol(hdl, vol); } break; } } if (sio_revents(hdl, &pfd[1]) & POLLOUT) { len = read(STDIN_FILENO, buf, BUFSZ); if (len < 0) { perror("stdin"); exit(1); } if (len == 0) break; n = sio_write(hdl, buf, len); if (n == 0) { fprintf(stderr, "sio_write: failed\n"); exit(1); } } } sio_close(hdl); return 0; }
/* * open device and setup parameters * return: 0=success -1=fail */ static int init(struct ao *ao) { struct priv *p = ao->priv; struct af_to_par { int format, bits, sig, le; } static const af_to_par[] = { {AF_FORMAT_U8, 8, 0, 0}, {AF_FORMAT_S8, 8, 1, 0}, {AF_FORMAT_U16_LE, 16, 0, 1}, {AF_FORMAT_U16_BE, 16, 0, 0}, {AF_FORMAT_S16_LE, 16, 1, 1}, {AF_FORMAT_S16_BE, 16, 1, 0}, {AF_FORMAT_U24_LE, 16, 0, 1}, {AF_FORMAT_U24_BE, 24, 0, 0}, {AF_FORMAT_S24_LE, 24, 1, 1}, {AF_FORMAT_S24_BE, 24, 1, 0}, {AF_FORMAT_U32_LE, 32, 0, 1}, {AF_FORMAT_U32_BE, 32, 0, 0}, {AF_FORMAT_S32_LE, 32, 1, 1}, {AF_FORMAT_S32_BE, 32, 1, 0} }, *ap; int i; p->hdl = sio_open(p->dev, SIO_PLAY, 0); if (p->hdl == NULL) { MP_ERR(ao, "can't open sndio %s\n", p->dev); goto error; } ao->format = af_fmt_from_planar(ao->format); sio_initpar(&p->par); for (i = 0, ap = af_to_par;; i++, ap++) { if (i == sizeof(af_to_par) / sizeof(struct af_to_par)) { MP_VERBOSE(ao, "unsupported format\n"); p->par.bits = 16; p->par.sig = 1; p->par.le = SIO_LE_NATIVE; break; } if (ap->format == ao->format) { p->par.bits = ap->bits; p->par.sig = ap->sig; if (ap->bits > 8) p->par.le = ap->le; if (ap->bits != SIO_BPS(ap->bits)) p->par.bps = ap->bits / 8; break; } } p->par.rate = ao->samplerate; struct mp_chmap_sel sel = {0}; for (int n = 0; n < MP_NUM_CHANNELS+1; n++) mp_chmap_sel_add_map(&sel, &sndio_layouts[n]); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto error; p->par.pchan = ao->channels.num; p->par.appbufsz = p->par.rate * 250 / 1000; /* 250ms buffer */ p->par.round = p->par.rate * 10 / 1000; /* 10ms block size */ if (!sio_setpar(p->hdl, &p->par)) { MP_ERR(ao, "couldn't set params\n"); goto error; } if (!sio_getpar(p->hdl, &p->par)) { MP_ERR(ao, "couldn't get params\n"); goto error; } if (p->par.bits == 8 && p->par.bps == 1) { ao->format = p->par.sig ? AF_FORMAT_S8 : AF_FORMAT_U8; } else if (p->par.bits == 16 && p->par.bps == 2) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S16_LE : AF_FORMAT_S16_BE) : (p->par.le ? AF_FORMAT_U16_LE : AF_FORMAT_U16_BE); } else if ((p->par.bits == 24 || p->par.msb) && p->par.bps == 3) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S24_LE : AF_FORMAT_S24_BE) : (p->par.le ? AF_FORMAT_U24_LE : AF_FORMAT_U24_BE); } else if ((p->par.bits == 32 || p->par.msb) && p->par.bps == 4) { ao->format = p->par.sig ? (p->par.le ? AF_FORMAT_S32_LE : AF_FORMAT_S32_BE) : (p->par.le ? AF_FORMAT_U32_LE : AF_FORMAT_U32_BE); } else { MP_ERR(ao, "couldn't set format\n"); goto error; } ao->bps = p->par.bps * p->par.pchan * p->par.rate; p->havevol = sio_onvol(p->hdl, volcb, p); sio_onmove(p->hdl, movecb, p); p->delay = 0; if (!sio_start(p->hdl)) MP_ERR(ao, "init: couldn't start\n"); p->pfd = calloc (sio_nfds(p->hdl), sizeof (struct pollfd)); if (!p->pfd) goto error; return 0; error: if (p->hdl) sio_close(p->hdl); return -1; }
static int sndio_init(int input, int voices) { char tmp1[128], tmp2[128]; if (input) { digi_driver->rec_cap_bits = 16; digi_driver->rec_cap_stereo = TRUE; return 0; } if (open_sndio_device(0) != 0) return -1; sndio_play_bufdata = _AL_MALLOC_ATOMIC(sndio_play_bufsize); if (sndio_play_bufdata == 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer")); sio_close(hdl); return -1; } sndio_realpos = sndio_playpos = 0; sio_onmove(hdl, movecb, NULL); sndio_volume = 127; sio_onvol(hdl, volcb, NULL); if (!sio_start(hdl)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not start sndio")); sio_close(hdl); return -1; } digi_sndio.voices = voices; /* first arg is total number of samples */ if (_mixer_init(sndio_play_round * (_sound_stereo ? 2 : 1), _sound_freq, _sound_stereo, ((_sound_bits == 16) ? 1 : 0), &digi_sndio.voices) != 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer")); sio_close(hdl); return -1; } _mix_some_samples((uintptr_t) sndio_play_bufdata, 0, sndio_signed); /* Add audio interrupt. */ _unix_bg_man->register_func(sndio_update); uszprintf(sndio_desc, sizeof(sndio_desc), get_config_text("%s: %d bits, %s, %d Hz, %s"), "sndio device", _sound_bits, uconvert_ascii((sndio_signed ? "signed" : "unsigned"), tmp1), _sound_freq, uconvert_ascii((par.pchan == 2 ? "stereo" : "mono"), tmp2)); digi_driver->desc = sndio_desc; return 0; }