int roar_vs_volume_get (roar_vs_t * vss, float * l, float * r, int * error) { struct roar_mixer_settings mixer; int channels; if ( vss == NULL || l == NULL || r == NULL ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } _initerr(); if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) { _seterrre(); return -1; } if ( channels == 1 ) mixer.mixer[1] = mixer.mixer[0]; *l = mixer.mixer[0] / (float)mixer.scale; *r = mixer.mixer[1] / (float)mixer.scale; return 0; }
ssize_t roar_vs_position(roar_vs_t * vss, int backend, int * error) { struct roar_stream stream; struct roar_stream out_stream; struct roar_stream_info out_info; size_t offset; _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } _initerr(); if ( roar_get_stream(vss->con, &stream, roar_stream_get_id(&(vss->stream))) == -1 ) { _seterrre(); return -1; } switch (backend) { case ROAR_VS_BACKEND_NONE: return stream.pos; break; case ROAR_VS_BACKEND_FIRST: // _roar_vs_find_first_prim(vss); if ( vss->first_primid == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } roar_stream_new_by_id(&out_stream, vss->first_primid); if ( roar_stream_get_info(vss->con, &out_stream, &out_info) == -1 ) { _seterrre(); return -1; } offset = out_info.delay * vss->info.rate; offset /= 1000000; return stream.pos + offset; break; default: _seterr(ROAR_ERROR_NOTSUP); return -1; break; } _seterr(ROAR_ERROR_NOSYS); return -1; }
roar_mus_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) { ssize_t pos = roar_vs_position(vss, backend, error); ssize_t bps; // byte per sample size_t lioc; // local IO (byte) counter size_t lpos; // local possition roar_mus_t lag; _initerr(); _ckvss(-1); if (pos == -1) { _seterrre(); return 0; } if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return 0; } if ( vss->writec == 0 ) { lioc = vss->readc; } else { lioc = vss->writec; } bps = roar_info2samplesize(&(vss->info)); if ( bps == -1 ) { _seterrre(); return 0; } lpos = lioc / bps; lag = (roar_mus_t)lpos - (roar_mus_t)pos; // we now have the lag in frames // return value are ms // so we need to multiply with 1s/ms and // multiply by 1/rate lag *= 1000000; // 1s/ms lag /= vss->info.rate; if ( lag == 0 ) { _seterr(ROAR_ERROR_NONE); } return lag; }
ssize_t roar_vs_write(roar_vs_t * vss, const void * buf, size_t len, int * error) { ssize_t ret; _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } _initerr(); ret = roar_vio_write(&(vss->vio), (void*)buf, len); if ( ret == -1 ) { #ifdef EAGAIN if ( errno == EAGAIN ) return 0; #endif #ifdef EWOULDBLOCK if ( errno == EWOULDBLOCK ) return 0; #endif _seterrre(); } else { vss->writec += ret; } return ret; }
int roar_vs_stream(roar_vs_t * vss, const struct roar_audio_info * info, int dir, int * error) { struct roar_stream_info sinfo; int ret; _ckvss(-1); if ( vss->flags & FLAG_STREAM ) { _seterr(ROAR_ERROR_INVAL); return -1; } _initerr(); if ( info != &(vss->info) ) memcpy(&(vss->info), info, sizeof(struct roar_audio_info)); ret = roar_vio_simple_new_stream_obj(&(vss->vio), vss->con, &(vss->stream), info->rate, info->channels, info->bits, info->codec, dir ); if ( ret == -1 ) { _seterrre(); return -1; } if ( roar_stream_get_info(vss->con, &(vss->stream), &sinfo) != -1 ) { vss->mixerid = sinfo.mixer; _roar_vs_find_first_prim(vss); } vss->flags |= FLAG_STREAM; return 0; }
int roar_vs_blocking (roar_vs_t * vss, int val, int * error) { int old = -1; _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } old = vss->flags & FLAG_NONBLOCK ? ROAR_VS_FALSE : ROAR_VS_TRUE; _initerr(); switch (val) { case ROAR_VS_TRUE: if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) { _seterrre(); return -1; } vss->flags |= FLAG_NONBLOCK; vss->flags -= FLAG_NONBLOCK; return old; break; case ROAR_VS_FALSE: if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_NONBLOCK) == -1 ) { _seterrre(); return -1; } vss->flags |= FLAG_NONBLOCK; return old; break; case ROAR_VS_TOGGLE: if ( old == ROAR_VS_TRUE ) { return roar_vs_blocking(vss, ROAR_VS_FALSE, error); } else { return roar_vs_blocking(vss, ROAR_VS_TRUE, error); } break; case ROAR_VS_ASK: return old; break; } _seterr(ROAR_ERROR_INVAL); return -1; }
struct roar_vio_calls * roar_vs_vio_obj (roar_vs_t * vss, int * error) { _ckvss(NULL); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return NULL; } return &(vss->vio); }
struct roar_stream * roar_vs_stream_obj (roar_vs_t * vss, int * error) { _ckvss(NULL); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return NULL; } return &(vss->stream); }
static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) { struct roar_stream_info info; int old = -1; _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( val != ROAR_VS_ASK ) old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error); _initerr(); switch (val) { case ROAR_VS_TRUE: case ROAR_VS_FALSE: if ( roar_stream_set_flags(vss->con, &(vss->stream), flag, val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) { _seterrre(); return -1; } return old; break; case ROAR_VS_TOGGLE: return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error); break; case ROAR_VS_ASK: if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) { _seterrre(); return -1; } return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE; break; } _seterr(ROAR_ERROR_INVAL); return -1; }
int roar_vs_sync (roar_vs_t * vss, int wait, int * error) { _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( wait != ROAR_VS_NOWAIT ) { _seterr(ROAR_ERROR_INVAL); return -1; } _initerr(); if ( roar_vio_sync(&(vss->vio)) == -1 ) { _seterrre(); return -1; } return 0; }
int roar_vs_role (roar_vs_t * vss, int role, int * error) { _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } _initerr(); if ( roar_stream_set_role(vss->con, &(vss->stream), role) == -1 ) { _seterrre(); return -1; } return 0; }
int roar_vs_meta (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) { struct roar_meta meta; size_t i; int type; int ret = 0; _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } meta.type = ROAR_META_TYPE_NONE; meta.key[0] = 0; meta.value = NULL; _initerr(); if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) { _seterrre(); ret = -1; } for (i = 0; i < len; i++) { type = roar_meta_inttype(kv[i].key); meta.type = type; meta.value = kv[i].value; if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) { _seterrre(); ret = -1; } } meta.type = ROAR_META_TYPE_NONE; meta.key[0] = 0; meta.value = NULL; if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) { _seterrre(); ret = -1; } return ret; }
ssize_t roar_vs_read (roar_vs_t * vss, void * buf, size_t len, int * error) { ssize_t ret; _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } _initerr(); ret = roar_vio_read(&(vss->vio), buf, len); if ( ret == -1 ) { _seterrre(); } else { vss->readc += ret; } return ret; }
int roar_vs_close(roar_vs_t * vss, int killit, int * error) { if ( killit != ROAR_VS_TRUE && killit != ROAR_VS_FALSE ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } _ckvss(-1); if ( vss->flags & FLAG_STREAM ) { if ( killit == ROAR_VS_TRUE ) { roar_kick(vss->con, ROAR_OT_STREAM, roar_stream_get_id(&(vss->stream))); } roar_vio_close(&(vss->vio)); } if ( vss->con == &(vss->con_store) ) { roar_disconnect(vss->con); } roar_mm_free(vss); return 0; }
static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) { struct roar_mixer_settings mixer; size_t i; register float s; int oldchannels; int handled; _ckvss(-1); if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( channels > ROAR_MAX_CHANNELS ) { _seterr(ROAR_ERROR_INVAL); return -1; } _initerr(); if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) { _seterrre(); return -1; } for (i = 0; i < channels; i++) { s = c[i] * 65535.0; if ( s > 66190.0 || s < -655.0 ) { _seterr(ROAR_ERROR_RANGE); return -1; } else if ( s > 65535.0 ) { s = 65535.0; } else if ( s < 0.0 ) { s = 0.0; } mixer.mixer[i] = s; } mixer.scale = 65535; if ( channels != oldchannels ) { handled = 0; switch (oldchannels) { case 1: if ( channels == 2 ) { mixer.mixer[0] = (mixer.mixer[0] + mixer.mixer[1]) / 2; handled = 1; } break; case 2: if ( channels == 1 ) { mixer.mixer[1] = mixer.mixer[0]; handled = 1; } break; case 4: if ( channels == 1 ) { mixer.mixer[1] = mixer.mixer[0]; mixer.mixer[2] = mixer.mixer[0]; mixer.mixer[3] = mixer.mixer[0]; handled = 1; } else if ( channels == 2 ) { mixer.mixer[2] = mixer.mixer[0]; mixer.mixer[3] = mixer.mixer[1]; handled = 1; } break; } if ( handled ) { channels = oldchannels; } else { _seterr(ROAR_ERROR_INVAL); return -1; } } if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels) == -1 ) { _seterrre(); return -1; } return 0; }
static int devopen(FILE * f, const char * name, int oflags, const char * mde) { struct fnarg fna = {0}; const char * t; const char * s=name; int len; int fnftlen; int rv, rsn; struct exsbuff exs; struct exsbuff * pexs; int exsl=sizeof(exs); int nofile = 0; /* assume file exists */ int zero = 0; /* For SFS plist */ static const char blanks[10] = " "; static const char noc[] = "NOCOMMIT"; static const int nocl = sizeof(noc) - 1; const char * mode = mde; enum intent intent; #if DEBUG __WERROR("Opening %s for mode %s", name, mode); #endif switch (name[0]) { case '/': s += strspn(s, "/"); t=strpbrk(s, "/:"); if (!t) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_onesl, "Leading slash, but no further slash or colon.", name); len = t - s; if ('/' == *t) /* Mode letter and maybe number */ { if (2 < len) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_modelong, "File mode longer than two characters.", name); fna.mode = toupper(0xff & s[0]); fna.moden = 2 == len ? s[1] : ' '; s = t + 1; break; } /* ':' File pool */ if (8 < len) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_fplong, "File pool name longer than 8 characters.", name); memcpy(fna.filepool, s, len); s = t; /* Fall through */ case '~': /* File space */ t = strchr(++s, '/'); if (!t) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_fpfsunterm, "File space name not terminated with forward slash (/).", name); len = t - s; if (len) { if (8<len) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_fslong, "File space name longer than 8 characters.", name); memcpy(fna.filespace, s, len); } for (;;) /* Look for directory levels */ { s += strspn(s, "/"); t = strchr(s, '/'); if (!t) break; if (fna.alen) fna.dir[fna.alen++] = '.'; len = t - s; if (sizeof(fna.dir) < fna.alen + len) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_fslong, "Directory path too long.", name); memcpy(fna.dir + fna.alen, s, len); fna.alen += len; s=t + 1; } break; case '.': return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_leaddot, "File name omitted.", name); default: fna.mode = (O_RDONLY & f->oflags) ? '*' : 'A'; } t = strchr(s, '.'); if (!t) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_noft, "File type omitted.", name); len = t - s; fnftlen = strlen(s); if (17 < fnftlen) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_fnftlong, "File name and type too long.", name); memcpy(fna.fid, s, fnftlen); fna.fid[len] = ' '; fna.fidlen = fnftlen; fna.fid[fna.fidlen++] = ' '; #define PSF(x...) fna.fidlen += sprintf(fna.fid + fna.fidlen, x) if (fna.filepool[0]) { PSF("%s:", fna.filepool); if (!fna.filespace[0]) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_fn_fsmissing, "File space not specified.", name); } if (fna.alen) PSF("%s.%s", fna.filespace, fna.dir); else PSF("%c", fna.mode); if (fna.moden) PSF(" %c", fna.moden); #if DEBUG __WERROR("%d >%s<", fna.fidlen, fna.fid); #endif #undef PDF /*********************************************************************/ /* Now look for the file. If user wants caseless, he will have to */ /* do the uppercasing. We in turn make no noise. */ /* */ /* Aw, c'm on. If it is read, look for uppercase. */ /*********************************************************************/ exs.exstype = 0; /* Assume not old */ rsn = 0; nofile = 0; tocsl(8, "DMSEXIST", &rv, &rsn, fna.fid, &fna.fidlen, &exs, &exsl, noc, &nocl); if (rv && 90220 == rsn && (O_RDONLY & oflags) && islower(0xff & fna.fid[0])) { int i; for (i = 0; fna.fidlen > i; i++) { fna.fid[i] = toupper(0xff & fna.fid[i]); } tocsl(8, "DMSEXIST", &rv, &rsn, fna.fid, &fna.fidlen, &exs, &exsl, noc, &nocl); } if (rv) { if (90220 == rsn) nofile = 1; else { char bfr[256]; sprintf(bfr, "DMSEXIST reason %d file '%.*s'", rsn, fna.fidlen, fna.fid); return _seterr(EINVAL, EINVAL, _einv_rsn_bad_dmsexist, "CMS error locating file", bfr); } } else { #define M(x, y) f->x = exs.exsf ## y M(recform, recf); M(lrecl, recl); M(numrecs, recs); M(numblks, blks); #undef M } /*********************************************************************/ /* Figure operation intent and set the keyword accordingly. */ /*********************************************************************/ if (nofile) { if (O_RDONLY & f->oflags) return ENOENT; intent = int_create; /* If it ain't there, surely we create */ } else { if (O_EXCL & f->oflags) return EEXISTS; if (O_RDONLY & f->oflags) intent = int_read; else if (O_TRUNC & f->oflags) intent = int_replace; else intent = int_update; } #define POP(x...) fna.optlen += sprintf(fna.opt + fna.optlen, x) POP("%s", sfsint[intent]); /* Intent */ #if DEBUG __WERROR("%d %s", fna.optlen, fna.opt); #endif /*********************************************************************/ /* Process remaining part of mode string. */ /* */ /* It may be a comma and lrecl=nnn, and SFS open options which */ /* should not include new/read/replace, as we construct that word */ /* from the standard type. */ /*********************************************************************/ s = mode; while (s && *s) { if (0==strncasecmp(s, "lrecl=", 6)) { int got=0; int lrecl; sscanf(s+6, "%d %n", &lrecl, &got); if (0==got) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_lrecl, "Record length missing.", s); if (nofile) f->lrecl = lrecl; else s += 6 + got; } else if (0==strncasecmp(s, "recfm=", 6)) { char recfm = toupper(0xff & s[6]); if ('F' != recfm && 'V' != recfm) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_recfm, "Record format not valid.", s); if (!nofile && recfm != f->recform) { char bfr[2] = {f->recform}; return _seterr(EINVAL, EINVAL, _einv_rsn_recfm_diff, "Record format not same as existing file.", bfr); } if (!(O_RDONLY & f->oflags)) POP(" %c", recfm); s += 7; } else return _seterr(EINVAL, EINVAL, _einv_rsn_bad_mode, "Unrecognised mode string.", s); if (*s && ',' != *s++) return _seterr(EINVAL, EINVAL, _einv_rsn_bad_mode_del, "Comma expected in mode string.", s); } /* Supply defaults if create */ if (int_create == intent) { if (!f->recform) { f->recform = 'V'; POP(" %c", f->recform); } if (!f->lrecl) { /* Setting the LRECL for V files is for the write function */ /* to know when to cut a record; SFS will ignore the record */ /* length? */ if ('F' == f->recform) f->lrecl = 80; else if (O_BINARY & f->oflags) f->lrecl = 255; } } if (sizeof(fna.opt) - fna.optlen <= len) return _seterr(EINVAL, EINVAL, _einv_rsn_long_opt, "Option string too long.", s); #if DEBUG __WERROR("fd %d mode '%s' options %d '%-*.*s' open flag %x", f->fd, mde, fna.optlen, fna.optlen, fna.optlen, fna.opt, f->oflags); #endif #undef POP /*********************************************************************/ /* And finally. */ /*********************************************************************/ tocsl(15, "DMSOPEN ", &rv, &rsn, fna.fid, &fna.fidlen, fna.opt, &fna.optlen, f->token, &zero, /* Work unit */ &zero, /* Wu error */ &zero, /* Wu error length */ &zero, /* User data */ &zero, /* User data length */ blanks, /* Create date */ blanks, /* Create time */ &f->lrecl /* Explicit record length */ ); switch (rv) { case 0: break; case 4: break; case 8: switch (rsn) { case 90310: __sayf("fd %d %s bad keyword in list '%s'", f->fd, name, fna.opt); break; default: goto error; } return EINVAL; default: error: __sayf("DMSOPEN fd %d rc=%d reason=%d.", f->fd, rv, rsn); return EINVAL; } if (!fna.mode) f->blksize = 0x1000; else { if (0) __sayf("FIXME " __FILE__ ".%d", __LINE__); } pexs = f->accwork = malloc(sizeof(struct exsbuff)); if (!f) return ENOMEM; *pexs = exs; return 0; }