mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 13:01:40 +00:00
261 lines
6.3 KiB
C
261 lines
6.3 KiB
C
/*
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Multimedia
|
|
* FILE: dll/win32/mmdrv/common.c
|
|
* PURPOSE: Multimedia User Mode Driver (Common functions)
|
|
* PROGRAMMER: Andrew Greenwood
|
|
* UPDATE HISTORY:
|
|
* Jan 14, 2007: Created
|
|
*/
|
|
|
|
#include "mmdrv.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/*
|
|
Translates errors to MMRESULT codes.
|
|
*/
|
|
|
|
MMRESULT
|
|
ErrorToMmResult(UINT error_code)
|
|
{
|
|
switch ( error_code )
|
|
{
|
|
case NO_ERROR :
|
|
case ERROR_IO_PENDING :
|
|
return MMSYSERR_NOERROR;
|
|
|
|
case ERROR_BUSY :
|
|
return MMSYSERR_ALLOCATED;
|
|
|
|
case ERROR_NOT_SUPPORTED :
|
|
case ERROR_INVALID_FUNCTION :
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
|
|
case ERROR_NOT_ENOUGH_MEMORY :
|
|
return MMSYSERR_NOMEM;
|
|
|
|
case ERROR_ACCESS_DENIED :
|
|
return MMSYSERR_BADDEVICEID;
|
|
|
|
case ERROR_INSUFFICIENT_BUFFER :
|
|
return MMSYSERR_INVALPARAM;
|
|
};
|
|
|
|
/* If all else fails, it's just a plain old error */
|
|
|
|
return MMSYSERR_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
Obtains a device count for a specific kind of device.
|
|
*/
|
|
|
|
DWORD
|
|
GetDeviceCount(DeviceType device_type)
|
|
{
|
|
UINT index = 0;
|
|
HANDLE handle;
|
|
|
|
/* Cycle through devices until an error occurs */
|
|
|
|
while ( OpenKernelDevice(device_type, index, GENERIC_READ, &handle) == MMSYSERR_NOERROR )
|
|
{
|
|
CloseHandle(handle);
|
|
index ++;
|
|
}
|
|
|
|
DPRINT("Found %d devices of type %d\n", index, device_type);
|
|
|
|
return index;
|
|
}
|
|
|
|
|
|
/*
|
|
Obtains device capabilities. This could either be done as individual
|
|
functions for wave, MIDI and aux, or like this. I chose this method as
|
|
it centralizes everything.
|
|
*/
|
|
|
|
DWORD
|
|
GetDeviceCapabilities(
|
|
DeviceType device_type,
|
|
UINT device_id,
|
|
DWORD_PTR capabilities,
|
|
DWORD capabilities_size)
|
|
{
|
|
MMRESULT result;
|
|
DWORD ioctl;
|
|
HANDLE handle;
|
|
DWORD bytes_returned;
|
|
BOOL device_io_result;
|
|
|
|
ASSERT(capabilities);
|
|
|
|
/* Choose the right IOCTL for the job */
|
|
|
|
if ( IsWaveDevice(device_type) )
|
|
ioctl = IOCTL_WAVE_GET_CAPABILITIES;
|
|
else if ( IsMidiDevice(device_type) )
|
|
ioctl = IOCTL_MIDI_GET_CAPABILITIES;
|
|
else if ( IsAuxDevice(device_type) )
|
|
return MMSYSERR_NOTSUPPORTED; /* TODO */
|
|
else
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
|
|
result = OpenKernelDevice(device_type,
|
|
device_id,
|
|
GENERIC_READ,
|
|
&handle);
|
|
|
|
if ( result != MMSYSERR_NOERROR )
|
|
{
|
|
DPRINT("Failed to open kernel device\n");
|
|
return result;
|
|
}
|
|
|
|
device_io_result = DeviceIoControl(handle,
|
|
ioctl,
|
|
NULL,
|
|
0,
|
|
(LPVOID) capabilities,
|
|
capabilities_size,
|
|
&bytes_returned,
|
|
NULL);
|
|
|
|
/* Translate result */
|
|
|
|
if ( device_io_result )
|
|
result = MMSYSERR_NOERROR;
|
|
else
|
|
result = ErrorToMmResult(GetLastError());
|
|
|
|
/* Clean up and return */
|
|
|
|
CloseKernelDevice(handle);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
A wrapper around OpenKernelDevice that creates a session,
|
|
opens the kernel device, initializes session data and notifies
|
|
the client (application) that the device has been opened. Again,
|
|
this supports any device type and the only real difference is
|
|
the open descriptor.
|
|
*/
|
|
|
|
DWORD
|
|
OpenDevice(
|
|
DeviceType device_type,
|
|
UINT device_id,
|
|
PVOID open_descriptor,
|
|
DWORD flags,
|
|
DWORD_PTR private_handle)
|
|
{
|
|
SessionInfo* session_info;
|
|
MMRESULT result;
|
|
DWORD message;
|
|
|
|
/* This will automatically check for duplicate sessions */
|
|
result = CreateSession(device_type, device_id, &session_info);
|
|
|
|
if ( result != MMSYSERR_NOERROR )
|
|
{
|
|
DPRINT("Couldn't allocate session info\n");
|
|
return result;
|
|
}
|
|
|
|
result = OpenKernelDevice(device_type,
|
|
device_id,
|
|
GENERIC_READ,
|
|
&session_info->kernel_device_handle);
|
|
|
|
if ( result != MMSYSERR_NOERROR )
|
|
{
|
|
DPRINT("Failed to open kernel device\n");
|
|
DestroySession(session_info);
|
|
return result;
|
|
}
|
|
|
|
/* Set common session data */
|
|
|
|
session_info->flags = flags;
|
|
|
|
/* Set wave/MIDI specific data */
|
|
|
|
if ( IsWaveDevice(device_type) )
|
|
{
|
|
LPWAVEOPENDESC wave_open_desc = (LPWAVEOPENDESC) open_descriptor;
|
|
session_info->callback = wave_open_desc->dwCallback;
|
|
session_info->mme_wave_handle = wave_open_desc->hWave;
|
|
session_info->app_user_data = wave_open_desc->dwInstance;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Only wave devices are supported at present!\n");
|
|
DestroySession(session_info);
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
/* Start the processing thread */
|
|
|
|
result = StartSessionThread(session_info);
|
|
|
|
if ( result != MMSYSERR_NOERROR )
|
|
{
|
|
DestroySession(session_info);
|
|
return result;
|
|
}
|
|
|
|
/* Store the session info */
|
|
|
|
*((SessionInfo**)private_handle) = session_info;
|
|
|
|
/* Send the right message */
|
|
|
|
message = (device_type == WaveOutDevice) ? WOM_OPEN :
|
|
(device_type == WaveInDevice) ? WIM_OPEN :
|
|
(device_type == MidiOutDevice) ? MOM_OPEN :
|
|
(device_type == MidiInDevice) ? MIM_OPEN : 0xFFFFFFFF;
|
|
|
|
NotifyClient(session_info, message, 0, 0);
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
Attempts to close a device. This can fail if playback/recording has
|
|
not been stopped. We need to make sure it's safe to destroy the
|
|
session as well (mainly by killing the session thread.)
|
|
*/
|
|
|
|
DWORD
|
|
CloseDevice(
|
|
DWORD_PTR private_handle)
|
|
{
|
|
MMRESULT result;
|
|
SessionInfo* session_info = (SessionInfo*) private_handle;
|
|
/* TODO: Maybe this is best off inside the playback thread? */
|
|
|
|
ASSERT(session_info);
|
|
|
|
result = CallSessionThread(session_info, WODM_CLOSE, 0);
|
|
|
|
if ( result == MMSYSERR_NOERROR )
|
|
{
|
|
/* TODO: Wait for it to be safe to terminate */
|
|
|
|
CloseKernelDevice(session_info->kernel_device_handle);
|
|
|
|
DestroySession(session_info);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|