Commit 64fa72a8 authored by David Reid's avatar David Reid

Improve error handling for the ALSA and OSS backends.

parent 8d5c715e
...@@ -356,6 +356,8 @@ typedef int mal_result; ...@@ -356,6 +356,8 @@ typedef int mal_result;
#define MAL_ALSA_FAILED_TO_OPEN_DEVICE -2048 #define MAL_ALSA_FAILED_TO_OPEN_DEVICE -2048
#define MAL_ALSA_FAILED_TO_SET_HW_PARAMS -2049 #define MAL_ALSA_FAILED_TO_SET_HW_PARAMS -2049
#define MAL_ALSA_FAILED_TO_SET_SW_PARAMS -2050 #define MAL_ALSA_FAILED_TO_SET_SW_PARAMS -2050
#define MAL_ALSA_FAILED_TO_PREPARE_DEVICE -2051
#define MAL_ALSA_FAILED_TO_RECOVER_DEVICE -2052
#define MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR -3072 #define MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR -3072
#define MAL_WASAPI_FAILED_TO_CREATE_DEVICE -3073 #define MAL_WASAPI_FAILED_TO_CREATE_DEVICE -3073
#define MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE -3074 #define MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE -3074
...@@ -4702,11 +4704,13 @@ static mal_bool32 mal_device_write__alsa(mal_device* pDevice) ...@@ -4702,11 +4704,13 @@ static mal_bool32 mal_device_write__alsa(mal_device* pDevice)
} else if (framesWritten == -EPIPE) { } else if (framesWritten == -EPIPE) {
// Underrun. Just recover and try writing again. // Underrun. Just recover and try writing again.
if (snd_pcm_recover((snd_pcm_t*)pDevice->alsa.pPCM, framesWritten, MAL_TRUE) < 0) { if (snd_pcm_recover((snd_pcm_t*)pDevice->alsa.pPCM, framesWritten, MAL_TRUE) < 0) {
mal_post_error(pDevice, "[ALSA] Failed to recover device after underrun.", MAL_ALSA_FAILED_TO_RECOVER_DEVICE);
return MAL_FALSE; return MAL_FALSE;
} }
framesWritten = snd_pcm_writei((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); framesWritten = snd_pcm_writei((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable);
if (framesWritten < 0) { if (framesWritten < 0) {
mal_post_error(pDevice, "[ALSA] Failed to write data to the internal device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
return MAL_FALSE; return MAL_FALSE;
} }
...@@ -4778,11 +4782,13 @@ static mal_bool32 mal_device_read__alsa(mal_device* pDevice) ...@@ -4778,11 +4782,13 @@ static mal_bool32 mal_device_read__alsa(mal_device* pDevice)
} else if (framesRead == -EPIPE) { } else if (framesRead == -EPIPE) {
// Overrun. Just recover and try reading again. // Overrun. Just recover and try reading again.
if (snd_pcm_recover((snd_pcm_t*)pDevice->alsa.pPCM, framesRead, MAL_TRUE) < 0) { if (snd_pcm_recover((snd_pcm_t*)pDevice->alsa.pPCM, framesRead, MAL_TRUE) < 0) {
mal_post_error(pDevice, "[ALSA] Failed to recover device after overrun.", MAL_ALSA_FAILED_TO_RECOVER_DEVICE);
return MAL_FALSE; return MAL_FALSE;
} }
framesRead = snd_pcm_readi((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); framesRead = snd_pcm_readi((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable);
if (framesRead < 0) { if (framesRead < 0) {
mal_post_error(pDevice, "[ALSA] Failed to read data from the internal device.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE);
return MAL_FALSE; return MAL_FALSE;
} }
...@@ -5145,14 +5151,20 @@ static mal_result mal_device__start_backend__alsa(mal_device* pDevice) ...@@ -5145,14 +5151,20 @@ static mal_result mal_device__start_backend__alsa(mal_device* pDevice)
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
// Prepare the device first... // Prepare the device first...
snd_pcm_prepare((snd_pcm_t*)pDevice->alsa.pPCM); if (snd_pcm_prepare((snd_pcm_t*)pDevice->alsa.pPCM) < 0) {
return mal_post_error(pDevice, "[ALSA] Failed to prepare device.", MAL_ALSA_FAILED_TO_PREPARE_DEVICE);
}
// ... and then grab an initial chunk from the client. After this is done, the device should // ... and then grab an initial chunk from the client. After this is done, the device should
// automatically start playing, since that's how we configured the software parameters. // automatically start playing, since that's how we configured the software parameters.
if (pDevice->type == mal_device_type_playback) { if (pDevice->type == mal_device_type_playback) {
mal_device_write__alsa(pDevice); if (!mal_device_write__alsa(pDevice)) {
return mal_post_error(pDevice, "[ALSA] Failed to write initial chunk of data to the playback device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
}
} else { } else {
snd_pcm_start((snd_pcm_t*)pDevice->alsa.pPCM); if (snd_pcm_start((snd_pcm_t*)pDevice->alsa.pPCM) < 0) {
return mal_post_error(pDevice, "[ALSA] Failed to start capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE);
}
} }
return MAL_SUCCESS; return MAL_SUCCESS;
...@@ -5225,7 +5237,7 @@ mal_result mal_context_init__oss(mal_context* pContext) ...@@ -5225,7 +5237,7 @@ mal_result mal_context_init__oss(mal_context* pContext)
// Try opening a temporary device first so we can get version information. This is closed at the end. // Try opening a temporary device first so we can get version information. This is closed at the end.
int fd = mal_open_temp_device__oss(); int fd = mal_open_temp_device__oss();
if (fd == -1) { if (fd == -1) {
return MAL_NO_BACKEND; // Looks liks OSS isn't installed, or there are no available devices. return mal_context_post_error(pContext, NULL, "[OSS] Failed to open temporary device for retrieving system properties.", MAL_NO_BACKEND); // Looks liks OSS isn't installed, or there are no available devices.
} }
// Grab the OSS version. // Grab the OSS version.
...@@ -5233,7 +5245,7 @@ mal_result mal_context_init__oss(mal_context* pContext) ...@@ -5233,7 +5245,7 @@ mal_result mal_context_init__oss(mal_context* pContext)
int result = ioctl(fd, OSS_GETVERSION, &ossVersion); int result = ioctl(fd, OSS_GETVERSION, &ossVersion);
if (result == -1) { if (result == -1) {
close(fd); close(fd);
return MAL_ERROR; // Looks like OSS isn't installed. return mal_context_post_error(pContext, NULL, "[OSS] Failed to retrieve OSS version.", MAL_NO_BACKEND);
} }
pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16); pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16);
...@@ -5262,7 +5274,7 @@ static mal_result mal_enumerate_devices__oss(mal_context* pContext, mal_device_t ...@@ -5262,7 +5274,7 @@ static mal_result mal_enumerate_devices__oss(mal_context* pContext, mal_device_t
// The object returned by SNDCTL_SYSINFO will have the information we're after. // The object returned by SNDCTL_SYSINFO will have the information we're after.
int fd = mal_open_temp_device__oss(); int fd = mal_open_temp_device__oss();
if (fd == -1) { if (fd == -1) {
return MAL_ERROR; // Failed to open a temporary device for retrieving the system info. return mal_context_post_error(pContext, NULL, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MAL_NO_BACKEND);
} }
oss_sysinfo si; oss_sysinfo si;
...@@ -5343,7 +5355,7 @@ static mal_result mal_device_init__oss(mal_context* pContext, mal_device_type ty ...@@ -5343,7 +5355,7 @@ static mal_result mal_device_init__oss(mal_context* pContext, mal_device_type ty
pDevice->oss.fd = open(deviceName, (type == mal_device_type_playback) ? O_WRONLY : O_RDONLY, 0); pDevice->oss.fd = open(deviceName, (type == mal_device_type_playback) ? O_WRONLY : O_RDONLY, 0);
if (pDevice->oss.fd == -1) { if (pDevice->oss.fd == -1) {
return mal_post_error(pDevice, "[OSS] Failed to open device.", MAL_NO_DEVICE); return mal_post_error(pDevice, "[OSS] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
} }
// The OSS documantation is very clear about the order we should be initializing the device's properties: // The OSS documantation is very clear about the order we should be initializing the device's properties:
...@@ -5456,12 +5468,12 @@ static mal_result mal_device__start_backend__oss(mal_device* pDevice) ...@@ -5456,12 +5468,12 @@ static mal_result mal_device__start_backend__oss(mal_device* pDevice)
// Playback. // Playback.
mal_uint32 samplesRead = mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); mal_uint32 samplesRead = mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer);
if (samplesRead == 0) { if (samplesRead == 0) {
return MAL_FAILED_TO_READ_DATA_FROM_CLIENT; return mal_post_error(pDevice, "[OSS] Failed to read initial chunk of data from the client.", MAL_FAILED_TO_READ_DATA_FROM_CLIENT);
} }
int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, samplesRead * mal_get_sample_size_in_bytes(pDevice->internalFormat)); int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, samplesRead * mal_get_sample_size_in_bytes(pDevice->internalFormat));
if (bytesWritten == -1) { if (bytesWritten == -1) {
return MAL_FAILED_TO_START_BACKEND_DEVICE; return mal_post_error(pDevice, "[OSS] Failed to send initial chunk of data to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
} }
} else { } else {
// Capture. Do nothing. // Capture. Do nothing.
...@@ -5487,7 +5499,7 @@ static mal_result mal_device__stop_backend__oss(mal_device* pDevice) ...@@ -5487,7 +5499,7 @@ static mal_result mal_device__stop_backend__oss(mal_device* pDevice)
int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_HALT, 0); int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_HALT, 0);
if (result == -1) { if (result == -1) {
return mal_post_error(pDevice, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", MAL_ERROR); return mal_post_error(pDevice, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE);
} }
return MAL_SUCCESS; return MAL_SUCCESS;
...@@ -5519,13 +5531,13 @@ static mal_result mal_device__main_loop__oss(mal_device* pDevice) ...@@ -5519,13 +5531,13 @@ static mal_result mal_device__main_loop__oss(mal_device* pDevice)
int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); 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) { if (bytesWritten < 0) {
return MAL_FAILED_TO_SEND_DATA_TO_DEVICE; return mal_post_error(pDevice, "[OSS] Failed to send data from the client to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
} }
} else { } else {
// Capture. // Capture.
int bytesRead = read(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * mal_get_sample_size_in_bytes(pDevice->internalFormat)); int bytesRead = read(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * mal_get_sample_size_in_bytes(pDevice->internalFormat));
if (bytesRead < 0) { if (bytesRead < 0) {
return MAL_FAILED_TO_READ_DATA_FROM_DEVICE; return mal_post_error(pDevice, "[OSS] Failed to read data from the device to be sent to the client.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE);
} }
mal_uint32 framesRead = (mal_uint32)bytesRead / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); mal_uint32 framesRead = (mal_uint32)bytesRead / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat);
......
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