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
3afb29af
Commit
3afb29af
authored
Feb 27, 2018
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Plug in some stub APIs for PulseAudio.
parent
891258a5
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
269 additions
and
7 deletions
+269
-7
mini_al.h
mini_al.h
+269
-7
No files found.
mini_al.h
View file @
3afb29af
// Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file.
// mini_al - v0.
7 - 2018-02-25
// mini_al - v0.
x - 2018-xx-xx
//
// David Reid - davidreidsoftware@gmail.com
...
...
@@ -17,6 +17,7 @@
// - DirectSound
// - WinMM
// - ALSA
// - PulseAudio
// - OSS
// - OpenSL|ES / Android
// - OpenAL
...
...
@@ -144,6 +145,9 @@
// #define MAL_NO_ALSA
// Disables the ALSA backend.
//
// #define MAL_NO_PULSEAUDIO
// Disables the PulseAudio backend.
//
// #define MAL_NO_OSS
// Disables the OSS backend.
//
...
...
@@ -233,6 +237,9 @@ extern "C" {
#define MAL_SUPPORT_ALSA
#endif
#endif
#if !defined(MAL_APPLE) && !defined(MAL_ANDROID) && !defined(MAL_EMSCRIPTEN)
#define MAL_SUPPORT_PULSEAUDIO
#endif
#if defined(MAL_APPLE)
#define MAL_SUPPORT_COREAUDIO
#endif
...
...
@@ -265,6 +272,9 @@ extern "C" {
#if !defined(MAL_NO_ALSA) && defined(MAL_SUPPORT_ALSA)
#define MAL_ENABLE_ALSA
#endif
#if !defined(MAL_NO_PULSEAUDIO) && defined(MAL_SUPPORT_PULSEAUDIO)
#define MAL_ENABLE_PULSEAUDIO
#endif
#if !defined(MAL_NO_COREAUDIO) && defined(MAL_SUPPORT_COREAUDIO)
#define MAL_ENABLE_COREAUDIO
#endif
...
...
@@ -502,6 +512,7 @@ typedef enum
mal_backend_dsound,
mal_backend_winmm,
mal_backend_alsa,
mal_backend_pulseaudio,
mal_backend_oss,
mal_backend_opensl,
mal_backend_openal,
...
...
@@ -546,6 +557,9 @@ typedef union
#ifdef MAL_SUPPORT_ALSA
char alsa[256]; // ALSA uses a name string for identification.
#endif
#ifdef MAL_SUPPORT_PULSEAUDIO
char pulseaudio[256]; // PulseAudio uses a name string for identification.
#endif
#ifdef MAL_SUPPORT_COREAUDIO
// TODO: Implement me.
#endif
...
...
@@ -780,6 +794,12 @@ struct mal_context
mal_proc snd_pcm_info_get_name;
} alsa;
#endif
#ifdef MAL_SUPPORT_PULSEAUDIO
struct
{
mal_handle pulseSO;
} pulse;
#endif
#ifdef MAL_SUPPORT_COREAUDIO
struct
{
...
...
@@ -883,8 +903,8 @@ struct mal_context
mal_proc alGetBufferiv;
mal_bool32 isEnumerationSupported : 1;
mal_bool32 isFloat32Supported : 1;
mal_bool32 isMCFormatsSupported : 1;
mal_bool32 isFloat32Supported
: 1;
mal_bool32 isMCFormatsSupported
: 1;
} openal;
#endif
#ifdef MAL_SUPPORT_SDL
...
...
@@ -1036,6 +1056,15 @@ struct mal_device
void* pIntermediaryBuffer;
} alsa;
#endif
#ifdef MAL_SUPPORT_PULSEAUDIO
struct
{
/*pa_simple**/ mal_ptr pPA;
mal_uint32 fragmentSizeInFrames;
mal_bool32 breakFromMainLoop : 1;
void* pIntermediaryBuffer;
} pulse;
#endif
#ifdef MAL_SUPPORT_COREAUDIO
struct
{
...
...
@@ -1114,6 +1143,7 @@ struct mal_device
// - WASAPI
// - DirectSound
// - WinMM
// - PulseAudio
// - ALSA
// - OSS
// - OpenSL|ES
...
...
@@ -1755,6 +1785,14 @@ mal_result mal_decoder_seek_to_frame(mal_decoder* pDecoder, mal_uint64 frameInde
#endif
#endif
#endif
#ifdef MAL_ENABLE_PULSEAUDIO
#define MAL_HAS_PULSEAUDIO
#ifdef __has_include
#if !__has_include(<pulse/simple.h>)
#undef MAL_HAS_PULSEAUDIO
#endif
#endif
#endif
#ifdef MAL_ENABLE_COREAUDIO
#define MAL_HAS_COREAUDIO
#endif
...
...
@@ -5632,6 +5670,7 @@ static mal_result mal_device__main_loop__winmm(mal_device* pDevice)
///////////////////////////////////////////////////////////////////////////////
//
// ALSA Backend
...
...
@@ -6847,6 +6886,172 @@ static mal_result mal_device__main_loop__alsa(mal_device* pDevice)
#endif // ALSA
///////////////////////////////////////////////////////////////////////////////
//
// PulseAudio Backend
//
///////////////////////////////////////////////////////////////////////////////
#ifdef MAL_HAS_PULSEAUDIO
#include <pulse/simple.h>
#include <pulse/error.h>
static mal_result mal_result_from_pulse(int result)
{
switch (result) {
case PA_OK: return MAL_SUCCESS;
case PA_ERR_ACCESS: return MAL_ACCESS_DENIED;
case PA_ERR_INVALID: return MAL_INVALID_ARGS;
case PA_ERR_NOENTITY: return MAL_NO_DEVICE;
default: return MAL_ERROR;
}
}
static mal_result mal_context_init__pulse(mal_context* pContext)
{
mal_assert(pContext != NULL);
const char* libs[] = {
"libpulse.so",
"libpulse.so.0"
};
for (size_t i = 0; i < mal_countof(libs); ++i) {
pContext->pulse.pulseSO = mal_dlopen(libs[i]);
if (pContext->pulse.pulseSO != NULL) {
break;
}
}
if (pContext->pulse.pulseSO != NULL) {
return MAL_NO_BACKEND;
}
// TODO: Retrieve pointers to relevant APIs.
return MAL_SUCCESS;
}
static mal_result mal_context_uninit__pulse(mal_context* pContext)
{
mal_assert(pContext != NULL);
mal_assert(pContext->backend == mal_backend_pulseaudio);
mal_dlclose(pContext->pulse.pulseSO);
return MAL_SUCCESS;
}
static mal_result mal_enumerate_devices__pulse(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo)
{
(void)pContext;
//mal_uint32 infoSize = *pCount;
*pCount = 0;
return MAL_SUCCESS;
}
static void mal_device_uninit__pulse(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
}
static mal_result mal_device_init__pulse(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice)
{
(void)pContext;
mal_assert(pDevice != NULL);
mal_zero_object(&pDevice->pulse);
return MAL_SUCCESS;
}
static mal_result mal_device__start_backend__pulse(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
#if 0
// The device is started by the next calls to read() and write(). For playback it's simple - just read
// data from the client, then write it to the device with write() which will in turn start the device.
// For capture it's a bit less intuitive - we do nothing (it'll be started automatically by the first
// call to read().
if (pDevice->type == mal_device_type_playback) {
// Playback.
mal_device__read_frames_from_client(pDevice, pDevice->pulse.fragmentSizeInFrames, pDevice->pulse.pIntermediaryBuffer);
//int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat));
if (bytesWritten == -1) {
return mal_post_error(pDevice, "[PulseAudio] Failed to send initial chunk of data to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
}
} else {
// Capture. Do nothing.
}
#endif
return MAL_SUCCESS;
}
static mal_result mal_device__stop_backend__pulse(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
// The simple API doesn't seem to have any explicit start/stop APIs, so when stopping we just flush.
int error = PA_OK;
pa_simple_flush((pa_simple*)pDevice->pulse.pPA, &error);
return mal_result_from_pulse(error);
}
static mal_result mal_device__break_main_loop__pulse(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
pDevice->pulse.breakFromMainLoop = MAL_TRUE;
return MAL_SUCCESS;
}
static mal_result mal_device__main_loop__pulse(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
pDevice->pulse.breakFromMainLoop = MAL_FALSE;
while (!pDevice->pulse.breakFromMainLoop) {
// Break from the main loop if the device isn't started anymore. Likely what's happened is the application
// has requested that the device be stopped.
if (!mal_device_is_started(pDevice)) {
break;
}
if (pDevice->type == mal_device_type_playback) {
// Playback.
mal_device__read_frames_from_client(pDevice, pDevice->pulse.fragmentSizeInFrames, pDevice->pulse.pIntermediaryBuffer);
//int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat));
//if (bytesWritten < 0) {
// return mal_post_error(pDevice, "[PulseAudio] Failed to send data from the client to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
//}
} else {
// Capture.
//int bytesRead = read(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * mal_get_sample_size_in_bytes(pDevice->internalFormat));
//if (bytesRead < 0) {
// return mal_post_error(pDevice, "[PulseAudio] Failed to read data from the device to be sent to the client.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE);
//}
int bytesRead = 0;
mal_uint32 framesRead = (mal_uint32)bytesRead / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat);
mal_device__send_frames_to_client(pDevice, framesRead, pDevice->pulse.pIntermediaryBuffer);
}
}
return MAL_SUCCESS;
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
// OSS Backend
...
...
@@ -9160,6 +9365,11 @@ static mal_result mal_device__start_backend(mal_device* pDevice)
result = mal_device__start_backend__alsa(pDevice);
}
#endif
#ifdef MAL_HAS_PULSEAUDIO
if (pDevice->pContext->backend == mal_backend_pulseaudio) {
result = mal_device__start_backend__pulse(pDevice);
}
#endif
#ifdef MAL_HAS_OSS
if (pDevice->pContext->backend == mal_backend_oss) {
result = mal_device__start_backend__oss(pDevice);
...
...
@@ -9204,6 +9414,11 @@ static mal_result mal_device__stop_backend(mal_device* pDevice)
result = mal_device__stop_backend__alsa(pDevice);
}
#endif
#ifdef MAL_HAS_PULSEAUDIO
if (pDevice->pContext->backend == mal_backend_pulseaudio) {
result = mal_device__stop_backend__pulse(pDevice);
}
#endif
#ifdef MAL_HAS_OSS
if (pDevice->pContext->backend == mal_backend_oss) {
result = mal_device__stop_backend__oss(pDevice);
...
...
@@ -9248,6 +9463,11 @@ static mal_result mal_device__break_main_loop(mal_device* pDevice)
result = mal_device__break_main_loop__alsa(pDevice);
}
#endif
#ifdef MAL_HAS_PULSEAUDIO
if (pDevice->pContext->backend == mal_backend_pulseaudio) {
result = mal_device__break_main_loop__pulse(pDevice);
}
#endif
#ifdef MAL_HAS_OSS
if (pDevice->pContext->backend == mal_backend_oss) {
result = mal_device__break_main_loop__oss(pDevice);
...
...
@@ -9292,6 +9512,11 @@ static mal_result mal_device__main_loop(mal_device* pDevice)
result = mal_device__main_loop__alsa(pDevice);
}
#endif
#ifdef MAL_HAS_PULSEAUDIO
if (pDevice->pContext->backend == mal_backend_pulseaudio) {
result = mal_device__main_loop__pulse(pDevice);
}
#endif
#ifdef MAL_HAS_OSS
if (pDevice->pContext->backend == mal_backend_oss) {
result = mal_device__main_loop__oss(pDevice);
...
...
@@ -9532,6 +9757,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con
mal_backend_wasapi,
mal_backend_dsound,
mal_backend_winmm,
mal_backend_pulseaudio,
mal_backend_alsa,
mal_backend_oss,
mal_backend_opensl,
...
...
@@ -9542,7 +9768,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con
if (backends == NULL) {
backends = defaultBackends;
backendCount =
sizeof(defaultBackends) / sizeof(defaultBackends[0]
);
backendCount =
mal_countof(defaultBackends
);
}
mal_assert(backends != NULL);
...
...
@@ -9576,6 +9802,12 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con
result = mal_context_init__alsa(pContext);
} break;
#endif
#ifdef MAL_HAS_PULSEAUDIO
case mal_backend_pulseaudio:
{
result = mal_context_init__pulse(pContext);
} break;
#endif
#ifdef MAL_HAS_OSS
case mal_backend_oss:
{
...
...
@@ -9650,6 +9882,12 @@ mal_result mal_context_uninit(mal_context* pContext)
return mal_context_uninit__alsa(pContext);
} break;
#endif
#ifdef MAL_HAS_PULSEAUDIO
case mal_backend_pulseaudio:
{
return mal_context_uninit__pulse(pContext);
} break;
#endif
#ifdef MAL_HAS_OSS
case mal_backend_oss:
{
...
...
@@ -9726,6 +9964,12 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma
return mal_enumerate_devices__alsa(pContext, type, pCount, pInfo);
} break;
#endif
#ifdef MAL_HAS_PULSEAUDIO
case mal_backend_pulseaudio:
{
return mal_enumerate_devices__pulse(pContext, type, pCount, pInfo);
} break;
#endif
#ifdef MAL_HAS_OSS
case mal_backend_oss:
{
...
...
@@ -9892,6 +10136,12 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi
result = mal_device_init__alsa(pContext, type, pDeviceID, &config, pDevice);
} break;
#endif
#ifdef MAL_HAS_PULSEAUDIO
case mal_backend_pulseaudio:
{
result = mal_device_init__pulse(pContext, type, pDeviceID, &config, pDevice);
} break;
#endif
#ifdef MAL_HAS_OSS
case mal_backend_oss:
{
...
...
@@ -10069,6 +10319,11 @@ void mal_device_uninit(mal_device* pDevice)
mal_device_uninit__alsa(pDevice);
}
#endif
#ifdef MAL_HAS_PULSEAUDIO
if (pDevice->pContext->backend == mal_backend_pulseaudio) {
mal_device_uninit__pulse(pDevice);
}
#endif
#ifdef MAL_HAS_OSS
if (pDevice->pContext->backend == mal_backend_oss) {
mal_device_uninit__oss(pDevice);
...
...
@@ -10275,6 +10530,8 @@ mal_context_config mal_context_config_init(mal_log_proc onLog)
static void mal_get_default_device_config_channel_map(mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS])
{
mal_zero_memory(channelMap, sizeof(mal_uint8)*MAL_MAX_CHANNELS);
switch (channels)
{
case 1:
...
...
@@ -10348,7 +10605,6 @@ static void mal_get_default_device_config_channel_map(mal_uint32 channels, mal_u
default:
{
// Just leave it all blank in this case. This will use the same mapping as the device's native mapping.
mal_zero_memory(channelMap, sizeof(channelMap));
} break;
}
}
...
...
@@ -11794,6 +12050,7 @@ static mal_uint32 mal_decoder_internal_on_read_frames__wav(mal_dsp* pDSP, mal_ui
case mal_format_s16: return (mal_uint32)drwav_read_s16(pWav, frameCount*pDecoder->internalChannels, (drwav_int16*)pSamplesOut) / pDecoder->internalChannels;
case mal_format_s32: return (mal_uint32)drwav_read_s32(pWav, frameCount*pDecoder->internalChannels, (drwav_int32*)pSamplesOut) / pDecoder->internalChannels;
case mal_format_f32: return (mal_uint32)drwav_read_f32(pWav, frameCount*pDecoder->internalChannels, (float*)pSamplesOut) / pDecoder->internalChannels;
default: break;
}
// Should never get here. If we do, it means the internal format was not set correctly at initialization time.
...
...
@@ -11871,6 +12128,8 @@ mal_result mal_decoder_init_wav__internal(const mal_decoder_config* pConfig, mal
static void mal_get_flac_channel_map(mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS])
{
mal_zero_memory(channelMap, sizeof(mal_uint8)*MAL_MAX_CHANNELS);
switch (channels) {
case 1:
{
...
...
@@ -11942,8 +12201,7 @@ static void mal_get_flac_channel_map(mal_uint32 channels, mal_uint8 channelMap[M
default:
{
// Should never get here because FLAC has a maximum of 8 channels. In any case, just set the channel map to all zeros.
mal_zero_memory(channelMap, sizeof(channelMap));
// Should never get here because FLAC has a maximum of 8 channels.
} break;
}
}
...
...
@@ -13097,6 +13355,10 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count)
// REVISION HISTORY
// ================
//
// v0.x - 2018-xx-xx
// - Add support for PulseAudio.
// - Miscellaneous bug fixes.
//
// v0.7 - 2018-02-25
// - API CHANGE: Change mal_src_read_frames() and mal_dsp_read_frames() to use 64-bit sample counts.
// - Add decoder APIs for loading WAV, FLAC, Vorbis and MP3 files.
...
...
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