On 04.05.19 20:54, Alexander E. Patrakov wrote:
сб, 4 мая 2019 г. в 20:25, Georg Chini <georg@xxxxxxxx>:
On 04.05.19 16:42, Alexander E. Patrakov wrote:
сб, 4 мая 2019 г. в 16:17, Georg Chini <georg@xxxxxxxx>:
Here is the new version of the header file, based on your feedback.
The main changes are:
- The create_filter() function now receives the channel maps for input
and output.
- The create_filter() function receives a kill_filter() function and a
module pointer
which makes it possible for the filter to initiate unloading of the
module if it
detects that it is no longer applicable.
- An output_changed() function was added which communicates current sink
and port name to the filter, so that it can detect if the output has
changed.
Also I did a bit of cleanup and added a few more comments. Hope it looks
better now.
It definitely looks better.
I am still confused about disable_rewind and max_latency. Let's
suppose that someone wants to implement a rewindable filter. In this
case, they need to keep history, because PulseAudio can ask the filter
to rewind some samples. And, as it is not allowed to say "no", they
must keep enough history to satisfy any possible rewind request. But
some upper bound must exist. Do I understand correctly that
max_latency serves as such upper bound?
Regarding the non-rewindable filters, we do need to limit the latency,
but I believe it is wrong for each individual filter to specify its
own value for such limit. It should be a global policy (the same value
for all non-rewindable sinks), and I don't see any reason for the
filter to be able to influence it.
Therefore, I believe these two fields can be replaced by one,
max_rewind, which is the size of history, in samples, that the filter
is willing to keep. Zero means a non-rewindable filter.
That sounds like a good suggestion. I would however think
that it is better if 0 means that the filter will rewind as far as
PA wants it to. There may be filters that are stateless (like the
trivial amplifier example). We could use -1 to disable rewinding.
OK.
That would also mean to limit the latency to whatever the filter
can rewind, correct? I would use the maximum of max_rewind
and the default latency for non-rewindable filters as the
max_latency value then, because I don't think it makes sense
to set the maximum latency even smaller than for non-rewindable
filters.
Makes sense.
What do you think is reasonable for non-rewindable filters?
50 ms?
There were different opinions on that matter. 50 ms is indeed in a
range that I would agree to.
Just finished the next version. Does this look OK to you now?
/***
This file is part of PulseAudio.
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
***/
/* Channel positions copied from pulseaudio channelmap.h */
enum channel_position {
CHANNEL_POSITION_INVALID = -1,
CHANNEL_POSITION_MONO = 0,
CHANNEL_POSITION_FRONT_LEFT, /**< Apple, Dolby call this 'Left' */
CHANNEL_POSITION_FRONT_RIGHT, /**< Apple, Dolby call this 'Right' */
CHANNEL_POSITION_FRONT_CENTER, /**< Apple, Dolby call this 'Center' */
CHANNEL_POSITION_LEFT = CHANNEL_POSITION_FRONT_LEFT,
CHANNEL_POSITION_RIGHT = CHANNEL_POSITION_FRONT_RIGHT,
CHANNEL_POSITION_CENTER = CHANNEL_POSITION_FRONT_CENTER,
CHANNEL_POSITION_REAR_CENTER, /**< Microsoft calls this 'Back Center', Apple calls this 'Center Surround', Dolby calls this 'Surround Rear Center' */
CHANNEL_POSITION_REAR_LEFT, /**< Microsoft calls this 'Back Left', Apple calls this 'Left Surround' (!), Dolby calls this 'Surround Rear Left' */
CHANNEL_POSITION_REAR_RIGHT, /**< Microsoft calls this 'Back Right', Apple calls this 'Right Surround' (!), Dolby calls this 'Surround Rear Right' */
CHANNEL_POSITION_LFE, /**< Microsoft calls this 'Low Frequency', Apple calls this 'LFEScreen' */
CHANNEL_POSITION_SUBWOOFER = CHANNEL_POSITION_LFE,
CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, /**< Apple, Dolby call this 'Left Center' */
CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, /**< Apple, Dolby call this 'Right Center */
CHANNEL_POSITION_SIDE_LEFT, /**< Apple calls this 'Left Surround Direct', Dolby calls this 'Surround Left' (!) */
CHANNEL_POSITION_SIDE_RIGHT, /**< Apple calls this 'Right Surround Direct', Dolby calls this 'Surround Right' (!) */
CHANNEL_POSITION_AUX0,
CHANNEL_POSITION_AUX1,
CHANNEL_POSITION_AUX2,
CHANNEL_POSITION_AUX3,
CHANNEL_POSITION_AUX4,
CHANNEL_POSITION_AUX5,
CHANNEL_POSITION_AUX6,
CHANNEL_POSITION_AUX7,
CHANNEL_POSITION_AUX8,
CHANNEL_POSITION_AUX9,
CHANNEL_POSITION_AUX10,
CHANNEL_POSITION_AUX11,
CHANNEL_POSITION_AUX12,
CHANNEL_POSITION_AUX13,
CHANNEL_POSITION_AUX14,
CHANNEL_POSITION_AUX15,
CHANNEL_POSITION_AUX16,
CHANNEL_POSITION_AUX17,
CHANNEL_POSITION_AUX18,
CHANNEL_POSITION_AUX19,
CHANNEL_POSITION_AUX20,
CHANNEL_POSITION_AUX21,
CHANNEL_POSITION_AUX22,
CHANNEL_POSITION_AUX23,
CHANNEL_POSITION_AUX24,
CHANNEL_POSITION_AUX25,
CHANNEL_POSITION_AUX26,
CHANNEL_POSITION_AUX27,
CHANNEL_POSITION_AUX28,
CHANNEL_POSITION_AUX29,
CHANNEL_POSITION_AUX30,
CHANNEL_POSITION_AUX31,
CHANNEL_POSITION_TOP_CENTER, /**< Apple calls this 'Top Center Surround' */
CHANNEL_POSITION_TOP_FRONT_LEFT, /**< Apple calls this 'Vertical Height Left' */
CHANNEL_POSITION_TOP_FRONT_RIGHT, /**< Apple calls this 'Vertical Height Right' */
CHANNEL_POSITION_TOP_FRONT_CENTER, /**< Apple calls this 'Vertical Height Center' */
CHANNEL_POSITION_TOP_REAR_LEFT, /**< Microsoft and Apple call this 'Top Back Left' */
CHANNEL_POSITION_TOP_REAR_RIGHT, /**< Microsoft and Apple call this 'Top Back Right' */
CHANNEL_POSITION_TOP_REAR_CENTER, /**< Microsoft and Apple call this 'Top Back Center' */
CHANNEL_POSITION_MAX
};
/* Error codes copied from pulseaudio def.h */
enum {
OK = 0, /**< No error */
ERR_ACCESS, /**< Access failure */
ERR_COMMAND, /**< Unknown command */
ERR_INVALID, /**< Invalid argument */
ERR_EXIST, /**< Entity exists */
ERR_NOENTITY, /**< No such entity */
ERR_CONNECTIONREFUSED, /**< Connection refused */
ERR_PROTOCOL, /**< Protocol error */
ERR_TIMEOUT, /**< Timeout */
ERR_AUTHKEY, /**< No authentication key */
ERR_INTERNAL, /**< Internal error */
ERR_CONNECTIONTERMINATED, /**< Connection terminated */
ERR_KILLED, /**< Entity killed */
ERR_INVALIDSERVER, /**< Invalid server */
ERR_MODINITFAILED, /**< Module initialization failed */
ERR_BADSTATE, /**< Bad state */
ERR_NODATA, /**< No data */
ERR_VERSION, /**< Incompatible protocol version */
ERR_TOOLARGE, /**< Data too large */
ERR_NOTSUPPORTED, /**< Operation not supported \since 0.9.5 */
ERR_UNKNOWN, /**< The error code was unknown to the client */
ERR_NOEXTENSION, /**< Extension does not exist. \since 0.9.12 */
ERR_OBSOLETE, /**< Obsolete functionality. \since 0.9.15 */
ERR_NOTIMPLEMENTED, /**< Missing implementation. \since 0.9.15 */
ERR_FORKED, /**< The caller forked without calling execve() and tried to reuse the context. \since 0.9.15 */
ERR_IO, /**< An IO error happened. \since 0.9.16 */
ERR_BUSY, /**< Device or resource busy. \since 0.9.17 */
ERR_MAX /**< Not really an error but the first invalid error code */
};
/* Function called when the filter detects a condition to unload the filter. */
typedef void (*Kill_Filter_Function)(void *module);
/* Filter plugin structure */
typedef struct filter_plugin {
const char *name; /* Name of the filter. Used to identify the filter. */
const char *desc_head; /* Leading part of description string used for the
* sink and sink input description in PA. */
const char *filter_type; /* Name for the type of filter, used as suffix for
* the sink name if the name is derived from the
* master sink. */
unsigned input_channels; /* Number of audio input channels, 0 if variable */
unsigned output_channels; /* Number of audio output channels, 0 if variable */
size_t max_chunk_size; /* Maximum chunk size in bytes that the filter will
* accept, 0 for default */
size_t fixed_block_size; /* Block size in frames for fixed block size filters,
* 0 if block size is variable */
int max_rewind; /* Maximum number of frames that the sink can rewind.
* 0 means use value from master sink, -1 disables
* rewinding. Unless the filter implements rewinding
* the value should be set to -1. */
/* Functions defined by the filter */
/* Initializes a new filter instance and returns a handle to it. Passes the number of
* input and output channels, the corresponding channel positions and the sample rate
* to the filter. kill_filter can be called by the filter if it detects a condition
* that makes it necessary to remove the filter. kill_filter must be called with
* the module pointer as argument. */
void *(*create_filter)(unsigned input_channels, int *input_map,
unsigned output_channels, int *output_map,
Kill_Filter_Function kill_filter, void *module, unsigned sample_rate);
/* Deletes filter instance. */
void (*delete_filter)(void *filter_handle);
/* Activates filter. Returns 0 on success and a negative errror code on failure.
* May be NULL. */
int (*activate_filter)(void *filter_handle);
/* Deactivates filter. May be NULL. */
void (*deactivate_filter)(void *filter_handle);
/* Callback to process a chunk of data by the filter. May be NULL */
void (*process_chunk)(float *src, float *dst, unsigned count, void *filter_handle);
/* Callback to retrieve additional latency caused by the filter. May be NULL */
uint64_t (*get_extra_latency)(void *filter_handle);
/* Callback to rewind the filter when pulseaudio requests it. May be NULL.
* Amount indicates the number of bytes to roll back. The filter state must
* not be reset, but seamlessly restored to the specified point in the past
* (which is the filter's responsibility to keep).
* If it is not possible to do so, the best option is to disable rewinding
* completely and limit the latency. */
void (*rewind_filter)(size_t amount, void *filter_handle);
/* If not NULL, this function is called whenever the active port of a sink or
* the sink itself changes. It is used to communicate the currently active port
* and sink to the filter. */
void (*output_changed)(const char *sink_name, const char *port_name, void *filter_handle);
/* If set, this function is called in thread context when an update of the
* filter parameters is requested, may be NULL. The function must replace
* the currently used parameter structure by the new structure and return
* a pointer to the old structure so that it can be freed in the main thread
* using parameter_free(). If the old structure can be re-used, the function
* may return NULL. */
void *(*update_filter_parameters)(void *parameters, void *filter_handle);
/* Frees a parameter structure. May only be NULL, if update_filter_parameters()
* is also NULL or if update_filter_parameters() always returns NULL. */
void (*parameter_free)(void *parameters);
/* The following functions can be provided to set and get parameters. The parameter
* structure is defined by the filter and should contain all parameters that are
* configurable by the user. The host code makes no assumption on the contents
* of the structure but only passes references. The host implements a message
* handler which supports the following messages that use the functions below:
* parameter-get - Retrieve a single parameter.
* parameter-set - Set a single parameter.
* parameter-get-all - Retrieve all parameters as a list in message format.
* parameter-set-all - Set all parameters simultaneously.
* parameter-get-description - Returns a filter description and a list that describes
* all parameters. Example of the list element format:
* {{Identifier}{Type}{default}{min}{max}}
* The last message can be used to get information about the filter or to implement
* a filter control GUI that is independent of the filter type.
* If filter_message_handler() is defined, all other messages are passed on to the
* filter. The get functions are expected to return a string in the message handler
* format while the set functions receive plain strings. On failure, all get/set
* functions will return NULL. */
/* Get the value of the parameter described by identifier. The value shall be returned
* as a string enclosed in double curly braces. The identifier may be any string that
* the filter recognizes like a name or index, depending on the implementation of this
* function. */
char *(*parameter_get)(const char *identifier, void *filter_handle);
/* Sets the value of the parameter described by identifier. The value is expected as
* a string. The identifier may be any string that the filter recognizes like a name
* or index. Returns a parameter structure filled with all current parameter values,
* reflecting the updated parameter, so that the structure can be passed to
* update_filter_parameters(). update_filter_parameters() will replace the current
* parameter set with the new structure. */
void *(*parameter_set)(const char *identifier, const char *value, void *filter_handle);
/* Returns a list of the values of all filter parameters. Each parameter must be enclosed
* in curly braces and there must be braces around the whole list. */
char *(*parameter_get_all)(void *filter_handle);
/* Expects an array of all filter parameter values as strings and returns a parameter
* structure that can be passed to update_filter_parameters(). See set_parameter().
* If all_params is NULL, the function should return a default set of parameters. */
void *(*parameter_set_all)(const char **all_params, int param_count, void *filter_handle);
/* Returns a parameter description string as described above. */
char *(*parameter_get_description)(void *filter_handle);
/* Handler for additional messages. */
int (*filter_message_handler)(const char *message, char *message_parameters, char **response, void *filter_handle);
} filter_plugin;
/* Datatype corresponding to the get_Filter_Info() function. */
typedef const struct filter_plugin *(*Filter_Info_Function)(unsigned long Index);
_______________________________________________
pulseaudio-discuss mailing list
pulseaudio-discuss@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss