Blame channels/audin/client/winmm/audin_winmm.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * Audio Input Redirection Virtual Channel - WinMM implementation
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2013 Zhang Zhaolong <zhangzl2013@126.com>
Packit Service fa4841
 * Copyright 2015 Thincast Technologies GmbH
Packit Service fa4841
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <stdio.h>
Packit Service fa4841
#include <stdlib.h>
Packit Service fa4841
#include <string.h>
Packit Service fa4841
Packit Service b1ea74
#include <windows.h>
Packit Service b1ea74
#include <mmsystem.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/cmdline.h>
Packit Service fa4841
#include <freerdp/addin.h>
Packit Service fa4841
#include <freerdp/client/audin.h>
Packit Service fa4841
Packit Service fa4841
#include "audin_main.h"
Packit Service fa4841
Packit Service fa4841
typedef struct _AudinWinmmDevice
Packit Service fa4841
{
Packit Service fa4841
	IAudinDevice iface;
Packit Service fa4841
Packit Service fa4841
	char* device_name;
Packit Service fa4841
	AudinReceive receive;
Packit Service fa4841
	void* user_data;
Packit Service fa4841
	HANDLE thread;
Packit Service fa4841
	HANDLE stopEvent;
Packit Service fa4841
	HWAVEIN hWaveIn;
Packit Service fa4841
	PWAVEFORMATEX* ppwfx;
Packit Service fa4841
	PWAVEFORMATEX pwfx_cur;
Packit Service fa4841
	UINT32 ppwfx_size;
Packit Service fa4841
	UINT32 cFormats;
Packit Service fa4841
	UINT32 frames_per_packet;
Packit Service fa4841
	rdpContext* rdpcontext;
Packit Service fa4841
	wLog* log;
Packit Service fa4841
} AudinWinmmDevice;
Packit Service fa4841
Packit Service fa4841
static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance,
Packit Service fa4841
                                DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Packit Service fa4841
{
Packit Service b1ea74
	AudinWinmmDevice* winmm = (AudinWinmmDevice*)dwInstance;
Packit Service fa4841
	PWAVEHDR pWaveHdr;
Packit Service fa4841
	UINT error = CHANNEL_RC_OK;
Packit Service fa4841
	MMRESULT mmResult;
Packit Service fa4841
Packit Service fa4841
	switch (uMsg)
Packit Service fa4841
	{
Packit Service fa4841
		case WIM_CLOSE:
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case WIM_DATA:
Packit Service fa4841
			pWaveHdr = (WAVEHDR*)dwParam1;
Packit Service fa4841
Packit Service fa4841
			if (WHDR_DONE == (WHDR_DONE & pWaveHdr->dwFlags))
Packit Service fa4841
			{
Packit Service b1ea74
				if (pWaveHdr->dwBytesRecorded &&
Packit Service b1ea74
				    !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0))
Packit Service fa4841
				{
Packit Service fa4841
					AUDIO_FORMAT format;
Packit Service fa4841
					format.cbSize = winmm->pwfx_cur->cbSize;
Packit Service fa4841
					format.nBlockAlign = winmm->pwfx_cur->nBlockAlign;
Packit Service fa4841
					format.nAvgBytesPerSec = winmm->pwfx_cur->nAvgBytesPerSec;
Packit Service fa4841
					format.nChannels = winmm->pwfx_cur->nChannels;
Packit Service fa4841
					format.nSamplesPerSec = winmm->pwfx_cur->nSamplesPerSec;
Packit Service fa4841
					format.wBitsPerSample = winmm->pwfx_cur->wBitsPerSample;
Packit Service fa4841
					format.wFormatTag = winmm->pwfx_cur->wFormatTag;
Packit Service fa4841
Packit Service b1ea74
					if ((error = winmm->receive(&format, pWaveHdr->lpData,
Packit Service b1ea74
					                            pWaveHdr->dwBytesRecorded, winmm->user_data)))
Packit Service fa4841
						break;
Packit Service fa4841
Packit Service fa4841
					mmResult = waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR));
Packit Service fa4841
Packit Service fa4841
					if (mmResult != MMSYSERR_NOERROR)
Packit Service fa4841
						error = ERROR_INTERNAL_ERROR;
Packit Service fa4841
				}
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case WIM_OPEN:
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (error && winmm->rdpcontext)
Packit Service fa4841
		setChannelError(winmm->rdpcontext, error, "waveInProc reported an error");
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
Packit Service fa4841
{
Packit Service b1ea74
	AudinWinmmDevice* winmm = (AudinWinmmDevice*)arg;
Packit Service fa4841
	char* buffer;
Packit Service fa4841
	int size, i;
Packit Service fa4841
	WAVEHDR waveHdr[4];
Packit Service fa4841
	DWORD status;
Packit Service fa4841
	MMRESULT rc;
Packit Service fa4841
Packit Service fa4841
	if (!winmm->hWaveIn)
Packit Service fa4841
	{
Packit Service fa4841
		if (MMSYSERR_NOERROR != waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur,
Packit Service b1ea74
		                                   (DWORD_PTR)waveInProc, (DWORD_PTR)winmm,
Packit Service b1ea74
		                                   CALLBACK_FUNCTION))
Packit Service fa4841
		{
Packit Service fa4841
			if (winmm->rdpcontext)
Packit Service fa4841
				setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
Packit Service fa4841
				                "audin_winmm_thread_func reported an error");
Packit Service fa4841
Packit Service fa4841
			return ERROR_INTERNAL_ERROR;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	size =
Packit Service b1ea74
	    (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet +
Packit Service b1ea74
	     7) /
Packit Service b1ea74
	    8;
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < 4; i++)
Packit Service fa4841
	{
Packit Service b1ea74
		buffer = (char*)malloc(size);
Packit Service fa4841
Packit Service fa4841
		if (!buffer)
Packit Service fa4841
			return CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
Packit Service fa4841
		waveHdr[i].dwBufferLength = size;
Packit Service fa4841
		waveHdr[i].dwFlags = 0;
Packit Service fa4841
		waveHdr[i].lpData = buffer;
Packit Service fa4841
		rc = waveInPrepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
Packit Service fa4841
Packit Service fa4841
		if (MMSYSERR_NOERROR != rc)
Packit Service fa4841
		{
Packit Service b1ea74
			WLog_Print(winmm->log, WLOG_DEBUG, "waveInPrepareHeader failed. %" PRIu32 "", rc);
Packit Service fa4841
Packit Service fa4841
			if (winmm->rdpcontext)
Packit Service fa4841
				setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
Packit Service fa4841
				                "audin_winmm_thread_func reported an error");
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		rc = waveInAddBuffer(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
Packit Service fa4841
Packit Service fa4841
		if (MMSYSERR_NOERROR != rc)
Packit Service fa4841
		{
Packit Service b1ea74
			WLog_Print(winmm->log, WLOG_DEBUG, "waveInAddBuffer failed. %" PRIu32 "", rc);
Packit Service fa4841
Packit Service fa4841
			if (winmm->rdpcontext)
Packit Service fa4841
				setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
Packit Service fa4841
				                "audin_winmm_thread_func reported an error");
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	rc = waveInStart(winmm->hWaveIn);
Packit Service fa4841
Packit Service fa4841
	if (MMSYSERR_NOERROR != rc)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_Print(winmm->log, WLOG_DEBUG, "waveInStart failed. %" PRIu32 "", rc);
Packit Service fa4841
Packit Service fa4841
		if (winmm->rdpcontext)
Packit Service fa4841
			setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
Packit Service fa4841
			                "audin_winmm_thread_func reported an error");
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	status = WaitForSingleObject(winmm->stopEvent, INFINITE);
Packit Service fa4841
Packit Service fa4841
	if (status == WAIT_FAILED)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_Print(winmm->log, WLOG_DEBUG, "WaitForSingleObject failed.");
Packit Service fa4841
Packit Service fa4841
		if (winmm->rdpcontext)
Packit Service fa4841
			setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
Packit Service fa4841
			                "audin_winmm_thread_func reported an error");
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	rc = waveInReset(winmm->hWaveIn);
Packit Service fa4841
Packit Service fa4841
	if (MMSYSERR_NOERROR != rc)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_Print(winmm->log, WLOG_DEBUG, "waveInReset failed. %" PRIu32 "", rc);
