Commit a311b906 authored by David Reid's avatar David Reid

Work in progress on full-duplex for audio(4).

parent 9f294cf8
...@@ -2188,10 +2188,8 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device ...@@ -2188,10 +2188,8 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device
#ifdef MAL_SUPPORT_AUDIO4 #ifdef MAL_SUPPORT_AUDIO4
struct struct
{ {
int fd; int fdPlayback;
mal_uint32 fragmentSizeInFrames; int fdCapture;
mal_bool32 breakFromMainLoop;
void* pIntermediaryBuffer;
} audio4; } audio4;
#endif #endif
#ifdef MAL_SUPPORT_OSS #ifdef MAL_SUPPORT_OSS
...@@ -18010,7 +18008,7 @@ mal_bool32 mal_context_is_device_id_equal__audio4(mal_context* pContext, const m ...@@ -18010,7 +18008,7 @@ mal_bool32 mal_context_is_device_id_equal__audio4(mal_context* pContext, const m
return mal_strcmp(pID0->audio4, pID1->audio4) == 0; return mal_strcmp(pID0->audio4, pID1->audio4) == 0;
} }
#if !defined(MAL_AUDIO4_USE_NEW_API) #if !defined(MAL_AUDIO4_USE_NEW_API) /* Old API */
mal_format mal_format_from_encoding__audio4(unsigned int encoding, unsigned int precision) mal_format mal_format_from_encoding__audio4(unsigned int encoding, unsigned int precision)
{ {
if (precision == 8 && (encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR_LE || encoding == AUDIO_ENCODING_ULINEAR_BE)) { if (precision == 8 && (encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR_LE || encoding == AUDIO_ENCODING_ULINEAR_BE)) {
...@@ -18038,6 +18036,42 @@ mal_format mal_format_from_encoding__audio4(unsigned int encoding, unsigned int ...@@ -18038,6 +18036,42 @@ mal_format mal_format_from_encoding__audio4(unsigned int encoding, unsigned int
return mal_format_unknown; // Encoding not supported. return mal_format_unknown; // Encoding not supported.
} }
void mal_encoding_from_format__audio4(mal_format format, unsigned int* pEncoding, unsigned int* pPrecision)
{
mal_assert(format != mal_format_unknown);
mal_assert(pEncoding != NULL);
mal_assert(pPrecision != NULL);
switch (format)
{
case mal_format_u8:
{
*pEncoding = AUDIO_ENCODING_ULINEAR;
*pPrecision = 8;
} break;
case mal_format_s24:
{
*pEncoding = (mal_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
*pPrecision = 24;
} break;
case mal_format_s32:
{
*pEncoding = (mal_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
*pPrecision = 32;
} break;
case mal_format_s16:
case mal_format_f32:
default:
{
*pEncoding = (mal_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
*pPrecision = 16;
} break;
}
}
mal_format mal_format_from_prinfo__audio4(struct audio_prinfo* prinfo) mal_format mal_format_from_prinfo__audio4(struct audio_prinfo* prinfo)
{ {
return mal_format_from_encoding__audio4(prinfo->encoding, prinfo->precision); return mal_format_from_encoding__audio4(prinfo->encoding, prinfo->precision);
...@@ -18249,260 +18283,309 @@ void mal_device_uninit__audio4(mal_device* pDevice) ...@@ -18249,260 +18283,309 @@ void mal_device_uninit__audio4(mal_device* pDevice)
{ {
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
close(pDevice->audio4.fd); if (pDevice->type == mal_device_type_capture || pDevice->type == mal_device_type_duplex) {
mal_free(pDevice->audio4.pIntermediaryBuffer); close(pDevice->audio4.fdCapture);
}
if (pDevice->type == mal_device_type_playback || pDevice->type == mal_device_type_duplex) {
close(pDevice->audio4.fdPlayback);
}
} }
mal_result mal_device_init__audio4(mal_context* pContext, const mal_device_config* pConfig, mal_device* pDevice) mal_result mal_device_init_fd__audio4(mal_context* pContext, const mal_device_config* pConfig, mal_device_type deviceType, mal_device* pDevice)
{ {
(void)pContext; mal_result result;
const char* pDeviceName;
int fd;
int fdFlags = 0;
#if !defined(MAL_AUDIO4_USE_NEW_API) /* Old API */
audio_info_t fdInfo;
mal_device_info nativeInfo;
#else
struct audio_swpar fdPar;
#endif
mal_format internalFormat;
mal_uint32 internalChannels;
mal_uint32 internalSampleRate;
mal_uint32 internalBufferSizeInFrames;
mal_uint32 internalPeriods;
mal_assert(pDevice != NULL); mal_assert(pContext != NULL);
mal_zero_object(&pDevice->audio4); mal_assert(pConfig != NULL);
pDevice->audio4.fd = -1; mal_assert(deviceType != mal_device_type_duplex);
mal_assert(pDevice != NULL);
/* Full-duplex is not yet implemented. */ (void)pContext;
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
// The version of the operating system dictates whether or not the device is exclusive or shared. NetBSD /* The first thing to do is open the file. */
// introduced in-kernel mixing which means it's shared. All other BSD flavours are exclusive as far as pDeviceName = "/dev/audio";
// I'm aware. if (deviceType == mal_device_type_capture) {
#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 800000000 pDeviceName = pConfig->capture.pDeviceID->audio4;
/* NetBSD 8.0+ */ fdFlags = O_RDONLY;
if (((pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) && pConfig->playback.shareMode == mal_share_mode_exclusive) ||
((pConfig->deviceType == mal_device_type_capture || pConfig->deviceType == mal_device_type_duplex) && pConfig->capture.shareMode == mal_share_mode_exclusive)) {
return MAL_SHARE_MODE_NOT_SUPPORTED;
}
#else
/* All other flavors. */
#endif
// The first thing to do is open the file.
const char* deviceNamePlayback = "/dev/audio";
const char* deviceNameCapture = "/dev/audio";
if (pConfig->playback.pDeviceID != NULL) {
deviceNamePlayback = pConfig->playback.pDeviceID->audio4;
}
if (pConfig->capture.pDeviceID != NULL) {
deviceNameCapture = pConfig->capture.pDeviceID->audio4;
}
if (pConfig->deviceType == mal_device_type_playback) {
pDevice->audio4.fd = open(deviceNamePlayback, O_WRONLY | O_NONBLOCK, 0);
} else if (pConfig->deviceType == mal_device_type_capture) {
pDevice->audio4.fd = open(deviceNameCapture, O_RDONLY | O_NONBLOCK, 0);
} else if (pConfig->deviceType == mal_device_type_duplex) {
/* TOOD: Implement me. */
mal_assert(MAL_FALSE);
return MAL_INVALID_ARGS;
} else { } else {
mal_assert(MAL_FALSE); pDeviceName = pConfig->playback.pDeviceID->audio4;
return MAL_INVALID_ARGS; fdFlags = O_WRONLY;
} }
fdFlags |= O_NONBLOCK;
if (pDevice->audio4.fd == -1) {
fd = open(pDeviceName, fdFlags, 0);
if (fd == -1) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
} }
#if !defined(MAL_AUDIO4_USE_NEW_API) #if !defined(MAL_AUDIO4_USE_NEW_API) /* Old API */
audio_info_t fdInfo;
AUDIO_INITINFO(&fdInfo); AUDIO_INITINFO(&fdInfo);
struct audio_prinfo* prinfo; /* We get the driver to do as much of the data conversion as possible. */
if (pConfig->deviceType == mal_device_type_playback) { if (deviceType == mal_device_type_capture) {
prinfo = &fdInfo.play;
fdInfo.mode = AUMODE_PLAY;
} else {
prinfo = &fdInfo.record;
fdInfo.mode = AUMODE_RECORD; fdInfo.mode = AUMODE_RECORD;
mal_encoding_from_format__audio4(pConfig->capture.format, &fdInfo.record.encoding, &fdInfo.record.precision);
fdInfo.record.channels = pConfig->capture.channels;
fdInfo.record.sample_rate = pConfig->sampleRate;
} else {
fdInfo.mode = AUMODE_PLAY;
mal_encoding_from_format__audio4(pConfig->playback.format, &fdInfo.play.encoding, &fdInfo.play.precision);
fdInfo.play.channels = pConfig->playback.channels;
fdInfo.play.sample_rate = pConfig->sampleRate;
} }
// Format. Note that it looks like audio4 does not support floating point formats. In this case if (fd, AUDIO_SETINFO, &fdInfo) < 0) {
// we just fall back to s16. close(fd);
switch (pDevice->format)
{
case mal_format_u8:
{
prinfo->encoding = AUDIO_ENCODING_ULINEAR;
prinfo->precision = 8;
} break;
case mal_format_s24:
{
prinfo->encoding = (mal_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
prinfo->precision = 24;
} break;
case mal_format_s32:
{
prinfo->encoding = (mal_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
prinfo->precision = 32;
} break;
case mal_format_s16:
case mal_format_f32:
default:
{
prinfo->encoding = (mal_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
prinfo->precision = 16;
} break;
}
// We always want to the use the devices native channel count and sample rate.
mal_device_info nativeInfo;
mal_result result = mal_context_get_device_info(pContext, pConfig->deviceType, pConfig->pDeviceID, pConfig->shareMode, &nativeInfo);
if (result != MAL_SUCCESS) {
close(pDevice->audio4.fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve device format.", result);
}
prinfo->channels = nativeInfo.maxChannels;
prinfo->sample_rate = nativeInfo.maxSampleRate;
// We need to apply the settings so far so we can get back the actual sample rate which we need for calculating
// the default buffer size below.
if (ioctl(pDevice->audio4.fd, AUDIO_SETINFO, &fdInfo) < 0) {
close(pDevice->audio4.fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.", MAL_FORMAT_NOT_SUPPORTED); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.", MAL_FORMAT_NOT_SUPPORTED);
} }
if (ioctl(pDevice->audio4.fd, AUDIO_GETINFO, &fdInfo) < 0) { if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) {
close(pDevice->audio4.fd); close(fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.", MAL_FORMAT_NOT_SUPPORTED); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.", MAL_FORMAT_NOT_SUPPORTED);
} }
pDevice->internalFormat = mal_format_from_prinfo__audio4(prinfo); if (deviceType == mal_device_type_capture) {
if (pDevice->internalFormat == mal_format_unknown) { internalFormat = mal_format_from_prinfo__audio4(&fdInfo.record);
close(pDevice->audio4.fd); internalChannels = fdInfo.record.channels;
internalSampleRate = fdInfo.record.sample_rate;
} else {
internalFormat = mal_format_from_prinfo__audio4(&fdInfo.play);
internalChannels = fdInfo.play.channels;
internalSampleRate = fdInfo.play.sample_rate;
}
if (internalFormat == mal_format_unknown) {
close(fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by mini_al. The device is unusable.", MAL_FORMAT_NOT_SUPPORTED); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by mini_al. The device is unusable.", MAL_FORMAT_NOT_SUPPORTED);
} }
pDevice->internalChannels = prinfo->channels; /* Buffer. */
pDevice->internalSampleRate = prinfo->sample_rate; {
mal_uint32 internalBufferSizeInBytes;
internalBufferSizeInFrames = pConfig->bufferSizeInFrames;
if (internalBufferSizeInFrames == 0) {
internalBufferSizeInFrames = mal_calculate_buffer_size_in_frames_from_milliseconds(pConfig->bufferSizeInMilliseconds, internalSampleRate);
}
internalBufferSizeInBytes = internalBufferSizeInFrames * mal_get_bytes_per_frame(internalFormat, internalChannels);
if (internalBufferSizeInBytes < 16) {
internalBufferSizeInBytes = 16;
}
// Try calculating an appropriate default buffer size. internalPeriods = pConfig->periods;
if (pDevice->bufferSizeInFrames == 0) { if (internalPeriods < 2) {
pDevice->bufferSizeInFrames = mal_calculate_buffer_size_in_frames_from_milliseconds(pDevice->bufferSizeInMilliseconds, pDevice->internalSampleRate); internalPeriods = 2;
} }
// What mini_al calls a fragment, audio4 calls a block. /* What mini_al calls a fragment, audio4 calls a block. */
mal_uint32 bufferSizeInBytes = pDevice->bufferSizeInFrames * mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels); AUDIO_INITINFO(&fdInfo);
if (bufferSizeInBytes < 16) { fdInfo.hiwat = internalPeriods;
bufferSizeInBytes = 16; fdInfo.lowat = internalPeriods-1;
} fdInfo.blocksize = internalBufferSizeInBytes / internalPeriods;
if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) {
close(fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.", MAL_FORMAT_NOT_SUPPORTED);
}
internalPeriods = fdInfo.hiwat;
AUDIO_INITINFO(&fdInfo); internalBufferSizeInFrames = (fdInfo.blocksize * fdInfo.hiwat) / mal_get_bytes_per_frame(internalFormat, internalChannels);
fdInfo.hiwat = pDevice->periods;
fdInfo.lowat = pDevice->periods-1;
fdInfo.blocksize = bufferSizeInBytes / pDevice->periods;
if (ioctl(pDevice->audio4.fd, AUDIO_SETINFO, &fdInfo) < 0) {
close(pDevice->audio4.fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.", MAL_FORMAT_NOT_SUPPORTED);
} }
pDevice->periods = fdInfo.hiwat;
pDevice->bufferSizeInFrames = (fdInfo.blocksize * fdInfo.hiwat) / mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels);
#else #else
// We need to retrieve the format of the device so we can know the channel count and sample rate. Then we /* We need to retrieve the format of the device so we can know the channel count and sample rate. Then we can calculate the buffer size. */
// can calculate the buffer size. if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
struct audio_swpar fdPar; close(fd);
if (ioctl(pDevice->audio4.fd, AUDIO_GETPAR, &fdPar) < 0) {
close(pDevice->audio4.fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.", MAL_FORMAT_NOT_SUPPORTED); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.", MAL_FORMAT_NOT_SUPPORTED);
} }
// Set the initial internal formats so we can do calculations below. internalFormat = mal_format_from_swpar__audio4(&fdPar);
pDevice->internalFormat = mal_format_from_swpar__audio4(&fdPar); internalChannels = (deviceType == mal_device_type_capture) ? fdPar.rchan : fdPar.pchan;
if (pConfig->deviceType == mal_device_type_playback) { internalSampleRate = fdPar.rate;
pDevice->internalChannels = fdPar.pchan;
} else { if (internalFormat == mal_format_unknown) {
pDevice->internalChannels = fdPar.rchan; close(fd);
} return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by mini_al. The device is unusable.", MAL_FORMAT_NOT_SUPPORTED);
pDevice->internalSampleRate = fdPar.rate;
if (pDevice->bufferSizeInFrames == 0) {
pDevice->bufferSizeInFrames = mal_calculate_buffer_size_in_frames_from_milliseconds(pDevice->bufferSizeInMilliseconds, pDevice->internalSampleRate);
}
// What mini_al calls a fragment, audio4 calls a block.
mal_uint32 bufferSizeInBytes = pDevice->bufferSizeInFrames * mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels);
if (bufferSizeInBytes < 16) {
bufferSizeInBytes = 16;
} }
/* Buffer. */
{
mal_uint32 internalBufferSizeInBytes;
internalBufferSizeInFrames = pDevice->bufferSizeInFrames;
if (internalBufferSizeInFrames == 0) {
internalBufferSizeInFrames = mal_calculate_buffer_size_in_frames_from_milliseconds(pDevice->bufferSizeInMilliseconds, internalSampleRate);
}
/* What mini_al calls a fragment, audio4 calls a block. */
internalBufferSizeInBytes = internalBufferSizeInFrames * mal_get_bytes_per_frame(internalFormat, internalChannels);
if (internalBufferSizeInBytes < 16) {
internalBufferSizeInBytes = 16;
}
fdPar.nblks = pDevice->periods; fdPar.nblks = pConfig->periods;
fdPar.round = bufferSizeInBytes / fdPar.nblks; fdPar.round = internalBufferSizeInBytes / fdPar.nblks;
if (ioctl(pDevice->audio4.fd, AUDIO_SETPAR, &fdPar) < 0) { if (ioctl(fd, AUDIO_SETPAR, &fdPar) < 0) {
close(pDevice->audio4.fd); close(fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.", MAL_FORMAT_NOT_SUPPORTED); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.", MAL_FORMAT_NOT_SUPPORTED);
}
if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
close(fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.", MAL_FORMAT_NOT_SUPPORTED);
}
} }
if (ioctl(pDevice->audio4.fd, AUDIO_GETPAR, &fdPar) < 0) { internalFormat = mal_format_from_swpar__audio4(&fdPar);
close(pDevice->audio4.fd); internalChannels = (deviceType == mal_device_type_capture) ? fdPar.rchan : fdPar.pchan;
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.", MAL_FORMAT_NOT_SUPPORTED); internalSampleRate = fdPar.rate;
internalPeriods = fdPar.nblks;
internalBufferSizeInFrames = (fdPar.nblks * fdPar.round) / mal_get_bytes_per_frame(internalFormat, internalChannels);
#endif
if (internalFormat == mal_format_unknown) {
close(fd);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by mini_al. The device is unusable.", MAL_FORMAT_NOT_SUPPORTED);
} }
pDevice->internalFormat = mal_format_from_swpar__audio4(&fdPar); if (deviceType == mal_device_type_capture) {
if (pConfig->deviceType == mal_device_type_playback) { pDevice->capture.internalFormat = internalFormat;
pDevice->internalChannels = fdPar.pchan; pDevice->capture.internalChannels = internalChannels;
pDevice->capture.internalSampleRate = internalSampleRate;
mal_get_standard_channel_map(mal_standard_channel_map_sound4, internalChannels, pDevice->capture.internalChannelMap);
pDevice->capture.internalBufferSizeInFrames = internalBufferSizeInFrames;
pDevice->capture.internalPeriods = internalPeriods;
} else { } else {
pDevice->internalChannels = fdPar.rchan; pDevice->playback.internalFormat = internalFormat;
pDevice->playback.internalChannels = internalChannels;
pDevice->playback.internalSampleRate = internalSampleRate;
mal_get_standard_channel_map(mal_standard_channel_map_sound4, internalChannels, pDevice->playback.internalChannelMap);
pDevice->playback.internalBufferSizeInFrames = internalBufferSizeInFrames;
pDevice->playback.internalPeriods = internalPeriods;
} }
pDevice->internalSampleRate = fdPar.rate;
pDevice->periods = fdPar.nblks; return MAL_SUCCESS;
pDevice->bufferSizeInFrames = (fdPar.nblks * fdPar.round) / mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels); }
#endif
mal_result mal_device_init__audio4(mal_context* pContext, const mal_device_config* pConfig, mal_device* pDevice)
{
mal_assert(pDevice != NULL);
// For the channel map, I'm not sure how to query the channel map (or if it's even possible). I'm just mal_zero_object(&pDevice->audio4);
// using the channels defined in FreeBSD's sound(4) man page.
mal_get_standard_channel_map(mal_standard_channel_map_sound4, pDevice->internalChannels, pDevice->internalChannelMap);
pDevice->audio4.fdCapture = -1;
pDevice->audio4.fdPlayback = -1;
// The version of the operating system dictates whether or not the device is exclusive or shared. NetBSD
// introduced in-kernel mixing which means it's shared. All other BSD flavours are exclusive as far as
// I'm aware.
#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 800000000
/* NetBSD 8.0+ */
if (((pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) && pConfig->playback.shareMode == mal_share_mode_exclusive) ||
((pConfig->deviceType == mal_device_type_capture || pConfig->deviceType == mal_device_type_duplex) && pConfig->capture.shareMode == mal_share_mode_exclusive)) {
return MAL_SHARE_MODE_NOT_SUPPORTED;
}
#else
/* All other flavors. */
#endif
if (pConfig->deviceType == mal_device_type_capture || pConfig->deviceType == mal_device_type_duplex) {
mal_result result = mal_device_init_fd__audio4(pContext, pConfig, mal_device_type_capture, pDevice);
if (result != MAL_SUCCESS) {
return result;
}
}
if (pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) {
mal_result result = mal_device_init_fd__audio4(pContext, pConfig, mal_device_type_playback, pDevice);
if (result != MAL_SUCCESS) {
if (pConfig->deviceType == mal_device_type_duplex) {
close(pDevice->audio4.fdCapture);
}
return result;
}
}
return MAL_SUCCESS; return MAL_SUCCESS;
} }
#if 0
mal_result mal_device_start__audio4(mal_device* pDevice) mal_result mal_device_start__audio4(mal_device* pDevice)
{ {
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
if (pDevice->audio4.fd == -1) { if (pDevice->type == mal_device_type_capture || pDevice->type == mal_device_type_duplex) {
return MAL_INVALID_ARGS; if (pDevice->audio4.fdCapture == -1) {
return MAL_INVALID_ARGS;
}
}
if (pDevice->type == mal_device_type_playback || pDevice->type == mal_device_type_duplex) {
if (pDevice->audio4.fdPlayback == -1) {
return MAL_INVALID_ARGS;
}
} }
return MAL_SUCCESS; return MAL_SUCCESS;
} }
#endif
mal_result mal_device_stop__audio4(mal_device* pDevice) mal_result mal_device_stop_fd__audio4(int fd)
{ {
mal_assert(pDevice != NULL); if (pDevice->audio4.fdCapture == -1) {
if (pDevice->audio4.fd == -1) {
return MAL_INVALID_ARGS; return MAL_INVALID_ARGS;
} }
#if !defined(MAL_AUDIO4_USE_NEW_API) #if !defined(MAL_AUDIO4_USE_NEW_API)
if (ioctl(pDevice->audio4.fd, AUDIO_FLUSH, 0) < 0) { if (ioctl(pDevice->audio4.fdCapture, AUDIO_FLUSH, 0) < 0) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE);
} }
#else #else
if (ioctl(pDevice->audio4.fd, AUDIO_STOP, 0) < 0) { if (ioctl(pDevice->audio4.fdCapture, AUDIO_STOP, 0) < 0) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE);
} }
#endif #endif
}
mal_result mal_device_stop__audio4(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
if (pDevice->type == mal_device_type_capture || pDevice->type == mal_device_type_duplex) {
mal_result result = mal_device_stop_fd__audio4(pDevice->audio4.fdCapture);
if (result != MAL_SUCCESS) {
return result;
}
}
if (pDevice->type == mal_device_type_playback || pDevice->type == mal_device_type_duplex) {
mal_result result = mal_device_stop_fd__audio4(pDevice->audio4.fdPlayback);
if (result != MAL_SUCCESS) {
return result;
}
}
return MAL_SUCCESS; return MAL_SUCCESS;
} }
mal_result mal_device_write__audio4(mal_device* pDevice, const void* pPCMFrames, mal_uint32 frameCount) mal_result mal_device_write__audio4(mal_device* pDevice, const void* pPCMFrames, mal_uint32 frameCount)
{ {
int result = write(pDevice->audio4.fd, pPCMFrames, frameCount * mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels)); int result = write(pDevice->audio4.fdPlayback, pPCMFrames, frameCount * mal_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
if (result < 0) { if (result < 0) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
} }
...@@ -18512,7 +18595,7 @@ mal_result mal_device_write__audio4(mal_device* pDevice, const void* pPCMFrames, ...@@ -18512,7 +18595,7 @@ mal_result mal_device_write__audio4(mal_device* pDevice, const void* pPCMFrames,
mal_result mal_device_read__audio4(mal_device* pDevice, void* pPCMFrames, mal_uint32 frameCount) mal_result mal_device_read__audio4(mal_device* pDevice, void* pPCMFrames, mal_uint32 frameCount)
{ {
int result = read(pDevice->audio4.fd, pPCMFrames, frameCount * mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels)); int result = read(pDevice->audio4.fdCapture, pPCMFrames, frameCount * mal_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
if (result < 0) { if (result < 0) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE);
} }
...@@ -18539,7 +18622,7 @@ mal_result mal_context_init__audio4(mal_context* pContext) ...@@ -18539,7 +18622,7 @@ mal_result mal_context_init__audio4(mal_context* pContext)
pContext->onGetDeviceInfo = mal_context_get_device_info__audio4; pContext->onGetDeviceInfo = mal_context_get_device_info__audio4;
pContext->onDeviceInit = mal_device_init__audio4; pContext->onDeviceInit = mal_device_init__audio4;
pContext->onDeviceUninit = mal_device_uninit__audio4; pContext->onDeviceUninit = mal_device_uninit__audio4;
pContext->onDeviceStart = mal_device_start__audio4; pContext->onDeviceStart = NULL;
pContext->onDeviceStop = mal_device_stop__audio4; pContext->onDeviceStop = mal_device_stop__audio4;
pContext->onDeviceWrite = mal_device_write__audio4; pContext->onDeviceWrite = mal_device_write__audio4;
pContext->onDeviceRead = mal_device_read__audio4; pContext->onDeviceRead = mal_device_read__audio4;
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