Blame channels/audin/client/audin_main.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Audio Input Redirection Virtual Channel
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2010-2011 Vic Lee
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit 1fb8d4
 * Copyright 2015 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
#include <assert.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/cmdline.h>
Packit 1fb8d4
#include <winpr/wlog.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/addin.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/stream.h>
Packit 1fb8d4
#include <freerdp/freerdp.h>
Packit 1fb8d4
#include <freerdp/codec/dsp.h>
Packit 1fb8d4
Packit 1fb8d4
#include "audin_main.h"
Packit 1fb8d4
Packit 1fb8d4
#define MSG_SNDIN_VERSION       0x01
Packit 1fb8d4
#define MSG_SNDIN_FORMATS       0x02
Packit 1fb8d4
#define MSG_SNDIN_OPEN          0x03
Packit 1fb8d4
#define MSG_SNDIN_OPEN_REPLY    0x04
Packit 1fb8d4
#define MSG_SNDIN_DATA_INCOMING 0x05
Packit 1fb8d4
#define MSG_SNDIN_DATA          0x06
Packit 1fb8d4
#define MSG_SNDIN_FORMATCHANGE  0x07
Packit 1fb8d4
Packit 1fb8d4
typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK;
Packit 1fb8d4
struct _AUDIN_LISTENER_CALLBACK
Packit 1fb8d4
{
Packit 1fb8d4
	IWTSListenerCallback iface;
Packit 1fb8d4
Packit 1fb8d4
	IWTSPlugin* plugin;
Packit 1fb8d4
	IWTSVirtualChannelManager* channel_mgr;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
typedef struct _AUDIN_CHANNEL_CALLBACK AUDIN_CHANNEL_CALLBACK;
Packit 1fb8d4
struct _AUDIN_CHANNEL_CALLBACK
Packit 1fb8d4
{
Packit 1fb8d4
	IWTSVirtualChannelCallback iface;
Packit 1fb8d4
Packit 1fb8d4
	IWTSPlugin* plugin;
Packit 1fb8d4
	IWTSVirtualChannelManager* channel_mgr;
Packit 1fb8d4
	IWTSVirtualChannel* channel;
Packit 1fb8d4
Packit 1fb8d4
	/**
Packit 1fb8d4
	 * The supported format list sent back to the server, which needs to
Packit 1fb8d4
	 * be stored as reference when the server sends the format index in
Packit 1fb8d4
	 * Open PDU and Format Change PDU
Packit 1fb8d4
	 */
Packit 1fb8d4
	AUDIO_FORMAT* formats;
Packit 1fb8d4
	UINT32 formats_count;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
typedef struct _AUDIN_PLUGIN AUDIN_PLUGIN;
Packit 1fb8d4
struct _AUDIN_PLUGIN
Packit 1fb8d4
{
Packit 1fb8d4
	IWTSPlugin iface;
Packit 1fb8d4
Packit 1fb8d4
	AUDIN_LISTENER_CALLBACK* listener_callback;
Packit 1fb8d4
Packit 1fb8d4
	/* Parsed plugin data */
Packit 1fb8d4
	AUDIO_FORMAT* fixed_format;
Packit 1fb8d4
	char* subsystem;
Packit 1fb8d4
	char* device_name;
Packit 1fb8d4
Packit 1fb8d4
	/* Device interface */
Packit 1fb8d4
	IAudinDevice* device;
Packit 1fb8d4
Packit 1fb8d4
	rdpContext* rdpcontext;
Packit 1fb8d4
	BOOL attached;
Packit 1fb8d4
	wStream* data;
Packit 1fb8d4
	AUDIO_FORMAT* format;
Packit 1fb8d4
	UINT32 FramesPerPacket;
Packit 1fb8d4
Packit 1fb8d4
	FREERDP_DSP_CONTEXT* dsp_context;
Packit 1fb8d4
	wLog* log;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args);
Packit 1fb8d4
Packit 1fb8d4
static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStream* out,
Packit 1fb8d4
        BOOL freeStream)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
Packit 1fb8d4
	if (!callback || !out)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	if (!callback->channel || !callback->channel->Write)
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
Packit 1fb8d4
	Stream_SealLength(out);
Packit 1fb8d4
	error = callback->channel->Write(callback->channel,
Packit 1fb8d4
	                                 Stream_Length(out),
Packit 1fb8d4
	                                 Stream_Buffer(out), NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (freeStream)
Packit 1fb8d4
		Stream_Free(out, TRUE);
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* out;
Packit 1fb8d4
	const UINT32 ClientVersion = 0x01;
Packit 1fb8d4
	UINT32 ServerVersion;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, ServerVersion);
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_DEBUG, "ServerVersion=%"PRIu32", ClientVersion=%"PRIu32, ServerVersion,
Packit 1fb8d4
	           ClientVersion);
Packit 1fb8d4
Packit 1fb8d4
	/* Do not answer server packet, we do not support the channel version. */
Packit 1fb8d4
	if (ServerVersion != ClientVersion)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_WARN,
Packit 1fb8d4
		           "Incompatible channel version server=%"PRIu32", client supports version=%"PRIu32, ServerVersion,
Packit 1fb8d4
		           ClientVersion);
Packit 1fb8d4
		return CHANNEL_RC_OK;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	out = Stream_New(NULL, 5);
Packit 1fb8d4
Packit 1fb8d4
	if (!out)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT8(out, MSG_SNDIN_VERSION);
Packit 1fb8d4
	Stream_Write_UINT32(out, ClientVersion);
Packit 1fb8d4
	return audin_channel_write_and_free(callback, out, TRUE);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_send_incoming_data_pdu(AUDIN_CHANNEL_CALLBACK* callback)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE out_data[1] = { MSG_SNDIN_DATA_INCOMING };
Packit 1fb8d4
Packit 1fb8d4
	if (!callback || !callback->channel || !callback->channel->Write)
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
Packit 1fb8d4
	return callback->channel->Write(callback->channel, 1, out_data, NULL);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
	wStream* out;
Packit 1fb8d4
	UINT32 NumFormats;
Packit 1fb8d4
	UINT32 cbSizeFormatsPacket;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 8)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, NumFormats);
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_DEBUG, "NumFormats %"PRIu32"", NumFormats);
Packit 1fb8d4
Packit 1fb8d4
	if ((NumFormats < 1) || (NumFormats > 1000))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "bad NumFormats %"PRIu32"", NumFormats);
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */
Packit 1fb8d4
	callback->formats = audio_formats_new(NumFormats);
Packit 1fb8d4
Packit 1fb8d4
	if (!callback->formats)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "calloc failed!");
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	out = Stream_New(NULL, 9);
Packit 1fb8d4
Packit 1fb8d4
	if (!out)
