<commit_before>/*
	audio_alsa: sound output with Advanced Linux Sound Architecture 1.x API

	copyright 2006 by the mpg123 project - free software under the terms of the LGPL 2.1
	see COPYING and AUTHORS files in distribution or http://mpg123.de

	written by <NAME> <<EMAIL>>
*/

#include "config.h"
#include "mpg123.h"
#include "debug.h"
#include <errno.h>

/* make ALSA 0.9.x compatible to the 1.0.x API */
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API

#include <alsa/asoundlib.h>

/* My laptop has probs playing low-sampled files with only 0.5s buffer... this should be a user setting -- ThOr */
#define BUFFER_LENGTH 0.5	/* in seconds */

static const struct {
	snd_pcm_format_t alsa;
	int mpg123;
} format_map[] = {
	{ SND_PCM_FORMAT_S16,    AUDIO_FORMAT_SIGNED_16   },
	{ SND_PCM_FORMAT_U16,    AUDIO_FORMAT_UNSIGNED_16 },
	{ SND_PCM_FORMAT_U8,     AUDIO_FORMAT_UNSIGNED_8  },
	{ SND_PCM_FORMAT_S8,     AUDIO_FORMAT_SIGNED_8    },
	{ SND_PCM_FORMAT_A_LAW,  AUDIO_FORMAT_ALAW_8      },
	{ SND_PCM_FORMAT_MU_LAW, AUDIO_FORMAT_ULAW_8      },
};
#define NUM_FORMATS (sizeof format_map / sizeof format_map[0])

static int initialize_device(struct audio_info_struct *ai);

