[Intel-gfx] [PATCH i-g-t 2/3] lib: Add ALSA library with dedicated helpers

Paul Kocialkowski paul.kocialkowski at linux.intel.com
Mon Aug 21 15:11:03 UTC 2017


Hi,

On Fri, 2017-08-18 at 12:20 -0400, Lyude Paul wrote:
> And two more small changes
> 
> On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> > This introduces an ALSA library, with dedicated helpers for handling
> > playback and capture. It handles ALSA device identification and
> > configuration as well as a run loop with callback mechanisms for
> > feeding
> > output data and handling input data.
> > 
> > This library paves the way for testing audio going through display
> > connectors, such as HDMI.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
> > ---
> >  configure.ac                                       |   3 +
> >  .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
> >  lib/Makefile.am                                    |   7 +
> >  lib/igt.h                                          |   1 +
> >  lib/igt_alsa.c                                     | 624
> > +++++++++++++++++++++
> >  lib/igt_alsa.h                                     |  60 ++
> >  6 files changed, 696 insertions(+)
> >  create mode 100644 lib/igt_alsa.c
> >  create mode 100644 lib/igt_alsa.h
> > 
> > diff --git a/configure.ac b/configure.ac
> > index 50aa86b5..e66273a4 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -219,6 +219,9 @@ if test "x$enable_chamelium" = xyes; then
> >  	AC_DEFINE(HAVE_CHAMELIUM, 1, [Enable Chamelium support])
> >  fi
> >  
> > +PKG_CHECK_MODULES(ALSA, [alsa], [alsa=yes], [alsa=no])
> > +AM_CONDITIONAL(HAVE_ALSA, [test "x$alsa" = xyes])
> > +
> >  # ---------------------------------------------------------------
> > ---
> > -----------
> >  #			Configuration options
> >  # ---------------------------------------------------------------
> > ---
> > -----------
> > diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > index c77159cf..0c34e4a5 100644
> > --- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > +++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > @@ -16,6 +16,7 @@
> >    <chapter>
> >      <title>API Reference</title>
> >      <xi:include href="xml/drmtest.xml"/>
> > +    <xi:include href="xml/igt_alsa.xml"/>
> >      <xi:include href="xml/igt_audio.xml"/>
> >      <xi:include href="xml/igt_aux.xml"/>
> >      <xi:include href="xml/igt_chamelium.xml"/>
> > diff --git a/lib/Makefile.am b/lib/Makefile.am
> > index 5ea08314..3ff14f66 100644
> > --- a/lib/Makefile.am
> > +++ b/lib/Makefile.am
> > @@ -38,6 +38,13 @@ lib_source_list +=		\
> >  	$(NULL)
> >  endif
> >  
> > +if HAVE_ALSA
> > +lib_source_list +=		\
> > +	igt_alsa.c		\
> > +	igt_alsa.h		\
> > +	$(NULL)
> > +endif
> > +
> >  AM_CPPFLAGS = -I$(top_srcdir)
> >  AM_CFLAGS = \
> >  	    $(CWARNFLAGS) \
> > diff --git a/lib/igt.h b/lib/igt.h
> > index a75d2db7..ebf92349 100644
> > --- a/lib/igt.h
> > +++ b/lib/igt.h
> > @@ -35,6 +35,7 @@
> >  #include "igt_dummyload.h"
> >  #include "igt_fb.h"
> >  #include "igt_frame.h"
> > +#include "igt_alsa.h"
> >  #include "igt_audio.h"
> >  #include "igt_gt.h"
> >  #include "igt_kms.h"
> > diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
> > new file mode 100644
> > index 00000000..d8bd0873
> > --- /dev/null
> > +++ b/lib/igt_alsa.c
> > @@ -0,0 +1,624 @@
> > +/*
> > + * Copyright © 2017 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > + * copy of this software and associated documentation files (the
> > "Software"),
> > + * to deal in the Software without restriction, including without
> > limitation
> > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > + * and/or sell copies of the Software, and to permit persons to
> > whom
> > the
> > + * Software is furnished to do so, subject to the following
> > conditions:
> > + *
> > + * The above copyright notice and this permission notice (including
> > the next
> > + * paragraph) shall be included in all copies or substantial
> > portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO
> > EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES
> > OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + *
> > + * Authors:
> > + *  Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
> > + */
> > +
> > +#include "config.h"
> > +
> > +#include <alsa/asoundlib.h>
> > +
> > +#include "igt.h"
> > +
> > +#define HANDLES_MAX	8
> > +
> > +/**
> > + * SECTION:igt_alsa
> > + * @short_description: Library with ALSA helpers
> > + * @title: ALSA
> > + * @include: igt_alsa.h
> > + *
> > + * This library contains helpers for ALSA playback and capture.
> > + */
> > +
> > +struct alsa {
> > +	snd_pcm_t *output_handles[HANDLES_MAX];
> > +	int output_handles_count;
> > +	int output_sampling_rate;
> > +	int output_channels;
> > +
> > +	int (*output_callback)(void *data, short *buffer, int
> > samples);
> > +	void *output_callback_data;
> > +	int output_samples_trigger;
> > +
> > +	snd_pcm_t *input_handle;
> > +	int input_sampling_rate;
> > +	int input_channels;
> > +
> > +	int (*input_callback)(void *data, short *buffer, int
> > samples);
> > +	void *input_callback_data;
> > +	int input_samples_trigger;
> > +};
> > +
> > +static void alsa_error_handler(const char *file, int line, const
> > char *function,
> > +			       int err, const char *fmt, ...)
> > +{
> > +	if (err)
> > +		igt_debug("[ALSA] %s: %s\n", function,
> > snd_strerror(err));
> > +}
> 
> Would be a good idea to add an __attribute__((printf)) here

