Error reporting, pcm_buffer, performance tweaks
This commit is contained in:
parent
a4fbf772c1
commit
8587fcbb93
@ -42,9 +42,11 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "audio_format.h"
|
#include "audio_format.h"
|
||||||
|
#include "audio_check.h"
|
||||||
#include "filter_plugin.h"
|
#include "filter_plugin.h"
|
||||||
#include "filter_internal.h"
|
#include "filter_internal.h"
|
||||||
#include "filter_registry.h"
|
#include "filter_registry.h"
|
||||||
|
#include "pcm_buffer.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -91,26 +93,21 @@ struct route_filter {
|
|||||||
struct audio_format output_format;
|
struct audio_format output_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size, in bytes, of each multichannel sample in the
|
* The size, in bytes, of each multichannel frame in the
|
||||||
* input buffer
|
* input buffer
|
||||||
*/
|
*/
|
||||||
size_t input_sample_size;
|
size_t input_frame_size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size, in bytes, of each multichannel sample in the
|
* The size, in bytes, of each multichannel frame in the
|
||||||
* output buffer
|
* output buffer
|
||||||
*/
|
*/
|
||||||
size_t output_sample_size;
|
size_t output_frame_size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The output buffer used last time around, can be reused if the size doesn't differ.
|
* The output buffer used last time around, can be reused if the size doesn't differ.
|
||||||
*/
|
*/
|
||||||
void *output_buffer;
|
struct pcm_buffer output_buffer;
|
||||||
|
|
||||||
/**
|
|
||||||
* The size in bytes of the currently allocated output buffer
|
|
||||||
*/
|
|
||||||
size_t output_buffer_size;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -123,7 +120,9 @@ struct route_filter {
|
|||||||
* @param filter a route_filter whose min_channels and sources[] to set
|
* @param filter a route_filter whose min_channels and sources[] to set
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
route_filter_parse(const struct config_param *param, struct route_filter *filter) {
|
route_filter_parse(const struct config_param *param,
|
||||||
|
struct route_filter *filter,
|
||||||
|
GError **error_r) {
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* With a more clever way of marking "don't copy to output N",
|
* With a more clever way of marking "don't copy to output N",
|
||||||
@ -157,9 +156,10 @@ route_filter_parse(const struct config_param *param, struct route_filter *filter
|
|||||||
// Split the a>b string into source and destination
|
// Split the a>b string into source and destination
|
||||||
sd = g_strsplit(tokens[c], ">", 2);
|
sd = g_strsplit(tokens[c], ">", 2);
|
||||||
if (g_strv_length(sd) != 2) {
|
if (g_strv_length(sd) != 2) {
|
||||||
g_error("Invalid copy around %d in routes spec: %s",
|
g_set_error(error_r, config_quark(), 1,
|
||||||
param->line, tokens[c]);
|
"Invalid copy around %d in routes spec: %s",
|
||||||
continue;
|
param->line, tokens[c]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
source = strtol(sd[0], NULL, 10);
|
source = strtol(sd[0], NULL, 10);
|
||||||
@ -193,9 +193,10 @@ route_filter_parse(const struct config_param *param, struct route_filter *filter
|
|||||||
// Split the a>b string into source and destination
|
// Split the a>b string into source and destination
|
||||||
sd = g_strsplit(tokens[c], ">", 2);
|
sd = g_strsplit(tokens[c], ">", 2);
|
||||||
if (g_strv_length(sd) != 2) {
|
if (g_strv_length(sd) != 2) {
|
||||||
g_error("Invalid copy around %d in routes spec: %s",
|
g_set_error(error_r, config_quark(), 1,
|
||||||
param->line, tokens[c]);
|
"Invalid copy around %d in routes spec: %s",
|
||||||
continue;
|
param->line, tokens[c]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
source = strtol(sd[0], NULL, 10);
|
source = strtol(sd[0], NULL, 10);
|
||||||
@ -217,7 +218,7 @@ route_filter_init(const struct config_param *param,
|
|||||||
filter_init(&filter->base, &route_filter_plugin);
|
filter_init(&filter->base, &route_filter_plugin);
|
||||||
|
|
||||||
// Allocate and set the filter->sources[] array
|
// Allocate and set the filter->sources[] array
|
||||||
route_filter_parse(param, filter);
|
route_filter_parse(param, filter, error_r);
|
||||||
|
|
||||||
return &filter->base;
|
return &filter->base;
|
||||||
}
|
}
|
||||||
@ -234,15 +235,21 @@ route_filter_finish(struct filter *_filter)
|
|||||||
static const struct audio_format *
|
static const struct audio_format *
|
||||||
route_filter_open(struct filter *_filter,
|
route_filter_open(struct filter *_filter,
|
||||||
const struct audio_format *audio_format,
|
const struct audio_format *audio_format,
|
||||||
G_GNUC_UNUSED GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
struct route_filter *filter = (struct route_filter *)_filter;
|
struct route_filter *filter = (struct route_filter *)_filter;
|
||||||
|
|
||||||
// Copy the input format for later reference
|
// Copy the input format for later reference
|
||||||
filter->input_format = *audio_format;
|
filter->input_format = *audio_format;
|
||||||
filter->input_sample_size =
|
filter->input_frame_size =
|
||||||
audio_format_sample_size(&filter->input_format) *
|
audio_format_frame_size(&filter->input_format);
|
||||||
filter->input_format.channels;
|
|
||||||
|
if (!audio_valid_channel_count(filter->min_output_channels)) {
|
||||||
|
g_set_error(error_r, audio_format_quark(), 2,
|
||||||
|
"Invalid number of output channels requested: %d",
|
||||||
|
filter->min_output_channels);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Decide on an output format which has enough channels,
|
// Decide on an output format which has enough channels,
|
||||||
// and is otherwise identical
|
// and is otherwise identical
|
||||||
@ -250,13 +257,11 @@ route_filter_open(struct filter *_filter,
|
|||||||
filter->output_format.channels = filter->min_output_channels;
|
filter->output_format.channels = filter->min_output_channels;
|
||||||
|
|
||||||
// Precalculate this simple value, to speed up allocation later
|
// Precalculate this simple value, to speed up allocation later
|
||||||
filter->output_sample_size =
|
filter->output_frame_size =
|
||||||
audio_format_sample_size(&filter->output_format) *
|
audio_format_frame_size(&filter->output_format);
|
||||||
filter->output_format.channels;
|
|
||||||
|
|
||||||
// This buffer grows as needed
|
// This buffer grows as needed
|
||||||
filter->output_buffer_size = filter->output_sample_size;
|
pcm_buffer_init(&filter->output_buffer);
|
||||||
filter->output_buffer = g_malloc0(filter->output_buffer_size);
|
|
||||||
|
|
||||||
return &filter->output_format;
|
return &filter->output_format;
|
||||||
}
|
}
|
||||||
@ -266,8 +271,7 @@ route_filter_close(struct filter *_filter)
|
|||||||
{
|
{
|
||||||
struct route_filter *filter = (struct route_filter *)_filter;
|
struct route_filter *filter = (struct route_filter *)_filter;
|
||||||
|
|
||||||
filter->output_buffer_size = 0;
|
pcm_buffer_deinit(&filter->output_buffer);
|
||||||
g_free(filter->output_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void *
|
static const void *
|
||||||
@ -277,32 +281,24 @@ route_filter_filter(struct filter *_filter,
|
|||||||
{
|
{
|
||||||
struct route_filter *filter = (struct route_filter *)_filter;
|
struct route_filter *filter = (struct route_filter *)_filter;
|
||||||
|
|
||||||
size_t number_of_samples = src_size / filter->input_sample_size;
|
size_t number_of_frames = src_size / filter->input_frame_size;
|
||||||
|
|
||||||
size_t bytes_per_sample_per_channel =
|
size_t bytes_per_frame_per_channel =
|
||||||
audio_format_sample_size(&filter->input_format);
|
audio_format_sample_size(&filter->input_format);
|
||||||
|
|
||||||
// A moving pointer that always refers to channel 0 in the input, at the currently handled sample
|
// A moving pointer that always refers to channel 0 in the input, at the currently handled frame
|
||||||
const uint8_t *base_source = src;
|
const uint8_t *base_source = src;
|
||||||
|
|
||||||
// A moving pointer that always refers to the currently filled channel of the currently handled sample, in the output
|
// A moving pointer that always refers to the currently filled channel of the currently handled frame, in the output
|
||||||
uint8_t *chan_destination;
|
uint8_t *chan_destination;
|
||||||
|
|
||||||
// Grow our reusable buffer, if needed
|
// Grow our reusable buffer, if needed, and set the moving pointer
|
||||||
*dest_size_r = number_of_samples * filter->output_sample_size;
|
*dest_size_r = number_of_frames * filter->output_frame_size;
|
||||||
if (*dest_size_r > filter->output_buffer_size) {
|
chan_destination = pcm_buffer_get(&filter->output_buffer, *dest_size_r);
|
||||||
filter->output_buffer_size = *dest_size_r;
|
|
||||||
|
|
||||||
filter->output_buffer =
|
|
||||||
g_realloc(filter->output_buffer,
|
|
||||||
filter->output_buffer_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A moving pointer that always refers to the currently filled channel of the currently handled sample, in the output
|
|
||||||
chan_destination = filter->output_buffer;
|
|
||||||
|
|
||||||
// Perform our copy operations, with N input channels and M output channels
|
// Perform our copy operations, with N input channels and M output channels
|
||||||
for (unsigned int s=0; s<number_of_samples; ++s) {
|
for (unsigned int s=0; s<number_of_frames; ++s) {
|
||||||
|
|
||||||
// Need to perform one copy per output channel
|
// Need to perform one copy per output channel
|
||||||
for (unsigned int c=0; c<filter->min_output_channels; ++c) {
|
for (unsigned int c=0; c<filter->min_output_channels; ++c) {
|
||||||
@ -312,27 +308,27 @@ route_filter_filter(struct filter *_filter,
|
|||||||
// give it zeroes as input
|
// give it zeroes as input
|
||||||
memset(chan_destination,
|
memset(chan_destination,
|
||||||
0x00,
|
0x00,
|
||||||
bytes_per_sample_per_channel);
|
bytes_per_frame_per_channel);
|
||||||
} else {
|
} else {
|
||||||
// Get the data from channel sources[c]
|
// Get the data from channel sources[c]
|
||||||
// and copy it to the output
|
// and copy it to the output
|
||||||
const uint8_t *data = base_source +
|
const uint8_t *data = base_source +
|
||||||
(filter->sources[c] * bytes_per_sample_per_channel);
|
(filter->sources[c] * bytes_per_frame_per_channel);
|
||||||
g_memmove(chan_destination,
|
memcpy(chan_destination,
|
||||||
data,
|
data,
|
||||||
bytes_per_sample_per_channel);
|
bytes_per_frame_per_channel);
|
||||||
}
|
}
|
||||||
// Move on to the next output channel
|
// Move on to the next output channel
|
||||||
chan_destination += bytes_per_sample_per_channel;
|
chan_destination += bytes_per_frame_per_channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Go on to the next N input samples
|
// Go on to the next N input samples
|
||||||
base_source += filter->input_sample_size;
|
base_source += filter->input_frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here it is, ladies and gentlemen! Rerouted data!
|
// Here it is, ladies and gentlemen! Rerouted data!
|
||||||
return filter->output_buffer;
|
return (void *) filter->output_buffer.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct filter_plugin route_filter_plugin = {
|
const struct filter_plugin route_filter_plugin = {
|
||||||
|
Loading…
Reference in New Issue
Block a user