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
bf67d5a3
Commit
bf67d5a3
authored
Oct 18, 2016
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ALSA: Experiment with a more user-friendly device enumeration.
parent
4094293c
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
174 additions
and
34 deletions
+174
-34
mini_al.h
mini_al.h
+174
-34
No files found.
mini_al.h
View file @
bf67d5a3
...
@@ -119,20 +119,21 @@ typedef int mal_result;
...
@@ -119,20 +119,21 @@ typedef int mal_result;
#define MAL_OUT_OF_MEMORY -3
#define MAL_OUT_OF_MEMORY -3
#define MAL_FORMAT_NOT_SUPPORTED -4
#define MAL_FORMAT_NOT_SUPPORTED -4
#define MAL_NO_BACKEND -5
#define MAL_NO_BACKEND -5
#define MAL_API_NOT_FOUND -6
#define MAL_NO_DEVICE -6
#define MAL_DEVICE_BUSY -7
#define MAL_API_NOT_FOUND -7
#define MAL_DEVICE_NOT_INITIALIZED -8
#define MAL_DEVICE_BUSY -8
#define MAL_DEVICE_ALREADY_STARTED -9
#define MAL_DEVICE_NOT_INITIALIZED -9
#define MAL_DEVICE_ALREADY_STARTING -10
#define MAL_DEVICE_ALREADY_STARTED -10
#define MAL_DEVICE_ALREADY_STOPPED -11
#define MAL_DEVICE_ALREADY_STARTING -11
#define MAL_DEVICE_ALREADY_STOPPING -12
#define MAL_DEVICE_ALREADY_STOPPED -12
#define MAL_FAILED_TO_MAP_DEVICE_BUFFER -13
#define MAL_DEVICE_ALREADY_STOPPING -13
#define MAL_FAILED_TO_INIT_BACKEND -14
#define MAL_FAILED_TO_MAP_DEVICE_BUFFER -14
#define MAL_FAILED_TO_READ_DATA_FROM_CLIENT -15
#define MAL_FAILED_TO_INIT_BACKEND -15
#define MAL_FAILED_TO_START_BACKEND_DEVICE -16
#define MAL_FAILED_TO_READ_DATA_FROM_CLIENT -16
#define MAL_FAILED_TO_STOP_BACKEND_DEVICE -17
#define MAL_FAILED_TO_START_BACKEND_DEVICE -17
#define MAL_FAILED_TO_CREATE_EVENT -18
#define MAL_FAILED_TO_STOP_BACKEND_DEVICE -18
#define MAL_FAILED_TO_CREATE_THREAD -19
#define MAL_FAILED_TO_CREATE_EVENT -19
#define MAL_FAILED_TO_CREATE_THREAD -20
#define MAL_DSOUND_FAILED_TO_CREATE_DEVICE -1024
#define MAL_DSOUND_FAILED_TO_CREATE_DEVICE -1024
#define MAL_DSOUND_FAILED_TO_SET_COOP_LEVEL -1025
#define MAL_DSOUND_FAILED_TO_SET_COOP_LEVEL -1025
#define MAL_DSOUND_FAILED_TO_CREATE_BUFFER -1026
#define MAL_DSOUND_FAILED_TO_CREATE_BUFFER -1026
...
@@ -177,14 +178,14 @@ typedef enum
...
@@ -177,14 +178,14 @@ typedef enum
typedef
union
typedef
union
{
{
char
name
[
256
];
// ALSA uses a name string for identification.
char
str
[
32
];
// ALSA uses a name string for identification.
mal_uint8
guid
[
16
];
// DirectSound uses a GUID to identify a device.
mal_uint8
guid
[
16
];
// DirectSound uses a GUID to identify a device.
}
mal_device_id
;
}
mal_device_id
;
typedef
struct
typedef
struct
{
{
mal_device_id
id
;
mal_device_id
id
;
char
description
[
256
];
char
name
[
256
];
}
mal_device_info
;
}
mal_device_info
;
struct
mal_device
struct
mal_device
...
@@ -465,6 +466,10 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format);
...
@@ -465,6 +466,10 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format);
#include <assert.h>
#include <assert.h>
#endif
#endif
#ifdef MAL_ENABLE_ALSA
#include <stdio.h> // Needed for printf() which is used for "hw:%d,%d" formatting. TODO: Remove this later.
#endif
#if !defined(MAL_64BIT) && !defined(MAL_32BIT)
#if !defined(MAL_64BIT) && !defined(MAL_32BIT)
#ifdef _WIN32
#ifdef _WIN32
#ifdef _WIN64
#ifdef _WIN64
...
@@ -924,9 +929,9 @@ mal_result mal_enumerate_devices__null(mal_device_type type, mal_uint32* pCount,
...
@@ -924,9 +929,9 @@ mal_result mal_enumerate_devices__null(mal_device_type type, mal_uint32* pCount,
mal_zero_object
(
pInfo
);
mal_zero_object
(
pInfo
);
if
(
type
==
mal_device_type_playback
)
{
if
(
type
==
mal_device_type_playback
)
{
mal_strncpy_s
(
pInfo
->
description
,
sizeof
(
pInfo
->
description
),
"NULL Playback Device"
,
(
size_t
)
-
1
);
mal_strncpy_s
(
pInfo
->
name
,
sizeof
(
pInfo
->
name
),
"NULL Playback Device"
,
(
size_t
)
-
1
);
}
else
{
}
else
{
mal_strncpy_s
(
pInfo
->
description
,
sizeof
(
pInfo
->
description
),
"NULL Capture Device"
,
(
size_t
)
-
1
);
mal_strncpy_s
(
pInfo
->
name
,
sizeof
(
pInfo
->
name
),
"NULL Capture Device"
,
(
size_t
)
-
1
);
}
}
}
}
...
@@ -1616,6 +1621,29 @@ static mal_result mal_device__main_loop__dsound(mal_device* pDevice)
...
@@ -1616,6 +1621,29 @@ static mal_result mal_device__main_loop__dsound(mal_device* pDevice)
#ifdef MAL_ENABLE_ALSA
#ifdef MAL_ENABLE_ALSA
#include <alsa/asoundlib.h>
#include <alsa/asoundlib.h>
const
char
*
mal_find_char
(
const
char
*
str
,
char
c
,
int
*
index
)
{
int
i
=
0
;
for
(;;)
{
if
(
str
[
i
]
==
'\0'
)
{
if
(
index
)
*
index
=
-
1
;
return
NULL
;
}
if
(
str
[
i
]
==
c
)
{
if
(
index
)
*
index
=
i
;
return
str
+
i
;
}
i
+=
1
;
}
// Should never get here, but treat it as though the character was not found to make me feel
// better inside.
if
(
index
)
*
index
=
-
1
;
return
NULL
;
}
// Waits for a number of frames to become available for either capture or playback. The return
// Waits for a number of frames to become available for either capture or playback. The return
// value is the number of frames available. If this is less than the fragment size it means the
// value is the number of frames available. If this is less than the fragment size it means the
// main loop has been terminated from another thread. The return value will be clamped to the
// main loop has been terminated from another thread. The return value will be clamped to the
...
@@ -1849,6 +1877,98 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
...
@@ -1849,6 +1877,98 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
mal_uint32
infoSize
=
*
pCount
;
mal_uint32
infoSize
=
*
pCount
;
*
pCount
=
0
;
*
pCount
=
0
;
// What I've learned about device iteration with ALSA
// ==================================================
//
// The preferred method for enumerating devices is to use snd_device_name_hint() and family. The
// reason this is preferred is because it includes user-space devices like the "default" device
// which goes through PulseAudio. The problem, however, is that it is extremely un-user-friendly
// because it enumerates a _lot_ of devices. On my test machine I have only a typical output device
// for speakers/headerphones and a microphone - this results 52 devices getting enumerated!
//
// One way to pull this back a bit is to ignore all but "hw" devices. At initialization time we
// can simply append "plug" to the ID string to enable software conversions.
//
// An alternative enumeration technique is to use snd_card_next() and family. The problem with this
// one, which is significant, is that it does _not_ include user-space devices.
#if 0
// Devices are in card/device pairs and formatted as "hw:{card},{device}". Note that we actually use
// "plughw:{card},{device}"
int card = -1;
if (snd_card_next(&card) < 0 || card < 0) {
return MAL_NO_DEVICE;
}
snd_ctl_card_info_t *pCardInfo;
snd_ctl_card_info_alloca(&pCardInfo);
snd_pcm_info_t* pPCMInfo;
snd_pcm_info_alloca(&pPCMInfo);
do
{
char cardName[32];
snprintf(cardName, sizeof(cardName), "hw:%d", card);
snd_ctl_t* pCTL;
int result = snd_ctl_open(&pCTL, cardName, 0);
if (result < 0) {
snd_ctl_close(pCTL);
continue;
}
result = snd_ctl_card_info(pCTL, pCardInfo);
if (result < 0) {
snd_ctl_close(pCTL);
continue;
}
int device = -1;
if (snd_ctl_pcm_next_device(pCTL, &device) < 0) {
snd_ctl_close(pCTL);
continue;
}
do
{
snd_pcm_info_set_device(pPCMInfo, device);
snd_pcm_info_set_stream(pPCMInfo, (type == mal_device_type_playback) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE);
snd_pcm_info_set_subdevice(pPCMInfo, 0);
result = snd_ctl_pcm_info(pCTL, pPCMInfo);
if (result < 0) {
if (result != -ENOENT) {
goto next_card;
}
goto next_device;
}
if (pInfo != NULL) {
if (infoSize > 0) {
mal_zero_object(pInfo);
snprintf(pInfo->id.str, sizeof(pInfo->id.str), "plughw:%d,%d", card, device);
snprintf(pInfo->name, sizeof(pInfo->name), "%s, %s", snd_ctl_card_info_get_name(pCardInfo), snd_pcm_info_get_name(pPCMInfo));
mal_strncpy_s(pInfo->description, sizeof(pInfo->description), snd_ctl_card_info_get_longname(pCardInfo), (size_t)-1);
pInfo += 1;
infoSize -= 1;
*pCount += 1;
}
} else {
*pCount += 1;
}
next_device:;
} while (snd_ctl_pcm_next_device(pCTL, &device) >= 0 && device >= 0);
next_card:;
} while (snd_card_next(&card) >= 0 && card >= 0);
return MAL_SUCCESS;
#else
char
**
ppDeviceHints
;
char
**
ppDeviceHints
;
if
(
snd_device_name_hint
(
-
1
,
"pcm"
,
(
void
***
)
&
ppDeviceHints
)
<
0
)
{
if
(
snd_device_name_hint
(
-
1
,
"pcm"
,
(
void
***
)
&
ppDeviceHints
)
<
0
)
{
return
MAL_NO_BACKEND
;
return
MAL_NO_BACKEND
;
...
@@ -1864,11 +1984,23 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
...
@@ -1864,11 +1984,23 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
(
type
==
mal_device_type_playback
&&
strcmp
(
IOID
,
"Output"
)
==
0
)
||
(
type
==
mal_device_type_playback
&&
strcmp
(
IOID
,
"Output"
)
==
0
)
||
(
type
==
mal_device_type_capture
&&
strcmp
(
IOID
,
"Input"
)
==
0
))
(
type
==
mal_device_type_capture
&&
strcmp
(
IOID
,
"Input"
)
==
0
))
{
{
// Experiment. Skip over any non "hw" devices to try and pull back on the number
// of enumerated devices.
int
colonPos
;
mal_find_char
(
NAME
,
':'
,
&
colonPos
);
if
(
colonPos
==
-
1
||
(
colonPos
==
2
&&
(
NAME
[
0
]
==
'h'
&&
NAME
[
1
]
==
'w'
)))
{
if
(
pInfo
!=
NULL
)
{
if
(
pInfo
!=
NULL
)
{
if
(
infoSize
>
0
)
{
if
(
infoSize
>
0
)
{
mal_zero_object
(
pInfo
);
mal_zero_object
(
pInfo
);
mal_strncpy_s
(
pInfo
->
id
.
name
,
sizeof
(
pInfo
->
id
.
name
),
NAME
?
NAME
:
""
,
(
size_t
)
-
1
);
mal_strncpy_s
(
pInfo
->
description
,
sizeof
(
pInfo
->
description
),
DESC
?
DESC
:
""
,
(
size_t
)
-
1
);
// NAME is the ID.
mal_strncpy_s
(
pInfo
->
id
.
str
,
sizeof
(
pInfo
->
id
.
str
),
NAME
?
NAME
:
""
,
(
size_t
)
-
1
);
// DESC is the name, followed by the description on a new line.
int
lfPos
=
0
;
mal_find_char
(
DESC
,
'\n'
,
&
lfPos
);
mal_strncpy_s
(
pInfo
->
name
,
sizeof
(
pInfo
->
name
),
DESC
?
DESC
:
""
,
(
lfPos
!=
-
1
)
?
(
size_t
)
lfPos
:
(
size_t
)
-
1
);
pInfo
+=
1
;
pInfo
+=
1
;
infoSize
-=
1
;
infoSize
-=
1
;
...
@@ -1877,6 +2009,7 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
...
@@ -1877,6 +2009,7 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
}
else
{
}
else
{
*
pCount
+=
1
;
*
pCount
+=
1
;
}
}
}
}
}
free
(
NAME
);
free
(
NAME
);
...
@@ -1887,6 +2020,7 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
...
@@ -1887,6 +2020,7 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
snd_device_name_free_hint
((
void
**
)
ppDeviceHints
);
snd_device_name_free_hint
((
void
**
)
ppDeviceHints
);
return
MAL_SUCCESS
;
return
MAL_SUCCESS
;
#endif
}
}
void
mal_device_uninit__alsa
(
mal_device
*
pDevice
)
void
mal_device_uninit__alsa
(
mal_device
*
pDevice
)
...
@@ -1907,11 +2041,19 @@ mal_result mal_device_init__alsa(mal_device* pDevice, mal_device_type type, mal_
...
@@ -1907,11 +2041,19 @@ mal_result mal_device_init__alsa(mal_device* pDevice, mal_device_type type, mal_
mal_assert
(
pDevice
!=
NULL
);
mal_assert
(
pDevice
!=
NULL
);
pDevice
->
api
=
mal_api_alsa
;
pDevice
->
api
=
mal_api_alsa
;
char
deviceName
[
256
];
char
deviceName
[
32
];
if
(
pDeviceID
==
NULL
)
{
if
(
pDeviceID
==
NULL
)
{
strcpy
(
deviceName
,
"default"
);
strcpy
(
deviceName
,
"default"
);
// TODO: What if PulseAudio is not installed? Use "plughw:0,0" instead?
}
else
{
// For now, convert "hw" devices to "plughw". The reason for this is that mini_al is still a
// a quite unstable with non "plughw" devices.
if
(
pDeviceID
->
str
[
0
]
==
'h'
&&
pDeviceID
->
str
[
1
]
==
'w'
&&
pDeviceID
->
str
[
2
]
==
':'
)
{
deviceName
[
0
]
=
'p'
;
deviceName
[
1
]
=
'l'
;
deviceName
[
2
]
=
'u'
;
deviceName
[
3
]
=
'g'
;
strcpy
(
deviceName
+
4
,
pDeviceID
->
str
);
}
else
{
}
else
{
strcpy
(
deviceName
,
pDeviceID
->
name
);
strcpy
(
deviceName
,
pDeviceID
->
str
);
}
}
}
snd_pcm_format_t
formatALSA
;
snd_pcm_format_t
formatALSA
;
...
@@ -2520,12 +2662,10 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format)
...
@@ -2520,12 +2662,10 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format)
// f32 to cover the 8-, 16 and 32-bit ranges.
// f32 to cover the 8-, 16 and 32-bit ranges.
// - The rationale for this is to make it easier for applications to get audio working
// - The rationale for this is to make it easier for applications to get audio working
// without any fuss.
// without any fuss.
// - Test s24 format on ALSA. Needs to be 32-bit aligned, but use only 24-bits.
//
//
//
//
// ALSA
// ALSA
// ----
// ----
// - Fix device iteration.
// - Make device initialization more robust.
// - Make device initialization more robust.
// - Need to have my test hardware working with plughw at a minimum.
// - Need to have my test hardware working with plughw at a minimum.
// - Finish mmap mode for ALSA.
// - Finish mmap mode for ALSA.
...
...
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