diff options
-rw-r--r-- | sys/dev/sound/pcm/channel.c | 20 | ||||
-rw-r--r-- | sys/dev/sound/pcm/feeder.c | 61 | ||||
-rw-r--r-- | sys/dev/sound/pcm/feeder.h | 2 |
3 files changed, 64 insertions, 19 deletions
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index 4fc5f07..0c73dd0 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -997,7 +997,7 @@ chn_buildfeeder(struct pcm_channel *c) { struct feeder_class *fc; struct pcm_feederdesc desc; - u_int32_t tmp[2], type, flags; + u_int32_t tmp[2], type, flags, hwfmt; CHN_LOCKASSERT(c); while (chn_removefeeder(c) == 0); @@ -1072,14 +1072,22 @@ chn_buildfeeder(struct pcm_channel *c) } } - if (!fmtvalid(c->feeder->desc->out, chn_getcaps(c)->fmtlist)) { - if (chn_fmtchain(c, chn_getcaps(c)->fmtlist) == 0) { - DEB(printf("can't build fmtchain from %x\n", c->feeder->desc->out)); - return EINVAL; + if (fmtvalid(c->feeder->desc->out, chn_getcaps(c)->fmtlist)) { + hwfmt = c->feeder->desc->out; + } else { + if (c->direction == PCMDIR_REC) { + tmp[0] = c->format; + tmp[1] = NULL; + hwfmt = chn_fmtchain(c, tmp); + } else { + hwfmt = chn_fmtchain(c, chn_getcaps(c)->fmtlist); } - DEB(printf("built fmtchain from %x\n", c->feeder->desc->out)); } + if (hwfmt == 0) + return EINVAL; + + sndbuf_setfmt(c->bufhard, hwfmt); return 0; } diff --git a/sys/dev/sound/pcm/feeder.c b/sys/dev/sound/pcm/feeder.c index f361ada..5f5da6b 100644 --- a/sys/dev/sound/pcm/feeder.c +++ b/sys/dev/sound/pcm/feeder.c @@ -267,25 +267,60 @@ no: u_int32_t chn_fmtchain(struct pcm_channel *c, u_int32_t *to) { - struct pcm_feeder *try, *stop; - int max; + struct pcm_feeder *try, *del, *stop; + u_int32_t tmpfrom[2], best, *from; + int i, max, bestmax; + + KASSERT(c != NULL, ("c == NULL")); + KASSERT(c->feeder != NULL, ("c->feeder == NULL")); + KASSERT(to != NULL, ("to == NULL")); + KASSERT(to[0] != 0, ("to[0] == 0")); - /* we're broken for recording currently, reject attempts */ - if (c->direction == PCMDIR_REC) - return EINVAL; stop = c->feeder; - try = NULL; - max = 0; - while (try == NULL && max < 8) { - try = feeder_fmtchain(to, c->feeder, stop, max); - max++; + + if (c->direction == PCMDIR_REC && c->feeder->desc->type == FEEDER_ROOT) { + from = chn_getcaps(c)->fmtlist; + } else { + tmpfrom[0] = c->feeder->desc->out; + tmpfrom[1] = 0; + from = tmpfrom; } + + i = 0; + best = 0; + bestmax = 100; + while (from[i] != 0) { + c->feeder->desc->out = from[i]; + try = NULL; + max = 0; + while (try == NULL && max < 8) { + try = feeder_fmtchain(to, c->feeder, stop, max); + if (try == NULL) + max++; + } + if (try != NULL && max < bestmax) { + bestmax = max; + best = from[i]; + } + while (try != NULL && try != stop) { + del = try; + try = try->source; + feeder_destroy(del); + } + i++; + } + if (best == 0) + return 0; + + c->feeder->desc->out = best; + try = feeder_fmtchain(to, c->feeder, stop, bestmax); if (try == NULL) return 0; + c->feeder = try; c->align = 0; #ifdef FEEDER_DEBUG - printf("chain: "); + printf("\n\nchain: "); #endif while (try && (try != stop)) { #ifdef FEEDER_DEBUG @@ -293,6 +328,8 @@ chn_fmtchain(struct pcm_channel *c, u_int32_t *to) if (try->source) printf(" -> "); #endif + if (try->source) + try->source->parent = try; if (try->align > 0) c->align += try->align; else if (try->align < 0 && c->align < -try->align) @@ -302,7 +339,7 @@ chn_fmtchain(struct pcm_channel *c, u_int32_t *to) #ifdef FEEDER_DEBUG printf("%s [%d]\n", try->class->name, try->desc->idx); #endif - return c->feeder->desc->out; + return (c->direction == PCMDIR_REC)? best : c->feeder->desc->out; } /*****************************************************************************/ diff --git a/sys/dev/sound/pcm/feeder.h b/sys/dev/sound/pcm/feeder.h index 7ee6a63..f3374a1 100644 --- a/sys/dev/sound/pcm/feeder.h +++ b/sys/dev/sound/pcm/feeder.h @@ -46,7 +46,7 @@ struct pcm_feeder { struct pcm_feederdesc *desc; void *data; struct feeder_class *class; - struct pcm_feeder *source; + struct pcm_feeder *source, *parent; }; void feeder_register(void *p); |