Commit c68700ba authored by David Reid's avatar David Reid

OSS: Migrate over to the new backend callback system.

parent 0809d8fa
...@@ -10886,6 +10886,22 @@ not officially supporting this, but I'm leaving it here in case it's useful for ...@@ -10886,6 +10886,22 @@ not officially supporting this, but I'm leaving it here in case it's useful for
#endif #endif
MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags)
{
if (pDeviceInfo == NULL) {
return;
}
if (pDeviceInfo->nativeDataFormatCount < ma_countof(pDeviceInfo->nativeDataFormats)) {
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = format;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = channels;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = flags;
pDeviceInfo->nativeDataFormatCount += 1;
}
}
MA_API const char* ma_get_backend_name(ma_backend backend) MA_API const char* ma_get_backend_name(ma_backend backend)
{ {
switch (backend) switch (backend)
...@@ -28687,7 +28703,57 @@ static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum ...@@ -28687,7 +28703,57 @@ static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo) static void ma_context_add_native_data_format__oss(ma_context* pContext, oss_audioinfo* pAudioInfo, ma_format format, ma_device_info* pDeviceInfo)
{
unsigned int minChannels;
unsigned int maxChannels;
unsigned int iRate;
MA_ASSERT(pContext != NULL);
MA_ASSERT(pAudioInfo != NULL);
MA_ASSERT(pDeviceInfo != NULL);
/* If we support all channels we just report 0. */
minChannels = ma_clamp(pAudioInfo->min_channels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
maxChannels = ma_clamp(pAudioInfo->max_channels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
/*
OSS has this annoying thing where sample rates can be reported in two ways. We prefer explicitness,
which OSS has in the form of nrates/rates, however there are times where nrates can be 0, in which
case we'll need to use min_rate and max_rate and report only standard rates.
*/
if (pAudioInfo->nrates > 0) {
for (iRate = 0; iRate < pAudioInfo->nrates; iRate += 1) {
unsigned int rate = pAudioInfo->rates[iRate];
if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) {
ma_device_info_add_native_data_format(pDeviceInfo, format, 0, rate, 0); /* Set the channel count to 0 to indicate that all channel counts are supported. */
} else {
unsigned int iChannel;
for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) {
ma_device_info_add_native_data_format(pDeviceInfo, format, iChannel, rate, 0);
}
}
}
} else {
for (iRate = 0; iRate < ma_countof(g_maStandardSampleRatePriorities); iRate += 1) {
ma_uint32 standardRate = g_maStandardSampleRatePriorities[iRate];
if (standardRate >= (ma_uint32)pAudioInfo->min_rate && standardRate <= (ma_uint32)pAudioInfo->max_rate) {
if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) {
ma_device_info_add_native_data_format(pDeviceInfo, format, 0, standardRate, 0); /* Set the channel count to 0 to indicate that all channel counts are supported. */
} else {
unsigned int iChannel;
for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) {
ma_device_info_add_native_data_format(pDeviceInfo, format, iChannel, standardRate, 0);
}
}
}
}
}
}
static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
{ {
ma_bool32 foundDevice; ma_bool32 foundDevice;
int fdTemp; int fdTemp;
...@@ -28695,7 +28761,6 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device ...@@ -28695,7 +28761,6 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device
int result; int result;
MA_ASSERT(pContext != NULL); MA_ASSERT(pContext != NULL);
(void)shareMode;
/* Handle the default device a little differently. */ /* Handle the default device a little differently. */
if (pDeviceID == NULL) { if (pDeviceID == NULL) {
...@@ -28745,11 +28810,8 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device ...@@ -28745,11 +28810,8 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.name, (size_t)-1); ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.name, (size_t)-1);
} }
pDeviceInfo->minChannels = ai.min_channels;
pDeviceInfo->maxChannels = ai.max_channels; pDeviceInfo->nativeDataFormatCount = 0;
pDeviceInfo->minSampleRate = ai.min_rate;
pDeviceInfo->maxSampleRate = ai.max_rate;
pDeviceInfo->formatCount = 0;
if (deviceType == ma_device_type_playback) { if (deviceType == ma_device_type_playback) {
formatMask = ai.oformats; formatMask = ai.oformats;
...@@ -28757,14 +28819,14 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device ...@@ -28757,14 +28819,14 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device
formatMask = ai.iformats; formatMask = ai.iformats;
} }
if ((formatMask & AFMT_U8) != 0) {
pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_u8;
}
if (((formatMask & AFMT_S16_LE) != 0 && ma_is_little_endian()) || (AFMT_S16_BE && ma_is_big_endian())) { if (((formatMask & AFMT_S16_LE) != 0 && ma_is_little_endian()) || (AFMT_S16_BE && ma_is_big_endian())) {
pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s16; ma_context_add_native_data_format__oss(pContext, &ai, ma_format_s16, pDeviceInfo);
} }
if (((formatMask & AFMT_S32_LE) != 0 && ma_is_little_endian()) || (AFMT_S32_BE && ma_is_big_endian())) { if (((formatMask & AFMT_S32_LE) != 0 && ma_is_little_endian()) || (AFMT_S32_BE && ma_is_big_endian())) {
pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s32; ma_context_add_native_data_format__oss(pContext, &ai, ma_format_s32, pDeviceInfo);
}
if ((formatMask & AFMT_U8) != 0) {
ma_context_add_native_data_format__oss(pContext, &ai, ma_format_u8, pDeviceInfo);
} }
foundDevice = MA_TRUE; foundDevice = MA_TRUE;
...@@ -28788,7 +28850,7 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device ...@@ -28788,7 +28850,7 @@ static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device
return MA_SUCCESS; return MA_SUCCESS;
} }
static void ma_device_uninit__oss(ma_device* pDevice) static ma_result ma_device_uninit__oss(ma_device* pDevice)
{ {
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
...@@ -28799,6 +28861,8 @@ static void ma_device_uninit__oss(ma_device* pDevice) ...@@ -28799,6 +28861,8 @@ static void ma_device_uninit__oss(ma_device* pDevice)
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
close(pDevice->oss.fdPlayback); close(pDevice->oss.fdPlayback);
} }
return MA_SUCCESS;
} }
static int ma_format_to_oss(ma_format format) static int ma_format_to_oss(ma_format format)
...@@ -28839,7 +28903,7 @@ static ma_format ma_format_from_oss(int ossFormat) ...@@ -28839,7 +28903,7 @@ static ma_format ma_format_from_oss(int ossFormat)
return ma_format_unknown; return ma_format_unknown;
} }
static ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice) static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
{ {
ma_result result; ma_result result;
int ossResult; int ossResult;
...@@ -28851,28 +28915,17 @@ static ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_co ...@@ -28851,28 +28915,17 @@ static ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_co
int ossSampleRate; int ossSampleRate;
int ossFragment; int ossFragment;
MA_ASSERT(pContext != NULL); MA_ASSERT(pDevice != NULL);
MA_ASSERT(pConfig != NULL); MA_ASSERT(pConfig != NULL);
MA_ASSERT(deviceType != ma_device_type_duplex); MA_ASSERT(deviceType != ma_device_type_duplex);
MA_ASSERT(pDevice != NULL);
pDeviceID = pDescriptor->pDeviceID;
(void)pContext; shareMode = pDescriptor->shareMode;
ossFormat = ma_format_to_oss((pDescriptor->format != ma_format_unknown) ? pDescriptor->format : ma_format_s16); /* Use s16 by default because OSS doesn't like floating point. */
if (deviceType == ma_device_type_capture) { ossChannels = (int)(pDescriptor->channels > 0) ? pDescriptor->channels : MA_DEFAULT_CHANNELS;
pDeviceID = pConfig->capture.pDeviceID; ossSampleRate = (int)(pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE;
shareMode = pConfig->capture.shareMode;
ossFormat = ma_format_to_oss(pConfig->capture.format);
ossChannels = (int)pConfig->capture.channels;
ossSampleRate = (int)pConfig->sampleRate;
} else {
pDeviceID = pConfig->playback.pDeviceID;
shareMode = pConfig->playback.shareMode;
ossFormat = ma_format_to_oss(pConfig->playback.format);
ossChannels = (int)pConfig->playback.channels;
ossSampleRate = (int)pConfig->sampleRate;
}
result = ma_context_open_device__oss(pContext, deviceType, pDeviceID, shareMode, &fd); result = ma_context_open_device__oss(pDevice->pContext, deviceType, pDeviceID, shareMode, &fd);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
} }
...@@ -28919,10 +28972,7 @@ static ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_co ...@@ -28919,10 +28972,7 @@ static ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_co
ma_uint32 periodSizeInBytes; ma_uint32 periodSizeInBytes;
ma_uint32 ossFragmentSizePower; ma_uint32 ossFragmentSizePower;
periodSizeInFrames = pConfig->periodSizeInFrames; periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, (ma_uint32)ossSampleRate, pConfig->performanceProfile);
if (periodSizeInFrames == 0) {
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, (ma_uint32)ossSampleRate);
}
periodSizeInBytes = ma_round_to_power_of_2(periodSizeInFrames * ma_get_bytes_per_frame(ma_format_from_oss(ossFormat), ossChannels)); periodSizeInBytes = ma_round_to_power_of_2(periodSizeInFrames * ma_get_bytes_per_frame(ma_format_from_oss(ossFormat), ossChannels));
if (periodSizeInBytes < 16) { if (periodSizeInBytes < 16) {
...@@ -28945,39 +28995,29 @@ static ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_co ...@@ -28945,39 +28995,29 @@ static ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_co
/* Internal settings. */ /* Internal settings. */
if (deviceType == ma_device_type_capture) { if (deviceType == ma_device_type_capture) {
pDevice->oss.fdCapture = fd; pDevice->oss.fdCapture = fd;
pDevice->capture.internalFormat = ma_format_from_oss(ossFormat);
pDevice->capture.internalChannels = ossChannels;
pDevice->capture.internalSampleRate = ossSampleRate;
ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap);
pDevice->capture.internalPeriods = (ma_uint32)(ossFragment >> 16);
pDevice->capture.internalPeriodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
if (pDevice->capture.internalFormat == ma_format_unknown) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
}
} else { } else {
pDevice->oss.fdPlayback = fd; pDevice->oss.fdPlayback = fd;
pDevice->playback.internalFormat = ma_format_from_oss(ossFormat); }
pDevice->playback.internalChannels = ossChannels;
pDevice->playback.internalSampleRate = ossSampleRate;
ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
pDevice->playback.internalPeriods = (ma_uint32)(ossFragment >> 16);
pDevice->playback.internalPeriodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
if (pDevice->playback.internalFormat == ma_format_unknown) { pDescriptor->format = ma_format_from_oss(ossFormat);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED); pDescriptor->channels = ossChannels;
} pDescriptor->sampleRate = ossSampleRate;
ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDescriptor->channels, pDescriptor->channelMap);
pDescriptor->periodCount = (ma_uint32)(ossFragment >> 16);
pDescriptor->periodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDescriptor->format, pDescriptor->channels);
if (pDescriptor->format == ma_format_unknown) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
} }
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_device_init__oss(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) static ma_result ma_device_init__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
{ {
MA_ASSERT(pContext != NULL);
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
MA_ASSERT(pConfig != NULL);
MA_ZERO_OBJECT(&pDevice->oss); MA_ZERO_OBJECT(&pDevice->oss);
...@@ -28986,14 +29026,14 @@ static ma_result ma_device_init__oss(ma_context* pContext, const ma_device_confi ...@@ -28986,14 +29026,14 @@ static ma_result ma_device_init__oss(ma_context* pContext, const ma_device_confi
} }
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_result result = ma_device_init_fd__oss(pContext, pConfig, ma_device_type_capture, pDevice); ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
} }
} }
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_result result = ma_device_init_fd__oss(pContext, pConfig, ma_device_type_playback, pDevice); ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
} }
...@@ -29002,36 +29042,41 @@ static ma_result ma_device_init__oss(ma_context* pContext, const ma_device_confi ...@@ -29002,36 +29042,41 @@ static ma_result ma_device_init__oss(ma_context* pContext, const ma_device_confi
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_device_stop__oss(ma_device* pDevice) /*
Note on Starting and Stopping
=============================
In the past I was using SNDCTL_DSP_HALT to stop the device, however this results in issues when
trying to resume the device again. If we use SNDCTL_DSP_HALT, the next write() or read() will
fail. Instead what we need to do is just not write or read to and from the device when the
device is not running.
As a result, both the start and stop functions for OSS are just empty stubs. The starting and
stopping logic is handled by ma_device_write__oss() and ma_device_read__oss(). These will check
the device state, and if the device is stopped they will simply not do any kind of processing.
The downside to this technique is that I've noticed a fairly lengthy delay in stopping the
device, up to a second. This is on a virtual machine, and as such might just be due to the
virtual drivers, but I'm not fully sure. I am not sure how to work around this problem so for
the moment that's just how it's going to have to be.
When starting the device, OSS will automatically start it when write() or read() is called.
*/
static ma_result ma_device_start__oss(ma_device* pDevice)
{ {
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
/* /* The device is automatically started with reading and writing. */
We want to use SNDCTL_DSP_HALT. From the documentation: (void)pDevice;
In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread
that actually reads/writes the audio device. It must not be called by some master thread to kill the
audio thread. The audio thread will not stop or get any kind of notification that the device was
stopped by the master thread. The device gets stopped but the next read or write call will silently
restart the device.
This is actually safe in our case, because this function is only ever called from within our worker return MA_SUCCESS;
thread anyway. Just keep this in mind, though... }
*/
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { static ma_result ma_device_stop__oss(ma_device* pDevice)
int result = ioctl(pDevice->oss.fdCapture, SNDCTL_DSP_HALT, 0); {
if (result == -1) { MA_ASSERT(pDevice != NULL);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", ma_result_from_errno(errno));
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { /* See note above on why this is empty. */
int result = ioctl(pDevice->oss.fdPlayback, SNDCTL_DSP_HALT, 0); (void)pDevice;
if (result == -1) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", ma_result_from_errno(errno));
}
}
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -29039,11 +29084,18 @@ static ma_result ma_device_stop__oss(ma_device* pDevice) ...@@ -29039,11 +29084,18 @@ static ma_result ma_device_stop__oss(ma_device* pDevice)
static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
{ {
int resultOSS; int resultOSS;
ma_uint32 deviceState;
if (pFramesWritten != NULL) { if (pFramesWritten != NULL) {
*pFramesWritten = 0; *pFramesWritten = 0;
} }
/* Don't do any processing if the device is stopped. */
deviceState = ma_device_get_state(pDevice);
if (deviceState != MA_STATE_STARTED && deviceState != MA_STATE_STARTING) {
return MA_SUCCESS;
}
resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels)); resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
if (resultOSS < 0) { if (resultOSS < 0) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.", ma_result_from_errno(errno)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.", ma_result_from_errno(errno));
...@@ -29059,11 +29111,18 @@ static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames ...@@ -29059,11 +29111,18 @@ static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames
static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead) static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
{ {
int resultOSS; int resultOSS;
ma_uint32 deviceState;
if (pFramesRead != NULL) { if (pFramesRead != NULL) {
*pFramesRead = 0; *pFramesRead = 0;
} }
/* Don't do any processing if the device is stopped. */
deviceState = ma_device_get_state(pDevice);
if (deviceState != MA_STATE_STARTED && deviceState != MA_STATE_STARTING) {
return MA_SUCCESS;
}
resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
if (resultOSS < 0) { if (resultOSS < 0) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.", ma_result_from_errno(errno)); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.", ma_result_from_errno(errno));
...@@ -29076,171 +29135,6 @@ static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_ui ...@@ -29076,171 +29135,6 @@ static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_ui
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_device_main_loop__oss(ma_device* pDevice)
{
ma_result result = MA_SUCCESS;
ma_bool32 exitLoop = MA_FALSE;
/* No need to explicitly start the device like the other backends. */
while (ma_device_get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
switch (pDevice->type)
{
case ma_device_type_duplex:
{
/* The process is: device_read -> convert -> callback -> convert -> device_write */
ma_uint32 totalCapturedDeviceFramesProcessed = 0;
ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 capturedDeviceFramesRemaining;
ma_uint32 capturedDeviceFramesProcessed;
ma_uint32 capturedDeviceFramesToProcess;
ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
}
result = ma_device_read__oss(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
capturedDeviceFramesProcessed = 0;
for (;;) {
ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
/* Convert capture data from device format to client format. */
result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
if (result != MA_SUCCESS) {
break;
}
/*
If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
*/
if (capturedClientFramesToProcessThisIteration == 0) {
break;
}
ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
/* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
for (;;) {
ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
if (result != MA_SUCCESS) {
break;
}
result = ma_device_write__oss(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
if (capturedClientFramesToProcessThisIteration == 0) {
break;
}
}
/* In case an error happened from ma_device_write__oss()... */
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
}
totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
}
} break;
case ma_device_type_capture:
{
/* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
ma_uint32 framesReadThisPeriod = 0;
while (framesReadThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
framesToReadThisIteration = intermediaryBufferSizeInFrames;
}
result = ma_device_read__oss(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
framesReadThisPeriod += framesProcessed;
}
} break;
case ma_device_type_playback:
{
/* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
ma_uint32 framesWrittenThisPeriod = 0;
while (framesWrittenThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
framesToWriteThisIteration = intermediaryBufferSizeInFrames;
}
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
result = ma_device_write__oss(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
framesWrittenThisPeriod += framesProcessed;
}
} break;
/* To silence a warning. Will never hit this. */
case ma_device_type_loopback:
default: break;
}
}
/* Here is where the device is stopped. */
ma_device_stop__oss(pDevice);
return result;
}
static ma_result ma_context_uninit__oss(ma_context* pContext) static ma_result ma_context_uninit__oss(ma_context* pContext)
{ {
MA_ASSERT(pContext != NULL); MA_ASSERT(pContext != NULL);
...@@ -29250,7 +29144,7 @@ static ma_result ma_context_uninit__oss(ma_context* pContext) ...@@ -29250,7 +29144,7 @@ static ma_result ma_context_uninit__oss(ma_context* pContext)
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_context_init__oss(const ma_context_config* pConfig, ma_context* pContext) static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
{ {
int fd; int fd;
int ossVersion; int ossVersion;
...@@ -29280,14 +29174,17 @@ static ma_result ma_context_init__oss(const ma_context_config* pConfig, ma_conte ...@@ -29280,14 +29174,17 @@ static ma_result ma_context_init__oss(const ma_context_config* pConfig, ma_conte
pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16); pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16);
pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8); pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8);
pContext->onUninit = ma_context_uninit__oss; pCallbacks->onContextInit = ma_context_init__oss;
pContext->onEnumDevices = ma_context_enumerate_devices__oss; pCallbacks->onContextUninit = ma_context_uninit__oss;
pContext->onGetDeviceInfo = ma_context_get_device_info__oss; pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__oss;
pContext->onDeviceInit = ma_device_init__oss; pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__oss;
pContext->onDeviceUninit = ma_device_uninit__oss; pCallbacks->onDeviceInit = ma_device_init__oss;
pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */ pCallbacks->onDeviceUninit = ma_device_uninit__oss;
pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */ pCallbacks->onDeviceStart = ma_device_start__oss;
pContext->onDeviceMainLoop = ma_device_main_loop__oss; pCallbacks->onDeviceStop = ma_device_stop__oss;
pCallbacks->onDeviceRead = ma_device_read__oss;
pCallbacks->onDeviceWrite = ma_device_write__oss;
pCallbacks->onDeviceAudioThread = NULL;
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -32448,6 +32345,12 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC ...@@ -32448,6 +32345,12 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
pContext->callbacks.onContextInit = ma_context_init__coreaudio; pContext->callbacks.onContextInit = ma_context_init__coreaudio;
} break; } break;
#endif #endif
#ifdef MA_HAS_OSS
case ma_backend_oss:
{
pContext->callbacks.onContextInit = ma_context_init__oss;
} break;
#endif
#ifdef MA_HAS_PULSEAUDIO #ifdef MA_HAS_PULSEAUDIO
case ma_backend_pulseaudio: case ma_backend_pulseaudio:
{ {
...@@ -32568,8 +32471,7 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC ...@@ -32568,8 +32471,7 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
#ifdef MA_HAS_OSS #ifdef MA_HAS_OSS
case ma_backend_oss: case ma_backend_oss:
{ {
ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, "Attempting to initialize OSS backend..."); /*result = ma_context_init__oss(pConfig, pContext);*/
result = ma_context_init__oss(pConfig, pContext);
} break; } break;
#endif #endif
#ifdef MA_HAS_AAUDIO #ifdef MA_HAS_AAUDIO
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment