pcm: rate: Improve the support multiple formats

This patch extends the PCM rate plugin for allowing its converter
plugin to deal with multiple formats.  Currently, the converter plugin
is allowed to take different formats only when convert callback is
defined.  And for this way (so far only the standard linear rate
plugin does), all linear formats have to be handled, and it's
cumbersome.

OTOH, most other rate plugins are implemented with convert_s16
callback, which accepts only S16 format.  This is often not ideal
because many converter engines can handle 32bit formats.  Also, the
target format is often 32bit format, hence this would require
additional conversion even if the converter engine can output 32bit
natively.

In this patch, for addressing the problems above, the rate plugin API
is extended in the following way:

- The new get_supported_formats callback is added; this stores the bit
  masks of the supported input and output formats, as well as the
  behavior flags.  Currently only linear formats are allowed.
- When the plugin accepts only the interleaved stream, set
  SND_PCM_RATE_FLAG_INTERLEAVED flag bit.  Otherwise the code has to
  handle snd_pcm_channel_area at each call.
- When both input and output formats have to be identical, pass
  SND_PCM_RATE_FLAG_SYNC_FORMATS flag bit.
- When the converter wants to process different formats, use convert
  callback instead of convert_s16.  You can put both in the ops for
  compatibility, too.
  The input and output formats are found in the info argument of init
  callback.
- Now the PCM rate plugin core will skip the temporary buffer
  allocation and conversions for pre- and post-process if not needed
  (i.e. matching with the requested input or output format).

The rate plugin API version is bumped to 0x010003.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2021-06-17 10:03:17 +02:00
parent 5089358aa9
commit 119d9c1678
2 changed files with 250 additions and 142 deletions

View file

@ -38,7 +38,7 @@ extern "C" {
/**
* Protocol version
*/
#define SND_PCM_RATE_PLUGIN_VERSION 0x010002
#define SND_PCM_RATE_PLUGIN_VERSION 0x010003
/** hw_params information for a single side */
typedef struct snd_pcm_rate_side_info {
@ -55,6 +55,11 @@ typedef struct snd_pcm_rate_info {
unsigned int channels;
} snd_pcm_rate_info_t;
enum {
SND_PCM_RATE_FLAG_INTERLEAVED = (1U << 0), /** only interleaved format */
SND_PCM_RATE_FLAG_SYNC_FORMATS = (1U << 1), /** both input and output formats have to be identical */
};
/** Callback table of rate-converter */
typedef struct snd_pcm_rate_ops {
/**
@ -114,6 +119,13 @@ typedef struct snd_pcm_rate_ops {
* new ops since version 0x010002
*/
void (*dump)(void *obj, snd_output_t *out);
/**
* get the supported input and output formats (optional);
* new ops since version 0x010003
*/
int (*get_supported_formats)(void *obj, uint64_t *in_formats,
uint64_t *out_formats,
unsigned int *flags);
} snd_pcm_rate_ops_t;
/** open function type */
@ -147,6 +159,28 @@ typedef struct snd_pcm_rate_old_ops {
snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames);
snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames);
} snd_pcm_rate_old_ops_t;
/* old rate_ops for protocol version 0x010002 */
typedef struct snd_pcm_rate_v2_ops {
void (*close)(void *obj);
int (*init)(void *obj, snd_pcm_rate_info_t *info);
void (*free)(void *obj);
void (*reset)(void *obj);
int (*adjust_pitch)(void *obj, snd_pcm_rate_info_t *info);
void (*convert)(void *obj,
const snd_pcm_channel_area_t *dst_areas,
snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
const snd_pcm_channel_area_t *src_areas,
snd_pcm_uframes_t src_offset, unsigned int src_frames);
void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames,
const int16_t *src, unsigned int src_frames);
snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames);
snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames);
unsigned int version;
int (*get_supported_rates)(void *obj, unsigned int *rate_min,
unsigned int *rate_max);
void (*dump)(void *obj, snd_output_t *out);
} snd_pcm_rate_v2_ops_t;
#endif
#ifdef __cplusplus