Packit Service fa4841
Packit Service fa4841
		if (winmm->rdpcontext)
Packit Service fa4841
			setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
Packit Service fa4841
			                "audin_winmm_thread_func reported an error");
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < 4; i++)
Packit Service fa4841
	{
Packit Service fa4841
		rc = waveInUnprepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
Packit Service fa4841
Packit Service fa4841
		if (MMSYSERR_NOERROR != rc)
Packit Service fa4841
		{
Packit Service b1ea74
			WLog_Print(winmm->log, WLOG_DEBUG, "waveInUnprepareHeader failed. %" PRIu32 "", rc);
Packit Service fa4841
Packit Service fa4841
			if (winmm->rdpcontext)
Packit Service fa4841
				setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
Packit Service fa4841
				                "audin_winmm_thread_func reported an error");
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		free(waveHdr[i].lpData);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	rc = waveInClose(winmm->hWaveIn);
Packit Service fa4841
Packit Service fa4841
	if (MMSYSERR_NOERROR != rc)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_Print(winmm->log, WLOG_DEBUG, "waveInClose failed. %" PRIu32 "", rc);
Packit Service fa4841
Packit Service fa4841
		if (winmm->rdpcontext)
Packit Service fa4841
			setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
Packit Service fa4841
			                "audin_winmm_thread_func reported an error");
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	winmm->hWaveIn = NULL;
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT audin_winmm_free(IAudinDevice* device)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service b1ea74
	AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
