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
bfc4d3ff
Commit
bfc4d3ff
authored
Oct 21, 2016
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
DirectSound: Add back notifications to better handle waking up the worker thread based on periods.
parent
46aaa53f
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
66 additions
and
12 deletions
+66
-12
mini_al.h
mini_al.h
+66
-12
No files found.
mini_al.h
View file @
bfc4d3ff
...
@@ -56,7 +56,7 @@
...
@@ -56,7 +56,7 @@
// // to pSamples (but no more than frameCount) and then return the number of frames you wrote.
// // to pSamples (but no more than frameCount) and then return the number of frames you wrote.
// //
// //
// // You can pass in user data by setting pDevice->pUserData after initialization.
// // You can pass in user data by setting pDevice->pUserData after initialization.
// return (mal_uint32)drwav_read_f32(
&wav
, frameCount * pDevice->channels, (float*)pSamples) / pDevice->channels;
// return (mal_uint32)drwav_read_f32(
(drwav*)pDevice->pUserData
, frameCount * pDevice->channels, (float*)pSamples) / pDevice->channels;
// }
// }
//
//
// ...
// ...
...
@@ -94,6 +94,7 @@
...
@@ -94,6 +94,7 @@
// ===============
// ===============
// - The absolute best latency I am able to get on DirectSound is about 10 milliseconds. This seems very
// - The absolute best latency I am able to get on DirectSound is about 10 milliseconds. This seems very
// consistent so I'm suspecting there's some kind of hard coded limit there or something.
// consistent so I'm suspecting there's some kind of hard coded limit there or something.
// - DirectSound currently supports a maximum of 4 periods.
// - The ALSA backend does not support rewinding.
// - The ALSA backend does not support rewinding.
//
//
//
//
...
@@ -111,11 +112,11 @@
...
@@ -111,11 +112,11 @@
// #define MAL_NO_NULL
// #define MAL_NO_NULL
// Disables the null backend.
// Disables the null backend.
//
//
// #define MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS
(Default = 15)
// #define MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS
// When a buffer size of 0 is specified when a device is initialized, it will default to a size with
// When a buffer size of 0 is specified when a device is initialized, it will default to a size with
// this number of milliseconds worth of data.
// this number of milliseconds worth of data.
//
//
// #define MAL_DEFAULT_PERIODS
(Default = 2)
// #define MAL_DEFAULT_PERIODS
// When a period count of 0 is specified when a device is initialized, it will default to this.
// When a period count of 0 is specified when a device is initialized, it will default to this.
#ifndef mini_al_h
#ifndef mini_al_h
...
@@ -127,14 +128,12 @@ extern "C" {
...
@@ -127,14 +128,12 @@ extern "C" {
// Config.
// Config.
// The default size of the device's buffer in milliseconds. In my testing, if this is a multiple of the
// The default size of the device's buffer in milliseconds.
// periods it can result in audio glitching on the DirectSound backend, so make sure it's not a clean
// multiple of the period.
//
//
// If this is too small you may get underruns and overruns in which case you'll need to either increase
// If this is too small you may get underruns and overruns in which case you'll need to either increase
// this value or use an explicit buffer size.
// this value or use an explicit buffer size.
#ifndef MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS
#ifndef MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS
#define MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS
1
5
#define MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS
2
5
#endif
#endif
// Default periods when none is specified in mal_device_init(). More periods means more work on the CPU.
// Default periods when none is specified in mal_device_init(). More periods means more work on the CPU.
...
@@ -205,6 +204,10 @@ typedef void* mal_ptr;
...
@@ -205,6 +204,10 @@ typedef void* mal_ptr;
}
mal_event
;
}
mal_event
;
#endif
#endif
#ifdef MAL_ENABLE_DSOUND
#define MAL_MAX_PERIODS_DSOUND 4
#endif
typedef
int
mal_result
;
typedef
int
mal_result
;
#define MAL_SUCCESS 0
#define MAL_SUCCESS 0
#define MAL_ERROR -1 // A generic error.
#define MAL_ERROR -1 // A generic error.
...
@@ -320,6 +323,8 @@ struct mal_device
...
@@ -320,6 +323,8 @@ struct mal_device
/*LPDIRECTSOUNDBUFFER*/
mal_ptr
pPlaybackBuffer
;
/*LPDIRECTSOUNDBUFFER*/
mal_ptr
pPlaybackBuffer
;
/*LPDIRECTSOUNDCAPTURE8*/
mal_ptr
pCapture
;
/*LPDIRECTSOUNDCAPTURE8*/
mal_ptr
pCapture
;
/*LPDIRECTSOUNDCAPTUREBUFFER8*/
mal_ptr
pCaptureBuffer
;
/*LPDIRECTSOUNDCAPTUREBUFFER8*/
mal_ptr
pCaptureBuffer
;
/*LPDIRECTSOUNDNOTIFY*/
mal_ptr
pNotify
;
/*HANDLE*/
mal_handle
pNotifyEvents
[
MAL_MAX_PERIODS_DSOUND
];
// One event handle for each period.
/*HANDLE*/
mal_handle
hStopEvent
;
/*HANDLE*/
mal_handle
hStopEvent
;
/*HANDLE*/
mal_handle
hRewindEvent
;
/*HANDLE*/
mal_handle
hRewindEvent
;
mal_uint32
lastProcessedFrame
;
// This is circular.
mal_uint32
lastProcessedFrame
;
// This is circular.
...
@@ -1532,12 +1537,21 @@ static void mal_device_uninit__dsound(mal_device* pDevice)
...
@@ -1532,12 +1537,21 @@ static void mal_device_uninit__dsound(mal_device* pDevice)
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
if
(
pDevice
->
dsound
.
hDSoundDLL
!=
NULL
)
{
if
(
pDevice
->
dsound
.
hDSoundDLL
!=
NULL
)
{
if
(
pDevice
->
dsound
.
pNotify
)
{
IDirectSoundNotify_Release
((
LPDIRECTSOUNDNOTIFY
)
pDevice
->
dsound
.
pNotify
);
}
if
(
pDevice
->
dsound
.
hRewindEvent
)
{
if
(
pDevice
->
dsound
.
hRewindEvent
)
{
CloseHandle
(
pDevice
->
dsound
.
hRewindEvent
);
CloseHandle
(
pDevice
->
dsound
.
hRewindEvent
);
}
}
if
(
pDevice
->
dsound
.
hStopEvent
)
{
if
(
pDevice
->
dsound
.
hStopEvent
)
{
CloseHandle
(
pDevice
->
dsound
.
hStopEvent
);
CloseHandle
(
pDevice
->
dsound
.
hStopEvent
);
}
}
for
(
mal_uint32
i
=
0
;
i
<
pDevice
->
periods
;
++
i
)
{
if
(
pDevice
->
dsound
.
pNotifyEvents
[
i
])
{
CloseHandle
(
pDevice
->
dsound
.
pNotifyEvents
[
i
]);
}
}
if
(
pDevice
->
dsound
.
pCaptureBuffer
)
{
if
(
pDevice
->
dsound
.
pCaptureBuffer
)
{
IDirectSoundCaptureBuffer8_Release
((
LPDIRECTSOUNDBUFFER8
)
pDevice
->
dsound
.
pCaptureBuffer
);
IDirectSoundCaptureBuffer8_Release
((
LPDIRECTSOUNDBUFFER8
)
pDevice
->
dsound
.
pCaptureBuffer
);
...
@@ -1678,6 +1692,9 @@ static mal_result mal_device_init__dsound(mal_device* pDevice, mal_device_type t
...
@@ -1678,6 +1692,9 @@ static mal_result mal_device_init__dsound(mal_device* pDevice, mal_device_type t
// Meaning of dwFlags (from MSDN):
// Meaning of dwFlags (from MSDN):
//
//
// DSBCAPS_CTRLPOSITIONNOTIFY
// The buffer has position notification capability.
//
// DSBCAPS_GLOBALFOCUS
// DSBCAPS_GLOBALFOCUS
// With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to
// With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to
// another application, even if the new application uses DirectSound.
// another application, even if the new application uses DirectSound.
...
@@ -1689,13 +1706,19 @@ static mal_result mal_device_init__dsound(mal_device* pDevice, mal_device_type t
...
@@ -1689,13 +1706,19 @@ static mal_result mal_device_init__dsound(mal_device* pDevice, mal_device_type t
DSBUFFERDESC
descDS
;
DSBUFFERDESC
descDS
;
memset
(
&
descDS
,
0
,
sizeof
(
DSBUFFERDESC
));
memset
(
&
descDS
,
0
,
sizeof
(
DSBUFFERDESC
));
descDS
.
dwSize
=
sizeof
(
DSBUFFERDESC
);
descDS
.
dwSize
=
sizeof
(
DSBUFFERDESC
);
descDS
.
dwFlags
=
DSBCAPS_GLOBALFOCUS
|
DSBCAPS_GETCURRENTPOSITION2
;
descDS
.
dwFlags
=
DSBCAPS_
CTRLPOSITIONNOTIFY
|
DSBCAPS_
GLOBALFOCUS
|
DSBCAPS_GETCURRENTPOSITION2
;
descDS
.
dwBufferBytes
=
bufferSizeInBytes
;
descDS
.
dwBufferBytes
=
bufferSizeInBytes
;
descDS
.
lpwfxFormat
=
(
WAVEFORMATEX
*
)
&
wf
;
descDS
.
lpwfxFormat
=
(
WAVEFORMATEX
*
)
&
wf
;
if
(
FAILED
(
IDirectSound_CreateSoundBuffer
((
LPDIRECTSOUND8
)
pDevice
->
dsound
.
pPlayback
,
&
descDS
,
(
LPDIRECTSOUNDBUFFER
*
)
&
pDevice
->
dsound
.
pPlaybackBuffer
,
NULL
)))
{
if
(
FAILED
(
IDirectSound_CreateSoundBuffer
((
LPDIRECTSOUND8
)
pDevice
->
dsound
.
pPlayback
,
&
descDS
,
(
LPDIRECTSOUNDBUFFER
*
)
&
pDevice
->
dsound
.
pPlaybackBuffer
,
NULL
)))
{
mal_device_uninit__dsound
(
pDevice
);
mal_device_uninit__dsound
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer."
,
MAL_DSOUND_FAILED_TO_CREATE_BUFFER
);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer."
,
MAL_DSOUND_FAILED_TO_CREATE_BUFFER
);
}
}
// Notifications are set up via a DIRECTSOUNDNOTIFY object which is retrieved from the buffer.
if
(
FAILED
(
IDirectSoundBuffer8_QueryInterface
((
LPDIRECTSOUNDBUFFER
)
pDevice
->
dsound
.
pPlaybackBuffer
,
g_mal_GUID_IID_DirectSoundNotify
,
(
void
**
)
&
pDevice
->
dsound
.
pNotify
)))
{
mal_device_uninit__dsound
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSoundBuffer8_QueryInterface() failed for playback device's IDirectSoundNotify object."
,
MAL_DSOUND_FAILED_TO_QUERY_INTERFACE
);
}
}
else
{
}
else
{
mal_DirectSoundCaptureCreate8Proc
pDirectSoundCaptureCreate8
=
(
mal_DirectSoundCaptureCreate8Proc
)
GetProcAddress
((
HMODULE
)
pDevice
->
dsound
.
hDSoundDLL
,
"DirectSoundCaptureCreate8"
);
mal_DirectSoundCaptureCreate8Proc
pDirectSoundCaptureCreate8
=
(
mal_DirectSoundCaptureCreate8Proc
)
GetProcAddress
((
HMODULE
)
pDevice
->
dsound
.
hDSoundDLL
,
"DirectSoundCaptureCreate8"
);
if
(
pDirectSoundCaptureCreate8
==
NULL
)
{
if
(
pDirectSoundCaptureCreate8
==
NULL
)
{
...
@@ -1728,6 +1751,34 @@ static mal_result mal_device_init__dsound(mal_device* pDevice, mal_device_type t
...
@@ -1728,6 +1751,34 @@ static mal_result mal_device_init__dsound(mal_device* pDevice, mal_device_type t
mal_device_uninit__dsound
(
pDevice
);
mal_device_uninit__dsound
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSoundCapture_QueryInterface() failed for capture device's IDirectSoundCaptureBuffer8 object."
,
MAL_DSOUND_FAILED_TO_QUERY_INTERFACE
);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSoundCapture_QueryInterface() failed for capture device's IDirectSoundCaptureBuffer8 object."
,
MAL_DSOUND_FAILED_TO_QUERY_INTERFACE
);
}
}
// Notifications are set up via a DIRECTSOUNDNOTIFY object which is retrieved from the buffer.
if
(
FAILED
(
IDirectSoundCaptureBuffer8_QueryInterface
((
LPDIRECTSOUNDCAPTUREBUFFER
)
pDevice
->
dsound
.
pCaptureBuffer
,
g_mal_GUID_IID_DirectSoundNotify
,
(
void
**
)
&
pDevice
->
dsound
.
pNotify
)))
{
mal_device_uninit__dsound
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSoundCaptureBuffer8_QueryInterface() failed for capture device's IDirectSoundNotify object."
,
MAL_DSOUND_FAILED_TO_QUERY_INTERFACE
);
}
}
// We need a notification for each period. The notification offset is slightly different depending on whether or not the
// device is a playback or capture device. For a playback device we want to be notified when a period just starts playing,
// whereas for a capture device we want to be notified when a period has just _finished_ capturing.
mal_uint32
periodSizeInBytes
=
pDevice
->
bufferSizeInFrames
/
pDevice
->
periods
;
DSBPOSITIONNOTIFY
notifyPoints
[
MAL_MAX_PERIODS_DSOUND
];
// One notification event for each period.
for
(
mal_uint32
i
=
0
;
i
<
pDevice
->
periods
;
++
i
)
{
pDevice
->
dsound
.
pNotifyEvents
[
i
]
=
CreateEventA
(
NULL
,
FALSE
,
FALSE
,
NULL
);
if
(
pDevice
->
dsound
.
pNotifyEvents
[
i
]
==
NULL
)
{
mal_device_uninit__dsound
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[DirectSound] Failed to create event for buffer notifications."
,
MAL_FAILED_TO_CREATE_EVENT
);
}
// The notification offset is in bytes.
notifyPoints
[
i
].
dwOffset
=
i
*
periodSizeInBytes
;
notifyPoints
[
i
].
hEventNotify
=
pDevice
->
dsound
.
pNotifyEvents
[
i
];
}
if
(
FAILED
(
IDirectSoundNotify_SetNotificationPositions
((
LPDIRECTSOUNDNOTIFY
)
pDevice
->
dsound
.
pNotify
,
pDevice
->
periods
,
notifyPoints
)))
{
mal_device_uninit__dsound
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSoundNotify_SetNotificationPositions() failed."
,
MAL_DSOUND_FAILED_TO_SET_NOTIFICATIONS
);
}
}
// When the device is playing the worker thread will be waiting on a bunch of notification events. To return from
// When the device is playing the worker thread will be waiting on a bunch of notification events. To return from
...
@@ -1898,6 +1949,12 @@ static mal_uint32 mal_device__wait_for_frames__dsound(mal_device* pDevice)
...
@@ -1898,6 +1949,12 @@ static mal_uint32 mal_device__wait_for_frames__dsound(mal_device* pDevice)
timeoutInMilliseconds
=
1
;
timeoutInMilliseconds
=
1
;
}
}
unsigned
int
eventCount
=
pDevice
->
periods
+
2
;
HANDLE
pEvents
[
MAL_MAX_PERIODS_DSOUND
+
2
];
// +2 for the stop and rewind event.
mal_copy_memory
(
pEvents
,
pDevice
->
dsound
.
pNotifyEvents
,
sizeof
(
HANDLE
)
*
pDevice
->
periods
);
pEvents
[
eventCount
-
2
]
=
pDevice
->
dsound
.
hStopEvent
;
pEvents
[
eventCount
-
1
]
=
pDevice
->
dsound
.
hRewindEvent
;
while
(
!
pDevice
->
dsound
.
breakFromMainLoop
)
{
while
(
!
pDevice
->
dsound
.
breakFromMainLoop
)
{
mal_uint32
framesAvailable
=
mal_device__get_available_frames__dsound
(
pDevice
);
mal_uint32
framesAvailable
=
mal_device__get_available_frames__dsound
(
pDevice
);
if
(
framesAvailable
>
0
)
{
if
(
framesAvailable
>
0
)
{
...
@@ -1905,10 +1962,7 @@ static mal_uint32 mal_device__wait_for_frames__dsound(mal_device* pDevice)
...
@@ -1905,10 +1962,7 @@ static mal_uint32 mal_device__wait_for_frames__dsound(mal_device* pDevice)
}
}
// If we get here it means we weren't able to find any frames. We'll just wait here for a bit.
// If we get here it means we weren't able to find any frames. We'll just wait here for a bit.
HANDLE
pEvents
[
2
];
WaitForMultipleObjects
(
eventCount
,
pEvents
,
FALSE
,
timeoutInMilliseconds
);
pEvents
[
0
]
=
pDevice
->
dsound
.
hStopEvent
;
pEvents
[
1
]
=
pDevice
->
dsound
.
hRewindEvent
;
WaitForMultipleObjects
(
sizeof
(
pEvents
)
/
sizeof
(
pEvents
[
0
]),
pEvents
,
FALSE
,
timeoutInMilliseconds
);
}
}
// We'll get here if the loop was terminated. Just return whatever's available.
// We'll get here if the loop was terminated. Just return whatever's available.
...
...
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