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
fc3ee393
Commit
fc3ee393
authored
Aug 24, 2018
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
audio(4): Some tweaks to device IO.
parent
c5d30341
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
55 additions
and
44 deletions
+55
-44
mini_al.h
mini_al.h
+55
-44
No files found.
mini_al.h
View file @
fc3ee393
...
@@ -505,6 +505,7 @@ typedef int mal_result;
...
@@ -505,6 +505,7 @@ typedef int mal_result;
#define MAL_ACCESS_DENIED -32
#define MAL_ACCESS_DENIED -32
#define MAL_TOO_LARGE -33
#define MAL_TOO_LARGE -33
#define MAL_DEVICE_UNAVAILABLE -34
#define MAL_DEVICE_UNAVAILABLE -34
#define MAL_TIMEOUT -35
// Standard sample rates.
// Standard sample rates.
#define MAL_SAMPLE_RATE_8000 8000
#define MAL_SAMPLE_RATE_8000 8000
...
@@ -16734,6 +16735,7 @@ mal_result mal_device_init__audio4(mal_context* pContext, mal_device_type device
...
@@ -16734,6 +16735,7 @@ mal_result mal_device_init__audio4(mal_context* pContext, mal_device_type device
mal_assert(pDevice != NULL);
mal_assert(pDevice != NULL);
mal_zero_object(&pDevice->audio4);
mal_zero_object(&pDevice->audio4);
pDevice->audio4.fd = -1;
// The first thing to do is open the file.
// The first thing to do is open the file.
const char* deviceName = "/dev/audio";
const char* deviceName = "/dev/audio";
...
@@ -16741,7 +16743,6 @@ mal_result mal_device_init__audio4(mal_context* pContext, mal_device_type device
...
@@ -16741,7 +16743,6 @@ mal_result mal_device_init__audio4(mal_context* pContext, mal_device_type device
deviceName = pDeviceID->audio4;
deviceName = pDeviceID->audio4;
}
}
// TODO: Consider non blocking mode: O_NONBLOCK. Needed for detecting device unplugs.
pDevice->audio4.fd = open(deviceName, ((deviceType == mal_device_type_playback) ? O_WRONLY : O_RDONLY) | O_NONBLOCK, 0);
pDevice->audio4.fd = open(deviceName, ((deviceType == mal_device_type_playback) ? O_WRONLY : O_RDONLY) | O_NONBLOCK, 0);
if (pDevice->audio4.fd == -1) {
if (pDevice->audio4.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);
...
@@ -16935,6 +16936,10 @@ mal_result mal_device__start_backend__audio4(mal_device* pDevice)
...
@@ -16935,6 +16936,10 @@ mal_result mal_device__start_backend__audio4(mal_device* pDevice)
{
{
mal_assert(pDevice != NULL);
mal_assert(pDevice != NULL);
if (pDevice->audio4.fd == -1) {
return MAL_INVALID_ARGS;
}
// The device is started by the next calls to read() and write(). For playback it's simple - just read
// 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.
// 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
// For capture it's a bit less intuitive - we do nothing (it'll be started automatically by the first
...
@@ -16960,6 +16965,10 @@ mal_result mal_device__stop_backend__audio4(mal_device* pDevice)
...
@@ -16960,6 +16965,10 @@ mal_result mal_device__stop_backend__audio4(mal_device* pDevice)
{
{
mal_assert(pDevice != NULL);
mal_assert(pDevice != NULL);
if (pDevice->audio4.fd == -1) {
return MAL_INVALID_ARGS;
}
#if defined(__NetBSD__)
#if defined(__NetBSD__)
if (ioctl(pDevice->audio4.fd, AUDIO_FLUSH, 0) < 0) {
if (ioctl(pDevice->audio4.fd, 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);
...
@@ -16981,6 +16990,44 @@ mal_result mal_device__break_main_loop__audio4(mal_device* pDevice)
...
@@ -16981,6 +16990,44 @@ mal_result mal_device__break_main_loop__audio4(mal_device* pDevice)
return MAL_SUCCESS;
return MAL_SUCCESS;
}
}
mal_result mal_device__wait__audio4(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
struct pollfd fds[1];
fds[0].fd = pDevice->audio4.fd;
fds[0].events = (pDevice->type == mal_device_type_playback) ? (POLLOUT | POLLWRBAND) : (POLLIN | POLLPRI);
int timeout = 2 * 1000;
int ioresult = poll(fds, mal_countof(fds), timeout);
if (ioresult < 0) {
#ifdef MAL_DEBUG_OUTPUT
printf("poll() failed: timeout=%d, ioresult=%d\n", pDevice->bufferSizeInMilliseconds, ioresult);
#endif
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to wait for device.", MAL_ERROR);
}
// Check for a timeout. This has been annoying in my testing. In my testing, when the device is unplugged it will just
// hang on the next calls to write(), ioctl(), etc. The only way I have figured out how to handle this is to wait for
// a timeout from poll(). In the unplugging case poll() will timeout, however there's no indication that the device is
// unusable - no flags are set, no errors are reported, nothing. To work around this I have decided to outright fail
// in the event of a timeout.
if (ioresult == 0) {
// Check for errors.
if ((fds[0].revents & (POLLERR | POLLNVAL)) != 0) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to wait for device.", MAL_NO_DEVICE);
}
if ((fds[0].revents & (POLLHUP)) != 0) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to wait for device. Disconnected.", MAL_NO_DEVICE);
}
// A return value of 0 from poll indicates a timeout.
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Timeout while waiting for device.", MAL_TIMEOUT);
}
mal_assert(ioresult > 0);
return MAL_SUCCESS;
}
mal_result mal_device__main_loop__audio4(mal_device* pDevice)
mal_result mal_device__main_loop__audio4(mal_device* pDevice)
{
{
mal_assert(pDevice != NULL);
mal_assert(pDevice != NULL);
...
@@ -16998,29 +17045,11 @@ mal_result mal_device__main_loop__audio4(mal_device* pDevice)
...
@@ -16998,29 +17045,11 @@ mal_result mal_device__main_loop__audio4(mal_device* pDevice)
mal_device__read_frames_from_client(pDevice, pDevice->audio4.fragmentSizeInFrames, pDevice->audio4.pIntermediaryBuffer);
mal_device__read_frames_from_client(pDevice, pDevice->audio4.fragmentSizeInFrames, pDevice->audio4.pIntermediaryBuffer);
// Wait for data to become available.
// Wait for data to become available.
struct pollfd fds[1];
mal_result result = mal_device__wait__audio4(pDevice);
fds[0].fd = pDevice->audio4.fd;
if (result != MAL_SUCCESS) {
fds[0].events = POLLOUT | POLLWRBAND;
return result;
int timeout = 2 * 1000; //mal_calculate_buffer_size_in_milliseconds_from_frames(pDevice->audio4.fragmentSizeInFrames, pDevice->internalSampleRate);
for (;;) {
int ioresult = poll(fds, mal_countof(fds), timeout);
if (ioresult < 0) {
#ifdef MAL_DEBUG_OUTPUT
printf("poll() failed: timeout=%d, ioresult=%d\n", pDevice->bufferSizeInMilliseconds, ioresult);
#endif
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to wait for device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
}
if (ioresult > 0) {
break;
}
mal_assert(ioresult == 0);
// A return value of 0 from pool indicates a timeout.
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Timeout while waiting for device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
}
}
size_t bytesToWrite = pDevice->audio4.fragmentSizeInFrames * mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels);
size_t bytesToWrite = pDevice->audio4.fragmentSizeInFrames * mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels);
while (bytesToWrite > 0) {
while (bytesToWrite > 0) {
ssize_t bytesWritten = write(pDevice->audio4.fd, pDevice->audio4.pIntermediaryBuffer, bytesToWrite);
ssize_t bytesWritten = write(pDevice->audio4.fd, pDevice->audio4.pIntermediaryBuffer, bytesToWrite);
...
@@ -17036,27 +17065,9 @@ mal_result mal_device__main_loop__audio4(mal_device* pDevice)
...
@@ -17036,27 +17065,9 @@ mal_result mal_device__main_loop__audio4(mal_device* pDevice)
}
}
} else {
} else {
// Capture.
// Capture.
struct pollfd fds[1];
mal_result result = mal_device__wait__audio4(pDevice);
fds[0].fd = pDevice->audio4.fd;
if (result != MAL_SUCCESS) {
fds[0].events = POLLIN | POLLPRI;
return result;
int timeout = 2 * 1000; //mal_calculate_buffer_size_in_milliseconds_from_frames(pDevice->audio4.fragmentSizeInFrames, pDevice->internalSampleRate);
for (;;) {
int ioresult = poll(fds, mal_countof(fds), timeout);
if (ioresult < 0) { // 0 = timeout.
#ifdef MAL_DEBUG_OUTPUT
printf("poll() failed: timeout=%d, ioresult=%d\n", pDevice->bufferSizeInMilliseconds, ioresult);
#endif
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to wait for device.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE);
}
if (ioresult > 0) {
break;
}
mal_assert(ioresult == 0);
// A return value of 0 from pool indicates a timeout.
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Timeout while waiting for device.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE);
}
}
size_t totalBytesRead = 0;
size_t totalBytesRead = 0;
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