|
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 |
}
|