int audio_open(struct audio_info_struct *ai)
{
	const char *pcm_name;
	snd_pcm_t *pcm;

	pcm_name = ai->device ? ai->device : "default";
	if (snd_pcm_open(&pcm, pcm_name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
		fprintf(stderr, "audio_open(): cannot open device %s\n", pcm_name);
		return -1;
	}
	ai->handle = pcm;
	if (ai->format != -1) {
		/* we're going to play: initalize sample format */
		return initialize_device(ai);
	} else {
		/* query mode; sample format will be set for each query */
		return 0;
	}
}

static int rates_match(long int desired, unsigned int actual)
{
	return actual * 100 > desired * (100 - AUDIO_RATE_TOLERANCE) &&
	       actual * 100 < desired * (100 + AUDIO_RATE_TOLERANCE);
}

static int initialize_device(struct audio_info_struct *ai)
{
	snd_pcm_hw_params_t *hw;
	int i;
	snd_pcm_format_t format;
	unsigned int rate;
	snd_pcm_uframes_t buffer_size;
	snd_pcm_uframes_t period_size;
	snd_pcm_sw_params_t *sw;
	snd_pcm_uframes_t boundary;

	snd_pcm_hw_params_alloca(&hw);
	if (snd_pcm_hw_params_any(ai->handle, hw) < 0) {
		fprintf(stderr, "initialize_device(): no configuration available\n");
		return -1;
	}
	if (snd_pcm_hw_params_set_access(ai->handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
		fprintf(stderr, "initialize_device(): device does not support interleaved access\n");
		return -1;
	}
	format = SND_PCM_FORMAT_UNKNOWN;
	for (i = 0; i < NUM_FORMATS; ++i) {
		if (ai->format == format_map[i].mpg123) {
			format = format_map[i].alsa;
			break;
		}
	}
	if (format == SND_PCM_FORMAT_UNKNOWN) {
		fprintf(stderr, "initialize_device(): invalid sample format %d\n", ai->format);
		errno = EINVAL;
		return -1;
	}
	if (snd_pcm_hw_params_set_format(ai->handle, hw, format) < 0) {
		fprintf(stderr, "initialize_device(): cannot set format %s\n", snd_pcm_format_name(format));
		return -1;
	}
	if (snd_pcm_hw_params_set_channels(ai->handle, hw, ai->channels) < 0) {
		fprintf(stderr, "initialize_device(): cannot set %d channels\n", ai->channels);
		return -1;
	}
	rate = ai->rate;
	if (snd_pcm_hw_params_set_rate_near(ai->handle, hw, &rate, NULL) < 0) {
		fprintf(stderr, "initialize_device(): cannot set rate %u\n", rate);
		return -1;
	}
	if (!rates_match(ai->rate, rate)) {
		fprintf(stderr, "initialize_device(): rate %ld not available, using %u\n", ai->rate, rate);
		/* return -1; */
	}
	buffer_size = rate * BUFFER_LENGTH;
	if (snd_pcm_hw_params_set_buffer_size_near(ai->handle, hw, &buffer_size) < 0) {
		fprintf(stderr, "initialize_device(): cannot set buffer size\n");
		return -1;
	}
	period_size = buffer_size / 4;
	if (snd_pcm_hw_params_set_period_size_near(ai->handle, hw, &period_size, NULL) < 0) {
		fprintf(stderr, "initialize_device(): cannot set period size\n");
		return -1;
	}
	if (snd_pcm_hw_params(ai->handle, hw) < 0) {
		fprintf(stderr, "initialize_device(): cannot set hw params\n");
		return -1;
	}

	snd_pcm_sw_params_alloca(&sw);
	if (snd_pcm_sw_params_current(ai->handle, sw) < 0) {
		fprintf(stderr, "initialize_device(): cannot get sw params\n");
		return -1;
	}
	/* start playing after the first write */
	if (snd_pcm_sw_params_set_start_threshold(ai->handle, sw, 1) < 0) {
		fprintf(stderr, "initialize_device(): cannot set start threshold\n");
		return -1;
	}
	if (snd_pcm_sw_params_get_boundary(sw, &boundary) < 0) {
		fprintf(stderr, "initialize_device(): cannot get boundary\n");
		return -1;
	}
	/* never stop on underruns */
	if (snd_pcm_sw_params_set_stop_threshold(ai->handle, sw, boundary) < 0) {
		fprintf(stderr, "initialize_device(): cannot set stop threshold\n");
		return -1;
	}
	/* wake up on every interrupt */
	if (snd_pcm_sw_params_set_avail_min(ai->handle, sw, 1) < 0) {
		fprintf(stderr, "initialize_device(): cannot set min avail\n");
		return -1;<commit_msg>info for bug 1547470<commit_after>/*
	audio_alsa: sound output with Advanced Linux Sound Architecture 1.x API

	copyright 2006 by the mpg123 project - free software under the terms of the LGPL 2.1
	see COPYING and AUTHORS files in distribution or http://mpg123.de

	written by <NAME> <<EMAIL>>
*/

#include "config.h"
#include "mpg123.h"
#include "debug.h"
#include <errno.h>

/* make ALSA 0.9.x compatible to the 1.0.x API */
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API

#include <alsa/asoundlib.h>

/* My laptop has probs playing low-sampled files with only 0.5s buffer... this should be a user setting -- ThOr */
#define BUFFER_LENGTH 0.5	/* in seconds */

static const struct {
	snd_pcm_format_t alsa;
	int mpg123;
} format_map[] = {
	{ SND_PCM_FORMAT_S16,    AUDIO_FORMAT_SIGNED_16   },
	{ SND_PCM_FORMAT_U16,    AUDIO_FORMAT_UNSIGNED_16 },
	{ SND_PCM_FORMAT_U8,     AUDIO_FORMAT_UNSIGNED_8  },
	{ SND_PCM_FORMAT_S8,     AUDIO_FORMAT_SIGNED_8    },
	{ SND_PCM_FORMAT_A_LAW,  AUDIO_FORMAT_ALAW_8      },
	{ SND_PCM_FORMAT_MU_LAW, AUDIO_FORMAT_ULAW_8      },
};
#define NUM_FORMATS (sizeof format_map / sizeof format_map[0])

static int initialize_device(struct audio_info_struct *ai);

int audio_open(struct audio_info_struct *ai)
{
	const char *pcm_name;
	snd_pcm_t *pcm;

	pcm_name = ai->device ? ai->device : "default";
	if (snd_pcm_open(&pcm, pcm_name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
		fprintf(stderr, "audio_open(): cannot open device %s\n", pcm_name);
		return -1;
	}
	ai->handle = pcm;
	if (ai->format != -1) {
		/* we're going to play: initalize sample format */
		return initialize_device(ai);
	} else {
		/* query mode; sample format will be set for each query */
		return 0;
	}
}

static int rates_match(long int desired, unsigned int actual)
{
	return actual * 100 > desired * (100 - AUDIO_RATE_TOLERANCE) &&
	       actual * 100 < desired * (100 + AUDIO_RATE_TOLERANCE);
}

static int initialize_device(struct audio_info_struct *ai)
{
	snd_pcm_hw_params_t *hw;
	int i;
	snd_pcm_format_t format;
	unsigned int rate;
	snd_pcm_uframes_t buffer_size;
	snd_pcm_uframes_t period_size;
	snd_pcm_sw_params_t *sw;
	snd_pcm_uframes_t boundary;

	snd_pcm_hw_params_alloca(&hw);
	if (snd_pcm_hw_params_any(ai->handle, hw) < 0) {
		fprintf(stderr, "initialize_device(): no configuration available\n");
		return -1;
	}
	if (snd_pcm_hw_params_set_access(ai->handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
		fprintf(stderr, "initialize_device(): device does not support interleaved access\n");
		return -1;
	}
	format = SND_PCM_FORMAT_UNKNOWN;
	for (i = 0; i < NUM_FORMATS; ++i) {
		if (ai->format == format_map[i].mpg123) {
			format = format_map[i].alsa;
			break;
		}
	}
	if (format == SND_PCM_FORMAT_UNKNOWN) {
		fprintf(stderr, "initialize_device(): invalid sample format %d\n", ai->format);
		errno = EINVAL;
		return -1;
	}
	if (snd_pcm_hw_params_set_format(ai->handle, hw, format) < 0) {
		fprintf(stderr, "initialize_device(): cannot set format %s\n", snd_pcm_format_name(format));
		return -1;
	}
	if (snd_pcm_hw_params_set_channels(ai->handle, hw, ai->channels) < 0) {
		fprintf(stderr, "initialize_device(): cannot set %d channels\n", ai->channels);
		return -1;
	}
	rate = ai->rate;
	if (snd_pcm_hw_params_set_rate_near(ai->handle, hw, &rate, NULL) < 0) {
		fprintf(stderr, "initialize_device(): cannot set rate %u\n", rate);
		return -1;
	}
	if (!rates_match(ai->rate, rate)) {
		fprintf(stderr, "initialize_device(): rate %ld not available, using %u\n", ai->rate, rate);
		/* return -1; */
	}
	buffer_size = rate * BUFFER_LENGTH;
	if (snd_pcm_hw_params_set_buffer_size_near(ai->handle, hw, &buffer_size) < 0) {
		fprintf(stderr, "initialize_device(): cannot set buffer size\n");
		return -1;
	}
	period_size = buffer_size / 4;
	if (snd_pcm_hw_params_set_period_size_near(ai->handle, hw, &period_size, NULL) < 0) {
		fprintf(stderr, "initialize_device(): cannot set period size\n");
		return -1;
	}
	if (snd_pcm_hw_params(ai->handle, hw) < 0) {
		fprintf(stderr, "initialize_device(): cannot set hw params\n");
		return -1;
	}

	snd_pcm_sw_params_alloca(&sw);
	if (snd_pcm_sw_params_current(ai->handle, sw) < 0) {
		fprintf(stderr, "initialize_device(): cannot get sw params\n");
		return -1;
	}
	/* start playing after the first write */
	if (snd_pcm_sw_params_set_start_threshold(ai->handle, sw, 1) < 0) {
		fprintf(stderr, "initialize_device(): cannot set start threshold\n");
		return -1;
	}
	if (snd_pcm_sw_params_get_boundary(sw, &boundary) < 0) {
		fprintf(stderr, "initialize_device(): cannot get boundary\n");
		return -1;
	}
	#ifdef DEBUG
	{
		snd_pcm_uframes_t hw_buffer_size;
		snd_pcm_hw_params_get_buffer_size(hw, &hw_buffer_size);
		debug2("Alsa buffer_size %lu vs. boundary %lu", (unsigned long) hw_buffer_size, (unsigned long) boundary);
	}
	#endif
	/* never stop on underruns */
	if (snd_pcm_sw_params_set_stop_threshold(ai->handle, sw, boundary) < 0) {
		fprintf(stderr, "initialize_device(): cannot set stop threshold\n");
		return -1;
	}
	/* wake up on every interrupt */
	if (snd_pcm_sw_params_set_avail_min(ai->handle, sw, 1) < 0) {
		fprintf(stderr, "initialize_device(): cannot set min avail\n");
		return -1;
{'fraction_non_alphanumeric': 0.13015998419909144, 'fraction_numerical': 0.01935611297649615, 'mean_word_length': 4.619866814650388, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1826194', 'n_tokens_mistral': 4032, 'n_tokens_neox': 3846, 'n_words': 943}