Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
miniaudio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
miniaudio
Commits
16c3856d
Commit
16c3856d
authored
Nov 13, 2016
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WASAPI: Add initial support for playback.
parent
ff8ef784
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
355 additions
and
10 deletions
+355
-10
mini_al.h
mini_al.h
+355
-10
No files found.
mini_al.h
View file @
16c3856d
...
@@ -21,6 +21,7 @@
...
@@ -21,6 +21,7 @@
// - null
// - null
// - ... and more in the future.
// - ... and more in the future.
// - OpenSL|ES / Android (Unstable)
// - OpenSL|ES / Android (Unstable)
// - WASAPI (Unstable)
// - Core Audio (OSX, iOS)
// - Core Audio (OSX, iOS)
// - Maybe OSS
// - Maybe OSS
// - Maybe OpenAL
// - Maybe OpenAL
...
@@ -260,6 +261,10 @@ typedef int mal_result;
...
@@ -260,6 +261,10 @@ typedef int mal_result;
#define MAL_ALSA_FAILED_TO_OPEN_DEVICE -2048
#define MAL_ALSA_FAILED_TO_OPEN_DEVICE -2048
#define MAL_ALSA_FAILED_TO_SET_HW_PARAMS -2049
#define MAL_ALSA_FAILED_TO_SET_HW_PARAMS -2049
#define MAL_ALSA_FAILED_TO_SET_SW_PARAMS -2050
#define MAL_ALSA_FAILED_TO_SET_SW_PARAMS -2050
#define MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR -3072
#define MAL_WASAPI_FAILED_TO_CREATE_DEVICE -3073
#define MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE -3074
#define MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE -3075
typedef
struct
mal_device
mal_device
;
typedef
struct
mal_device
mal_device
;
...
@@ -355,7 +360,13 @@ struct mal_device
...
@@ -355,7 +360,13 @@ struct mal_device
#ifdef MAL_ENABLE_WASAPI
#ifdef MAL_ENABLE_WASAPI
struct
struct
{
{
/*IMMDevice**/
mal_ptr
pDevice
;
/*IAudioClient*/
mal_ptr
pAudioClient
;
/*IAudioRenderClient */
mal_ptr
pRenderClient
;
/*IAudioCaptureClient */
mal_ptr
pCaptureClient
;
/*HANDLE*/
mal_handle
hStopEvent
;
mal_bool32
needCoUninit
;
// Whether or not COM needs to be uninitialized.
mal_bool32
needCoUninit
;
// Whether or not COM needs to be uninitialized.
mal_bool32
breakFromMainLoop
;
}
wasapi
;
}
wasapi
;
#endif
#endif
...
@@ -1324,6 +1335,15 @@ static inline mal_uint32 mal_device__get_state(mal_device* pDevice)
...
@@ -1324,6 +1335,15 @@ static inline mal_uint32 mal_device__get_state(mal_device* pDevice)
}
}
#ifdef MAL_WIN32
static
GUID
MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM
=
{
0x00000001
,
0x0000
,
0x0010
,
{
0x80
,
0x00
,
0x00
,
0xaa
,
0x00
,
0x38
,
0x9b
,
0x71
}};
static
GUID
MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
=
{
0x00000003
,
0x0000
,
0x0010
,
{
0x80
,
0x00
,
0x00
,
0xaa
,
0x00
,
0x38
,
0x9b
,
0x71
}};
//static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
//static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
//
// Null Backend
// Null Backend
...
@@ -1361,6 +1381,8 @@ static mal_result mal_device_init__null(mal_device* pDevice, mal_device_type typ
...
@@ -1361,6 +1381,8 @@ static mal_result mal_device_init__null(mal_device* pDevice, mal_device_type typ
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
pDevice
->
api
=
mal_api_null
;
pDevice
->
api
=
mal_api_null
;
mal_zero_object
(
&
pDevice
->
null_device
);
pDevice
->
bufferSizeInFrames
=
pConfig
->
bufferSizeInFrames
;
pDevice
->
bufferSizeInFrames
=
pConfig
->
bufferSizeInFrames
;
pDevice
->
periods
=
pConfig
->
periods
;
pDevice
->
periods
=
pConfig
->
periods
;
...
@@ -1412,7 +1434,7 @@ static mal_bool32 mal_device__get_current_frame__null(mal_device* pDevice, mal_u
...
@@ -1412,7 +1434,7 @@ static mal_bool32 mal_device__get_current_frame__null(mal_device* pDevice, mal_u
return
MAL_TRUE
;
return
MAL_TRUE
;
}
}
static
mal_
bool
32
mal_device__get_available_frames__null
(
mal_device
*
pDevice
)
static
mal_
uint
32
mal_device__get_available_frames__null
(
mal_device
*
pDevice
)
{
{
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
...
@@ -1544,13 +1566,22 @@ const PROPERTYKEY g_malPKEY_Device_FriendlyName = {{0xa45c254e, 0xdf1c, 0x4efd,
...
@@ -1544,13 +1566,22 @@ const PROPERTYKEY g_malPKEY_Device_FriendlyName = {{0xa45c254e, 0xdf1c, 0x4efd,
const
IID
g_malCLSID_MMDeviceEnumerator_Instance
=
{
0xBCDE0395
,
0xE52F
,
0x467C
,
{
0x8E
,
0x3D
,
0xC4
,
0x57
,
0x92
,
0x91
,
0x69
,
0x2E
}};
// BCDE0395-E52F-467C-8E3D-C4579291692E = __uuidof(MMDeviceEnumerator)
const
IID
g_malCLSID_MMDeviceEnumerator_Instance
=
{
0xBCDE0395
,
0xE52F
,
0x467C
,
{
0x8E
,
0x3D
,
0xC4
,
0x57
,
0x92
,
0x91
,
0x69
,
0x2E
}};
// BCDE0395-E52F-467C-8E3D-C4579291692E = __uuidof(MMDeviceEnumerator)
const
IID
g_malIID_IMMDeviceEnumerator_Instance
=
{
0xA95664D2
,
0x9614
,
0x4F35
,
{
0xA7
,
0x46
,
0xDE
,
0x8D
,
0xB6
,
0x36
,
0x17
,
0xE6
}};
// A95664D2-9614-4F35-A746-DE8DB63617E6 = __uuidof(IMMDeviceEnumerator)
const
IID
g_malIID_IMMDeviceEnumerator_Instance
=
{
0xA95664D2
,
0x9614
,
0x4F35
,
{
0xA7
,
0x46
,
0xDE
,
0x8D
,
0xB6
,
0x36
,
0x17
,
0xE6
}};
// A95664D2-9614-4F35-A746-DE8DB63617E6 = __uuidof(IMMDeviceEnumerator)
const
IID
g_malIID_IAudioClient_Instance
=
{
0x1CB9AD4C
,
0xDBFA
,
0x4C32
,
{
0xB1
,
0x78
,
0xC2
,
0xF5
,
0x68
,
0xA7
,
0x03
,
0xB2
}};
// 1CB9AD4C-DBFA-4C32-B178-C2F568A703B2 = __uuidof(IAudioClient)
const
IID
g_malIID_IAudioRenderClient_Instance
=
{
0xF294ACFC
,
0x3146
,
0x4483
,
{
0xA7
,
0xBF
,
0xAD
,
0xDC
,
0xA7
,
0xC2
,
0x60
,
0xE2
}};
// F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient)
const
IID
g_malIID_IAudioCaptureClient_Instance
=
{
0xC8ADBD64
,
0xE71E
,
0x48A0
,
{
0xA4
,
0xDE
,
0x18
,
0x5C
,
0x39
,
0x5C
,
0xD3
,
0x17
}};
// C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient)
#ifdef __cplusplus
#ifdef __cplusplus
#define g_malCLSID_MMDeviceEnumerator g_malCLSID_MMDeviceEnumerator_Instance
#define g_malCLSID_MMDeviceEnumerator g_malCLSID_MMDeviceEnumerator_Instance
#define g_malIID_IMMDeviceEnumerator g_malIID_IMMDeviceEnumerator_Instance
#define g_malIID_IMMDeviceEnumerator g_malIID_IMMDeviceEnumerator_Instance
#define g_malIID_IAudioClient g_malIID_IAudioClient_Instance
#define g_malIID_IAudioRenderClient g_malIID_IAudioRenderClient_Instance
#define g_malIID_IAudioCaptureClient g_malIID_IAudioCaptureClient_Instance
#else
#else
#define g_malCLSID_MMDeviceEnumerator &g_malCLSID_MMDeviceEnumerator_Instance
#define g_malCLSID_MMDeviceEnumerator &g_malCLSID_MMDeviceEnumerator_Instance
#define g_malIID_IMMDeviceEnumerator &g_malIID_IMMDeviceEnumerator_Instance
#define g_malIID_IMMDeviceEnumerator &g_malIID_IMMDeviceEnumerator_Instance
#define g_malIID_IAudioClient &g_malIID_IAudioClient_Instance
#define g_malIID_IAudioRenderClient &g_malIID_IAudioRenderClient_Instance
#define g_malIID_IAudioCaptureClient &g_malIID_IAudioCaptureClient_Instance
#endif
#endif
static
mal_result
mal_enumerate_devices__wasapi
(
mal_device_type
type
,
mal_uint32
*
pCount
,
mal_device_info
*
pInfo
)
static
mal_result
mal_enumerate_devices__wasapi
(
mal_device_type
type
,
mal_uint32
*
pCount
,
mal_device_info
*
pInfo
)
...
@@ -1636,6 +1667,269 @@ static mal_result mal_enumerate_devices__wasapi(mal_device_type type, mal_uint32
...
@@ -1636,6 +1667,269 @@ static mal_result mal_enumerate_devices__wasapi(mal_device_type type, mal_uint32
if
(
needCoUninit
)
CoUninitialize
();
if
(
needCoUninit
)
CoUninitialize
();
return
MAL_SUCCESS
;
return
MAL_SUCCESS
;
}
}
static
void
mal_device_uninit__wasapi
(
mal_device
*
pDevice
)
{
mal_assert
(
pDevice
!=
NULL
);
if
(
pDevice
->
wasapi
.
pRenderClient
)
{
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
)
->
lpVtbl
->
Release
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
);
}
if
(
pDevice
->
wasapi
.
pCaptureClient
)
{
((
IAudioCaptureClient
*
)
pDevice
->
wasapi
.
pCaptureClient
)
->
lpVtbl
->
Release
((
IAudioCaptureClient
*
)
pDevice
->
wasapi
.
pCaptureClient
);
}
if
(
pDevice
->
wasapi
.
pAudioClient
)
{
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
Release
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
);
}
if
(
pDevice
->
wasapi
.
pDevice
)
{
((
IMMDevice
*
)
pDevice
->
wasapi
.
pDevice
)
->
lpVtbl
->
Release
((
IMMDevice
*
)
pDevice
->
wasapi
.
pDevice
);
}
if
(
pDevice
->
wasapi
.
hStopEvent
)
{
CloseHandle
(
pDevice
->
wasapi
.
hStopEvent
);
}
if
(
pDevice
->
wasapi
.
needCoUninit
)
{
CoUninitialize
();
}
}
static
mal_result
mal_device_init__wasapi
(
mal_device
*
pDevice
,
mal_device_type
type
,
mal_device_id
*
pDeviceID
,
mal_device_config
*
pConfig
)
{
mal_assert
(
pDevice
!=
NULL
);
pDevice
->
api
=
mal_api_wasapi
;
mal_zero_object
(
&
pDevice
->
wasapi
);
HRESULT
hr
=
CoInitializeEx
(
NULL
,
COINIT_APARTMENTTHREADED
);
if
(
hr
==
S_OK
||
hr
==
S_FALSE
)
{
pDevice
->
wasapi
.
needCoUninit
=
MAL_TRUE
;
}
IMMDeviceEnumerator
*
pDeviceEnumerator
;
hr
=
CoCreateInstance
(
g_malCLSID_MMDeviceEnumerator
,
NULL
,
CLSCTX_ALL
,
g_malIID_IMMDeviceEnumerator
,
(
void
**
)
&
pDeviceEnumerator
);
if
(
FAILED
(
hr
))
{
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to create IMMDeviceEnumerator."
,
MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR
);
}
if
(
pDeviceID
==
NULL
)
{
hr
=
pDeviceEnumerator
->
lpVtbl
->
GetDefaultAudioEndpoint
(
pDeviceEnumerator
,
(
type
==
mal_device_type_playback
)
?
eRender
:
eCapture
,
eConsole
,
(
IMMDevice
**
)
&
pDevice
->
wasapi
.
pDevice
);
if
(
FAILED
(
hr
))
{
pDeviceEnumerator
->
lpVtbl
->
Release
(
pDeviceEnumerator
);
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to create default backend device."
,
MAL_WASAPI_FAILED_TO_CREATE_DEVICE
);
}
}
else
{
hr
=
pDeviceEnumerator
->
lpVtbl
->
GetDevice
(
pDeviceEnumerator
,
pDeviceID
->
wstr
,
(
IMMDevice
**
)
&
pDevice
->
wasapi
.
pDevice
);
if
(
FAILED
(
hr
))
{
pDeviceEnumerator
->
lpVtbl
->
Release
(
pDeviceEnumerator
);
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to create backend device."
,
MAL_WASAPI_FAILED_TO_CREATE_DEVICE
);
}
}
pDeviceEnumerator
->
lpVtbl
->
Release
(
pDeviceEnumerator
);
hr
=
((
IMMDevice
*
)
pDevice
->
wasapi
.
pDevice
)
->
lpVtbl
->
Activate
((
IMMDevice
*
)
pDevice
->
wasapi
.
pDevice
,
g_malIID_IAudioClient
,
CLSCTX_ALL
,
NULL
,
&
pDevice
->
wasapi
.
pAudioClient
);
if
(
FAILED
(
hr
))
{
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to activate device."
,
MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE
);
}
REFERENCE_TIME
bufferDurationInMicroseconds
=
((
mal_uint64
)
pConfig
->
bufferSizeInFrames
*
1000
*
1000
)
/
pConfig
->
sampleRate
;
WAVEFORMATEXTENSIBLE
wf
;
mal_zero_object
(
&
wf
);
wf
.
Format
.
cbSize
=
sizeof
(
wf
);
wf
.
Format
.
wFormatTag
=
WAVE_FORMAT_EXTENSIBLE
;
wf
.
Format
.
nChannels
=
(
WORD
)
pConfig
->
channels
;
wf
.
Format
.
nSamplesPerSec
=
(
DWORD
)
pConfig
->
sampleRate
;
wf
.
Format
.
wBitsPerSample
=
(
WORD
)
mal_get_sample_size_in_bytes
(
pConfig
->
format
)
*
8
;
wf
.
Format
.
nBlockAlign
=
(
wf
.
Format
.
nChannels
*
wf
.
Format
.
wBitsPerSample
)
/
8
;
wf
.
Format
.
nAvgBytesPerSec
=
wf
.
Format
.
nBlockAlign
*
wf
.
Format
.
nSamplesPerSec
;
wf
.
Samples
.
wValidBitsPerSample
=
wf
.
Format
.
wBitsPerSample
;
wf
.
dwChannelMask
=
(
pConfig
->
channels
<=
2
)
?
0
:
~
(((
DWORD
)
-
1
)
<<
pConfig
->
channels
);
wf
.
SubFormat
=
MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
WAVEFORMATEXTENSIBLE
*
pClosestWF
;
#if 0
hr = ((IAudioClient*)pDevice->wasapi.pAudioClient)->lpVtbl->IsFormatSupported((IAudioClient*)pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)&wf, (WAVEFORMATEX**)&pClosestWF);
if (hr != S_OK && hr != S_FALSE) {
mal_device_uninit__wasapi(pDevice);
return mal_post_error(pDevice, "[WASAPI] Failed to get device mix format.", MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE);
}
#else
hr
=
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
GetMixFormat
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
,
(
WAVEFORMATEX
**
)
&
pClosestWF
);
if
(
hr
!=
S_OK
&&
hr
!=
S_FALSE
)
{
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to get device mix format."
,
MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE
);
}
#endif
//if (hr != S_OK) {
mal_copy_memory
(
&
wf
,
pClosestWF
,
sizeof
(
wf
));
//}
hr
=
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
Initialize
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
,
AUDCLNT_SHAREMODE_SHARED
,
0
,
bufferDurationInMicroseconds
*
10
,
0
,
(
WAVEFORMATEX
*
)
&
wf
,
NULL
);
if
(
FAILED
(
hr
))
{
CoTaskMemFree
(
pClosestWF
);
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to activate device."
,
MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE
);
}
CoTaskMemFree
(
pClosestWF
);
hr
=
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
GetBufferSize
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
,
&
pDevice
->
bufferSizeInFrames
);
if
(
FAILED
(
hr
))
{
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to get audio client's actual buffer size."
,
MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE
);
}
if
(
type
==
mal_device_type_playback
)
{
hr
=
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
GetService
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
,
g_malIID_IAudioRenderClient
,
&
pDevice
->
wasapi
.
pRenderClient
);
}
else
{
hr
=
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
GetService
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
,
g_malIID_IAudioCaptureClient
,
&
pDevice
->
wasapi
.
pCaptureClient
);
}
if
(
FAILED
(
hr
))
{
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to get audio client service."
,
MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE
);
}
// When the device is playing the worker thread will be waiting on a bunch of notification events. To return from
// this wait state we need to signal a special event.
pDevice
->
wasapi
.
hStopEvent
=
CreateEventA
(
NULL
,
FALSE
,
FALSE
,
NULL
);
if
(
pDevice
->
wasapi
.
hStopEvent
==
NULL
)
{
mal_device_uninit__wasapi
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[WASAPI] Failed to create event for main loop break notification."
,
MAL_FAILED_TO_CREATE_EVENT
);
}
return
MAL_SUCCESS
;
}
static
mal_result
mal_device__start_backend__wasapi
(
mal_device
*
pDevice
)
{
mal_assert
(
pDevice
!=
NULL
);
// Playback devices need to have an initial chunk of data loaded.
if
(
pDevice
->
type
==
mal_device_type_playback
)
{
BYTE
*
pData
;
HRESULT
hr
=
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
)
->
lpVtbl
->
GetBuffer
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
,
pDevice
->
bufferSizeInFrames
,
&
pData
);
if
(
FAILED
(
hr
))
{
return
MAL_FAILED_TO_READ_DATA_FROM_CLIENT
;
}
mal_device__read_frames_from_client
(
pDevice
,
pDevice
->
bufferSizeInFrames
,
pData
);
hr
=
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
)
->
lpVtbl
->
ReleaseBuffer
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
,
pDevice
->
bufferSizeInFrames
,
0
);
if
(
FAILED
(
hr
))
{
return
MAL_FAILED_TO_READ_DATA_FROM_CLIENT
;
}
}
HRESULT
hr
=
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
Start
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
);
if
(
FAILED
(
hr
))
{
return
MAL_FAILED_TO_START_BACKEND_DEVICE
;
}
return
MAL_SUCCESS
;
}
static
mal_result
mal_device__stop_backend__wasapi
(
mal_device
*
pDevice
)
{
mal_assert
(
pDevice
!=
NULL
);
HRESULT
hr
=
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
Stop
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
);
if
(
FAILED
(
hr
))
{
return
MAL_FAILED_TO_STOP_BACKEND_DEVICE
;
}
return
MAL_SUCCESS
;
}
static
mal_result
mal_device__break_main_loop__wasapi
(
mal_device
*
pDevice
)
{
mal_assert
(
pDevice
!=
NULL
);
// The main loop will be waiting on a bunch of events via the WaitForMultipleObjects() API. One of those events
// is a special event we use for forcing that function to return.
pDevice
->
wasapi
.
breakFromMainLoop
=
MAL_TRUE
;
SetEvent
(
pDevice
->
wasapi
.
hStopEvent
);
return
MAL_SUCCESS
;
}
static
mal_uint32
mal_device__get_available_frames__wasapi
(
mal_device
*
pDevice
)
{
mal_assert
(
pDevice
!=
NULL
);
UINT32
paddingFramesCount
;
HRESULT
hr
=
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
)
->
lpVtbl
->
GetCurrentPadding
((
IAudioClient
*
)
pDevice
->
wasapi
.
pAudioClient
,
&
paddingFramesCount
);
if
(
FAILED
(
hr
))
{
return
0
;
}
return
pDevice
->
bufferSizeInFrames
-
paddingFramesCount
;
}
static
mal_uint32
mal_device__wait_for_frames__wasapi
(
mal_device
*
pDevice
)
{
mal_assert
(
pDevice
!=
NULL
);
while
(
!
pDevice
->
wasapi
.
breakFromMainLoop
)
{
mal_uint32
framesAvailable
=
mal_device__get_available_frames__wasapi
(
pDevice
);
if
(
framesAvailable
>
0
)
{
return
framesAvailable
;
}
DWORD
timeoutInMilliseconds
=
1
;
WaitForSingleObject
(
pDevice
->
wasapi
.
hStopEvent
,
timeoutInMilliseconds
);
}
// We'll get here if the loop was terminated. Just return whatever's available.
return
mal_device__get_available_frames__wasapi
(
pDevice
);
}
static
mal_result
mal_device__main_loop__wasapi
(
mal_device
*
pDevice
)
{
mal_assert
(
pDevice
!=
NULL
);
// Make sure the stop event is not signaled to ensure we don't end up immediately returning from WaitForMultipleObjects().
ResetEvent
(
pDevice
->
wasapi
.
hStopEvent
);
pDevice
->
wasapi
.
breakFromMainLoop
=
MAL_FALSE
;
while
(
!
pDevice
->
wasapi
.
breakFromMainLoop
)
{
mal_uint32
framesAvailable
=
mal_device__wait_for_frames__wasapi
(
pDevice
);
if
(
framesAvailable
==
0
)
{
continue
;
}
// If it's a playback device, don't bother grabbing more data if the device is being stopped.
if
(
pDevice
->
wasapi
.
breakFromMainLoop
&&
pDevice
->
type
==
mal_device_type_playback
)
{
return
MAL_FALSE
;
}
if
(
pDevice
->
type
==
mal_device_type_playback
)
{
BYTE
*
pData
;
HRESULT
hr
=
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
)
->
lpVtbl
->
GetBuffer
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
,
framesAvailable
,
&
pData
);
if
(
FAILED
(
hr
))
{
return
MAL_FAILED_TO_READ_DATA_FROM_CLIENT
;
}
mal_device__read_frames_from_client
(
pDevice
,
framesAvailable
,
pData
);
hr
=
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
)
->
lpVtbl
->
ReleaseBuffer
((
IAudioRenderClient
*
)
pDevice
->
wasapi
.
pRenderClient
,
framesAvailable
,
0
);
if
(
FAILED
(
hr
))
{
return
MAL_FAILED_TO_READ_DATA_FROM_CLIENT
;
}
}
else
{
// TODO: Implement me.
}
}
return
MAL_SUCCESS
;
}
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
...
@@ -1794,6 +2088,8 @@ static mal_result mal_device_init__dsound(mal_device* pDevice, mal_device_type t
...
@@ -1794,6 +2088,8 @@ static mal_result mal_device_init__dsound(mal_device* pDevice, mal_device_type t
{
{
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
pDevice
->
api
=
mal_api_dsound
;
pDevice
->
api
=
mal_api_dsound
;
mal_zero_object
(
&
pDevice
->
dsound
);
pDevice
->
dsound
.
rewindTarget
=
~
0UL
;
pDevice
->
dsound
.
rewindTarget
=
~
0UL
;
pDevice
->
dsound
.
hDSoundDLL
=
(
mal_handle
)
mal_open_dsound_dll
();
pDevice
->
dsound
.
hDSoundDLL
=
(
mal_handle
)
mal_open_dsound_dll
();
...
@@ -2096,7 +2392,7 @@ static mal_bool32 mal_device__get_current_frame__dsound(mal_device* pDevice, mal
...
@@ -2096,7 +2392,7 @@ static mal_bool32 mal_device__get_current_frame__dsound(mal_device* pDevice, mal
return
MAL_TRUE
;
return
MAL_TRUE
;
}
}
static
mal_
bool
32
mal_device__get_available_frames__dsound
(
mal_device
*
pDevice
)
static
mal_
uint
32
mal_device__get_available_frames__dsound
(
mal_device
*
pDevice
)
{
{
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
...
@@ -2203,10 +2499,6 @@ static mal_result mal_device__main_loop__dsound(mal_device* pDevice)
...
@@ -2203,10 +2499,6 @@ static mal_result mal_device__main_loop__dsound(mal_device* pDevice)
DWORD
lockSize
=
framesAvailable
*
pDevice
->
channels
*
mal_get_sample_size_in_bytes
(
pDevice
->
format
);
DWORD
lockSize
=
framesAvailable
*
pDevice
->
channels
*
mal_get_sample_size_in_bytes
(
pDevice
->
format
);
if
(
pDevice
->
type
==
mal_device_type_playback
)
{
if
(
pDevice
->
type
==
mal_device_type_playback
)
{
if
(
pDevice
->
dsound
.
breakFromMainLoop
)
{
return
MAL_FALSE
;
}
void
*
pLockPtr
;
void
*
pLockPtr
;
DWORD
actualLockSize
;
DWORD
actualLockSize
;
void
*
pLockPtr2
;
void
*
pLockPtr2
;
...
@@ -2677,6 +2969,7 @@ static mal_result mal_device_init__alsa(mal_device* pDevice, mal_device_type typ
...
@@ -2677,6 +2969,7 @@ static mal_result mal_device_init__alsa(mal_device* pDevice, mal_device_type typ
{
{
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
pDevice
->
api
=
mal_api_alsa
;
pDevice
->
api
=
mal_api_alsa
;
mal_zero_object
(
&
pDevice
->
alsa
);
snd_pcm_format_t
formatALSA
;
snd_pcm_format_t
formatALSA
;
switch
(
pConfig
->
format
)
switch
(
pConfig
->
format
)
...
@@ -3180,6 +3473,8 @@ static mal_result mal_device_init__sles(mal_device* pDevice, mal_device_type typ
...
@@ -3180,6 +3473,8 @@ static mal_result mal_device_init__sles(mal_device* pDevice, mal_device_type typ
// Now we can start initializing the device properly.
// Now we can start initializing the device properly.
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
pDevice
->
api
=
mal_api_sles
;
pDevice
->
api
=
mal_api_sles
;
mal_zero_object
(
&
pDevice
->
sles
);
pDevice
->
sles
.
currentBufferIndex
=
0
;
pDevice
->
sles
.
currentBufferIndex
=
0
;
pDevice
->
sles
.
periodSizeInFrames
=
pConfig
->
bufferSizeInFrames
/
pConfig
->
periods
;
pDevice
->
sles
.
periodSizeInFrames
=
pConfig
->
bufferSizeInFrames
/
pConfig
->
periods
;
pDevice
->
bufferSizeInFrames
=
pDevice
->
sles
.
periodSizeInFrames
*
pConfig
->
periods
;
pDevice
->
bufferSizeInFrames
=
pDevice
->
sles
.
periodSizeInFrames
*
pConfig
->
periods
;
...
@@ -3406,6 +3701,11 @@ static mal_result mal_device__start_backend(mal_device* pDevice)
...
@@ -3406,6 +3701,11 @@ static mal_result mal_device__start_backend(mal_device* pDevice)
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
mal_result
result
=
MAL_NO_BACKEND
;
mal_result
result
=
MAL_NO_BACKEND
;
#ifdef MAL_ENABLE_WASAPI
if
(
pDevice
->
api
==
mal_api_wasapi
)
{
result
=
mal_device__start_backend__wasapi
(
pDevice
);
}
#endif
#ifdef MAL_ENABLE_DSOUND
#ifdef MAL_ENABLE_DSOUND
if
(
pDevice
->
api
==
mal_api_dsound
)
{
if
(
pDevice
->
api
==
mal_api_dsound
)
{
result
=
mal_device__start_backend__dsound
(
pDevice
);
result
=
mal_device__start_backend__dsound
(
pDevice
);
...
@@ -3430,6 +3730,11 @@ static mal_result mal_device__stop_backend(mal_device* pDevice)
...
@@ -3430,6 +3730,11 @@ static mal_result mal_device__stop_backend(mal_device* pDevice)
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
mal_result
result
=
MAL_NO_BACKEND
;
mal_result
result
=
MAL_NO_BACKEND
;
#ifdef MAL_ENABLE_WASAPI
if
(
pDevice
->
api
==
mal_api_wasapi
)
{
result
=
mal_device__stop_backend__wasapi
(
pDevice
);
}
#endif
#ifdef MAL_ENABLE_DSOUND
#ifdef MAL_ENABLE_DSOUND
if
(
pDevice
->
api
==
mal_api_dsound
)
{
if
(
pDevice
->
api
==
mal_api_dsound
)
{
result
=
mal_device__stop_backend__dsound
(
pDevice
);
result
=
mal_device__stop_backend__dsound
(
pDevice
);
...
@@ -3454,6 +3759,11 @@ static mal_result mal_device__break_main_loop(mal_device* pDevice)
...
@@ -3454,6 +3759,11 @@ static mal_result mal_device__break_main_loop(mal_device* pDevice)
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
mal_result
result
=
MAL_NO_BACKEND
;
mal_result
result
=
MAL_NO_BACKEND
;
#ifdef MAL_ENABLE_WASAPI
if
(
pDevice
->
api
==
mal_api_wasapi
)
{
result
=
mal_device__break_main_loop__wasapi
(
pDevice
);
}
#endif
#ifdef MAL_ENABLE_DSOUND
#ifdef MAL_ENABLE_DSOUND
if
(
pDevice
->
api
==
mal_api_dsound
)
{
if
(
pDevice
->
api
==
mal_api_dsound
)
{
result
=
mal_device__break_main_loop__dsound
(
pDevice
);
result
=
mal_device__break_main_loop__dsound
(
pDevice
);
...
@@ -3478,6 +3788,11 @@ static mal_result mal_device__main_loop(mal_device* pDevice)
...
@@ -3478,6 +3788,11 @@ static mal_result mal_device__main_loop(mal_device* pDevice)
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
mal_result
result
=
MAL_NO_BACKEND
;
mal_result
result
=
MAL_NO_BACKEND
;
#ifdef MAL_ENABLE_WASAPI
if
(
pDevice
->
api
==
mal_api_wasapi
)
{
result
=
mal_device__main_loop__wasapi
(
pDevice
);
}
#endif
#ifdef MAL_ENABLE_DSOUND
#ifdef MAL_ENABLE_DSOUND
if
(
pDevice
->
api
==
mal_api_dsound
)
{
if
(
pDevice
->
api
==
mal_api_dsound
)
{
result
=
mal_device__main_loop__dsound
(
pDevice
);
result
=
mal_device__main_loop__dsound
(
pDevice
);
...
@@ -3502,6 +3817,10 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData)
...
@@ -3502,6 +3817,10 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData)
mal_device
*
pDevice
=
(
mal_device
*
)
pData
;
mal_device
*
pDevice
=
(
mal_device
*
)
pData
;
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
#ifdef MAL_WIN32
CoInitializeEx
(
NULL
,
COINIT_MULTITHREADED
);
#endif
// This is only used to prevent posting onStop() when the device is first initialized.
// This is only used to prevent posting onStop() when the device is first initialized.
mal_bool32
skipNextStopEvent
=
MAL_TRUE
;
mal_bool32
skipNextStopEvent
=
MAL_TRUE
;
...
@@ -3556,6 +3875,11 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData)
...
@@ -3556,6 +3875,11 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData)
// Make sure we aren't continuously waiting on a stop event.
// Make sure we aren't continuously waiting on a stop event.
mal_event_signal
(
&
pDevice
->
stopEvent
);
// <-- Is this still needed?
mal_event_signal
(
&
pDevice
->
stopEvent
);
// <-- Is this still needed?
#ifdef MAL_WIN32
CoUninitialize
();
#endif
return
(
mal_thread_result
)
0
;
return
(
mal_thread_result
)
0
;
}
}
...
@@ -3573,14 +3897,14 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d
...
@@ -3573,14 +3897,14 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d
if
(
pCount
==
NULL
)
return
mal_post_error
(
NULL
,
"mal_enumerate_devices() called with invalid arguments."
,
MAL_INVALID_ARGS
);
if
(
pCount
==
NULL
)
return
mal_post_error
(
NULL
,
"mal_enumerate_devices() called with invalid arguments."
,
MAL_INVALID_ARGS
);
mal_result
result
=
MAL_NO_BACKEND
;
mal_result
result
=
MAL_NO_BACKEND
;
#ifdef MAL_ENABLE_
WASAPI
#ifdef MAL_ENABLE_
DSOUND
if
(
result
!=
MAL_SUCCESS
)
{
if
(
result
!=
MAL_SUCCESS
)
{
result
=
mal_enumerate_devices__
wasapi
(
type
,
pCount
,
pInfo
);
result
=
mal_enumerate_devices__
dsound
(
type
,
pCount
,
pInfo
);
}
}
#endif
#endif
#ifdef MAL_ENABLE_
DSOUND
#ifdef MAL_ENABLE_
WASAPI
if
(
result
!=
MAL_SUCCESS
)
{
if
(
result
!=
MAL_SUCCESS
)
{
result
=
mal_enumerate_devices__
dsound
(
type
,
pCount
,
pInfo
);
result
=
mal_enumerate_devices__
wasapi
(
type
,
pCount
,
pInfo
);
}
}
#endif
#endif
#ifdef MAL_ENABLE_ALSA
#ifdef MAL_ENABLE_ALSA
...
@@ -3671,6 +3995,11 @@ mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device
...
@@ -3671,6 +3995,11 @@ mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device
result
=
mal_device_init__dsound
(
pDevice
,
type
,
pDeviceID
,
pConfig
);
result
=
mal_device_init__dsound
(
pDevice
,
type
,
pDeviceID
,
pConfig
);
}
}
#endif
#endif
#ifdef MAL_ENABLE_WASAPI
if
(
result
!=
MAL_SUCCESS
)
{
result
=
mal_device_init__wasapi
(
pDevice
,
type
,
pDeviceID
,
pConfig
);
}
#endif
#ifdef MAL_ENABLE_ALSA
#ifdef MAL_ENABLE_ALSA
if
(
result
!=
MAL_SUCCESS
)
{
if
(
result
!=
MAL_SUCCESS
)
{
result
=
mal_device_init__alsa
(
pDevice
,
type
,
pDeviceID
,
pConfig
);
result
=
mal_device_init__alsa
(
pDevice
,
type
,
pDeviceID
,
pConfig
);
...
@@ -3736,6 +4065,11 @@ void mal_device_uninit(mal_device* pDevice)
...
@@ -3736,6 +4065,11 @@ void mal_device_uninit(mal_device* pDevice)
mal_event_delete
(
&
pDevice
->
wakeupEvent
);
mal_event_delete
(
&
pDevice
->
wakeupEvent
);
mal_mutex_delete
(
&
pDevice
->
lock
);
mal_mutex_delete
(
&
pDevice
->
lock
);
#ifdef MAL_ENABLE_WASAPI
if
(
pDevice
->
api
==
mal_api_wasapi
)
{
mal_device_uninit__wasapi
(
pDevice
);
}
#endif
#ifdef MAL_ENABLE_DSOUND
#ifdef MAL_ENABLE_DSOUND
if
(
pDevice
->
api
==
mal_api_dsound
)
{
if
(
pDevice
->
api
==
mal_api_dsound
)
{
mal_device_uninit__dsound
(
pDevice
);
mal_device_uninit__dsound
(
pDevice
);
...
@@ -4003,8 +4337,19 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format)
...
@@ -4003,8 +4337,19 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format)
// TODO
// TODO
// ====
// ====
// - Implement the notion of a context.
// - Needed to ensure device enumeration and initialization use the same backend.
// - Add support for channel mapping.
// - Add support for channel mapping.
//
//
//
// WASAPI
// ------
// - Add support for non-f32 formats.
// - Add support for exclusive mode?
// - GetMixFormat() instead of IsFormatSupported().
// - Requires a large suite of conversion routines including channel shuffling, SRC and format conversion.
//
//
// ALSA
// ALSA
// ----
// ----
// - Use runtime linking for asound.
// - Use runtime linking for asound.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment