<commit_before>/**
 * FreeRDP: A Remote Desktop Protocol client.
 * Audio Output Virtual Channel
 *
 * Copyright 2009-2011 <NAME>
 * Copyright 2010-2011 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/dsp.h>
#include <freerdp/utils/svc_plugin.h>

#include "rdpsnd_main.h"

typedef struct rdpsnd_alsa_plugin rdpsndAlsaPlugin;
struct rdpsnd_alsa_plugin
{
	rdpsndDevicePlugin device;

	char* device_name;
	snd_pcm_t* out_handle;
	uint32 source_rate;
	uint32 actual_rate;
	snd_pcm_format_t format;
	uint32 source_channels;
	uint32 actual_channels;
	int bytes_per_channel;
	int wformat;
	int block_size;
	int latency;
	ADPCM adpcm;
};

static void rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa)
{
	snd_pcm_hw_params_t* hw_params;
	snd_pcm_sw_params_t* sw_params;
	int error;
	snd_pcm_uframes_t frames;
	snd_pcm_uframes_t start_threshold;

	snd_pcm_drop(alsa->out_handle);

	error = snd_pcm_hw_params_malloc(&hw_params);
	if (error < 0)
	{
		DEBUG_WARN("snd_pcm_hw_params_malloc failed");
		return;
	}
	snd_pcm_hw_params_any(alsa->out_handle, hw_params);
	snd_pcm_hw_params_set_access(alsa->out_handle, hw_params,
		SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(alsa->out_handle, hw_params,
		alsa->format);
	snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params,
		&alsa->actual_rate, NULL);
	snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params,
		&alsa->actual_channels);
	frames = alsa->actual_rate * 4;
	snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params,
		&frames);
	snd_pcm_hw_params(alsa->out_handle, hw_params);
	snd_pcm_hw_params_free(hw_params);

	error = snd_pcm_sw_params_malloc(&sw_params);
	if (error < 0)
	{
		DEBUG_WARN("snd_pcm_sw_params_malloc failed");
		return;
	}
	snd_pcm_sw_params_current(alsa->out_handle, sw_params);
	if (alsa->latency < 0)
		start_threshold = frames / 2;
	else
		start_threshold = alsa->latency * alsa->actual_rate / 1000;
	if (start_threshold > frames)
		start_threshold = frames;
	snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, start_threshold);
	snd_pcm_sw_params(alsa->out_handle, sw_params);
	snd_pcm_sw_params_free(sw_params);

	snd_pcm_prepare(alsa->out_handle);

	DEBUG_SVC("hardware buffer %d frames, playback buffer %.2g seconds",
		(int)frames, (double)frames / 2.0 / (double)alsa->actual_rate);
	if ((alsa->actual_rate != alsa->source_rate) ||
		(alsa->actual_channels != alsa->source_channels))
	{
		DEBUG_SVC("actual rate %d / channel %d is different from source rate %d / channel %d, resampling required.",
			alsa->actual_rate, alsa->actual_channels, alsa->source_rate, alsa->source_channels);
	}<commit_msg>rdpsnd/alsa: better buffer size against requested latency.<commit_after>/**
 * FreeRDP: A Remote Desktop Protocol client.
 * Audio Output Virtual Channel
 *
 * Copyright 2009-2011 <NAME>
 * Copyright 2010-2011 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/dsp.h>
#include <freerdp/utils/svc_plugin.h>

#include "rdpsnd_main.h"

typedef struct rdpsnd_alsa_plugin rdpsndAlsaPlugin;
struct rdpsnd_alsa_plugin
{
	rdpsndDevicePlugin device;

	char* device_name;
	snd_pcm_t* out_handle;
	uint32 source_rate;
	uint32 actual_rate;
	snd_pcm_format_t format;
	uint32 source_channels;
	uint32 actual_channels;
	int bytes_per_channel;
	int wformat;
	int block_size;
	int latency;
	ADPCM adpcm;
};

static void rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa)
{
	snd_pcm_hw_params_t* hw_params;
	snd_pcm_sw_params_t* sw_params;
	int error;
	snd_pcm_uframes_t frames;
	snd_pcm_uframes_t start_threshold;

	snd_pcm_drop(alsa->out_handle);

	error = snd_pcm_hw_params_malloc(&hw_params);
	if (error < 0)
	{
		DEBUG_WARN("snd_pcm_hw_params_malloc failed");
		return;
	}
	snd_pcm_hw_params_any(alsa->out_handle, hw_params);
	snd_pcm_hw_params_set_access(alsa->out_handle, hw_params,
		SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(alsa->out_handle, hw_params,
		alsa->format);
	snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params,
		&alsa->actual_rate, NULL);
	snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params,
		&alsa->actual_channels);
	if (alsa->latency < 0)
		frames = alsa->actual_rate * 4; /* Default to 4-second buffer */
	else
		frames = alsa->latency * alsa->actual_rate * 2 / 1000; /* Double of the latency */
	if (frames < alsa->actual_rate / 2)
		frames = alsa->actual_rate / 2; /* Minimum 0.5-second buffer */
	snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params,
		&frames);
	snd_pcm_hw_params(alsa->out_handle, hw_params);
	snd_pcm_hw_params_free(hw_params);

	error = snd_pcm_sw_params_malloc(&sw_params);
	if (error < 0)
	{
		DEBUG_WARN("snd_pcm_sw_params_malloc failed");
		return;
	}
	snd_pcm_sw_params_current(alsa->out_handle, sw_params);
	if (alsa->latency == 0)
		start_threshold = 0;
	else
		start_threshold = frames / 2;
	snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, start_threshold);
	snd_pcm_sw_params(alsa->out_handle, sw_params);
	snd_pcm_sw_params_free(sw_params);

	snd_pcm_prepare(alsa->out_handle);

	DEBUG_SVC("hardware buffer %d frames, playback buffer %.2g seconds",
		(int)frames, (double)frames / 2.0 / (double)alsa->actual_rate);
	if ((alsa->actual_rate != alsa->source_rate) ||
		(alsa->actual_channels != alsa->source_channels))
	{
		DEBUG_SVC("actual rate %d / channel %d is different from source rate %d / channel %d, resampling required.",
			alsa->actual_rate, alsa->actual_channels, alsa->source_rate, alsa->source_channels);
	}
{'fraction_non_alphanumeric': 0.10697606538237012, 'fraction_numerical': 0.01284296555750146, 'mean_word_length': 5.570469798657718, 'pattern_counts': {'":': 0, '<': 30, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '2117399', 'n_tokens_mistral': 2645, 'n_tokens_neox': 2449, 'n_words': 548}