winmm: Implement waveIn* on top of MMDevAPI.
This commit is contained in:
parent
b3ab657c3b
commit
8cd5f12e6b
|
@ -89,6 +89,7 @@ typedef struct _WINMM_Device {
|
|||
IMMDevice *device;
|
||||
IAudioClient *client;
|
||||
IAudioRenderClient *render;
|
||||
IAudioCaptureClient *capture;
|
||||
IAudioClock *clock;
|
||||
IAudioStreamVolume *volume;
|
||||
|
||||
|
@ -150,6 +151,8 @@ typedef struct _WINMM_OpenInfo {
|
|||
|
||||
static LRESULT WOD_Open(WINMM_OpenInfo *info);
|
||||
static LRESULT WOD_Close(HWAVEOUT hwave);
|
||||
static LRESULT WID_Open(WINMM_OpenInfo *info);
|
||||
static LRESULT WID_Close(HWAVEIN hwave);
|
||||
|
||||
BOOL WINMM_InitWaveform(void)
|
||||
{
|
||||
|
@ -195,7 +198,7 @@ static WINMM_Device *WINMM_FindUnusedDevice(BOOL is_out, UINT mmdevice_index)
|
|||
if(is_out)
|
||||
mmdevice = &g_out_mmdevices[mmdevice_index];
|
||||
else
|
||||
return NULL;
|
||||
mmdevice = &g_in_mmdevices[mmdevice_index];
|
||||
|
||||
EnterCriticalSection(&mmdevice->lock);
|
||||
for(i = 0; i < MAX_DEVICES; ++i){
|
||||
|
@ -561,30 +564,53 @@ static MMRESULT WINMM_TryDeviceMapping(WINMM_OpenInfo *info, WORD channels,
|
|||
mr = acmStreamOpen(NULL, NULL, info->format, &target, NULL, 0,
|
||||
0, ACM_STREAMOPENF_QUERY);
|
||||
else
|
||||
return MMSYSERR_ERROR;
|
||||
mr = acmStreamOpen(NULL, NULL, &target, info->format, NULL, 0,
|
||||
0, ACM_STREAMOPENF_QUERY);
|
||||
if(mr != MMSYSERR_NOERROR)
|
||||
return mr;
|
||||
|
||||
/* ACM can convert from src->dst, so try to find a device
|
||||
* that supports dst */
|
||||
if(WINMM_IsMapper(info->req_device)){
|
||||
for(i = 0; i < g_outmmdevices_count; ++i){
|
||||
if(is_out){
|
||||
if(WINMM_IsMapper(info->req_device)){
|
||||
for(i = 0; i < g_outmmdevices_count; ++i){
|
||||
WINMM_OpenInfo l_info = *info;
|
||||
l_info.req_device = i;
|
||||
l_info.format = ⌖
|
||||
mr = WOD_Open(&l_info);
|
||||
if(mr == MMSYSERR_NOERROR){
|
||||
info->handle = l_info.handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
WINMM_OpenInfo l_info = *info;
|
||||
l_info.req_device = i;
|
||||
l_info.flags &= ~WAVE_MAPPED;
|
||||
l_info.format = ⌖
|
||||
mr = WOD_Open(&l_info);
|
||||
if(mr == MMSYSERR_NOERROR){
|
||||
if(mr == MMSYSERR_NOERROR)
|
||||
info->handle = l_info.handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
WINMM_OpenInfo l_info = *info;
|
||||
l_info.flags &= ~WAVE_MAPPED;
|
||||
l_info.format = ⌖
|
||||
mr = WOD_Open(&l_info);
|
||||
if(mr == MMSYSERR_NOERROR)
|
||||
info->handle = l_info.handle;
|
||||
if(WINMM_IsMapper(info->req_device)){
|
||||
for(i = 0; i < g_inmmdevices_count; ++i){
|
||||
WINMM_OpenInfo l_info = *info;
|
||||
l_info.req_device = i;
|
||||
l_info.format = ⌖
|
||||
mr = WID_Open(&l_info);
|
||||
if(mr == MMSYSERR_NOERROR){
|
||||
info->handle = l_info.handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
WINMM_OpenInfo l_info = *info;
|
||||
l_info.flags &= ~WAVE_MAPPED;
|
||||
l_info.format = ⌖
|
||||
mr = WID_Open(&l_info);
|
||||
if(mr == MMSYSERR_NOERROR)
|
||||
info->handle = l_info.handle;
|
||||
}
|
||||
}
|
||||
if(mr != MMSYSERR_NOERROR)
|
||||
return WAVERR_BADFORMAT;
|
||||
|
@ -594,10 +620,17 @@ static MMRESULT WINMM_TryDeviceMapping(WINMM_OpenInfo *info, WORD channels,
|
|||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
/* set up the ACM stream */
|
||||
mr = acmStreamOpen(&device->acm_handle, NULL, info->format, &target,
|
||||
NULL, 0, 0, 0);
|
||||
if(is_out)
|
||||
mr = acmStreamOpen(&device->acm_handle, NULL, info->format, &target,
|
||||
NULL, 0, 0, 0);
|
||||
else
|
||||
mr = acmStreamOpen(&device->acm_handle, NULL, &target, info->format,
|
||||
NULL, 0, 0, 0);
|
||||
if(mr != MMSYSERR_NOERROR){
|
||||
WOD_Close((HWAVEOUT)info->handle);
|
||||
if(is_out)
|
||||
WOD_Close((HWAVEOUT)info->handle);
|
||||
else
|
||||
WID_Close((HWAVEIN)info->handle);
|
||||
return mr;
|
||||
}
|
||||
|
||||
|
@ -633,8 +666,26 @@ static MMRESULT WINMM_MapDevice(WINMM_OpenInfo *info, BOOL is_out)
|
|||
return mr;
|
||||
}
|
||||
}
|
||||
}else
|
||||
return MMSYSERR_ERROR;
|
||||
}else{
|
||||
WINMM_OpenInfo l_info = *info;
|
||||
if(WINMM_IsMapper(info->req_device)){
|
||||
for(i = 0; i < g_inmmdevices_count; ++i){
|
||||
l_info.req_device = i;
|
||||
mr = WID_Open(&l_info);
|
||||
if(mr == MMSYSERR_NOERROR){
|
||||
info->handle = l_info.handle;
|
||||
return mr;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
l_info.flags &= ~WAVE_MAPPED;
|
||||
mr = WID_Open(&l_info);
|
||||
if(mr == MMSYSERR_NOERROR){
|
||||
info->handle = l_info.handle;
|
||||
return mr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* no direct match, so set up the ACM stream */
|
||||
if(info->format->wFormatTag != WAVE_FORMAT_PCM ||
|
||||
|
@ -959,6 +1010,73 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static LRESULT WID_Open(WINMM_OpenInfo *info)
|
||||
{
|
||||
WINMM_MMDevice *mmdevice;
|
||||
WINMM_Device *device = NULL;
|
||||
WINMM_CBInfo cb_info;
|
||||
LRESULT ret = MMSYSERR_ERROR;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%u, %p, %08x)\n", info->req_device, info, info->flags);
|
||||
|
||||
if(WINMM_IsMapper(info->req_device) || info->flags & WAVE_MAPPED)
|
||||
return WINMM_MapDevice(info, FALSE);
|
||||
|
||||
if(info->req_device >= g_inmmdevices_count)
|
||||
return MMSYSERR_BADDEVICEID;
|
||||
|
||||
mmdevice = &g_in_mmdevices[info->req_device];
|
||||
|
||||
if(!mmdevice->in_caps.szPname[0])
|
||||
return MMSYSERR_NOTENABLED;
|
||||
|
||||
device = WINMM_FindUnusedDevice(FALSE, info->req_device);
|
||||
if(!device)
|
||||
return MMSYSERR_ALLOCATED;
|
||||
|
||||
ret = WINMM_OpenDevice(device, mmdevice, info);
|
||||
if((info->flags & WAVE_FORMAT_QUERY) || ret != MMSYSERR_NOERROR)
|
||||
goto error;
|
||||
ret = MMSYSERR_ERROR;
|
||||
|
||||
hr = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
|
||||
(void**)&device->capture);
|
||||
if(FAILED(hr)){
|
||||
ERR("GetService failed: %08x\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(&cb_info, &device->cb_info, sizeof(cb_info));
|
||||
|
||||
LeaveCriticalSection(&device->lock);
|
||||
|
||||
WINMM_NotifyClient(&cb_info, WIM_OPEN, 0, 0);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
|
||||
error:
|
||||
if(device->device){
|
||||
IMMDevice_Release(device->device);
|
||||
device->device = NULL;
|
||||
}
|
||||
if(device->client){
|
||||
IAudioClient_Release(device->client);
|
||||
device->client = NULL;
|
||||
}
|
||||
if(device->capture){
|
||||
IAudioCaptureClient_Release(device->capture);
|
||||
device->capture = NULL;
|
||||
}
|
||||
if(device->clock){
|
||||
IAudioClock_Release(device->clock);
|
||||
device->clock = NULL;
|
||||
}
|
||||
device->open = FALSE;
|
||||
LeaveCriticalSection(&device->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT WINMM_CloseDevice(WINMM_Device *device)
|
||||
{
|
||||
device->open = FALSE;
|
||||
|
@ -1007,6 +1125,30 @@ static LRESULT WOD_Close(HWAVEOUT hwave)
|
|||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
static LRESULT WID_Close(HWAVEIN hwave)
|
||||
{
|
||||
WINMM_Device *device = WINMM_GetDeviceFromHWAVE((HWAVE)hwave);
|
||||
WINMM_CBInfo cb_info;
|
||||
|
||||
TRACE("(%p)\n", hwave);
|
||||
|
||||
if(!WINMM_ValidateAndLock(device))
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
WINMM_CloseDevice(device);
|
||||
|
||||
IAudioCaptureClient_Release(device->capture);
|
||||
device->capture = NULL;
|
||||
|
||||
memcpy(&cb_info, &device->cb_info, sizeof(cb_info));
|
||||
|
||||
LeaveCriticalSection(&device->lock);
|
||||
|
||||
WINMM_NotifyClient(&cb_info, WIM_CLOSE, 0, 0);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
static LRESULT WINMM_PrepareHeader(HWAVE hwave, WAVEHDR *header)
|
||||
{
|
||||
WINMM_Device *device = WINMM_GetDeviceFromHWAVE(hwave);
|
||||
|
@ -1305,6 +1447,186 @@ exit:
|
|||
}
|
||||
}
|
||||
|
||||
static void WID_PullACMData(WINMM_Device *device)
|
||||
{
|
||||
UINT32 packet, packet_bytes;
|
||||
DWORD flags;
|
||||
BYTE *data;
|
||||
WAVEHDR *queue;
|
||||
HRESULT hr;
|
||||
MMRESULT mr;
|
||||
|
||||
if(device->acm_hdr.cbDstLength == 0){
|
||||
hr = IAudioClient_GetCurrentPadding(device->client, &packet);
|
||||
if(FAILED(hr)){
|
||||
ERR("GetCurrentPadding failed: %08x\n", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
if(packet == 0)
|
||||
return;
|
||||
|
||||
hr = IAudioCaptureClient_GetBuffer(device->capture, &data, &packet,
|
||||
&flags, NULL, NULL);
|
||||
if(FAILED(hr)){
|
||||
ERR("GetBuffer failed: %08x\n", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
acmStreamSize(device->acm_handle, packet * device->bytes_per_frame,
|
||||
&packet_bytes, ACM_STREAMSIZEF_SOURCE);
|
||||
|
||||
device->acm_offs = 0;
|
||||
|
||||
device->acm_hdr.cbStruct = sizeof(device->acm_hdr);
|
||||
device->acm_hdr.fdwStatus = 0;
|
||||
device->acm_hdr.dwUser = 0;
|
||||
device->acm_hdr.pbSrc = data;
|
||||
device->acm_hdr.cbSrcLength = packet * device->bytes_per_frame;
|
||||
device->acm_hdr.cbSrcLengthUsed = 0;
|
||||
device->acm_hdr.dwSrcUser = 0;
|
||||
device->acm_hdr.pbDst = HeapAlloc(GetProcessHeap(), 0, packet_bytes);
|
||||
device->acm_hdr.cbDstLength = packet_bytes;
|
||||
device->acm_hdr.cbDstLengthUsed = 0;
|
||||
device->acm_hdr.dwDstUser = 0;
|
||||
|
||||
mr = acmStreamPrepareHeader(device->acm_handle, &device->acm_hdr, 0);
|
||||
if(mr != MMSYSERR_NOERROR){
|
||||
ERR("acmStreamPrepareHeader failed: %d\n", mr);
|
||||
return;
|
||||
}
|
||||
|
||||
mr = acmStreamConvert(device->acm_handle, &device->acm_hdr, 0);
|
||||
if(mr != MMSYSERR_NOERROR){
|
||||
ERR("acmStreamConvert failed: %d\n", mr);
|
||||
return;
|
||||
}
|
||||
|
||||
hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet);
|
||||
if(FAILED(hr))
|
||||
ERR("ReleaseBuffer failed: %08x\n", hr);
|
||||
}
|
||||
|
||||
queue = device->first;
|
||||
while(queue){
|
||||
UINT32 to_copy_bytes;
|
||||
|
||||
to_copy_bytes = min(queue->dwBufferLength - queue->dwBytesRecorded,
|
||||
device->acm_hdr.cbDstLengthUsed - device->acm_offs);
|
||||
|
||||
memcpy(queue->lpData + queue->dwBytesRecorded,
|
||||
device->acm_hdr.pbDst + device->acm_offs, to_copy_bytes);
|
||||
|
||||
queue->dwBytesRecorded += to_copy_bytes;
|
||||
device->acm_offs += to_copy_bytes;
|
||||
|
||||
if(queue->dwBufferLength - queue->dwBytesRecorded <
|
||||
device->bytes_per_frame){
|
||||
queue->dwFlags &= ~WHDR_INQUEUE;
|
||||
queue->dwFlags |= WHDR_DONE;
|
||||
device->first = queue = queue->lpNext;
|
||||
}
|
||||
|
||||
if(device->acm_offs >= device->acm_hdr.cbDstLengthUsed){
|
||||
acmStreamUnprepareHeader(device->acm_handle, &device->acm_hdr, 0);
|
||||
HeapFree(GetProcessHeap(), 0, device->acm_hdr.pbDst);
|
||||
device->acm_hdr.cbDstLength = 0;
|
||||
device->acm_hdr.cbDstLengthUsed = 0;
|
||||
|
||||
/* done with this ACM Header, so try to pull more data */
|
||||
WID_PullACMData(device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* out of WAVEHDRs to write into, so toss the rest of this packet */
|
||||
acmStreamUnprepareHeader(device->acm_handle, &device->acm_hdr, 0);
|
||||
HeapFree(GetProcessHeap(), 0, device->acm_hdr.pbDst);
|
||||
device->acm_hdr.cbDstLength = 0;
|
||||
device->acm_hdr.cbDstLengthUsed = 0;
|
||||
}
|
||||
|
||||
static void WID_PullData(WINMM_Device *device)
|
||||
{
|
||||
WINMM_CBInfo cb_info;
|
||||
WAVEHDR *queue, *first = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", device->handle);
|
||||
|
||||
EnterCriticalSection(&device->lock);
|
||||
|
||||
if(!device->device || !device->first)
|
||||
goto exit;
|
||||
|
||||
first = device->first;
|
||||
|
||||
if(device->acm_handle){
|
||||
WID_PullACMData(device);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while(device->first){
|
||||
BYTE *data;
|
||||
UINT32 pad, packet_len, packet;
|
||||
DWORD flags;
|
||||
|
||||
hr = IAudioClient_GetCurrentPadding(device->client, &pad);
|
||||
if(FAILED(hr)){
|
||||
ERR("GetCurrentPadding failed: %08x\n", hr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(pad == 0)
|
||||
goto exit;
|
||||
|
||||
hr = IAudioCaptureClient_GetBuffer(device->capture, &data, &packet,
|
||||
&flags, NULL, NULL);
|
||||
if(FAILED(hr)){
|
||||
ERR("GetBuffer failed: %08x\n", hr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
packet_len = packet;
|
||||
queue = device->first;
|
||||
while(queue && packet > 0){
|
||||
UINT32 to_copy_bytes;
|
||||
|
||||
to_copy_bytes = min(packet * device->bytes_per_frame,
|
||||
queue->dwBufferLength - queue->dwBytesRecorded);
|
||||
|
||||
memcpy(queue->lpData + queue->dwBytesRecorded, data,
|
||||
to_copy_bytes);
|
||||
|
||||
queue->dwBytesRecorded += to_copy_bytes;
|
||||
|
||||
if(queue->dwBufferLength - queue->dwBytesRecorded <
|
||||
device->bytes_per_frame){
|
||||
queue->dwFlags &= ~WHDR_INQUEUE;
|
||||
queue->dwFlags |= WHDR_DONE;
|
||||
device->first = queue = queue->lpNext;
|
||||
}
|
||||
|
||||
packet -= to_copy_bytes / device->bytes_per_frame;
|
||||
}
|
||||
|
||||
hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_len);
|
||||
if(FAILED(hr))
|
||||
ERR("ReleaseBuffer failed: %08x\n", hr);
|
||||
}
|
||||
|
||||
exit:
|
||||
memcpy(&cb_info, &device->cb_info, sizeof(cb_info));
|
||||
|
||||
LeaveCriticalSection(&device->lock);
|
||||
|
||||
while(first && (first->dwFlags & WHDR_DONE)){
|
||||
WAVEHDR *next = first->lpNext;
|
||||
WINMM_NotifyClient(&cb_info, WIM_DATA, (DWORD_PTR)first, 0);
|
||||
first = next;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT WINMM_BeginPlaying(WINMM_Device *device)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
@ -1377,7 +1699,10 @@ static LRESULT WINMM_Reset(HWAVE hwave)
|
|||
}
|
||||
device->stopped = TRUE;
|
||||
|
||||
first = WOD_MarkDoneHeaders(device);
|
||||
if(device->render)
|
||||
first = WOD_MarkDoneHeaders(device);
|
||||
else
|
||||
first = device->first;
|
||||
device->first = device->last = device->playing = NULL;
|
||||
device->ofs_bytes = 0;
|
||||
device->played_frames = 0;
|
||||
|
@ -1392,7 +1717,10 @@ static LRESULT WINMM_Reset(HWAVE hwave)
|
|||
WAVEHDR *next = first->lpNext;
|
||||
first->dwFlags &= ~WHDR_INQUEUE;
|
||||
first->dwFlags |= WHDR_DONE;
|
||||
WINMM_NotifyClient(&cb_info, WOM_DONE, (DWORD_PTR)first, 0);
|
||||
if(device->render)
|
||||
WINMM_NotifyClient(&cb_info, WOM_DONE, (DWORD_PTR)first, 0);
|
||||
else
|
||||
WINMM_NotifyClient(&cb_info, WIM_DATA, (DWORD_PTR)first, 0);
|
||||
first = next;
|
||||
}
|
||||
|
||||
|
@ -1463,6 +1791,10 @@ static LRESULT CALLBACK WINMM_DevicesMsgProc(HWND hwnd, UINT msg, WPARAM wparam,
|
|||
return WOD_Open((WINMM_OpenInfo*)wparam);
|
||||
case WODM_CLOSE:
|
||||
return WOD_Close((HWAVEOUT)wparam);
|
||||
case WIDM_OPEN:
|
||||
return WID_Open((WINMM_OpenInfo*)wparam);
|
||||
case WIDM_CLOSE:
|
||||
return WID_Close((HWAVEIN)wparam);
|
||||
}
|
||||
return DefWindowProcW(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
@ -1510,7 +1842,10 @@ static DWORD WINAPI WINMM_DevicesThreadProc(void *arg)
|
|||
ERR("Unexpected message: 0x%x\n", msg.message);
|
||||
}else if(wait < g_devhandle_count){
|
||||
WINMM_Device *device = g_handle_devices[wait - WAIT_OBJECT_0];
|
||||
WOD_PushData(device);
|
||||
if(device->render)
|
||||
WOD_PushData(device);
|
||||
else
|
||||
WID_PullData(device);
|
||||
}else
|
||||
ERR("Unexpected MsgWait result 0x%x, GLE: %d\n", wait,
|
||||
GetLastError());
|
||||
|
@ -2209,14 +2544,15 @@ static UINT WINMM_QueryInstanceID(UINT device, WCHAR *str, DWORD_PTR len,
|
|||
}
|
||||
|
||||
UINT WINMM_DRVMessage(UINT dev, UINT message, DWORD_PTR param1,
|
||||
DWORD_PTR param2)
|
||||
DWORD_PTR param2, BOOL is_out)
|
||||
{
|
||||
WINE_MLD *wmld;
|
||||
UINT type = is_out ? MMDRV_WAVEOUT : MMDRV_WAVEIN;
|
||||
|
||||
TRACE("(%u, %u, %ld, %ld)\n", dev, message, param1, param2);
|
||||
TRACE("(%u, %u, %ld, %ld, %d)\n", dev, message, param1, param2, is_out);
|
||||
|
||||
if((wmld = MMDRV_Get(ULongToHandle(dev), MMDRV_WAVEOUT, FALSE)) == NULL){
|
||||
if((wmld = MMDRV_Get(ULongToHandle(dev), MMDRV_WAVEOUT, TRUE)) != NULL)
|
||||
if((wmld = MMDRV_Get(ULongToHandle(dev), type, FALSE)) == NULL){
|
||||
if((wmld = MMDRV_Get(ULongToHandle(dev), type, TRUE)) != NULL)
|
||||
return MMDRV_PhysicalFeatures(wmld, message, param1, param2);
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
}
|
||||
|
@ -2274,7 +2610,7 @@ UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
|
|||
case DRV_QUERYDSOUNDIFACE:
|
||||
if(dwParam2 == DS_HW_ACCEL_FULL)
|
||||
return WINMM_DRVMessage(HandleToULong(hWaveOut), uMessage,
|
||||
dwParam1, 0);
|
||||
dwParam1, 0, TRUE);
|
||||
return WINMM_FillDSDriverDesc(HandleToULong(hWaveOut),
|
||||
(DSDRIVERDESC*)dwParam1, TRUE);
|
||||
}
|
||||
|
@ -2287,8 +2623,12 @@ UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
|
|||
*/
|
||||
UINT WINAPI waveInGetNumDevs(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
return 0;
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return 0;
|
||||
|
||||
TRACE("count: %u\n", g_inmmdevices_count);
|
||||
|
||||
return g_inmmdevices_count;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2296,11 +2636,40 @@ UINT WINAPI waveInGetNumDevs(void)
|
|||
*/
|
||||
UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
|
||||
{
|
||||
WAVEINCAPSW mapper_caps, *caps;
|
||||
|
||||
TRACE("(%lu, %p, %u)\n", uDeviceID, lpCaps, uSize);
|
||||
|
||||
if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
return MMSYSERR_BADDEVICEID;
|
||||
if(!lpCaps)
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
if(WINMM_IsMapper(uDeviceID)){
|
||||
/* FIXME: Should be localized */
|
||||
static const WCHAR mapper_pnameW[] = {'W','i','n','e',' ','S','o','u',
|
||||
'n','d',' ','M','a','p','p','e','r',0};
|
||||
|
||||
mapper_caps.wMid = 0xFF;
|
||||
mapper_caps.wPid = 0xFF;
|
||||
mapper_caps.vDriverVersion = 0x00010001;
|
||||
mapper_caps.dwFormats = 0xFFFFFFFF;
|
||||
mapper_caps.wReserved1 = 0;
|
||||
mapper_caps.wChannels = 2;
|
||||
lstrcpyW(mapper_caps.szPname, mapper_pnameW);
|
||||
|
||||
caps = &mapper_caps;
|
||||
}else{
|
||||
if(uDeviceID >= g_inmmdevices_count)
|
||||
return MMSYSERR_BADDEVICEID;
|
||||
|
||||
caps = &g_in_mmdevices[uDeviceID].in_caps;
|
||||
}
|
||||
|
||||
memcpy(lpCaps, caps, min(uSize, sizeof(*lpCaps)));
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2308,10 +2677,16 @@ UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSi
|
|||
*/
|
||||
UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
|
||||
{
|
||||
WAVEINCAPSW wicW;
|
||||
UINT ret;
|
||||
UINT ret;
|
||||
WAVEINCAPSW wicW;
|
||||
|
||||
if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
|
||||
TRACE("(%lu, %p, %u)\n", uDeviceID, lpCaps, uSize);
|
||||
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
if(!lpCaps)
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
ret = waveInGetDevCapsW(uDeviceID, &wicW, sizeof(wicW));
|
||||
|
||||
|
@ -2336,9 +2711,39 @@ MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
|
|||
LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
|
||||
DWORD_PTR dwInstance, DWORD dwFlags)
|
||||
{
|
||||
TRACE("(%p, %u, %p, %lx, %lx, %08x)\n", lphWaveIn, uDeviceID, lpFormat,
|
||||
LRESULT res;
|
||||
HRESULT hr;
|
||||
WINMM_OpenInfo info;
|
||||
|
||||
TRACE("(%p, %x, %p, %lx, %lx, %08x)\n", lphWaveIn, uDeviceID, lpFormat,
|
||||
dwCallback, dwInstance, dwFlags);
|
||||
return MMSYSERR_BADDEVICEID;
|
||||
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
if(!lphWaveIn && !(dwFlags & WAVE_FORMAT_QUERY))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
hr = WINMM_StartDevicesThread();
|
||||
if(FAILED(hr)){
|
||||
ERR("Couldn't start the device thread: %08x\n", hr);
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
|
||||
info.format = (WAVEFORMATEX*)lpFormat;
|
||||
info.callback = dwCallback;
|
||||
info.cb_user = dwInstance;
|
||||
info.req_device = uDeviceID;
|
||||
info.flags = dwFlags;
|
||||
|
||||
res = SendMessageW(g_devices_hwnd, WIDM_OPEN, (DWORD_PTR)&info, 0);
|
||||
if(res != MMSYSERR_NOERROR)
|
||||
return res;
|
||||
|
||||
if(lphWaveIn)
|
||||
*lphWaveIn = (HWAVEIN)info.handle;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2347,7 +2752,11 @@ MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
|
|||
UINT WINAPI waveInClose(HWAVEIN hWaveIn)
|
||||
{
|
||||
TRACE("(%p)\n", hWaveIn);
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
return SendMessageW(g_devices_hwnd, WIDM_CLOSE, (WPARAM)hWaveIn, 0);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2358,10 +2767,16 @@ UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
|
|||
{
|
||||
TRACE("(%p, %p, %u)\n", hWaveIn, lpWaveInHdr, uSize);
|
||||
|
||||
if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
if(!lpWaveInHdr || uSize < sizeof(WAVEHDR))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
if(lpWaveInHdr->dwFlags & WHDR_INQUEUE)
|
||||
return WAVERR_STILLPLAYING;
|
||||
|
||||
return WINMM_PrepareHeader((HWAVE)hWaveIn, lpWaveInHdr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2372,27 +2787,56 @@ UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
|
|||
{
|
||||
TRACE("(%p, %p, %u)\n", hWaveIn, lpWaveInHdr, uSize);
|
||||
|
||||
if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED))
|
||||
return MMSYSERR_NOERROR;
|
||||
if(!lpWaveInHdr || uSize < sizeof(WAVEHDR))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
if(!(lpWaveInHdr->dwFlags & WHDR_PREPARED))
|
||||
return MMSYSERR_NOERROR;
|
||||
|
||||
if(lpWaveInHdr->dwFlags & WHDR_INQUEUE)
|
||||
return WAVERR_STILLPLAYING;
|
||||
|
||||
return WINMM_UnprepareHeader((HWAVE)hWaveIn, lpWaveInHdr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* waveInAddBuffer [WINMM.@]
|
||||
*/
|
||||
UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
|
||||
WAVEHDR* lpWaveInHdr, UINT uSize)
|
||||
UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, WAVEHDR *header, UINT uSize)
|
||||
{
|
||||
TRACE("(%p, %p, %u)\n", hWaveIn, lpWaveInHdr, uSize);
|
||||
WINMM_Device *device;
|
||||
|
||||
if(!lpWaveInHdr)
|
||||
TRACE("(%p, %p, %u)\n", hWaveIn, header, uSize);
|
||||
|
||||
if(!header || uSize < sizeof(WAVEHDR))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
if(!(header->dwFlags & WHDR_PREPARED))
|
||||
return WAVERR_UNPREPARED;
|
||||
|
||||
device = WINMM_GetDeviceFromHWAVE((HWAVE)hWaveIn);
|
||||
|
||||
if(!WINMM_ValidateAndLock(device))
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
if(!device->first)
|
||||
device->first = device->last = header;
|
||||
else{
|
||||
device->last->lpNext = header;
|
||||
device->last = header;
|
||||
}
|
||||
|
||||
header->dwBytesRecorded = 0;
|
||||
header->lpNext = NULL;
|
||||
header->dwFlags &= ~WHDR_DONE;
|
||||
header->dwFlags |= WHDR_INQUEUE;
|
||||
|
||||
LeaveCriticalSection(&device->lock);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2401,7 +2845,11 @@ UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
|
|||
UINT WINAPI waveInReset(HWAVEIN hWaveIn)
|
||||
{
|
||||
TRACE("(%p)\n", hWaveIn);
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
return WINMM_Reset((HWAVE)hWaveIn);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2409,8 +2857,28 @@ UINT WINAPI waveInReset(HWAVEIN hWaveIn)
|
|||
*/
|
||||
UINT WINAPI waveInStart(HWAVEIN hWaveIn)
|
||||
{
|
||||
WINMM_Device *device;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", hWaveIn);
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
device = WINMM_GetDeviceFromHWAVE((HWAVE)hWaveIn);
|
||||
|
||||
if(!WINMM_ValidateAndLock(device))
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
hr = WINMM_BeginPlaying(device);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->lock);
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&device->lock);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2418,8 +2886,44 @@ UINT WINAPI waveInStart(HWAVEIN hWaveIn)
|
|||
*/
|
||||
UINT WINAPI waveInStop(HWAVEIN hWaveIn)
|
||||
{
|
||||
WINMM_CBInfo cb_info;
|
||||
WINMM_Device *device;
|
||||
WAVEHDR *buf;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", hWaveIn);
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
device = WINMM_GetDeviceFromHWAVE((HWAVE)hWaveIn);
|
||||
|
||||
if(!WINMM_ValidateAndLock(device))
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
hr = WINMM_Pause((HWAVE)hWaveIn);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->lock);
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
device->stopped = TRUE;
|
||||
|
||||
buf = device->first;
|
||||
if(buf && buf->dwBytesRecorded > 0){
|
||||
device->first = buf->lpNext;
|
||||
buf->dwFlags &= ~WHDR_INQUEUE;
|
||||
buf->dwFlags |= WHDR_DONE;
|
||||
}else
|
||||
buf = NULL;
|
||||
|
||||
memcpy(&cb_info, &device->cb_info, sizeof(cb_info));
|
||||
|
||||
LeaveCriticalSection(&device->lock);
|
||||
|
||||
if(buf)
|
||||
WINMM_NotifyClient(&cb_info, WIM_DATA, (DWORD_PTR)buf, 0);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2429,7 +2933,14 @@ UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
|
|||
UINT uSize)
|
||||
{
|
||||
TRACE("(%p, %p, %u)\n", hWaveIn, lpTime, uSize);
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
if(!uSize || !lpTime || uSize != sizeof(MMTIME))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
return WINMM_GetPosition((HWAVE)hWaveIn, lpTime);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2437,11 +2948,27 @@ UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
|
|||
*/
|
||||
UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
|
||||
{
|
||||
UINT dev, junk;
|
||||
BOOL is_out;
|
||||
WINMM_Device *device;
|
||||
|
||||
TRACE("(%p, %p)\n", hWaveIn, lpuDeviceID);
|
||||
|
||||
if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
|
||||
if(!WINMM_StartDevicesThread())
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
if(!lpuDeviceID)
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
device = WINMM_GetDeviceFromHWAVE((HWAVE)hWaveIn);
|
||||
if(!WINMM_ValidateAndLock(device))
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
LeaveCriticalSection(&device->lock);
|
||||
|
||||
WINMM_DecomposeHWAVE((HWAVE)hWaveIn, lpuDeviceID, &is_out, &dev, &junk);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2451,7 +2978,25 @@ UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
|
|||
DWORD_PTR dwParam1, DWORD_PTR dwParam2)
|
||||
{
|
||||
TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
switch(uMessage){
|
||||
case DRV_QUERYFUNCTIONINSTANCEIDSIZE:
|
||||
return WINMM_QueryInstanceIDSize(HandleToULong(hWaveIn),
|
||||
(DWORD_PTR*)dwParam1, FALSE);
|
||||
case DRV_QUERYFUNCTIONINSTANCEID:
|
||||
return WINMM_QueryInstanceID(HandleToULong(hWaveIn),
|
||||
(WCHAR*)dwParam1, (DWORD_PTR)dwParam2, FALSE);
|
||||
/* TODO: Remove after dsound has been rewritten for mmdevapi */
|
||||
case DRV_QUERYDSOUNDDESC:
|
||||
case DRV_QUERYDSOUNDIFACE:
|
||||
if(dwParam2 == DS_HW_ACCEL_FULL)
|
||||
return WINMM_DRVMessage(HandleToULong(hWaveIn), uMessage,
|
||||
dwParam1, 0, FALSE);
|
||||
return WINMM_FillDSDriverDesc(HandleToULong(hWaveIn),
|
||||
(DSDRIVERDESC*)dwParam1, FALSE);
|
||||
}
|
||||
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
|
Loading…
Reference in New Issue