Packit 1fb8d4
	{
Packit 1fb8d4
		error = CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(out, 9);
Packit 1fb8d4
Packit 1fb8d4
	/* SoundFormats (variable) */
Packit 1fb8d4
	for (i = 0; i < NumFormats; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		AUDIO_FORMAT format = { 0 };
Packit 1fb8d4
Packit 1fb8d4
		if (!audio_format_read(s, &format))
Packit 1fb8d4
		{
Packit 1fb8d4
			error = ERROR_INVALID_DATA;
Packit 1fb8d4
			goto out;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		audio_format_print(audin->log, WLOG_DEBUG, &format);
Packit 1fb8d4
Packit 1fb8d4
		if (!audio_format_compatible(audin->fixed_format, &format))
Packit 1fb8d4
		{
Packit 1fb8d4
			audio_format_free(&format);
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (freerdp_dsp_supports_format(&format, TRUE) ||
Packit 1fb8d4
		    audin->device->FormatSupported(audin->device, &format))
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Store the agreed format in the corresponding index */
Packit 1fb8d4
			callback->formats[callback->formats_count++] = format;
Packit 1fb8d4
Packit 1fb8d4
			if (!audio_format_write(out, &format))
Packit 1fb8d4
			{
Packit 1fb8d4
				error = CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
				WLog_Print(audin->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
				goto out;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			audio_format_free(&format);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((error = audin_send_incoming_data_pdu(callback)))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "audin_send_incoming_data_pdu failed!");
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	cbSizeFormatsPacket = (UINT32) Stream_GetPosition(out);
Packit 1fb8d4
	Stream_SetPosition(out, 0);
Packit 1fb8d4
	Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */
Packit 1fb8d4
	Stream_Write_UINT32(out, callback->formats_count); /* NumFormats (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */
Packit 1fb8d4
	Stream_SetPosition(out, cbSizeFormatsPacket);
Packit 1fb8d4
	error = audin_channel_write_and_free(callback, out, FALSE);
Packit 1fb8d4
out:
Packit 1fb8d4
Packit 1fb8d4
	if (error != CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		audio_formats_free(callback->formats, NumFormats);
Packit 1fb8d4
		callback->formats = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Free(out, TRUE);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_send_format_change_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback,
Packit 1fb8d4
        UINT32 NewFormat)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* out = Stream_New(NULL, 5);
Packit 1fb8d4
Packit 1fb8d4
	if (!out)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
Packit 1fb8d4
		return CHANNEL_RC_OK;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT8(out, MSG_SNDIN_FORMATCHANGE);
Packit 1fb8d4
	Stream_Write_UINT32(out, NewFormat);
Packit 1fb8d4
	return audin_channel_write_and_free(callback, out, TRUE);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_send_open_reply_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback,
Packit 1fb8d4
                                      UINT32 Result)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* out = Stream_New(NULL, 5);
Packit 1fb8d4
Packit 1fb8d4
	if (!out)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT8(out, MSG_SNDIN_OPEN_REPLY);
Packit 1fb8d4
	Stream_Write_UINT32(out, Result);
Packit 1fb8d4
	return audin_channel_write_and_free(callback, out, TRUE);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_receive_wave_data(const AUDIO_FORMAT* format,
Packit 1fb8d4
                                    const BYTE* data, size_t size, void* user_data)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
	BOOL compatible;
Packit 1fb8d4
	AUDIN_PLUGIN* audin;
Packit 1fb8d4
	AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data;
Packit 1fb8d4
Packit 1fb8d4
	if (!callback)
Packit 1fb8d4
		return CHANNEL_RC_BAD_CHANNEL_HANDLE;
Packit 1fb8d4
Packit 1fb8d4
	audin = (AUDIN_PLUGIN*)callback->plugin;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin)
Packit 1fb8d4
		return CHANNEL_RC_BAD_CHANNEL_HANDLE;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin->attached)
Packit 1fb8d4
		return CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	Stream_SetPosition(audin->data, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(audin->data, 1))
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT8(audin->data, MSG_SNDIN_DATA);
Packit 1fb8d4
Packit 1fb8d4
	compatible = audio_format_compatible(format, audin->format);
Packit 1fb8d4
	if (compatible && audin->device->FormatSupported(audin->device, audin->format))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!Stream_EnsureRemainingCapacity(audin->data, size))
Packit 1fb8d4
			return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Write(audin->data, data, size);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!freerdp_dsp_encode(audin->dsp_context, format, data, size, audin->data))
Packit 1fb8d4
			return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Did not encode anything, skip this, the codec is not ready for output. */
Packit 1fb8d4
	if (Stream_GetPosition(audin->data) <= 1)
Packit 1fb8d4
		return CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	audio_format_print(audin->log, WLOG_TRACE, audin->format);
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_TRACE, "[%"PRIdz"/%"PRIdz"]", size,
Packit 1fb8d4
	           Stream_GetPosition(audin->data) - 1);
Packit 1fb8d4
Packit 1fb8d4
	if ((error = audin_send_incoming_data_pdu(callback)))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "audin_send_incoming_data_pdu failed!");
Packit 1fb8d4
		return error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return audin_channel_write_and_free(callback, audin->data, FALSE);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error = ERROR_INTERNAL_ERROR;
Packit 1fb8d4
	BOOL supported;
Packit 1fb8d4
	AUDIO_FORMAT format;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin || !audin->device)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	format = *audin->format;