Packit Service fa4841
Packit Service fa4841
	if (!winmm)
Packit Service fa4841
		return ERROR_INVALID_PARAMETER;
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < winmm->cFormats; i++)
Packit Service fa4841
	{
Packit Service fa4841
		free(winmm->ppwfx[i]);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(winmm->ppwfx);
Packit Service fa4841
	free(winmm->device_name);
Packit Service fa4841
	free(winmm);
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT audin_winmm_close(IAudinDevice* device)
Packit Service fa4841
{
Packit Service fa4841
	DWORD status;
Packit Service fa4841
	UINT error = CHANNEL_RC_OK;
Packit Service b1ea74
	AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
Packit Service fa4841
Packit Service fa4841
	if (!winmm)
Packit Service fa4841
		return ERROR_INVALID_PARAMETER;
Packit Service fa4841
Packit Service fa4841
	SetEvent(winmm->stopEvent);
Packit Service fa4841
	status = WaitForSingleObject(winmm->thread, INFINITE);
Packit Service fa4841
Packit Service fa4841
	if (status == WAIT_FAILED)
Packit Service fa4841
	{
Packit Service fa4841
		error = GetLastError();
Packit Service b1ea74
		WLog_Print(winmm->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!",
Packit Service b1ea74
		           error);
Packit Service fa4841
		return error;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	CloseHandle(winmm->thread);
Packit Service fa4841
	CloseHandle(winmm->stopEvent);
Packit Service fa4841
	winmm->thread = NULL;
Packit Service fa4841
	winmm->stopEvent = NULL;
Packit Service fa4841
	winmm->receive = NULL;
Packit Service fa4841
	winmm->user_data = NULL;
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* format,
Packit Service fa4841
                                   UINT32 FramesPerPacket)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service b1ea74
	AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
Packit Service fa4841
Packit Service fa4841
	if (!winmm || !format)
Packit Service fa4841
		return ERROR_INVALID_PARAMETER;
Packit Service fa4841
Packit Service fa4841
	winmm->frames_per_packet = FramesPerPacket;
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < winmm->cFormats; i++)
Packit Service fa4841
	{
Packit Service b1ea74
		if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag &&
Packit Service b1ea74
		    winmm->ppwfx[i]->nChannels == format->nChannels &&
Packit Service b1ea74
		    winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample)
Packit Service fa4841
		{
Packit Service fa4841
			winmm->pwfx_cur = winmm->ppwfx[i];
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format)
Packit Service fa4841
{
Packit Service b1ea74
	AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
Packit Service fa4841
	PWAVEFORMATEX pwfx;
Packit Service fa4841
	BYTE* data;
Packit Service fa4841
Packit Service fa4841
	if (!winmm || !format)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	pwfx = (PWAVEFORMATEX)malloc(sizeof(WAVEFORMATEX) + format->cbSize);
Packit Service fa4841
Packit Service fa4841
	if (!pwfx)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	pwfx->cbSize = format->cbSize;
Packit Service fa4841
	pwfx->wFormatTag = format->wFormatTag;
Packit Service fa4841
	pwfx->nChannels = format->nChannels;
Packit Service fa4841
	pwfx->nSamplesPerSec = format->nSamplesPerSec;
Packit Service fa4841
	pwfx->nBlockAlign = format->nBlockAlign;
Packit Service fa4841
	pwfx->wBitsPerSample = format->wBitsPerSample;
Packit Service fa4841
	data = (BYTE*)pwfx + sizeof(WAVEFORMATEX);
Packit Service fa4841
	memcpy(data, format->data, format->cbSize);
Packit Service fa4841
Packit Service fa4841
	if (pwfx->wFormatTag == WAVE_FORMAT_PCM)
Packit Service fa4841
	{
Packit Service fa4841
		pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
Packit Service fa4841
Packit Service fa4841
		if (MMSYSERR_NOERROR == waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0, WAVE_FORMAT_QUERY))
Packit Service fa4841
		{
Packit Service fa4841
			if (winmm->cFormats >= winmm->ppwfx_size)
Packit Service fa4841
			{
Packit Service fa4841
				PWAVEFORMATEX* tmp_ppwfx;
Packit Service fa4841
				tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2);
Packit Service fa4841
Packit Service fa4841
				if (!tmp_ppwfx)
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				winmm->ppwfx_size *= 2;
Packit Service fa4841
				winmm->ppwfx = tmp_ppwfx;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			winmm->ppwfx[winmm->cFormats++] = pwfx;
Packit Service fa4841
			return TRUE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(pwfx);
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* user_data)
Packit Service fa4841
{
Packit Service b1ea74
	AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
Packit Service fa4841
Packit Service fa4841
	if (!winmm || !receive || !user_data)
Packit Service fa4841
		return ERROR_INVALID_PARAMETER;
Packit Service fa4841
Packit Service fa4841
	winmm->receive = receive;
Packit Service fa4841
	winmm->user_data = user_data;
Packit Service fa4841
Packit Service fa4841
	if (!(winmm->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_Print(winmm->log, WLOG_ERROR, "CreateEvent failed!");
Packit Service fa4841
		return ERROR_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	if (!(winmm->thread = CreateThread(NULL, 0, audin_winmm_thread_func, winmm, 0, NULL)))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_Print(winmm->log, WLOG_ERROR, "CreateThread failed!");
Packit Service fa4841
		CloseHandle(winmm->stopEvent);
Packit Service fa4841
		winmm->stopEvent = NULL;
Packit Service fa4841
		return ERROR_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* args)
Packit Service fa4841
{
Packit Service fa4841
	int status;
Packit Service fa4841
	DWORD flags;
Packit Service fa4841
	COMMAND_LINE_ARGUMENT_A* arg;
Packit Service b1ea74
	AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
Packit Service b1ea74
	COMMAND_LINE_ARGUMENT_A audin_winmm_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>",
Packit Service b1ea74
		                                             NULL, NULL, -1, NULL, "audio device name" },
Packit Service b1ea74
		                                           { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
Packit Service b1ea74
Packit Service b1ea74
	flags =
Packit Service b1ea74
	    COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
Packit Service b1ea74
	status = CommandLineParseArgumentsA(args->argc, args->argv, audin_winmm_args, flags, winmm,
Packit Service b1ea74
	                                    NULL, NULL);
Packit Service fa4841
	arg = audin_winmm_args;
Packit Service fa4841
Packit Service fa4841
	do
Packit Service fa4841
	{
Packit Service fa4841
		if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
Packit Service fa4841
			continue;
Packit Service fa4841
Packit Service b1ea74
		CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev")
Packit Service fa4841
		{
Packit Service fa4841
			winmm->device_name = _strdup(arg->Value);
Packit Service fa4841
Packit Service fa4841
			if (!winmm->device_name)
Packit Service fa4841
			{
Packit Service fa4841
				WLog_Print(winmm->log, WLOG_ERROR, "_strdup failed!");
Packit Service fa4841
				return CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
		CommandLineSwitchEnd(arg)
Packit Service b1ea74
	} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
Packit Service fa4841
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#ifdef BUILTIN_CHANNELS
Packit Service b1ea74
#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry
Packit Service fa4841
#else
Packit Service b1ea74
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
Packit Service fa4841
{
Packit Service fa4841
	ADDIN_ARGV* args;
Packit Service fa4841
	AudinWinmmDevice* winmm;
Packit Service fa4841
	UINT error;
Packit Service b1ea74
Packit Service b1ea74
	if (waveInGetNumDevs() == 0)
Packit Service b1ea74
	{
Packit Service b1ea74
		WLog_Print(WLog_Get(TAG), WLOG_ERROR, "No microphone available!");
Packit Service b1ea74
		return ERROR_DEVICE_NOT_AVAILABLE;
Packit Service b1ea74
	}
Packit Service b1ea74
Packit Service b1ea74
	winmm = (AudinWinmmDevice*)calloc(1, sizeof(AudinWinmmDevice));
Packit Service fa4841
Packit Service fa4841
	if (!winmm)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "calloc failed!");
Packit Service fa4841
		return CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	winmm->log = WLog_Get(TAG);
Packit Service fa4841
	winmm->iface.Open = audin_winmm_open;
Packit Service fa4841
	winmm->iface.FormatSupported = audin_winmm_format_supported;
Packit Service fa4841
	winmm->iface.SetFormat = audin_winmm_set_format;
Packit Service fa4841
	winmm->iface.Close = audin_winmm_close;
Packit Service fa4841
	winmm->iface.Free = audin_winmm_free;
Packit Service fa4841
	winmm->rdpcontext = pEntryPoints->rdpcontext;
Packit Service fa4841
	args = pEntryPoints->args;
Packit Service fa4841
Packit Service fa4841
	if ((error = audin_winmm_parse_addin_args(winmm, args)))
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_Print(winmm->log, WLOG_ERROR,
Packit Service b1ea74
		           "audin_winmm_parse_addin_args failed with error %" PRIu32 "!", error);
Packit Service fa4841
		goto error_out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!winmm->device_name)
Packit Service fa4841
	{
Packit Service fa4841
		winmm->device_name = _strdup("default");
Packit Service fa4841
Packit Service fa4841
		if (!winmm->device_name)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_Print(winmm->log, WLOG_ERROR, "_strdup failed!");
Packit Service fa4841
			error = CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
			goto error_out;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	winmm->ppwfx_size = 10;
Packit Service fa4841
	winmm->ppwfx = malloc(sizeof(PWAVEFORMATEX) * winmm->ppwfx_size);
Packit Service fa4841
Packit Service fa4841
	if (!winmm->ppwfx)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_Print(winmm->log, WLOG_ERROR, "malloc failed!");
Packit Service fa4841
		error = CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
		goto error_out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)winmm)))
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_Print(winmm->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!",
Packit Service b1ea74
		           error);
Packit Service fa4841
		goto error_out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
error_out:
Packit Service fa4841
	free(winmm->ppwfx);
Packit Service fa4841
	free(winmm->device_name);
Packit Service fa4841
	free(winmm);
Packit Service fa4841
	return error;
Packit Service fa4841
}