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
5b069848
Commit
5b069848
authored
Apr 25, 2018
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
DirectSound: Add support for retrieving detailed device info.
parent
e2f6d4ab
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
283 additions
and
90 deletions
+283
-90
mini_al.h
mini_al.h
+283
-90
No files found.
mini_al.h
View file @
5b069848
...
...
@@ -2811,6 +2811,7 @@ mal_uint32 g_malStandardSampleRatePriorities[] = {
#define mal_countof(x) (sizeof(x) / sizeof(x[0]))
#define mal_max(x, y) (((x) > (y)) ? (x) : (y))
#define mal_min(x, y) (((x) < (y)) ? (x) : (y))
#define mal_clamp(x, lo, hi) (mal_max(lo, mal_min(x, hi)))
#define mal_offset_ptr(p, offset) (((mal_uint8*)(p)) + (offset))
#define mal_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / mal_get_bytes_per_sample(format) / (channels))
...
...
@@ -3665,6 +3666,34 @@ mal_uint32 mal_get_best_sample_rate_within_range(mal_uint32 sampleRateMin, mal_u
return 0;
}
mal_uint32 mal_get_closest_standard_sample_rate(mal_uint32 sampleRateIn)
{
mal_uint32 closestRate = 0;
mal_uint32 closestDiff = 0xFFFFFFFF;
for (size_t iStandardRate = 0; iStandardRate < mal_countof(g_malStandardSampleRatePriorities); ++iStandardRate) {
mal_uint32 standardRate = g_malStandardSampleRatePriorities[iStandardRate];
mal_uint32 diff;
if (sampleRateIn > standardRate) {
diff = sampleRateIn - standardRate;
} else {
diff = standardRate - sampleRateIn;
}
if (diff == 0) {
return standardRate; // The input sample rate is a standard rate.
}
if (closestDiff > diff) {
closestDiff = diff;
closestRate = standardRate;
}
}
return closestRate;
}
// Posts a log message.
void mal_log(mal_context* pContext, mal_device* pDevice, const char* message)
...
...
@@ -6101,6 +6130,147 @@ void mal_get_channels_from_speaker_config__dsound(DWORD speakerConfig, WORD* pCh
}
mal_result mal_context_create_IDirectSound__dsound(mal_context* pContext, mal_share_mode shareMode, const mal_device_id* pDeviceID, mal_IDirectSound** ppDirectSound)
{
mal_assert(pContext != NULL);
mal_assert(ppDirectSound != NULL);
*ppDirectSound = NULL;
mal_IDirectSound* pDirectSound = NULL;
if (FAILED(((mal_DirectSoundCreateProc)pContext->dsound.DirectSoundCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSound, NULL))) {
return mal_context_post_error(pContext, NULL, "[DirectSound] DirectSoundCreate() failed for playback device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
// The cooperative level must be set before doing anything else.
HWND hWnd = ((MAL_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)();
if (hWnd == NULL) {
hWnd = ((MAL_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)();
}
if (FAILED(mal_IDirectSound_SetCooperativeLevel(pDirectSound, hWnd, (shareMode == mal_share_mode_exclusive) ? MAL_DSSCL_EXCLUSIVE : MAL_DSSCL_PRIORITY))) {
return mal_context_post_error(pContext, NULL, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
*ppDirectSound = pDirectSound;
return MAL_SUCCESS;
}
mal_result mal_context_create_IDirectSoundCapture__dsound(mal_context* pContext, mal_share_mode shareMode, const mal_device_id* pDeviceID, mal_IDirectSoundCapture** ppDirectSoundCapture)
{
mal_assert(pContext != NULL);
mal_assert(ppDirectSoundCapture != NULL);
// Everything is shared in capture mode by the looks of it.
(void)shareMode;
*ppDirectSoundCapture = NULL;
mal_IDirectSoundCapture* pDirectSoundCapture = NULL;
if (FAILED(((mal_DirectSoundCaptureCreateProc)pContext->dsound.DirectSoundCaptureCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSoundCapture, NULL))) {
return mal_context_post_error(pContext, NULL, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
*ppDirectSoundCapture = pDirectSoundCapture;
return MAL_SUCCESS;
}
mal_result mal_context_get_format_info_for_IDirectSoundCapture__dsound(mal_context* pContext, mal_IDirectSoundCapture* pDirectSoundCapture, WORD* pChannels, WORD* pBitsPerSample, DWORD* pSampleRate)
{
mal_assert(pContext != NULL);
mal_assert(pDirectSoundCapture != NULL);
if (pChannels) {
*pChannels = 0;
}
if (pBitsPerSample) {
*pBitsPerSample = 0;
}
if (pSampleRate) {
*pSampleRate = 0;
}
MAL_DSCCAPS caps;
mal_zero_object(&caps);
caps.dwSize = sizeof(caps);
if (FAILED(mal_IDirectSoundCapture_GetCaps(pDirectSoundCapture, &caps))) {
return mal_context_post_error(pContext, NULL, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
if (pChannels) {
*pChannels = (WORD)caps.dwChannels;
}
// The device can support multiple formats. We just go through the different formats in order of priority and
// pick the first one. This the same type of system as the WinMM backend.
WORD bitsPerSample = 16;
DWORD sampleRate = 48000;
if (caps.dwChannels == 1) {
if ((caps.dwFormats & WAVE_FORMAT_48M16) != 0) {
sampleRate = 48000;
} else if ((caps.dwFormats & WAVE_FORMAT_44M16) != 0) {
sampleRate = 44100;
} else if ((caps.dwFormats & WAVE_FORMAT_2M16) != 0) {
sampleRate = 22050;
} else if ((caps.dwFormats & WAVE_FORMAT_1M16) != 0) {
sampleRate = 11025;
} else if ((caps.dwFormats & WAVE_FORMAT_96M16) != 0) {
sampleRate = 96000;
} else {
bitsPerSample = 8;
if ((caps.dwFormats & WAVE_FORMAT_48M08) != 0) {
sampleRate = 48000;
} else if ((caps.dwFormats & WAVE_FORMAT_44M08) != 0) {
sampleRate = 44100;
} else if ((caps.dwFormats & WAVE_FORMAT_2M08) != 0) {
sampleRate = 22050;
} else if ((caps.dwFormats & WAVE_FORMAT_1M08) != 0) {
sampleRate = 11025;
} else if ((caps.dwFormats & WAVE_FORMAT_96M08) != 0) {
sampleRate = 96000;
} else {
bitsPerSample = 16; // Didn't find it. Just fall back to 16-bit.
}
}
} else if (caps.dwChannels == 2) {
if ((caps.dwFormats & WAVE_FORMAT_48S16) != 0) {
sampleRate = 48000;
} else if ((caps.dwFormats & WAVE_FORMAT_44S16) != 0) {
sampleRate = 44100;
} else if ((caps.dwFormats & WAVE_FORMAT_2S16) != 0) {
sampleRate = 22050;
} else if ((caps.dwFormats & WAVE_FORMAT_1S16) != 0) {
sampleRate = 11025;
} else if ((caps.dwFormats & WAVE_FORMAT_96S16) != 0) {
sampleRate = 96000;
} else {
bitsPerSample = 8;
if ((caps.dwFormats & WAVE_FORMAT_48S08) != 0) {
sampleRate = 48000;
} else if ((caps.dwFormats & WAVE_FORMAT_44S08) != 0) {
sampleRate = 44100;
} else if ((caps.dwFormats & WAVE_FORMAT_2S08) != 0) {
sampleRate = 22050;
} else if ((caps.dwFormats & WAVE_FORMAT_1S08) != 0) {
sampleRate = 11025;
} else if ((caps.dwFormats & WAVE_FORMAT_96S08) != 0) {
sampleRate = 96000;
} else {
bitsPerSample = 16; // Didn't find it. Just fall back to 16-bit.
}
}
}
if (pBitsPerSample) {
*pBitsPerSample = bitsPerSample;
}
if (pSampleRate) {
*pSampleRate = sampleRate;
}
return MAL_SUCCESS;
}
mal_bool32 mal_context_is_device_id_equal__dsound(mal_context* pContext, const mal_device_id* pID0, const mal_device_id* pID1)
{
mal_assert(pContext != NULL);
...
...
@@ -6230,10 +6400,8 @@ mal_result mal_context_get_device_info__dsound(mal_context* pContext, mal_device
((mal_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(mal_context_get_device_info_callback__dsound, &data);
}
if
(
data
.
found
)
{
if (
!
data.found) {
return MAL_SUCCESS;
}
else
{
return
MAL_NO_DEVICE
;
}
} else {
// I don't think there's a way to get the name of the default device with DirectSound. In this case we just need to use defaults.
...
...
@@ -6249,6 +6417,105 @@ mal_result mal_context_get_device_info__dsound(mal_context* pContext, mal_device
}
}
// Retrieving detailed information is slightly different depending on the device type.
if (deviceType == mal_device_type_playback) {
// Playback.
mal_IDirectSound* pDirectSound;
mal_result result = mal_context_create_IDirectSound__dsound(pContext, shareMode, pDeviceID, &pDirectSound);
if (result != MAL_SUCCESS) {
return result;
}
MAL_DSCAPS caps;
mal_zero_object(&caps);
caps.dwSize = sizeof(caps);
if (FAILED(mal_IDirectSound_GetCaps(pDirectSound, &caps))) {
return mal_context_post_error(pContext, NULL, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
if ((caps.dwFlags & MAL_DSCAPS_PRIMARYSTEREO) != 0) {
// It supports at least stereo, but could support more.
pDeviceInfo->minChannels = 2;
pDeviceInfo->maxChannels = 2;
// Look at the speaker configuration to get a better idea on the channel count.
DWORD speakerConfig;
if (SUCCEEDED(mal_IDirectSound_GetSpeakerConfig(pDirectSound, &speakerConfig))) {
WORD actualChannels;
mal_get_channels_from_speaker_config__dsound(speakerConfig, &actualChannels, NULL);
pDeviceInfo->minChannels = actualChannels;
pDeviceInfo->maxChannels = actualChannels;
}
} else {
// It does not support stereo, which means we are stuck with mono.
pDeviceInfo->minChannels = 1;
pDeviceInfo->maxChannels = 1;
}
// Sample rate.
if ((caps.dwFlags & MAL_DSCAPS_CONTINUOUSRATE) != 0) {
pDeviceInfo->minSampleRate = caps.dwMinSecondarySampleRate;
pDeviceInfo->maxSampleRate = caps.dwMaxSecondarySampleRate;
// On my machine the min and max sample rates can return 100 and 200000 respectively. I'd rather these be within
// the range of our standard sample rates so I'm clamping.
if (caps.dwMinSecondarySampleRate < MAL_MIN_SAMPLE_RATE && caps.dwMaxSecondarySampleRate >= MAL_MIN_SAMPLE_RATE) {
pDeviceInfo->minSampleRate = MAL_MIN_SAMPLE_RATE;
}
if (caps.dwMaxSecondarySampleRate > MAL_MAX_SAMPLE_RATE && caps.dwMinSecondarySampleRate <= MAL_MAX_SAMPLE_RATE) {
pDeviceInfo->maxSampleRate = MAL_MAX_SAMPLE_RATE;
}
} else {
// Only supports a single sample rate. Set both min an max to the same thing. Do not clamp within the standard rates.
pDeviceInfo->minSampleRate = caps.dwMaxSecondarySampleRate;
pDeviceInfo->maxSampleRate = caps.dwMaxSecondarySampleRate;
}
// DirectSound can support all formats.
pDeviceInfo->formatCount = mal_format_count - 1; // Minus one because we don't want to include mal_format_unknown.
for (mal_uint32 iFormat = 0; iFormat < pDeviceInfo->formatCount; ++iFormat) {
pDeviceInfo->formats[iFormat] = (mal_format)(iFormat + 1); // +1 to skip over mal_format_unknown.
}
mal_IDirectSound_Release(pDirectSound);
} else {
// Capture. This is a little different to playback due to the say the supported formats are reported. Technically capture
// devices can support a number of different formats, but for simplicity and consistency with mal_device_init() I'm just
// reporting the best format.
mal_IDirectSoundCapture* pDirectSoundCapture;
mal_result result = mal_context_create_IDirectSoundCapture__dsound(pContext, shareMode, pDeviceID, &pDirectSoundCapture);
if (result != MAL_SUCCESS) {
return result;
}
WORD channels;
WORD bitsPerSample;
DWORD sampleRate;
result = mal_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, pDirectSoundCapture, &channels, &bitsPerSample, &sampleRate);
if (result != MAL_SUCCESS) {
mal_IDirectSoundCapture_Release(pDirectSoundCapture);
return result;
}
pDeviceInfo->minChannels = channels;
pDeviceInfo->maxChannels = channels;
pDeviceInfo->minSampleRate = sampleRate;
pDeviceInfo->maxSampleRate = sampleRate;
pDeviceInfo->formatCount = 1;
if (bitsPerSample == 8) {
pDeviceInfo->formats[0] = mal_format_u8;
} else if (bitsPerSample == 16) {
pDeviceInfo->formats[0] = mal_format_s16;
} else if (bitsPerSample == 24) {
pDeviceInfo->formats[0] = mal_format_s24;
} else if (bitsPerSample == 32) {
pDeviceInfo->formats[0] = mal_format_s32;
}
mal_IDirectSoundCapture_Release(pDirectSoundCapture);
}
return MAL_SUCCESS;
}
...
...
@@ -6402,19 +6669,10 @@ mal_result mal_device_init__dsound(mal_context* pContext, mal_device_type type,
// Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices :(
if (type == mal_device_type_playback) {
if
(
FAILED
(((
mal_DirectSoundCreateProc
)
pContext
->
dsound
.
DirectSoundCreate
)((
pDeviceID
==
NULL
)
?
NULL
:
(
const
GUID
*
)
pDeviceID
->
dsound
,
(
mal_IDirectSound
**
)
&
pDevice
->
dsound
.
pPlayback
,
NULL
)))
{
mal_device_uninit__dsound
(
pDevice
);
return
mal_post_error
(
pDevice
,
"[DirectSound] DirectSoundCreate() failed for playback device."
,
MAL_FAILED_TO_OPEN_BACKEND_DEVICE
);
}
// The cooperative level must be set before doing anything else.
HWND
hWnd
=
((
MAL_PFN_GetForegroundWindow
)
pContext
->
win32
.
GetForegroundWindow
)();
if
(
hWnd
==
NULL
)
{
hWnd
=
((
MAL_PFN_GetDesktopWindow
)
pContext
->
win32
.
GetDesktopWindow
)();
}
if
(
FAILED
(
mal_IDirectSound_SetCooperativeLevel
((
mal_IDirectSound
*
)
pDevice
->
dsound
.
pPlayback
,
hWnd
,
(
pConfig
->
shareMode
==
mal_share_mode_exclusive
)
?
MAL_DSSCL_EXCLUSIVE
:
MAL_DSSCL_PRIORITY
)))
{
mal_result result = mal_context_create_IDirectSound__dsound(pContext, pConfig->shareMode, pDeviceID, (mal_IDirectSound**)&pDevice->dsound.pPlayback);
if (result != MAL_SUCCESS) {
mal_device_uninit__dsound(pDevice);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device."
,
MAL_FAILED_TO_OPEN_BACKEND_DEVICE
)
;
return
result
;
}
MAL_DSBUFFERDESC descDSPrimary;
...
...
@@ -6533,81 +6791,16 @@ mal_result mal_device_init__dsound(mal_context* pContext, mal_device_type type,
pDevice->bufferSizeInFrames *= 2; // <-- Might need to fiddle with this to find a more ideal value. May even be able to just add a fixed amount rather than scaling.
}
if
(
FAILED
(((
mal_DirectSoundCaptureCreateProc
)
pContext
->
dsound
.
DirectSoundCaptureCreate
)((
pDeviceID
==
NULL
)
?
NULL
:
(
const
GUID
*
)
pDeviceID
->
dsound
,
(
mal_IDirectSoundCapture
**
)
&
pDevice
->
dsound
.
pCapture
,
NULL
)))
{
mal_result result = mal_context_create_IDirectSoundCapture__dsound(pContext, pConfig->shareMode, pDeviceID, (mal_IDirectSoundCapture**)&pDevice->dsound.pCapture);
if (result != MAL_SUCCESS) {
mal_device_uninit__dsound(pDevice);
return
mal_post_error
(
pDevice
,
"[DirectSound] DirectSoundCaptureCreate() failed for capture device."
,
MAL_FAILED_TO_OPEN_BACKEND_DEVICE
)
;
return
result
;
}
MAL_DSCCAPS
caps
;
mal_zero_object
(
&
caps
);
caps
.
dwSize
=
sizeof
(
caps
);
if
(
FAILED
(
mal_IDirectSoundCapture_GetCaps
((
mal_IDirectSoundCapture
*
)
pDevice
->
dsound
.
pCapture
,
&
caps
)))
{
result = mal_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, (mal_IDirectSoundCapture*)pDevice->dsound.pCapture, &wf.Format.nChannels, &wf.Format.wBitsPerSample, &wf.Format.nSamplesPerSec);
if (result != MAL_SUCCESS) {
mal_device_uninit__dsound(pDevice);
return
mal_post_error
(
pDevice
,
"[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device."
,
MAL_FAILED_TO_OPEN_BACKEND_DEVICE
);
}
wf
.
Format
.
nChannels
=
(
WORD
)
caps
.
dwChannels
;
// The device can support multiple formats. We just go through the different formats in order of priority and
// pick the first one. This the same type of system as the WinMM backend.
wf
.
Format
.
wBitsPerSample
=
16
;
wf
.
Format
.
nSamplesPerSec
=
48000
;
if
(
caps
.
dwChannels
==
1
)
{
if
((
caps
.
dwFormats
&
WAVE_FORMAT_48M16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
48000
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_44M16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
44100
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_2M16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
22050
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_1M16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
11025
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_96M16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
96000
;
}
else
{
wf
.
Format
.
wBitsPerSample
=
8
;
if
((
caps
.
dwFormats
&
WAVE_FORMAT_48M08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
48000
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_44M08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
44100
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_2M08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
22050
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_1M08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
11025
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_96M08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
96000
;
}
else
{
wf
.
Format
.
wBitsPerSample
=
16
;
// Didn't find it. Just fall back to 16-bit.
}
}
}
else
if
(
caps
.
dwChannels
==
2
)
{
if
((
caps
.
dwFormats
&
WAVE_FORMAT_48S16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
48000
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_44S16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
44100
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_2S16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
22050
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_1S16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
11025
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_96S16
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
96000
;
}
else
{
wf
.
Format
.
wBitsPerSample
=
8
;
if
((
caps
.
dwFormats
&
WAVE_FORMAT_48S08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
48000
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_44S08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
44100
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_2S08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
22050
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_1S08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
11025
;
}
else
if
((
caps
.
dwFormats
&
WAVE_FORMAT_96S08
)
!=
0
)
{
wf
.
Format
.
nSamplesPerSec
=
96000
;
}
else
{
wf
.
Format
.
wBitsPerSample
=
16
;
// Didn't find it. Just fall back to 16-bit.
}
}
return result;
}
wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8;
...
...
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