Packit 1fb8d4
	supported = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format);
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_DEBUG, "microphone uses %s codec",
Packit 1fb8d4
	           audio_format_get_tag_string(format.wFormatTag));
Packit 1fb8d4
Packit 1fb8d4
	if (!supported)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Default sample rates supported by most backends. */
Packit 1fb8d4
		const UINT32 samplerates[] = {
Packit 1fb8d4
		    96000,
Packit 1fb8d4
		    48000,
Packit 1fb8d4
		    44100,
Packit 1fb8d4
		    22050
Packit 1fb8d4
		};
Packit 1fb8d4
		BOOL test = FALSE;
Packit 1fb8d4
Packit 1fb8d4
		format.wFormatTag = WAVE_FORMAT_PCM;
Packit 1fb8d4
		format.wBitsPerSample = 16;
Packit 1fb8d4
		test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format);
Packit 1fb8d4
		if (!test)
Packit 1fb8d4
		{
Packit 1fb8d4
			size_t x;
Packit 1fb8d4
			for (x=0; x
Packit 1fb8d4
			{
Packit 1fb8d4
				format.nSamplesPerSec = samplerates[x];
Packit 1fb8d4
				test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format);
Packit 1fb8d4
				if (test)
Packit 1fb8d4
					break;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		if (!test)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	IFCALLRET(audin->device->SetFormat, error,
Packit 1fb8d4
	          audin->device, &format,
Packit 1fb8d4
	          audin->FramesPerPacket);
Packit 1fb8d4
Packit 1fb8d4
	if (error != CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!supported)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	IFCALLRET(audin->device->Open, error, audin->device,
Packit 1fb8d4
	          audin_receive_wave_data, callback);
Packit 1fb8d4
Packit 1fb8d4
	if (error != CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 initialFormat;
Packit 1fb8d4
	UINT32 FramesPerPacket;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 8)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, FramesPerPacket);
Packit 1fb8d4
	Stream_Read_UINT32(s, initialFormat);
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_DEBUG, "FramesPerPacket=%"PRIu32" initialFormat=%"PRIu32"",
Packit 1fb8d4
	           FramesPerPacket, initialFormat);
Packit 1fb8d4
	audin->FramesPerPacket = FramesPerPacket;
Packit 1fb8d4
Packit 1fb8d4
	if (initialFormat >= callback->formats_count)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)",
Packit 1fb8d4
		           initialFormat, callback->formats_count);
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	audin->format = &callback->formats[initialFormat];
Packit 1fb8d4
Packit 1fb8d4
	if (!audin_open_device(audin, callback))
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
Packit 1fb8d4
	if ((error = audin_send_format_change_pdu(audin, callback, initialFormat)))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "audin_send_format_change_pdu failed!");
Packit 1fb8d4
		return error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((error = audin_send_open_reply_pdu(audin, callback, 0)))
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "audin_send_open_reply_pdu failed!");
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback,
Packit 1fb8d4
                                        wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 NewFormat;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, NewFormat);
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_DEBUG, "NewFormat=%"PRIu32"", NewFormat);
Packit 1fb8d4
Packit 1fb8d4
	if (NewFormat >= callback->formats_count)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)",
Packit 1fb8d4
		           NewFormat, callback->formats_count);
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	audin->format = &callback->formats[NewFormat];
Packit 1fb8d4
Packit 1fb8d4
	if (audin->device)
Packit 1fb8d4
	{
Packit 1fb8d4
		IFCALLRET(audin->device->Close, error, audin->device);
Packit 1fb8d4
Packit 1fb8d4
		if (error != CHANNEL_RC_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error);
Packit 1fb8d4
			return error;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!audin_open_device(audin, callback))
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
Packit 1fb8d4
	if ((error = audin_send_format_change_pdu(audin, callback, NewFormat)))
Packit 1fb8d4
		WLog_ERR(TAG, "audin_send_format_change_pdu failed!");
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
	BYTE MessageId;
Packit 1fb8d4
	AUDIN_PLUGIN* audin;
Packit 1fb8d4
	AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
Packit 1fb8d4
Packit 1fb8d4
	if (!callback || !data)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	audin = (AUDIN_PLUGIN*) callback->plugin;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin)
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingCapacity(data) < 1)
Packit 1fb8d4
		return ERROR_NO_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(data, MessageId);
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_DEBUG, "MessageId=0x%02"PRIx8"", MessageId);
Packit 1fb8d4
Packit 1fb8d4
	switch (MessageId)
Packit 1fb8d4
	{
Packit 1fb8d4
		case MSG_SNDIN_VERSION:
Packit 1fb8d4
			error = audin_process_version(audin, callback, data);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case MSG_SNDIN_FORMATS:
Packit 1fb8d4
			error = audin_process_formats(audin, callback, data);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case MSG_SNDIN_OPEN:
Packit 1fb8d4
			error = audin_process_open(audin, callback, data);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case MSG_SNDIN_FORMATCHANGE:
Packit 1fb8d4
			error = audin_process_format_change(audin, callback, data);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			WLog_Print(audin->log, WLOG_ERROR, "unknown MessageId=0x%02"PRIx8"", MessageId);
Packit 1fb8d4
			error = ERROR_INVALID_DATA;
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
Packit 1fb8d4
{
Packit 1fb8d4
	AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
Packit 1fb8d4
	AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_TRACE, "...");
Packit 1fb8d4
Packit 1fb8d4
	if (audin->device)
Packit 1fb8d4
	{
Packit 1fb8d4
		IFCALLRET(audin->device->Close, error, audin->device);
Packit 1fb8d4
Packit 1fb8d4
		if (error != CHANNEL_RC_OK)
Packit 1fb8d4
			WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	audin->format = NULL;
Packit 1fb8d4
	audio_formats_free(callback->formats, callback->formats_count);
Packit 1fb8d4
	free(callback);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
Packit 1fb8d4
        IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
Packit 1fb8d4
        IWTSVirtualChannelCallback** ppCallback)
Packit 1fb8d4
{
Packit 1fb8d4
	AUDIN_CHANNEL_CALLBACK* callback;
Packit 1fb8d4
	AUDIN_PLUGIN* audin;
Packit 1fb8d4
	AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback;
Packit 1fb8d4
Packit 1fb8d4
	if (!listener_callback || !listener_callback->plugin)
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
Packit 1fb8d4
	audin = (AUDIN_PLUGIN*) listener_callback->plugin;
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_TRACE, "...");
Packit 1fb8d4
	callback = (AUDIN_CHANNEL_CALLBACK*) calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK));
Packit 1fb8d4
Packit 1fb8d4
	if (!callback)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "calloc failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	callback->iface.OnDataReceived = audin_on_data_received;
Packit 1fb8d4
	callback->iface.OnClose = audin_on_close;
Packit 1fb8d4
	callback->plugin = listener_callback->plugin;
Packit 1fb8d4
	callback->channel_mgr = listener_callback->channel_mgr;
Packit 1fb8d4
	callback->channel = pChannel;
Packit 1fb8d4
	*ppCallback = (IWTSVirtualChannelCallback*) callback;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
Packit 1fb8d4
{
Packit 1fb8d4
	AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin)
Packit 1fb8d4
		return CHANNEL_RC_BAD_CHANNEL_HANDLE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pChannelMgr)
Packit 1fb8d4
		return ERROR_INVALID_PARAMETER;
Packit 1fb8d4
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_TRACE, "...");
Packit 1fb8d4
	audin->listener_callback = (AUDIN_LISTENER_CALLBACK*) calloc(1, sizeof(AUDIN_LISTENER_CALLBACK));
Packit 1fb8d4
Packit 1fb8d4
	if (!audin->listener_callback)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "calloc failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	audin->listener_callback->iface.OnNewChannelConnection = audin_on_new_channel_connection;
Packit 1fb8d4
	audin->listener_callback->plugin = pPlugin;
Packit 1fb8d4
	audin->listener_callback->channel_mgr = pChannelMgr;