Well, that function is registered as a callback for the ALSA library, so
there won't ever be code outside of the ALSA library that makes calls to
it. Thus, no call to the function will be built, which renders the
attribute useless.

> > +
> > +/**
> > + * alsa_init:
> > + * Allocate and initialize an alsa structure and configure the
> > error
> > handler.
> > + *
> > + * Returns: A newly-allocated alsa structure
> > + */
> > +struct alsa *alsa_init(void)
> > +{
> > +	struct alsa *alsa;
> > +
> > +	alsa = malloc(sizeof(struct alsa));
> > +	memset(alsa, 0, sizeof(struct alsa));
> > +
> > +	/* Redirect errors to igt_debug instead of stderr. */
> > +	snd_lib_error_set_handler(alsa_error_handler);
> > +
> > +	return alsa;
> > +}
> > +
> > +static char *alsa_resolve_indentifier(const char *device_name, int
> > skip)
> > +{
> > +	snd_ctl_card_info_t *card_info;
> > +	snd_pcm_info_t *pcm_info;
> > +	snd_ctl_t *handle = NULL;
> > +	const char *pcm_name;
> > +	char *identifier = NULL;
> > +	char name[32];
> > +	int card;
> > +	int dev;
> > +	int ret;
> > +
> > +	snd_ctl_card_info_alloca(&card_info);
> > +	snd_pcm_info_alloca(&pcm_info);
> > +
> > +	card = -1;
> 
> Just set card = -1 at it's declaration

Sure thing!

> > +
> > +	/* First try to open the device as-is. */
> > +	if (!skip) {
> > +		ret = snd_ctl_open(&handle, device_name, 0);
> > +		if (!ret) {
> > +			identifier = strdup(device_name);
> > +			goto resolved;
> > +		}
> > +	}
> > +
> > +	do {
> > +		ret = snd_card_next(&card);
> > +		if (ret < 0 || card < 0)
> > +			break;
> > +
> > +		snprintf(name, sizeof(name), "hw:%d", card);
> > +
> > +		ret = snd_ctl_open(&handle, name, 0);
> > +		if (ret < 0)
> > +			continue;
> > +
> > +		ret = snd_ctl_card_info(handle, card_info);
> > +		if (ret < 0) {
> > +			snd_ctl_close(handle);
> > +			handle = NULL;
> > +			continue;
> > +		}
> > +
> > +		dev = -1;
> > +
> > +		do {
> > +			ret = snd_ctl_pcm_next_device(handle,
> > &dev);
> > +			if (ret < 0 || dev < 0)
> > +				break;
> > +
> > +			snd_pcm_info_set_device(pcm_info, dev);
> > +			snd_pcm_info_set_subdevice(pcm_info, 0);
> > +
> > +			ret = snd_ctl_pcm_info(handle, pcm_info);
> > +			if (ret < 0)
> > +				continue;
> > +
> > +			pcm_name = snd_pcm_info_get_name(pcm_info);
> > +			if (!pcm_name)
> > +				continue;
> > +
> > +			ret = strncmp(device_name, pcm_name,
> > +				      strlen(device_name));
> > +
> > +			if (ret == 0) {
> > +				if (skip > 0) {
> > +					skip--;
> > +					continue;
> > +				}
> > +
> > +				snprintf(name, sizeof(name),
> > "hw:%d,%d", card,
> > +					 dev);
> > +
> > +				identifier = strdup(name);
> > +				goto resolved;
> > +			}
> > +		} while (dev >= 0);
> > +
> > +		snd_ctl_close(handle);
> > +		handle = NULL;
> > +	} while (card >= 0);
> > +
> > +resolved:
> > +	if (handle)
> > +		snd_ctl_close(handle);
> > +
> > +	return identifier;
> > +}
> > +
> > +/**
> > + * alsa_open_output:
> > + * @alsa: The target alsa structure
> > + * @device_name: The name prefix of the output device(s) to open
> > + *
> > + * Open ALSA output devices whose name prefixes match the provided
> > name prefix.
> > + *
> > + * Returns: An integer equal to zero for success and negative for
> > failure
> > + */
> > +int alsa_open_output(struct alsa *alsa, const char *device_name)
> > +{
> > +	snd_pcm_t *handle;
> > +	char *identifier;
> > +	int skip;
> > +	int index;
> > +	int ret;
> > +
> > +	skip = alsa->output_handles_count;
> > +	index = alsa->output_handles_count;
> > +
> > +	while (index < HANDLES_MAX) {
> > +		identifier = alsa_resolve_indentifier(device_name,
> > skip++);
> > +		if (!identifier)
> > +			break;
> > +
> > +		ret = snd_pcm_open(&handle, identifier,
> > SND_PCM_STREAM_PLAYBACK,
> > +				   SND_PCM_NONBLOCK);
> > +		if (ret < 0) {
> > +			free(identifier);
> > +			continue;
> > +		}
> > +
> > +		igt_debug("Opened output %s\n", identifier);
> > +
> > +		alsa->output_handles[index++] = handle;
> > +		free(identifier);
> > +	}
> > +
> > +	if (index == 0)
> > +		return -1;
> > +
> > +	alsa->output_handles_count = index;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * alsa_open_input:
> > + * @alsa: The target alsa structure
> > + * @device_name: The name of the input device to open
> > + *
> > + * Open the ALSA input device whose name matches the provided name
> > prefix.
> > + *
> > + * Returns: An integer equal to zero for success and negative for
> > failure
> > + */
> > +int alsa_open_input(struct alsa *alsa, const char *device_name)
> > +{
> > +	snd_pcm_t *handle;
> > +	char *identifier;
> > +	int ret;
> > +
> > +	identifier = alsa_resolve_indentifier(device_name, 0);
> > +
> > +	ret = snd_pcm_open(&handle, device_name,
> > SND_PCM_STREAM_CAPTURE,
> > +			   SND_PCM_NONBLOCK);
> > +	if (ret < 0)
> > +		goto complete;
> > +
> > +	igt_debug("Opened input %s\n", identifier);
> > +
> > +	alsa->input_handle = handle;
> > +
> > +	ret = 0;
> > +
> > +complete:
> > +	free(identifier);
> > +
> > +	return ret;
> > +}
> > +
> > +/**
> > + * alsa_close_output:
> > + * @alsa: The target alsa structure
> > + *
> > + * Close all the open ALSA outputs.
> > + */
> > +void alsa_close_output(struct alsa *alsa)
> > +{
> > +	snd_pcm_t *handle;
> > +	int i;
> > +
> > +	for (i = 0; i < alsa->output_handles_count; i++) {
> > +		handle = alsa->output_handles[i];
> > +		if (!handle)
> > +			continue;
> > +
> > +		snd_pcm_close(handle);
> > +		alsa->output_handles[i] = NULL;
> > +	}
> > +
> > +	alsa->output_handles_count = 0;
> > +}
> > +
> > +/**
> > + * alsa_close_output:
> > + * @alsa: The target alsa structure
> > + *
> > + * Close the open ALSA input.
> > + */
> > +void alsa_close_input(struct alsa *alsa)
> > +{
> > +	snd_pcm_t *handle = alsa->input_handle;
> > +	if (!handle)
> > +		return;
> > +
> > +	snd_pcm_close(handle);
> > +	alsa->input_handle = NULL;
> > +}
> > +
> > +static bool alsa_test_configuration(snd_pcm_t *handle, int
> > channels,
> > +			     int sampling_rate)
> > +{
> > +	snd_pcm_hw_params_t *params;
> > +	int ret;
> > +
> > +	snd_pcm_hw_params_alloca(&params);
> > +
> > +	ret = snd_pcm_hw_params_any(handle, params);
> > +	if (ret < 0)
> > +		return false;
> > +
> > +	ret = snd_pcm_hw_params_test_rate(handle, params,
> > sampling_rate, 0);
> > +	if (ret < 0)
> > +		return false;
> > +
> > +	ret = snd_pcm_hw_params_test_channels(handle, params,
> > channels);
> > +	if (ret < 0)
> > +		return false;
> > +
> > +	return true;
> > +}
> > +
> > +/**
> > + * alsa_test_output_configuration:
> > + * @alsa: The target alsa structure
> > + * @channels: The number of channels to test
> > + * @sampling_rate: The sampling rate to test
> > + *
> > + * Test the output configuration specified by @channels and
> > @sampling_rate
> > + * for the output devices.
> > + *
> > + * Returns: A boolean indicating whether the test succeeded
> > + */
> > +bool alsa_test_output_configuration(struct alsa *alsa, int
> > channels,
> > +			  	    int sampling_rate)
> > +{
> > +	snd_pcm_t *handle;
> > +	bool ret;
> > +	int i;
> > +
> > +	for (i = 0; i < alsa->output_handles_count; i++) {
> > +		handle = alsa->output_handles[i];
> > +
> > +		ret = alsa_test_configuration(handle, channels,
> > sampling_rate);
> > +		if (!ret)
> > +			return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +/**
> > + * alsa_test_input_configuration:
> > + * @alsa: The target alsa structure
> > + * @channels: The number of channels to test
> > + * @sampling_rate: The sampling rate to test
> > + *
> > + * Test the input configuration specified by @channels and
> > @sampling_rate
> > + * for the input device.
> > + *
> > + * Returns: A boolean indicating whether the test succeeded
> > + */
> > +bool alsa_test_input_configuration(struct alsa *alsa, int channels,
> > +			  	   int sampling_rate)
> > +{
> > +	return alsa_test_configuration(alsa->input_handle,
> > channels,
> > +				       sampling_rate);
> > +}
> > +
> > +/**
> > + * alsa_configure_output:
> > + * @alsa: The target alsa structure
> > + * @channels: The number of channels to test
> > + * @sampling_rate: The sampling rate to test
> > + *
> > + * Configure the output devices with the configuration specified by
> > @channels
> > + * and @sampling_rate.
> > + */
> > +void alsa_configure_output(struct alsa *alsa, int channels,
> > +			   int sampling_rate)
> > +{
> > +	snd_pcm_t *handle;
> > +	int ret;
> > +	int i;
> > +
> > +	for (i = 0; i < alsa->output_handles_count; i++) {
> > +		handle = alsa->output_handles[i];
> > +
> > +		ret = snd_pcm_set_params(handle,
> > SND_PCM_FORMAT_S16_LE,
> > +					 SND_PCM_ACCESS_RW_INTERLEA
> > V
> > ED,
> > +					 channels, sampling_rate,
> > 0,
> > 0);
> > +		igt_assert(ret >= 0);
> > +	}
> > +
> > +	alsa->output_channels = channels;
> > +	alsa->output_sampling_rate = sampling_rate;
> > +}
> > +
> > +/**
> > + * alsa_configure_input:
> > + * @alsa: The target alsa structure
> > + * @channels: The number of channels to test
> > + * @sampling_rate: The sampling rate to test
> > + *
> > + * Configure the input device with the configuration specified by
> > @channels
> > + * and @sampling_rate.
> > + */
> > +void alsa_configure_input(struct alsa *alsa, int channels,
> > +			  int sampling_rate)
> > +{
> > +	snd_pcm_t *handle;
> > +	int ret;
> > +
> > +	handle = alsa->input_handle;
> > +
> > +	ret = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,
> > +				 SND_PCM_ACCESS_RW_INTERLEAVED,
> > channels,
> > +				 sampling_rate, 0, 0);
> > +	igt_assert(ret >= 0);
> > +
> > +	alsa->input_channels = channels;
> > +	alsa->input_sampling_rate = sampling_rate;
> > +
> > +}
> > +
> > +/**
> > + * alsa_register_output_callback:
> > + * @alsa: The target alsa structure
> > + * @callback: The callback function to call to fill output data
> > + * @callback_data: The data pointer to pass to the callback
> > function
> > + * @samples_trigger: The required number of samples to trigger the
> > callback
> > + *
> > + * Register a callback function to be called to fill output data
> > during a run.
> > + * The callback is called when @samples_trigger samples are
> > required.
> > + *
> > + * The callback should return an integer equal to zero for success
> > and negative
> > + * for failure.
> > + */
> > +void alsa_register_output_callback(struct alsa *alsa,
> > +				   int (*callback)(void *data,
> > short
> > *buffer, int samples),
> > +				   void *callback_data, int
> > samples_trigger)
> > +{
> > +	alsa->output_callback = callback;
> > +	alsa->output_callback_data = callback_data;
> > +	alsa->output_samples_trigger = samples_trigger;
> > +}
> > +
> > +/**
> > + * alsa_register_input_callback:
> > + * @alsa: The target alsa structure
> > + * @callback: The callback function to call when input data is
> > available
> > + * @callback_data: The data pointer to pass to the callback
> > function
> > + * @samples_trigger: The required number of samples to trigger the
> > callback
> > + *
> > + * Register a callback function to be called when input data is
> > available during
> > + * a run. The callback is called when @samples_trigger samples are
> > available.
> > + *
> > + * The callback should return an integer equal to zero for success,
> > negative for
> > + * failure and positive to indicate that the run should stop.
> > + */
> > +void alsa_register_input_callback(struct alsa *alsa,
> > +				  int (*callback)(void *data, short
> > *buffer, int samples),
> > +				  void *callback_data, int
> > samples_trigger)
> > +{
> > +	alsa->input_callback = callback;
> > +	alsa->input_callback_data = callback_data;
> > +	alsa->input_samples_trigger = samples_trigger;
> > +}
> > +
> > +/**
> > + * alsa_run:
> > + * @alsa: The target alsa structure
> > + * @duration_ms: The maximum duration of the run in milliseconds
> > + *
> > + * Run ALSA playback and capture on the input and output devices
> > for
> > at
> > + * most @duration_ms milliseconds, calling the registered callbacks
> > when needed.
> > + *
> > + * Returns: An integer equal to zero for success, positive for a
> > stop caused
> > + * by the input callback and negative for failure
> > + */
> > +int alsa_run(struct alsa *alsa, int duration_ms)
> > +{
> > +	snd_pcm_t *handle;
> > +	short *output_buffer = NULL;
> > +	short *input_buffer = NULL;
> > +	int output_limit;
> > +	int output_total = 0;
> > +	int output_counts[alsa->output_handles_count];
> > +	bool output_ready = false;
> > +	int output_channels;
> > +	int output_trigger;
> > +	int input_limit;
> > +	int input_total = 0;
> > +	int input_count = 0;
> > +	int input_channels;
> > +	int input_trigger;
> > +	bool reached;
> > +	int index;
> > +	int count;
> > +	int avail;
> > +	int i;
> > +	int ret;
> > +
> > +	output_limit = alsa->output_sampling_rate * duration_ms /
> > 1000;
> > +	output_channels = alsa->output_channels;
> > +	output_trigger = alsa->output_samples_trigger;
> > +	output_buffer = malloc(sizeof(short) * output_channels *
> > +			       output_trigger);
> > +
> > +	if (alsa->input_callback) {
> > +		input_limit = alsa->input_sampling_rate *
> > duration_ms / 1000;
> > +		input_trigger = alsa->input_samples_trigger;
> > +		input_channels = alsa->input_channels;
> > +		input_buffer = malloc(sizeof(short) *
> > input_channels
> > *
> > +				      input_trigger);
> > +	}
> > +
> > +	do {
> > +		reached = true;
> > +
> > +		if (output_total < output_limit) {
> > +			reached = false;
> > +
> > +			if (!output_ready) {
> > +				output_ready = true;
> > +
> > +				for (i = 0; i < alsa-
> > > output_handles_count; i++)
> > 
> > +					output_counts[i] = 0;
> > +
> > +				ret = alsa->output_callback(alsa-
> > > output_callback_data,
> > 
> > +							    output_
> > b
> > uffer,
> > +							    output_
> > t
> > rigger);
> > +				if (ret < 0)
> > +					goto complete;
> > +			}
> > +
> > +			for (i = 0; i < alsa->output_handles_count;
> > i++) {
> > +				handle = alsa->output_handles[i];
> > +
> > +				if (output_counts[i] <
> > output_trigger &&
> > +				    snd_pcm_avail(handle) > 0) {
> > +					index = output_counts[i] *
> > +						output_channels;
> > +					count = output_trigger -
> > +						output_counts[i];
> > +					avail =
> > snd_pcm_avail(handle);
> > +
> > +					count = avail < count ?
> > avail : count;
> > +
> > +					ret =
> > snd_pcm_writei(handle,
> > +							     &outpu
> > t
> > _buffer[index],
> > +							     count)
> > ;
> > +					if (ret < 0) {
> > +						ret =
> > snd_pcm_recover(handle,
> > +								   
> >  
> >   count, 0);
> > +						if (ret < 0)
> > +							goto
> > complete;
> > +					}
> > +
> > +					output_counts[i] += ret;
> > +				}
> > +			}
> > +
> > +			output_ready = false;
> > +
> > +			for (i = 0; i < alsa->output_handles_count;
> > i++)
> > +				if (output_counts[i] <
> > output_trigger)
> > +					output_ready = true;
> > +
> > +			if (!output_ready)
> > +				output_total += output_trigger;
> > +
> > +		}
> > +
> > +		if (alsa->input_callback && input_total <
> > input_limit) {
> > +			reached = false;
> > +
> > +			if (input_count == input_trigger) {
> > +				input_count = 0;
> > +
> > +				ret = alsa->input_callback(alsa-
> > > input_callback_data,
> > 
> > +							   input_bu
> > f
> > fer,
> > +							   input_tr
> > i
> > gger);
> > +				if (ret != 0)
> > +					goto complete;
> > +			}
> > +
> > +			handle = alsa->input_handle;
> > +
> > +			if (input_count < input_trigger &&
> > +			    (snd_pcm_avail(handle) > 0 ||
> > input_total == 0)) {
> > +				index = input_count *
> > input_channels;
> > +				count = input_trigger -
> > input_count;
> > +				avail = snd_pcm_avail(handle);
> > +
> > +				count = avail > 0 && avail < count
> > ?
> > avail :
> > +					count;
> > +
> > +				ret = snd_pcm_readi(handle,
> > +						    &input_buffer[i
> > n
> > dex],
> > +						    count);
> > +				if (ret == -EAGAIN) {
> > +					ret = 0;
> > +				} else if (ret < 0) {
> > +					ret =
> > snd_pcm_recover(handle, count, 0);
> > +					if (ret < 0)
> > +						goto complete;
> > +				}
> > +
> > +				input_count += ret;
> > +				input_total += ret;
> > +			}
> > +		}
> > +	} while (!reached);
> > +
> > +	ret = 0;
> > +
> > +complete:
> > +	if (output_buffer)
> > +		free(output_buffer);
> > +
> > +	if (input_buffer)
> > +		free(input_buffer);
> > +
> > +	return ret;
> > +}
> > diff --git a/lib/igt_alsa.h b/lib/igt_alsa.h
> > new file mode 100644
> > index 00000000..9911ddde
> > --- /dev/null
> > +++ b/lib/igt_alsa.h
> > @@ -0,0 +1,60 @@
> > +/*
> > + * Copyright © 2017 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > + * copy of this software and associated documentation files (the
> > "Software"),
> > + * to deal in the Software without restriction, including without
> > limitation
> > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > + * and/or sell copies of the Software, and to permit persons to
> > whom
> > the
> > + * Software is furnished to do so, subject to the following
> > conditions:
> > + *
> > + * The above copyright notice and this permission notice (including
> > the next
> > + * paragraph) shall be included in all copies or substantial
> > portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO
> > EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES
> > OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + *
> > + * Authors:
> > + *  Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
> > + */
> > +
> > +#ifndef IGT_ALSA_H
> > +#define IGT_ALSA_H
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include "config.h"
> > +#endif
> > +
> > +#include "igt.h"
> > +#include <stdbool.h>
> > +
> > +struct alsa;
> > +
> > +struct alsa *alsa_init(void);
> > +int alsa_open_output(struct alsa *alsa, const char *device_name);
> > +int alsa_open_input(struct alsa *alsa, const char *device_name);
> > +void alsa_close_output(struct alsa *alsa);
> > +void alsa_close_input(struct alsa *alsa);
> > +bool alsa_test_output_configuration(struct alsa *alsa, int
> > channels,
> > +			  	    int sampling_rate);
> > +bool alsa_test_input_configuration(struct alsa *alsa, int channels,
> > +			  	   int sampling_rate);
> > +void alsa_configure_output(struct alsa *alsa, int channels,
> > +			   int sampling_rate);
> > +void alsa_configure_input(struct alsa *alsa, int channels,
> > +			  int sampling_rate);
> > +void alsa_register_output_callback(struct alsa *alsa,
> > +				   int (*callback)(void *data,
> > short
> > *buffer, int samples),
> > +				   void *callback_data, int
> > samples_trigger);
> > +void alsa_register_input_callback(struct alsa *alsa,
> > +				  int (*callback)(void *data, short
> > *buffer, int samples),
> > +				  void *callback_data, int
> > samples_trigger);
> > +int alsa_run(struct alsa *alsa, int duration_ms);
> > +
> > +#endif
-- 
Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland


More information about the Intel-gfx mailing list