<commit_before>/**
 * @file
 *
 * @date 14.05.2016
 * @author <NAME>
 */
#include <stddef.h>
#include <assert.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>

#include <util/log.h>

#include <kernel/lthread/lthread.h>

#include <drivers/audio/portaudio.h>
#include <drivers/audio/audio_dev.h>

static struct lthread portaudio_lthread;

struct pa_strm {
	uint8_t devid;
	uint8_t number_of_chan;
	uint32_t sample_format;

	PaStreamCallback *callback;
	void *user_data;

	int active;
};

static struct pa_strm pa_stream;
#if 0
static int sample_format_in_bytes(uint32_t pa_format) {
	switch (pa_format) {
	case paInt16:
		return 2;
	case paInt8:
		return 1;
	default:
		log_error("Unsupport stream format");
		return -EINVAL;
	}
	return -EINVAL;
}

static int _bytes_per_sample(struct pa_strm *stream) {
	return stream->number_of_chan *
	       sample_format_in_bytes(stream->sample_format);
}

/**
 * @brief Check if given device support given number of channels
 *
 * @param dev    Audio device
 * @param chan_n Number of channels
 *
 * @retval 0 No support
 * @retval 1 Support
 */
static int _dev_chan_support(struct audio_dev *dev, int chan_n) {
	int supp;

	if (NULL == dev->ad_ops->ad_ops_ioctl)
		return 0;

	supp = dev->ad_ops->ad_ops_ioctl(dev, ADIOCTL_SUPPORT, NULL);

	if (chan_n == 1 && (supp & AD_MONO_SUPPORT))
		return 1;

	if (chan_n == 2 && (supp & AD_STEREO_SUPPORT))
		return 1;

	return 0;
}
#endif

/**
 * @brief Duplicate left channel for the buffer
 */
static void _mono_to_stereo(void *buf, int len) {
	/* Assume data is 16-bit */
	uint16_t *b16 = buf;
	for (int i = len * 2 - 1; i >= 0; i--) {
		b16[i] = b16[i / 2];
	}
}

/**
 * @brief Remove right channel from audio buffer
 */
static void _stereo_to_mono(void *buf, int len) {
	/* Assume data is 16-bit */
	uint16_t *b16 = buf;
	for (int i = 0; i < len / 2; i++) {
		b16[i] = b16[i * 2];
	}
}