Packit 1fb8d4
	return pChannelMgr->CreateListener(pChannelMgr, "AUDIO_INPUT", 0,
Packit 1fb8d4
	                                   (IWTSListenerCallback*) audin->listener_callback, NULL);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_plugin_terminated(IWTSPlugin* pPlugin)
Packit 1fb8d4
{
Packit 1fb8d4
	AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin)
Packit 1fb8d4
		return CHANNEL_RC_BAD_CHANNEL_HANDLE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_TRACE, "...");
Packit 1fb8d4
	audio_format_free(audin->fixed_format);
Packit 1fb8d4
Packit 1fb8d4
	if (audin->device)
Packit 1fb8d4
	{
Packit 1fb8d4
		IFCALLRET(audin->device->Free, error, audin->device);
Packit 1fb8d4
Packit 1fb8d4
		if (error != CHANNEL_RC_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_Print(audin->log, WLOG_ERROR, "Free failed with errorcode %"PRIu32"", error);
Packit 1fb8d4
			// dont stop on error
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		audin->device = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	freerdp_dsp_context_free(audin->dsp_context);
Packit 1fb8d4
	Stream_Free(audin->data, TRUE);
Packit 1fb8d4
	free(audin->subsystem);
Packit 1fb8d4
	free(audin->device_name);
Packit 1fb8d4
	free(audin->listener_callback);
Packit 1fb8d4
	free(audin);
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static UINT audin_plugin_attached(IWTSPlugin* pPlugin)
Packit 1fb8d4
{
Packit 1fb8d4
	AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin)
Packit 1fb8d4
		return CHANNEL_RC_BAD_CHANNEL_HANDLE;
Packit 1fb8d4
Packit 1fb8d4
	audin->attached = TRUE;
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static UINT audin_plugin_detached(IWTSPlugin* pPlugin)
Packit 1fb8d4
{
Packit 1fb8d4
	AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin)
Packit 1fb8d4
		return CHANNEL_RC_BAD_CHANNEL_HANDLE;
Packit 1fb8d4
Packit 1fb8d4
	audin->attached = FALSE;
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* device)
Packit 1fb8d4
{
Packit 1fb8d4
	AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
Packit 1fb8d4
Packit 1fb8d4
	if (audin->device)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "existing device, abort.");
Packit 1fb8d4
		return ERROR_ALREADY_EXISTS;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_DEBUG, "device registered.");
Packit 1fb8d4
	audin->device = device;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_load_device_plugin(AUDIN_PLUGIN* audin, char* name, ADDIN_ARGV* args)
Packit 1fb8d4
{
Packit 1fb8d4
	PFREERDP_AUDIN_DEVICE_ENTRY entry;
Packit 1fb8d4
	FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints;
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
	entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL,
Packit 1fb8d4
	        0);
Packit 1fb8d4
Packit 1fb8d4
	if (entry == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR,
Packit 1fb8d4
		           "freerdp_load_channel_addin_entry did not return any function pointers for %s ",
Packit 1fb8d4
		           name);
Packit 1fb8d4
		return ERROR_INVALID_FUNCTION;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	entryPoints.plugin = (IWTSPlugin*) audin;
Packit 1fb8d4
	entryPoints.pRegisterAudinDevice = audin_register_device_plugin;
Packit 1fb8d4
	entryPoints.args = args;
Packit 1fb8d4
	entryPoints.rdpcontext = audin->rdpcontext;
Packit 1fb8d4
Packit 1fb8d4
	if ((error = entry(&entryPoints)))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "%s entry returned error %"PRIu32".", name, error);
Packit 1fb8d4
		return error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_Print(audin->log, WLOG_INFO, "Loaded %s backend for audin", name);
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_set_subsystem(AUDIN_PLUGIN* audin, const char* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	free(audin->subsystem);
Packit 1fb8d4
	audin->subsystem = _strdup(subsystem);
Packit 1fb8d4
Packit 1fb8d4
	if (!audin->subsystem)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "_strdup failed!");
Packit 1fb8d4
		return ERROR_NOT_ENOUGH_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT audin_set_device_name(AUDIN_PLUGIN* audin, const char* device_name)
