/* * There is a lot of scrap here. It's not very well organized junk to * provide minimal "emulation" of the kobj code for feeder objects. */ #ifndef _FEEDER_COMPAT_H_ #define _FEEDER_COMPAT_H_ #define KASSERT(x, y) assert(x) #define CHN_LOCKASSERT(c) struct feeder_class; struct pcm_channel; struct pcm_feeder; /* Types for function pointers */ typedef int feeder_init_t(struct pcm_feeder *f); typedef int feeder_free_t(struct pcm_feeder *f); typedef int feeder_set_t(struct pcm_feeder *f, int what, int value); typedef int feeder_get_t(struct pcm_feeder *f, int what); typedef int feeder_feed_t(struct pcm_feeder *f, struct pcm_channel* c, uint8_t *feed_buffer, uint32_t feed_bytes, void *source); typedef struct { const char* name; void *method; } kobj_method_t; #define KOBJMETHOD(x, y) { #x, y } #define KOBJMETHOD_END { NULL, NULL } #if 0 #define KOBJMETHOD(NAME, FUNC) \ { \ &NAME##_desc, \ (kobjop_t) ((FUNC != (NAME##_t *)NULL) ? FUNC : NULL) \ } #endif struct pcmchan_matrix { int id; uint32_t channels, ext; struct { int type; uint32_t members; } map[SND_CHN_T_MAX + 1]; uint32_t mask; int8_t offset[SND_CHN_T_MAX]; }; extern int feeder_volume_apply_matrix(struct pcm_feeder *, struct pcmchan_matrix *); /* feeder_matrix */ extern int feeder_matrix_default_id(uint32_t); extern struct pcmchan_matrix *feeder_matrix_default_channel_map(uint32_t); uint32_t feeder_matrix_default_format(uint32_t); extern int feeder_matrix_format_id(uint32_t); extern struct pcmchan_matrix *feeder_matrix_format_map(uint32_t); extern struct pcmchan_matrix *feeder_matrix_id_map(int); extern int feeder_matrix_setup(struct pcm_feeder *, struct pcmchan_matrix *, struct pcmchan_matrix *); extern int feeder_matrix_compare(struct pcmchan_matrix *, struct pcmchan_matrix *); extern int feeder_matrix_oss_get_channel_order(struct pcmchan_matrix *, unsigned long long *); extern int feeder_matrix_oss_set_channel_order(struct pcmchan_matrix *, unsigned long long *); struct pcm_feederdesc { uint32_t type; uint32_t in; uint32_t out; uint32_t flags; int idx; }; enum { FEEDER_ROOT, FEEDER_RATE, FEEDER_FORMAT, FEEDER_MATRIX, FEEDER_VOLUME, FEEDER_EQ, FEEDER_STDIO, FEEDER_LAST }; /* feeder_eq */ enum { FEEDEQ_CHANNELS, FEEDEQ_RATE, FEEDEQ_TREBLE, FEEDEQ_BASS, FEEDEQ_PREAMP, FEEDEQ_STATE, FEEDEQ_DISABLE, FEEDEQ_ENABLE, FEEDEQ_BYPASS, FEEDEQ_UNKNOWN }; int feeder_eq_validrate(uint32_t); /* feeder_format */ enum { FEEDFORMAT_CHANNELS }; /* feeder_volume */ enum { FEEDVOLUME_CLASS, FEEDVOLUME_CHANNELS, FEEDVOLUME_STATE, FEEDVOLUME_ENABLE, FEEDVOLUME_BYPASS }; /* feeder_matrix */ /*enum { FEEDMATRIX_TYPE, FEEDMATRIX_RESET, FEEDMATRIX_CHANNELS_IN, FEEDMATRIX_CHANNELS_OUT, FEEDMATRIX_SET_MAP }; enum { FEEDMATRIX_TYPE_NONE, FEEDMATRIX_TYPE_AUTO, FEEDMATRIX_TYPE_2X1, FEEDMATRIX_TYPE_1X2, FEEDMATRIX_TYPE_2X2 }; #define FEEDMATRIX_TYPE_STEREO_TO_MONO FEEDMATRIX_TYPE_2X1 #define FEEDMATRIX_TYPE_MONO_TO_STEREO FEEDMATRIX_TYPE_1X2 #define FEEDMATRIX_TYPE_SWAP_STEREO FEEDMATRIX_TYPE_2X2 #define FEEDMATRIX_MAP(x, y) ((((x) & 0x3f) << 6) | ((y) & 0x3f)) #define FEEDMATRIX_MAP_SRC(x) ((x) & 0x3f) #define FEEDMATRIX_MAP_DST(x) (((x) >> 6) & 0x3f)*/ /* feeder_rate */ enum { FEEDRATE_SRC, FEEDRATE_DST, FEEDRATE_QUALITY, FEEDRATE_CHANNELS }; #define FEEDRATE_RATEMIN 1 #define FEEDRATE_RATEMAX 2016000 /* 48000 * 42 */ #define FEEDRATE_MIN 1 #define FEEDRATE_MAX 0x7fffff /* sign 24bit ~ 8ghz ! */ #define FEEDRATE_ROUNDHZ 0 #define FEEDRATE_ROUNDHZ_MIN 0 #define FEEDRATE_ROUNDHZ_MAX 500 struct pcm_feeder { void *data; struct pcm_feeder *source; struct pcm_feeder *parent; struct pcm_feederdesc *desc; struct feeder_class *class; feeder_init_t *init; feeder_free_t *free; feeder_set_t *set; feeder_get_t *get; feeder_feed_t *feed; }; struct feeder_class { const char* name; kobj_method_t* methods; size_t size; int align; struct pcm_feederdesc *desc; void *data; }; #define FEEDER_DECLARE(feeder, pdata) \ static struct feeder_class feeder##_class = { \ .name = #feeder, \ .methods = feeder##_methods, \ .size = sizeof(struct pcm_feeder), \ .desc = feeder##_desc, \ .data = pdata \ } static void* class_get_method(struct feeder_class *cls, const char* name) { kobj_method_t * m = cls->methods; while (m->name) { if (strcmp(m->name, name) == 0) return m->method; m++; } return NULL; } static struct pcm_feeder* feeder_create(struct feeder_class *cls, struct pcm_feederdesc *desc) { struct pcm_feeder *f = (struct pcm_feeder *)malloc(sizeof(*f)); f->source = NULL; f->parent = NULL; f->data = cls->data; f->class = cls; f->init = (feeder_init_t *)class_get_method(cls, "feeder_init"); f->free = (feeder_free_t *)class_get_method(cls, "feeder_free"); f->set = (feeder_set_t *)class_get_method(cls, "feeder_set"); f->get = (feeder_get_t *)class_get_method(cls, "feeder_get"); f->feed = (feeder_feed_t *)class_get_method(cls, "feeder_feed"); f->desc = (struct pcm_feederdesc *)malloc(sizeof(*(f->desc))); if (desc != NULL) *(f->desc) = *desc; else f->desc->in = f->desc->out = 0xffffffffU; if (f->init && f->init(f)) { free(f); return NULL; } return f; } static void feeder_destroy(struct pcm_feeder *f) { if (f->free) f->free(f); free(f->desc); free(f); } static void feeder_flush(struct pcm_feeder *f) { struct pcm_feeder *source; while (f != NULL && f->parent != NULL) f = f->parent; while (f != NULL) { source = f->source; feeder_destroy(f); f = source; } } static void feeder_dump(struct pcm_feeder *f) { int i; while (f != NULL && f->source != NULL) f = f->source; i = 0; while (f != NULL) { i++; fprintf(stderr, "%3d. %-2s%13s (0x%08x -> 0x%08x) %s\n", i, (i == 1) ? "*" : " ", f->class->name, f->desc->in, f->desc->out, (f->parent != NULL) ? "+->" : "*"); f = f->parent; } } #define FEEDER_CREATE(feeder, desc) feeder_create(& feeder ## _class, desc) #define FEEDER_DESTROY(feeder) feeder_destroy(feeder) #define FEEDER_FLUSH(feeder) feeder_flush(feeder) #define FEEDER_DUMP(feeder) feeder_dump(feeder) #define FEEDER_FEED(f, c, v, cnt, s) (f)->feed(f, c, v, cnt, s) int FEEDER_SET(struct pcm_feeder *, int, int); int FEEDER_GET(struct pcm_feeder *, int); int FEEDER_SET(struct pcm_feeder *f, int what, int value) { if (f->set) return f->set(f, what, value); return -1; } int FEEDER_GET(struct pcm_feeder *f, int what) { if (f->get) return f->get(f, what); return -1; } static struct pcm_feeder* FEEDER_JOIN(struct pcm_feeder *src, struct pcm_feeder *dst, const char *fc) { if (dst->desc->in != src->desc->out) errx(EX_DATAERR, "%s(): dst->desc->in=0x%08x != src->desc->out=0x%08x", fc, dst->desc->in, src->desc->out); if (dst->desc->out == 0xffffffff) dst->desc->out = dst->desc->in; dst->source = src; src->parent = dst; return dst; } struct pcm_channel { struct pcm_feeder *feeder; uint32_t feederflags; uint32_t bufsize; uint8_t *buffer; int direction; int volume[SND_VOL_C_MAX][SND_CHN_T_VOL_MAX]; FILE *in_fp, *out_fp; }; #define PCMDIR_PLAY 1 #define PCMDIR_REC -1 static int chn_setvolume_matrix(struct pcm_channel *c, int vc, int vt, int val) { int i; /*KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX && (vc == SND_VOL_C_MASTER || (vc & 1)) && (vt == SND_CHN_T_VOL_0DB || (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)) && (vt != SND_CHN_T_VOL_0DB || (val >= SND_VOL_0DB_MIN && val <= SND_VOL_0DB_MAX)), ("%s(): invalid volume matrix c=%p vc=%d vt=%d val=%d", __func__, c, vc, vt, val));*/ CHN_LOCKASSERT(c); if (val < 0) val = 0; if (val > 100) val = 100; c->volume[vc][vt] = val; /* * Do relative calculation here and store it into class + 1 * to ease the job of feeder_volume. */ if (vc == SND_VOL_C_MASTER) { for (vc = SND_VOL_C_BEGIN; vc <= SND_VOL_C_END; vc += SND_VOL_C_STEP) c->volume[SND_VOL_C_VAL(vc)][vt] = SND_VOL_CALC_VAL(c->volume, vc, vt); } else if (vc & 1) { if (vt == SND_CHN_T_VOL_0DB) { for (i = 0; i != SND_CHN_T_MAX; i++) c->volume[SND_VOL_C_VAL(vc)][i] = SND_VOL_CALC_VAL(c->volume, vc, i); } else c->volume[SND_VOL_C_VAL(vc)][vt] = SND_VOL_CALC_VAL(c->volume, vc, vt); } return (val); } #define CHN_SETVOLUME(...) chn_setvolume_matrix(__VA_ARGS__) #define CHN_GETVOLUME(x, y, z) ((x)->volume[y][z]) static int chn_init(struct pcm_channel *c, int direction, uint32_t bufsize) { int i; bzero(c, sizeof(*c)); c->volume[SND_VOL_C_MASTER][SND_CHN_T_VOL_0DB] = SND_VOL_0DB_MASTER; c->volume[SND_VOL_C_PCM][SND_CHN_T_VOL_0DB] = SND_VOL_0DB_PCM; for (i = 0; i != SND_CHN_T_MAX; i++) { c->volume[SND_VOL_C_MASTER][i] = SND_VOL_0DB_MASTER; CHN_SETVOLUME(c, SND_VOL_C_PCM, i, c->volume[SND_VOL_C_PCM][SND_CHN_T_VOL_0DB]); } c->bufsize = bufsize; c->buffer = malloc(bufsize); c->direction = direction; c->in_fp = stdin; c->out_fp = stdout; if (c->buffer == NULL) return (ENOMEM); return (0); } static void chn_destroy(struct pcm_channel *c) { if (c == NULL) return; if (c->feeder != NULL) FEEDER_FLUSH(c->feeder); if (c->buffer != NULL) free(c->buffer); if (c->in_fp != stdin) fclose(c->in_fp); if (c->out_fp != stdout) fclose(c->out_fp); free(c); } static struct pcm_channel * chn_create(int direction, uint32_t bufsize) { struct pcm_channel *c; if (!(direction == PCMDIR_PLAY || direction == PCMDIR_REC)) errx(EINVAL, "invalid direction: 0x%08x", direction); c = malloc(sizeof(*c)); if (c != NULL && chn_init(c, direction, bufsize) != 0) { chn_destroy(c); c = NULL; } return (c); } #define chn_addfeeder(x, y) chn_addfeeder_int(x, y, __func__) static int chn_addfeeder_int(struct pcm_channel *c, struct pcm_feeder *f, const char *fc) { if (c == NULL) return (EINVAL); c->feeder = (c->feeder != NULL) ? FEEDER_JOIN(c->feeder, f, fc) : f; return (0); } #if 0 static struct pcm_feeder * chn_findfeeder(struct pcm_channel *c, uint32_t type) { struct pcm_feeder *f; f = c->feeder; while (f != NULL && f->desc != NULL) { if (f->desc->type == type) return f; f = f->source; } return NULL; } #endif #define chn_feed(c) \ FEEDER_FEED((c)->feeder, c, (c)->buffer, (c)->bufsize, NULL) #ifndef M_NOWAIT #define M_NOWAIT 0 #endif #ifndef M_ZERO #define M_ZERO 1 #endif #ifndef DSP_DEFAULT_SPEED #define DSP_DEFAULT_SPEED 8000 #endif #define MALLOC_DEFINE(x, y, z) static const int x = 0; #define malloc(x, y, z) calloc(1, x) #define free(x, y) free(x) static __inline u_int min(u_int a, u_int b) { return ((a < b) ? a : b); } static __inline u_int max(u_int a, u_int b) { return ((a < b) ? b : a); } static __inline int32_t sndbuf_zerodata(uint32_t fmt) { return ((fmt & AFMT_SIGNED) ? 0x00 : 0x80); } /* * 14bit format scoring * -------------------- * * 13 12 11 10 9 8 2 1 0 offset * +---+---+---+---+---+---+-------------+---+---+ * | X | X | X | X | X | X | X X X X X X | X | X | * +---+---+---+---+---+---+-------------+---+---+ * | | | | | | | | | * | | | | | | | | +--> signed? * | | | | | | | | * | | | | | | | +------> bigendian? * | | | | | | | * | | | | | | +---------------> total channels * | | | | | | * | | | | | +------------------------> AFMT_A_LAW * | | | | | * | | | | +----------------------------> AFMT_MU_LAW * | | | | * | | | +--------------------------------> AFMT_8BIT * | | | * | | +------------------------------------> AFMT_16BIT * | | * | +----------------------------------------> AFMT_24BIT * | * +--------------------------------------------> AFMT_32BIT */ #define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1)) #define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2)) #define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc)) #define score_chgt(s1, s2) (((s1) & 0xfc) > ((s2) & 0xfc)) #define score_chlt(s1, s2) (((s1) & 0xfc) < ((s2) & 0xfc)) #define score_val(s1) ((s1) & 0x3f00) #define score_cse(s1) ((s1) & 0x7f) static int fmtvalid(uint32_t fmt, uint32_t *fmtlist) { int i; for (i = 0; fmtlist[i]; i++) if (fmt == fmtlist[i]) return 1; return 0; } static uint32_t chn_fmtscore(uint32_t fmt) { uint32_t ret; ret = 0; if (fmt & AFMT_SIGNED) ret |= 1 << 0; if (fmt & AFMT_BIGENDIAN) ret |= 1 << 1; /*if (fmt & AFMT_STEREO) ret |= (2 & 0x3f) << 2; else ret |= (1 & 0x3f) << 2;*/ ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2; if (fmt & AFMT_A_LAW) ret |= 1 << 8; else if (fmt & AFMT_MU_LAW) ret |= 1 << 9; else if (fmt & AFMT_8BIT) ret |= 1 << 10; else if (fmt & AFMT_16BIT) ret |= 1 << 11; else if (fmt & AFMT_24BIT) ret |= 1 << 12; else if (fmt & AFMT_32BIT) ret |= 1 << 13; return ret; } static uint32_t chn_fmtbestfunc(uint32_t fmt, uint32_t *fmts, int cheq) { uint32_t best, score, score2, oldscore; int i; if (fmt == 0 || fmts == NULL || fmts[0] == 0) return 0; if (fmtvalid(fmt, fmts)) return fmt; best = 0; score = chn_fmtscore(fmt); oldscore = 0; for (i = 0; fmts[i] != 0; i++) { score2 = chn_fmtscore(fmts[i]); if (cheq && !score_cheq(score, score2) && (score_chlt(score2, score) || (oldscore != 0 && score_chgt(score2, oldscore)))) continue; if (oldscore == 0 || (score_val(score2) == score_val(score)) || (score_val(score2) == score_val(oldscore)) || (score_val(score2) > score_val(oldscore) && score_val(score2) < score_val(score)) || (score_val(score2) < score_val(oldscore) && score_val(score2) > score_val(score)) || (score_val(oldscore) < score_val(score) && score_val(score2) > score_val(oldscore))) { if (score_val(oldscore) != score_val(score2) || score_cse(score) == score_cse(score2) || ((score_cse(oldscore) != score_cse(score) && !score_endianeq(score, oldscore) && (score_endianeq(score, score2) || (!score_signeq(score, oldscore) && score_signeq(score, score2)))))) { best = fmts[i]; oldscore = score2; } } } return best; } static uint32_t chn_fmtbestbit(uint32_t fmt, uint32_t *fmts) { return chn_fmtbestfunc(fmt, fmts, 0); } static uint32_t chn_fmtbestchannel(uint32_t fmt, uint32_t *fmts) { return chn_fmtbestfunc(fmt, fmts, 1); } static uint32_t chn_fmtbest(uint32_t fmt, uint32_t *fmts) { uint32_t best1, best2; uint32_t score, score1, score2; if (fmtvalid(fmt, fmts)) return fmt; best1 = chn_fmtbestchannel(fmt, fmts); best2 = chn_fmtbestbit(fmt, fmts); if (best1 != 0 && best2 != 0 && best1 != best2) { /*if (fmt & AFMT_STEREO)*/ if (AFMT_CHANNEL(fmt) > 1) return best1; else { score = score_val(chn_fmtscore(fmt)); score1 = score_val(chn_fmtscore(best1)); score2 = score_val(chn_fmtscore(best2)); if (score1 == score2 || score1 == score) return best1; else if (score2 == score) return best2; else if (score1 > score2) return best1; return best2; } } else if (best2 == 0) return best1; else return best2; } #endif /* !_FEEDER_COMPAT_H_ */