mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
[ALSA] Support for non-standard rates in USB audio driver
There's at least one USB audio chipset out there which supports only one non-standard rate (ID 0e6a:0310 supports 46875Hz). There's a few other patches for this card which are unsatisfactory because they attempt to map this rate to 44.1k leading to sound distortion. The patch below uses SNDRV_PCM_RATE_KNOT to properly support the non-standard rates where they are available. Signed-off-by: Luke Ross <luke@lukeross.name> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
This commit is contained in:
parent
9f458e7fb5
commit
a79eee8d3d
1 changed files with 46 additions and 0 deletions
|
@ -123,6 +123,7 @@ struct audioformat {
|
||||||
unsigned int rate_min, rate_max; /* min/max rates */
|
unsigned int rate_min, rate_max; /* min/max rates */
|
||||||
unsigned int nr_rates; /* number of rate table entries */
|
unsigned int nr_rates; /* number of rate table entries */
|
||||||
unsigned int *rate_table; /* rate table */
|
unsigned int *rate_table; /* rate table */
|
||||||
|
unsigned int needs_knot; /* any unusual rates? */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct snd_usb_substream;
|
struct snd_usb_substream;
|
||||||
|
@ -1759,6 +1760,9 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
|
||||||
}
|
}
|
||||||
channels[f->format] |= (1 << f->channels);
|
channels[f->format] |= (1 << f->channels);
|
||||||
rates[f->format] |= f->rates;
|
rates[f->format] |= f->rates;
|
||||||
|
/* needs knot? */
|
||||||
|
if (f->needs_knot)
|
||||||
|
goto __out;
|
||||||
}
|
}
|
||||||
/* check whether channels and rates match for all formats */
|
/* check whether channels and rates match for all formats */
|
||||||
cmaster = rmaster = 0;
|
cmaster = rmaster = 0;
|
||||||
|
@ -1799,6 +1803,38 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device supports unusual bit rates, does the request meet these?
|
||||||
|
*/
|
||||||
|
static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
|
||||||
|
struct snd_usb_substream *subs)
|
||||||
|
{
|
||||||
|
struct list_head *p;
|
||||||
|
struct snd_pcm_hw_constraint_list constraints_rates;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
list_for_each(p, &subs->fmt_list) {
|
||||||
|
struct audioformat *fp;
|
||||||
|
fp = list_entry(p, struct audioformat, list);
|
||||||
|
|
||||||
|
if (!fp->needs_knot)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
constraints_rates.count = fp->nr_rates;
|
||||||
|
constraints_rates.list = fp->rate_table;
|
||||||
|
constraints_rates.mask = 0;
|
||||||
|
|
||||||
|
err = snd_pcm_hw_constraint_list(runtime, 0,
|
||||||
|
SNDRV_PCM_HW_PARAM_RATE,
|
||||||
|
&constraints_rates);
|
||||||
|
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set up the runtime hardware information.
|
* set up the runtime hardware information.
|
||||||
|
@ -1861,6 +1897,8 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
|
||||||
SNDRV_PCM_HW_PARAM_CHANNELS,
|
SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||||
-1)) < 0)
|
-1)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2406,6 +2444,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
|
||||||
unsigned char *fmt, int offset)
|
unsigned char *fmt, int offset)
|
||||||
{
|
{
|
||||||
int nr_rates = fmt[offset];
|
int nr_rates = fmt[offset];
|
||||||
|
int found;
|
||||||
if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
|
if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
|
||||||
snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
|
snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
|
||||||
chip->dev->devnum, fp->iface, fp->altsetting);
|
chip->dev->devnum, fp->iface, fp->altsetting);
|
||||||
|
@ -2428,6 +2467,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fp->needs_knot = 0;
|
||||||
fp->nr_rates = nr_rates;
|
fp->nr_rates = nr_rates;
|
||||||
fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
|
fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
|
||||||
for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
|
for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
|
||||||
|
@ -2436,13 +2476,19 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
|
||||||
fp->rate_min = rate;
|
fp->rate_min = rate;
|
||||||
else if (rate > fp->rate_max)
|
else if (rate > fp->rate_max)
|
||||||
fp->rate_max = rate;
|
fp->rate_max = rate;
|
||||||
|
found = 0;
|
||||||
for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) {
|
for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) {
|
||||||
if (rate == conv_rates[c]) {
|
if (rate == conv_rates[c]) {
|
||||||
|
found = 1;
|
||||||
fp->rates |= (1 << c);
|
fp->rates |= (1 << c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!found)
|
||||||
|
fp->needs_knot = 1;
|
||||||
}
|
}
|
||||||
|
if (fp->needs_knot)
|
||||||
|
fp->rates |= SNDRV_PCM_RATE_KNOT;
|
||||||
} else {
|
} else {
|
||||||
/* continuous rates */
|
/* continuous rates */
|
||||||
fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
|
fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
|
||||||
|
|
Loading…
Reference in a new issue