Packit 1fb8d4
{
Packit 1fb8d4
	free(audin->device_name);
Packit 1fb8d4
	audin->device_name = _strdup(device_name);
Packit 1fb8d4
Packit 1fb8d4
	if (!audin->device_name)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "_strdup failed!");
Packit 1fb8d4
		return ERROR_NOT_ENOUGH_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static COMMAND_LINE_ARGUMENT_A audin_args[] =
Packit 1fb8d4
{
Packit 1fb8d4
	{ "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
Packit 1fb8d4
	{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
Packit 1fb8d4
	{ "format", COMMAND_LINE_VALUE_REQUIRED, "<format>", NULL, NULL, -1, NULL, "format" },
Packit 1fb8d4
	{ "rate", COMMAND_LINE_VALUE_REQUIRED, "<rate>", NULL, NULL, -1, NULL, "rate" },
Packit 1fb8d4
	{ "channel", COMMAND_LINE_VALUE_REQUIRED, "<channel>", NULL, NULL, -1, NULL, "channel" },
Packit 1fb8d4
	{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	DWORD flags;
Packit 1fb8d4
	COMMAND_LINE_ARGUMENT_A* arg;
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
Packit 1fb8d4
	if (!args || args->argc == 1)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
Packit 1fb8d4
	status = CommandLineParseArgumentsA(args->argc, args->argv,
Packit 1fb8d4
	                                    audin_args, flags, audin, NULL, NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (status != 0)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	arg = audin_args;
Packit 1fb8d4
	errno = 0;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
		CommandLineSwitchStart(arg)
Packit 1fb8d4
		CommandLineSwitchCase(arg, "sys")
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((error = audin_set_subsystem(audin, arg->Value)))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem failed with error %"PRIu32"!", error);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "dev")
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((error = audin_set_device_name(audin, arg->Value)))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name failed with error %"PRIu32"!", error);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "format")
Packit 1fb8d4
		{
Packit 1fb8d4
			unsigned long val = strtoul(arg->Value, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if ((errno != 0) || (val > UINT16_MAX))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			audin->fixed_format->wFormatTag = val;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "rate")
Packit 1fb8d4
		{
Packit 1fb8d4
			long val = strtol(arg->Value, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			audin->fixed_format->nSamplesPerSec = val;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "channel")
Packit 1fb8d4
		{
Packit 1fb8d4
			unsigned long val = strtoul(arg->Value, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if ((errno != 0) || (val > UINT16_MAX))
Packit 1fb8d4
				audin->fixed_format->nChannels = val;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchDefault(arg)
Packit 1fb8d4
		{
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchEnd(arg)
Packit 1fb8d4
	}
Packit 1fb8d4
	while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#ifdef BUILTIN_CHANNELS
Packit 1fb8d4
#define DVCPluginEntry		audin_DVCPluginEntry
Packit 1fb8d4
#else
Packit 1fb8d4
#define DVCPluginEntry		FREERDP_API DVCPluginEntry
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
Packit 1fb8d4
{
Packit 1fb8d4
	struct SubsystemEntry
Packit 1fb8d4
	{
Packit 1fb8d4
		char* subsystem;
Packit 1fb8d4
		char* device;
Packit 1fb8d4
	};
Packit 1fb8d4
	UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
Packit 1fb8d4
	ADDIN_ARGV* args;
Packit 1fb8d4
	AUDIN_PLUGIN* audin;
Packit 1fb8d4
	struct SubsystemEntry entries[] =
Packit 1fb8d4
	{
Packit 1fb8d4
#if defined(WITH_PULSE)
Packit 1fb8d4
		{"pulse", ""},
Packit 1fb8d4
#endif
Packit 1fb8d4
#if defined(WITH_OSS)
Packit 1fb8d4
		{"oss", "default"},
Packit 1fb8d4
#endif
Packit 1fb8d4
#if defined(WITH_ALSA)
Packit 1fb8d4
		{"alsa", "default"},
Packit 1fb8d4
#endif
Packit 1fb8d4
#if defined(WITH_OPENSLES)
Packit 1fb8d4
		{"opensles", "default"},
Packit 1fb8d4
#endif
Packit 1fb8d4
#if defined(WITH_WINMM)
Packit 1fb8d4
		{"winmm", "default"},
Packit 1fb8d4
#endif
Packit 1fb8d4
#if defined(WITH_MACAUDIO)
Packit 1fb8d4
		{"mac", "default"},
Packit 1fb8d4
#endif
Packit 1fb8d4
		{NULL, NULL}
Packit 1fb8d4
	};
Packit 1fb8d4
	struct SubsystemEntry* entry = &entries[0];
Packit 1fb8d4
	assert(pEntryPoints);
Packit 1fb8d4
	assert(pEntryPoints->GetPlugin);
Packit 1fb8d4
	audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin");
Packit 1fb8d4
Packit 1fb8d4
	if (audin != NULL)
Packit 1fb8d4
		return CHANNEL_RC_ALREADY_INITIALIZED;
Packit 1fb8d4
Packit 1fb8d4
	audin = (AUDIN_PLUGIN*) calloc(1, sizeof(AUDIN_PLUGIN));
Packit 1fb8d4
Packit 1fb8d4
	if (!audin)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	audin->log = WLog_Get(TAG);
Packit 1fb8d4
	audin->data = Stream_New(NULL, 4096);
Packit 1fb8d4
	audin->fixed_format = audio_format_new();
Packit 1fb8d4
Packit 1fb8d4
	if (!audin->fixed_format)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	if (!audin->data)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	audin->dsp_context = freerdp_dsp_context_new(TRUE);
Packit 1fb8d4
Packit 1fb8d4
	if (!audin->dsp_context)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	audin->attached = TRUE;
Packit 1fb8d4
	audin->iface.Initialize = audin_plugin_initialize;
Packit 1fb8d4
	audin->iface.Connected = NULL;
Packit 1fb8d4
	audin->iface.Disconnected = NULL;
Packit 1fb8d4
	audin->iface.Terminated = audin_plugin_terminated;
Packit 1fb8d4
	audin->iface.Attached = audin_plugin_attached;
Packit 1fb8d4
	audin->iface.Detached = audin_plugin_detached;
Packit 1fb8d4
	args = pEntryPoints->GetPluginData(pEntryPoints);
Packit 1fb8d4
	audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(
Packit 1fb8d4
	                                    pEntryPoints))->instance)->context;
Packit 1fb8d4
Packit 1fb8d4
	if (args)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!audin_process_addin_args(audin, args))
Packit 1fb8d4
			goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (audin->subsystem)
Packit 1fb8d4
	{
Packit 1fb8d4
		if ((error = audin_load_device_plugin(audin, audin->subsystem, args)))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!",
Packit 1fb8d4
			           audin->subsystem, error);
Packit 1fb8d4
			goto out;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		while (entry && entry->subsystem && !audin->device)
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((error = audin_set_subsystem(audin, entry->subsystem)))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem for %s failed with error %"PRIu32"!",
Packit 1fb8d4
				           entry->subsystem, error);
Packit 1fb8d4
			}
Packit 1fb8d4
			else if ((error = audin_set_device_name(audin, entry->device)))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name for %s failed with error %"PRIu32"!",
Packit 1fb8d4
				           entry->subsystem, error);
Packit 1fb8d4
			}
Packit 1fb8d4
			else if ((error = audin_load_device_plugin(audin, audin->subsystem, args)))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!",
Packit 1fb8d4
				           entry->subsystem, error);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			entry++;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (audin->device == NULL)
Packit 1fb8d4
		WLog_Print(audin->log, WLOG_ERROR, "no sound device.");
Packit 1fb8d4
Packit 1fb8d4
	error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin);
Packit 1fb8d4
out:
Packit 1fb8d4
Packit 1fb8d4
	if (error != CHANNEL_RC_OK)
Packit 1fb8d4
		audin_plugin_terminated((IWTSPlugin*)audin);
Packit 1fb8d4
Packit 1fb8d4
	return error;
Packit 1fb8d4
}