static int portaudio_lthread_handle(struct lthread *self) {
	int retval;
	struct audio_dev *audio_dev;
	uint8_t *out_buf;
	int inp_frames;

	if (!pa_stream.callback || !pa_stream.active) {
		return 0;
	}

	audio_dev = audio_dev_get_by_idx(pa_stream.devid);
	assert(audio_dev);

	out_buf = audio_dev_get_out_cur_ptr(audio_dev);

	inp_frames = audio_dev->buf_len / 2; /* 16 bit sample */
	if (pa_stream.number_of_chan == 2)
		inp_frames /= 2;

	memset(out_buf, 0, audio_dev->buf_len);

	retval = pa_stream.callback(NULL,
			out_buf,
			inp_frames,
			NULL,
			0,
			pa_stream.user_data);

	/* Sort out problems related to the number of channels */
	if (pa_stream.number_of_chan != audio_dev->num_of_chan) {
		if (pa_stream.number_of_chan == 1 && audio_dev->num_of_chan == 2) {
			_mono_to_stereo(out_buf, inp_frames);
		} else if (pa_stream.number_of_chan == 2 && audio_dev->num_of_chan == 1) {
			_stereo_to_mono(out_buf, inp_frames);
		} else {
			log_error("Audio configuration is broken!"
			          "Check the number of channels.\n");
			return 0;<commit_msg>portaudio: Fix monochannel sound source handle<commit_after>/**
 * @file
 *
 * @date 14.05.2016
 * @author <NAME>
 */
#include <stddef.h>
#include <assert.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>

#include <util/log.h>

#include <kernel/lthread/lthread.h>

#include <drivers/audio/portaudio.h>
#include <drivers/audio/audio_dev.h>

static struct lthread portaudio_lthread;

struct pa_strm {
	uint8_t devid;
	uint8_t number_of_chan;
	uint32_t sample_format;

	PaStreamCallback *callback;
	void *user_data;

	int active;
};

static struct pa_strm pa_stream;
#if 0
static int sample_format_in_bytes(uint32_t pa_format) {
	switch (pa_format) {
	case paInt16:
		return 2;
	case paInt8:
		return 1;
	default:
		log_error("Unsupport stream format");
		return -EINVAL;
	}
	return -EINVAL;
}

static int _bytes_per_sample(struct pa_strm *stream) {
	return stream->number_of_chan *
	       sample_format_in_bytes(stream->sample_format);
}

/**
 * @brief Check if given device support given number of channels
 *
 * @param dev    Audio device
 * @param chan_n Number of channels
 *
 * @retval 0 No support
 * @retval 1 Support
 */
static int _dev_chan_support(struct audio_dev *dev, int chan_n) {
	int supp;

	if (NULL == dev->ad_ops->ad_ops_ioctl)
		return 0;

	supp = dev->ad_ops->ad_ops_ioctl(dev, ADIOCTL_SUPPORT, NULL);

	if (chan_n == 1 && (supp & AD_MONO_SUPPORT))
		return 1;

	if (chan_n == 2 && (supp & AD_STEREO_SUPPORT))
		return 1;

	return 0;
}
#endif

/**
 * @brief Duplicate left channel for the buffer
 */
static void _mono_to_stereo(void *buf, int len) {
	/* Assume data is 16-bit */
	uint16_t *b16 = buf;
	for (int i = len * 2 - 1; i >= 0; i--) {
		b16[i] = b16[i / 2];
	}
}

/**
 * @brief Remove right channel from audio buffer
 */
static void _stereo_to_mono(void *buf, int len) {
	/* Assume data is 16-bit */
	uint16_t *b16 = buf;
	for (int i = 0; i < len / 2; i++) {
		b16[i] = b16[i * 2];
	}
}

static int portaudio_lthread_handle(struct lthread *self) {
	int retval;
	struct audio_dev *audio_dev;
	uint8_t *out_buf;
	int inp_frames;

	if (!pa_stream.callback || !pa_stream.active) {
		return 0;
	}

	audio_dev = audio_dev_get_by_idx(pa_stream.devid);
	assert(audio_dev);

	out_buf = audio_dev_get_out_cur_ptr(audio_dev);

	inp_frames = audio_dev->buf_len / 2; /* 16 bit sample */
	/* Even if source is mono channel,
	 * we will anyway put twice as much data
	 * to fill right channel as well */
	inp_frames /= 2;

	memset(out_buf, 0, audio_dev->buf_len);

	retval = pa_stream.callback(NULL,
			out_buf,
			inp_frames,
			NULL,
			0,
			pa_stream.user_data);

	/* Sort out problems related to the number of channels */
	if (pa_stream.number_of_chan != audio_dev->num_of_chan) {
		if (pa_stream.number_of_chan == 1 && audio_dev->num_of_chan == 2) {
			_mono_to_stereo(out_buf, inp_frames);
		} else if (pa_stream.number_of_chan == 2 && audio_dev->num_of_chan == 1) {
			_stereo_to_mono(out_buf, inp_frames);
		} else {
			log_error("Audio configuration is broken!"
			          "Check the number of channels.\n");
			return 0;
{'fraction_non_alphanumeric': 0.12816272531833967, 'fraction_numerical': 0.022655862411112948, 'mean_word_length': 3.8384, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 49, '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': '1778553', 'n_tokens_mistral': 2564, 'n_tokens_neox': 2355, 'n_words': 597}