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
5b4b7fa2
Commit
5b4b7fa2
authored
Feb 24, 2019
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More work on full-duplex with WebAudio.
parent
51ebb048
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
202 additions
and
47 deletions
+202
-47
mini_al.h
mini_al.h
+181
-44
tests/mal_duplex.c
tests/mal_duplex.c
+21
-3
No files found.
mini_al.h
View file @
5b4b7fa2
...
@@ -1248,19 +1248,19 @@ typedef struct
...
@@ -1248,19 +1248,19 @@ typedef struct
mal_uint32 channels;
mal_uint32 channels;
} mal_pcm_rb;
} mal_pcm_rb;
mal_result mal_pcm_rb_init_ex(mal_format format, mal_uint32 channels,
size_t subbufferSizeInFrames, size_t subbufferCount, size_t
subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, mal_pcm_rb* pRB);
mal_result mal_pcm_rb_init_ex(mal_format format, mal_uint32 channels,
mal_uint32 subbufferSizeInFrames, mal_uint32 subbufferCount, mal_uint32
subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, mal_pcm_rb* pRB);
mal_result mal_pcm_rb_init(mal_format format, mal_uint32 channels,
size_t
bufferSizeInFrames, void* pOptionalPreallocatedBuffer, mal_pcm_rb* pRB);
mal_result mal_pcm_rb_init(mal_format format, mal_uint32 channels,
mal_uint32
bufferSizeInFrames, void* pOptionalPreallocatedBuffer, mal_pcm_rb* pRB);
void mal_pcm_rb_uninit(mal_pcm_rb* pRB);
void mal_pcm_rb_uninit(mal_pcm_rb* pRB);
mal_result mal_pcm_rb_acquire_read(mal_pcm_rb* pRB,
size_t
* pSizeInFrames, void** ppBufferOut);
mal_result mal_pcm_rb_acquire_read(mal_pcm_rb* pRB,
mal_uint32
* pSizeInFrames, void** ppBufferOut);
mal_result mal_pcm_rb_commit_read(mal_pcm_rb* pRB,
size_t
sizeInFrames, void* pBufferOut);
mal_result mal_pcm_rb_commit_read(mal_pcm_rb* pRB,
mal_uint32
sizeInFrames, void* pBufferOut);
mal_result mal_pcm_rb_acquire_write(mal_pcm_rb* pRB,
size_t
* pSizeInFrames, void** ppBufferOut);
mal_result mal_pcm_rb_acquire_write(mal_pcm_rb* pRB,
mal_uint32
* pSizeInFrames, void** ppBufferOut);
mal_result mal_pcm_rb_commit_write(mal_pcm_rb* pRB,
size_t
sizeInFrames, void* pBufferOut);
mal_result mal_pcm_rb_commit_write(mal_pcm_rb* pRB,
mal_uint32
sizeInFrames, void* pBufferOut);
mal_result mal_pcm_rb_seek_read(mal_pcm_rb* pRB,
size_t
offsetInFrames);
mal_result mal_pcm_rb_seek_read(mal_pcm_rb* pRB,
mal_uint32
offsetInFrames);
mal_result mal_pcm_rb_seek_write(mal_pcm_rb* pRB,
size_t
offsetInFrames);
mal_result mal_pcm_rb_seek_write(mal_pcm_rb* pRB,
mal_uint32
offsetInFrames);
mal_int32 mal_pcm_rb_pointer_disance(mal_pcm_rb* pRB); /* Return value is in frames. */
mal_int32 mal_pcm_rb_pointer_disance(mal_pcm_rb* pRB); /* Return value is in frames. */
size_t mal_pcm_rb_get_subbuffer_stride(mal_pcm_rb* pRB);
size_t mal_pcm_rb_get_subbuffer_stride(mal_pcm_rb* pRB);
size_t mal_pcm_rb_get_subbuffer_offset(mal_pcm_rb* pRB,
size_t
subbufferIndex);
size_t mal_pcm_rb_get_subbuffer_offset(mal_pcm_rb* pRB,
mal_uint32
subbufferIndex);
void* mal_pcm_rb_get_subbuffer_ptr(mal_pcm_rb* pRB,
size_t
subbufferIndex, void* pBuffer);
void* mal_pcm_rb_get_subbuffer_ptr(mal_pcm_rb* pRB,
mal_uint32
subbufferIndex, void* pBuffer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
...
@@ -2332,6 +2332,7 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device
...
@@ -2332,6 +2332,7 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device
{
{
int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
int indexCapture;
int indexCapture;
mal_pcm_rb duplexRB; /* In external capture format. */
} webaudio;
} webaudio;
#endif
#endif
#ifdef MAL_SUPPORT_NULL
#ifdef MAL_SUPPORT_NULL
...
@@ -4676,6 +4677,22 @@ mal_result mal_post_error(mal_device* pDevice, mal_uint32 logLevel, const char*
...
@@ -4676,6 +4677,22 @@ mal_result mal_post_error(mal_device* pDevice, mal_uint32 logLevel, const char*
}
}
mal_uint64 mal_calculate_frame_count_after_src(mal_uint32 sampleRateOut, mal_uint32 sampleRateIn, mal_uint64 frameCountIn)
{
double srcRatio = (double)sampleRateOut / sampleRateIn;
double frameCountOutF = frameCountIn * srcRatio;
mal_uint64 frameCountOut = (mal_uint64)frameCountOutF;
// If the output frame count is fractional, make sure we add an extra frame to ensure there's enough room for that last sample.
if ((frameCountOutF - frameCountOut) > 0.0) {
frameCountOut += 1;
}
return frameCountOut;
}
// The callback for reading from the client -> DSP -> device.
// The callback for reading from the client -> DSP -> device.
mal_uint32 mal_device__on_read_from_client(mal_pcm_converter* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData)
mal_uint32 mal_device__on_read_from_client(mal_pcm_converter* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData)
{
{
...
@@ -4788,6 +4805,111 @@ static MAL_INLINE void mal_device__send_frames_to_client(mal_device* pDevice, ma
...
@@ -4788,6 +4805,111 @@ static MAL_INLINE void mal_device__send_frames_to_client(mal_device* pDevice, ma
}
}
}
}
static mal_result mal_device__handle_duplex_callback_capture(mal_device* pDevice, mal_uint32 frameCount, const void* pFramesInInternalFormat, mal_pcm_rb* pRB)
{
mal_assert(pDevice != NULL);
mal_assert(frameCount > 0);
mal_assert(pFramesInInternalFormat != NULL);
mal_assert(pRB != NULL);
mal_result result;
pDevice->capture._dspFrameCount = (mal_uint32)frameCount;
pDevice->capture._dspFrames = (const mal_uint8*)pFramesInInternalFormat;
/* Write to the ring buffer. The ring buffer is in the external format. */
for (;;) {
mal_uint32 framesProcessed;
mal_uint32 framesToProcess = 256;
void* pFramesInExternalFormat;
result = mal_pcm_rb_acquire_write(pRB, &framesToProcess, &pFramesInExternalFormat);
if (result != MAL_SUCCESS) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.", result);
break;
}
if (framesToProcess == 0) {
break; /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */
}
/* Convert. */
framesProcessed = (mal_uint32)mal_pcm_converter_read(&pDevice->capture.converter, framesToProcess, pFramesInExternalFormat, pDevice->capture.converter.pUserData);
result = mal_pcm_rb_commit_write(pRB, framesProcessed, pFramesInExternalFormat);
if (result != MAL_SUCCESS) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.", result);
break;
}
if (framesProcessed < framesToProcess) {
break; /* Done. */
}
}
return MAL_SUCCESS;
}
static mal_result mal_device__handle_duplex_callback_playback(mal_device* pDevice, mal_uint32 frameCount, void* pFramesInInternalFormat, mal_pcm_rb* pRB)
{
mal_assert(pDevice != NULL);
mal_assert(frameCount > 0);
mal_assert(pFramesInInternalFormat != NULL);
mal_assert(pRB != NULL);
/*
Sitting in the ring buffer should be captured data from the capture callback in external format. If there's not enough data in there for
the whole frameCount frames we just use silence instead for the input data.
*/
mal_result result;
mal_uint8 playbackFramesInExternalFormat[4096];
mal_uint8 silentInputFrames[4096];
mal_zero_memory(silentInputFrames, sizeof(silentInputFrames));
/* We need to calculate how many output frames are required to be read from the client to completely fill frameCount internal frames. */
mal_uint32 totalFramesToReadFromClient = (mal_uint32)mal_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->playback.internalSampleRate, frameCount); // mal_pcm_converter_get_required_input_frame_count(&pDevice->playback.converter, (mal_uint32)frameCount);
mal_uint32 totalFramesReadFromClient = 0;
while (totalFramesReadFromClient < totalFramesToReadFromClient) {
mal_uint32 framesRemainingFromClient = (totalFramesToReadFromClient - totalFramesReadFromClient);
mal_uint32 framesToProcessFromClient = sizeof(playbackFramesInExternalFormat) / mal_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
if (framesToProcessFromClient > framesRemainingFromClient) {
framesToProcessFromClient = framesRemainingFromClient;
}
/* We need to grab captured samples before firing the callback. If there's not enough input samples we just pass silence. */
mal_uint32 inputFrameCount = framesToProcessFromClient;
void* pInputFrames;
result = mal_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames);
if (result == MAL_SUCCESS && inputFrameCount > 0) {
/* Use actual input frames. */
pDevice->onData(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount);
/* We're done with the captured samples. */
result = mal_pcm_rb_commit_read(pRB, inputFrameCount, pInputFrames);
if (result != MAL_SUCCESS) {
break; /* Don't know what to do here... Just abandon ship. */
}
} else {
/* Use silent input frames. */
inputFrameCount = mal_min(
sizeof(playbackFramesInExternalFormat) / mal_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels),
sizeof(silentInputFrames) / mal_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels)
);
pDevice->onData(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount);
}
/* We have samples in external format so now we need to convert to internal format and output to the device. */
pDevice->playback._dspFrameCount = inputFrameCount;
pDevice->playback._dspFrames = (const mal_uint8*)playbackFramesInExternalFormat;
mal_pcm_converter_read(&pDevice->playback.converter, inputFrameCount, pFramesInInternalFormat, pDevice->playback.converter.pUserData);
totalFramesReadFromClient += inputFrameCount;
pFramesInInternalFormat = mal_offset_ptr(pFramesInInternalFormat, inputFrameCount * mal_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
}
return MAL_SUCCESS;
}
// A helper for changing the state of the device.
// A helper for changing the state of the device.
static MAL_INLINE void mal_device__set_state(mal_device* pDevice, mal_uint32 newState)
static MAL_INLINE void mal_device__set_state(mal_device* pDevice, mal_uint32 newState)
{
{
...
@@ -6236,7 +6358,7 @@ ULONG STDMETHODCALLTYPE mal_IMMNotificationClient_Release(mal_IMMNotificationCli
...
@@ -6236,7 +6358,7 @@ ULONG STDMETHODCALLTYPE mal_IMMNotificationClient_Release(mal_IMMNotificationCli
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceStateChanged(mal_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState)
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceStateChanged(mal_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState)
{
{
#ifdef MAL_DEBUG_OUTPUT
#ifdef MAL_DEBUG_OUTPUT
printf("IMMNotificationClient_OnDeviceStateChanged(pDeviceID=%S, dwNewState=%u)\n",
pDeviceID
, (unsigned int)dwNewState);
printf("IMMNotificationClient_OnDeviceStateChanged(pDeviceID=%S, dwNewState=%u)\n",
(pDeviceID != NULL) ? pDeviceID : L"(NULL)"
, (unsigned int)dwNewState);
#endif
#endif
(void)pThis;
(void)pThis;
...
@@ -6248,7 +6370,7 @@ HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceStateChanged(mal_IMM
...
@@ -6248,7 +6370,7 @@ HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceStateChanged(mal_IMM
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceAdded(mal_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceAdded(mal_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
{
{
#ifdef MAL_DEBUG_OUTPUT
#ifdef MAL_DEBUG_OUTPUT
printf("IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n",
pDeviceID
);
printf("IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n",
(pDeviceID != NULL) ? pDeviceID : L"(NULL)"
);
#endif
#endif
// We don't need to worry about this event for our purposes.
// We don't need to worry about this event for our purposes.
...
@@ -6260,7 +6382,7 @@ HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceAdded(mal_IMMNotific
...
@@ -6260,7 +6382,7 @@ HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceAdded(mal_IMMNotific
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceRemoved(mal_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceRemoved(mal_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
{
{
#ifdef MAL_DEBUG_OUTPUT
#ifdef MAL_DEBUG_OUTPUT
printf("IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n",
pDeviceID
);
printf("IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n",
(pDeviceID != NULL) ? pDeviceID : L"(NULL)"
);
#endif
#endif
// We don't need to worry about this event for our purposes.
// We don't need to worry about this event for our purposes.
...
@@ -6272,7 +6394,7 @@ HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceRemoved(mal_IMMNotif
...
@@ -6272,7 +6394,7 @@ HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDeviceRemoved(mal_IMMNotif
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDefaultDeviceChanged(mal_IMMNotificationClient* pThis, mal_EDataFlow dataFlow, mal_ERole role, LPCWSTR pDefaultDeviceID)
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDefaultDeviceChanged(mal_IMMNotificationClient* pThis, mal_EDataFlow dataFlow, mal_ERole role, LPCWSTR pDefaultDeviceID)
{
{
#ifdef MAL_DEBUG_OUTPUT
#ifdef MAL_DEBUG_OUTPUT
printf("IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role,
pDefaultDeviceID
);
printf("IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role,
(pDefaultDeviceID != NULL) ? pDefaultDeviceID : L"(NULL)"
);
#endif
#endif
// We only ever use the eConsole role in mini_al.
// We only ever use the eConsole role in mini_al.
...
@@ -6314,7 +6436,7 @@ HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDefaultDeviceChanged(mal_I
...
@@ -6314,7 +6436,7 @@ HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnDefaultDeviceChanged(mal_I
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnPropertyValueChanged(mal_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key)
HRESULT STDMETHODCALLTYPE mal_IMMNotificationClient_OnPropertyValueChanged(mal_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key)
{
{
#ifdef MAL_DEBUG_OUTPUT
#ifdef MAL_DEBUG_OUTPUT
printf("IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n",
pDeviceID
);
printf("IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n",
(pDeviceID != NULL) ? pDeviceID : L"(NULL)"
);
#endif
#endif
(void)pThis;
(void)pThis;
...
@@ -20833,8 +20955,10 @@ extern "C" {
...
@@ -20833,8 +20955,10 @@ extern "C" {
#endif
#endif
EMSCRIPTEN_KEEPALIVE void mal_device_process_pcm_frames_capture__webaudio(mal_device* pDevice, int frameCount, float* pFrames)
EMSCRIPTEN_KEEPALIVE void mal_device_process_pcm_frames_capture__webaudio(mal_device* pDevice, int frameCount, float* pFrames)
{
{
mal_result result;
if (pDevice->type == mal_device_type_duplex) {
if (pDevice->type == mal_device_type_duplex) {
/* TODO: Write to the ring buffer. */
mal_device__handle_duplex_callback_capture(pDevice, (mal_uint32)frameCount, pFrames, &pDevice->webaudio.duplexRB);
} else {
} else {
mal_device__send_frames_to_client(pDevice, (mal_uint32)frameCount, pFrames); /* Send directly to the client. */
mal_device__send_frames_to_client(pDevice, (mal_uint32)frameCount, pFrames); /* Send directly to the client. */
}
}
...
@@ -20843,7 +20967,7 @@ EMSCRIPTEN_KEEPALIVE void mal_device_process_pcm_frames_capture__webaudio(mal_de
...
@@ -20843,7 +20967,7 @@ EMSCRIPTEN_KEEPALIVE void mal_device_process_pcm_frames_capture__webaudio(mal_de
EMSCRIPTEN_KEEPALIVE void mal_device_process_pcm_frames_playback__webaudio(mal_device* pDevice, int frameCount, float* pFrames)
EMSCRIPTEN_KEEPALIVE void mal_device_process_pcm_frames_playback__webaudio(mal_device* pDevice, int frameCount, float* pFrames)
{
{
if (pDevice->type == mal_device_type_duplex) {
if (pDevice->type == mal_device_type_duplex) {
/* TODO: Write to the ring buffer. */
mal_device__handle_duplex_callback_playback(pDevice, (mal_uint32)frameCount, pFrames, &pDevice->webaudio.duplexRB);
} else {
} else {
mal_device__read_frames_from_client(pDevice, (mal_uint32)frameCount, pFrames); /* Read directly from the device. */
mal_device__read_frames_from_client(pDevice, (mal_uint32)frameCount, pFrames); /* Read directly from the device. */
}
}
...
@@ -20994,6 +21118,10 @@ void mal_device_uninit__webaudio(mal_device* pDevice)
...
@@ -20994,6 +21118,10 @@ void mal_device_uninit__webaudio(mal_device* pDevice)
if (pDevice->type == mal_device_type_playback || pDevice->type == mal_device_type_duplex) {
if (pDevice->type == mal_device_type_playback || pDevice->type == mal_device_type_duplex) {
mal_device_uninit_by_index__webaudio(pDevice, mal_device_type_playback, pDevice->webaudio.indexPlayback);
mal_device_uninit_by_index__webaudio(pDevice, mal_device_type_playback, pDevice->webaudio.indexPlayback);
}
}
if (pDevice->type == mal_device_type_duplex) {
mal_pcm_rb_uninit(&pDevice->webaudio.duplexRB);
}
}
}
mal_result mal_device_init_by_type__webaudio(mal_context* pContext, const mal_device_config* pConfig, mal_device_type deviceType, mal_device* pDevice)
mal_result mal_device_init_by_type__webaudio(mal_context* pContext, const mal_device_config* pConfig, mal_device_type deviceType, mal_device* pDevice)
...
@@ -21206,6 +21334,8 @@ mal_result mal_device_init_by_type__webaudio(mal_context* pContext, const mal_de
...
@@ -21206,6 +21334,8 @@ mal_result mal_device_init_by_type__webaudio(mal_context* pContext, const mal_de
mal_result mal_device_init__webaudio(mal_context* pContext, const mal_device_config* pConfig, mal_device* pDevice)
mal_result mal_device_init__webaudio(mal_context* pContext, const mal_device_config* pConfig, mal_device* pDevice)
{
{
mal_result result;
/* No exclusive mode with Web Audio. */
/* No exclusive mode with Web Audio. */
if (((pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) && pConfig->playback.shareMode == mal_share_mode_exclusive) ||
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)) {
((pConfig->deviceType == mal_device_type_capture || pConfig->deviceType == mal_device_type_duplex) && pConfig->capture.shareMode == mal_share_mode_exclusive)) {
...
@@ -21213,15 +21343,37 @@ mal_result mal_device_init__webaudio(mal_context* pContext, const mal_device_con
...
@@ -21213,15 +21343,37 @@ mal_result mal_device_init__webaudio(mal_context* pContext, const mal_device_con
}
}
if (pConfig->deviceType == mal_device_type_capture || pConfig->deviceType == mal_device_type_duplex) {
if (pConfig->deviceType == mal_device_type_capture || pConfig->deviceType == mal_device_type_duplex) {
mal_result
result = mal_device_init_by_type__webaudio(pContext, pConfig, mal_device_type_capture, pDevice);
result = mal_device_init_by_type__webaudio(pContext, pConfig, mal_device_type_capture, pDevice);
if (result != MAL_SUCCESS) {
if (result != MAL_SUCCESS) {
return result;
return result;
}
}
}
}
if (pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) {
if (pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) {
mal_result
result = mal_device_init_by_type__webaudio(pContext, pConfig, mal_device_type_playback, pDevice);
result = mal_device_init_by_type__webaudio(pContext, pConfig, mal_device_type_playback, pDevice);
if (result != MAL_SUCCESS) {
if (result != MAL_SUCCESS) {
if (pConfig->deviceType == mal_device_type_duplex) {
mal_device_uninit_by_index__webaudio(pDevice, mal_device_type_capture, pDevice->webaudio.indexCapture);
}
return result;
}
}
/*
We need a ring buffer for moving data from the capture device to the playback device. The capture callback is the producer
and the playback callback is the consumer. The buffer needs to be large enough to hold internalBufferSizeInFrames based on
the external sample rate.
*/
if (pConfig->deviceType == mal_device_type_duplex) {
mal_uint32 rbSizeInFrames = mal_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalBufferSizeInFrames);
result = mal_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->webaudio.duplexRB);
if (result != MAL_SUCCESS) {
if (pDevice->type == mal_device_type_capture || pDevice->type == mal_device_type_duplex) {
mal_device_uninit_by_index__webaudio(pDevice, mal_device_type_capture, pDevice->webaudio.indexCapture);
}
if (pDevice->type == mal_device_type_playback || pDevice->type == mal_device_type_duplex) {
mal_device_uninit_by_index__webaudio(pDevice, mal_device_type_playback, pDevice->webaudio.indexPlayback);
}
return result;
return result;
}
}
}
}
...
@@ -26830,21 +26982,6 @@ static MAL_INLINE double mal_sinc(double x)
...
@@ -26830,21 +26982,6 @@ static MAL_INLINE double mal_sinc(double x)
#define mal_sincf(x) ((float)mal_sinc((double)(x)))
#define mal_sincf(x) ((float)mal_sinc((double)(x)))
mal_uint64 mal_calculate_frame_count_after_src(mal_uint32 sampleRateOut, mal_uint32 sampleRateIn, mal_uint64 frameCountIn)
{
double srcRatio = (double)sampleRateOut / sampleRateIn;
double frameCountOutF = frameCountIn * srcRatio;
mal_uint64 frameCountOut = (mal_uint64)frameCountOutF;
// If the output frame count is fractional, make sure we add an extra frame to ensure there's enough room for that last sample.
if ((frameCountOutF - frameCountOut) > 0.0) {
frameCountOut += 1;
}
return frameCountOut;
}
mal_uint64 mal_src_read_deinterleaved__passthrough(mal_src* pSRC, mal_uint64 frameCount, void** ppSamplesOut, void* pUserData);
mal_uint64 mal_src_read_deinterleaved__passthrough(mal_src* pSRC, mal_uint64 frameCount, void** ppSamplesOut, void* pUserData);
mal_uint64 mal_src_read_deinterleaved__linear(mal_src* pSRC, mal_uint64 frameCount, void** ppSamplesOut, void* pUserData);
mal_uint64 mal_src_read_deinterleaved__linear(mal_src* pSRC, mal_uint64 frameCount, void** ppSamplesOut, void* pUserData);
...
@@ -28820,7 +28957,7 @@ MAL_INLINE mal_uint32 mal_pcm_rb_get_bpf(mal_pcm_rb* pRB)
...
@@ -28820,7 +28957,7 @@ MAL_INLINE mal_uint32 mal_pcm_rb_get_bpf(mal_pcm_rb* pRB)
return mal_get_bytes_per_frame(pRB->format, pRB->channels);
return mal_get_bytes_per_frame(pRB->format, pRB->channels);
}
}
mal_result mal_pcm_rb_init_ex(mal_format format, mal_uint32 channels,
size_t subbufferSizeInFrames, size_t subbufferCount, size_t
subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, mal_pcm_rb* pRB)
mal_result mal_pcm_rb_init_ex(mal_format format, mal_uint32 channels,
mal_uint32 subbufferSizeInFrames, mal_uint32 subbufferCount, mal_uint32
subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, mal_pcm_rb* pRB)
{
{
if (pRB == NULL) {
if (pRB == NULL) {
return MAL_INVALID_ARGS;
return MAL_INVALID_ARGS;
...
@@ -28844,7 +28981,7 @@ mal_result mal_pcm_rb_init_ex(mal_format format, mal_uint32 channels, size_t sub
...
@@ -28844,7 +28981,7 @@ mal_result mal_pcm_rb_init_ex(mal_format format, mal_uint32 channels, size_t sub
return MAL_SUCCESS;
return MAL_SUCCESS;
}
}
mal_result mal_pcm_rb_init(mal_format format, mal_uint32 channels,
size_t
bufferSizeInFrames, void* pOptionalPreallocatedBuffer, mal_pcm_rb* pRB)
mal_result mal_pcm_rb_init(mal_format format, mal_uint32 channels,
mal_uint32
bufferSizeInFrames, void* pOptionalPreallocatedBuffer, mal_pcm_rb* pRB)
{
{
return mal_pcm_rb_init_ex(format, channels, bufferSizeInFrames, 1, 0, pOptionalPreallocatedBuffer, pRB);
return mal_pcm_rb_init_ex(format, channels, bufferSizeInFrames, 1, 0, pOptionalPreallocatedBuffer, pRB);
}
}
...
@@ -28858,7 +28995,7 @@ void mal_pcm_rb_uninit(mal_pcm_rb* pRB)
...
@@ -28858,7 +28995,7 @@ void mal_pcm_rb_uninit(mal_pcm_rb* pRB)
mal_rb_uninit(&pRB->rb);
mal_rb_uninit(&pRB->rb);
}
}
mal_result mal_pcm_rb_acquire_read(mal_pcm_rb* pRB,
size_t
* pSizeInFrames, void** ppBufferOut)
mal_result mal_pcm_rb_acquire_read(mal_pcm_rb* pRB,
mal_uint32
* pSizeInFrames, void** ppBufferOut)
{
{
size_t sizeInBytes;
size_t sizeInBytes;
mal_result result;
mal_result result;
...
@@ -28878,7 +29015,7 @@ mal_result mal_pcm_rb_acquire_read(mal_pcm_rb* pRB, size_t* pSizeInFrames, void*
...
@@ -28878,7 +29015,7 @@ mal_result mal_pcm_rb_acquire_read(mal_pcm_rb* pRB, size_t* pSizeInFrames, void*
return MAL_SUCCESS;
return MAL_SUCCESS;
}
}
mal_result mal_pcm_rb_commit_read(mal_pcm_rb* pRB,
size_t
sizeInFrames, void* pBufferOut)
mal_result mal_pcm_rb_commit_read(mal_pcm_rb* pRB,
mal_uint32
sizeInFrames, void* pBufferOut)
{
{
if (pRB == NULL) {
if (pRB == NULL) {
return MAL_INVALID_ARGS;
return MAL_INVALID_ARGS;
...
@@ -28887,7 +29024,7 @@ mal_result mal_pcm_rb_commit_read(mal_pcm_rb* pRB, size_t sizeInFrames, void* pB
...
@@ -28887,7 +29024,7 @@ mal_result mal_pcm_rb_commit_read(mal_pcm_rb* pRB, size_t sizeInFrames, void* pB
return mal_rb_commit_read(&pRB->rb, sizeInFrames * mal_pcm_rb_get_bpf(pRB), pBufferOut);
return mal_rb_commit_read(&pRB->rb, sizeInFrames * mal_pcm_rb_get_bpf(pRB), pBufferOut);
}
}
mal_result mal_pcm_rb_acquire_write(mal_pcm_rb* pRB,
size_t
* pSizeInFrames, void** ppBufferOut)
mal_result mal_pcm_rb_acquire_write(mal_pcm_rb* pRB,
mal_uint32
* pSizeInFrames, void** ppBufferOut)
{
{
size_t sizeInBytes;
size_t sizeInBytes;
mal_result result;
mal_result result;
...
@@ -28907,7 +29044,7 @@ mal_result mal_pcm_rb_acquire_write(mal_pcm_rb* pRB, size_t* pSizeInFrames, void
...
@@ -28907,7 +29044,7 @@ mal_result mal_pcm_rb_acquire_write(mal_pcm_rb* pRB, size_t* pSizeInFrames, void
return MAL_SUCCESS;
return MAL_SUCCESS;
}
}
mal_result mal_pcm_rb_commit_write(mal_pcm_rb* pRB,
size_t
sizeInFrames, void* pBufferOut)
mal_result mal_pcm_rb_commit_write(mal_pcm_rb* pRB,
mal_uint32
sizeInFrames, void* pBufferOut)
{
{
if (pRB == NULL) {
if (pRB == NULL) {
return MAL_INVALID_ARGS;
return MAL_INVALID_ARGS;
...
@@ -28916,7 +29053,7 @@ mal_result mal_pcm_rb_commit_write(mal_pcm_rb* pRB, size_t sizeInFrames, void* p
...
@@ -28916,7 +29053,7 @@ mal_result mal_pcm_rb_commit_write(mal_pcm_rb* pRB, size_t sizeInFrames, void* p
return mal_rb_commit_write(&pRB->rb, sizeInFrames * mal_pcm_rb_get_bpf(pRB), pBufferOut);
return mal_rb_commit_write(&pRB->rb, sizeInFrames * mal_pcm_rb_get_bpf(pRB), pBufferOut);
}
}
mal_result mal_pcm_rb_seek_read(mal_pcm_rb* pRB,
size_t
offsetInFrames)
mal_result mal_pcm_rb_seek_read(mal_pcm_rb* pRB,
mal_uint32
offsetInFrames)
{
{
if (pRB == NULL) {
if (pRB == NULL) {
return MAL_INVALID_ARGS;
return MAL_INVALID_ARGS;
...
@@ -28925,7 +29062,7 @@ mal_result mal_pcm_rb_seek_read(mal_pcm_rb* pRB, size_t offsetInFrames)
...
@@ -28925,7 +29062,7 @@ mal_result mal_pcm_rb_seek_read(mal_pcm_rb* pRB, size_t offsetInFrames)
return mal_rb_seek_read(&pRB->rb, offsetInFrames * mal_pcm_rb_get_bpf(pRB));
return mal_rb_seek_read(&pRB->rb, offsetInFrames * mal_pcm_rb_get_bpf(pRB));
}
}
mal_result mal_pcm_rb_seek_write(mal_pcm_rb* pRB,
size_t
offsetInFrames)
mal_result mal_pcm_rb_seek_write(mal_pcm_rb* pRB,
mal_uint32
offsetInFrames)
{
{
if (pRB == NULL) {
if (pRB == NULL) {
return MAL_INVALID_ARGS;
return MAL_INVALID_ARGS;
...
@@ -28952,7 +29089,7 @@ size_t mal_pcm_rb_get_subbuffer_stride(mal_pcm_rb* pRB)
...
@@ -28952,7 +29089,7 @@ size_t mal_pcm_rb_get_subbuffer_stride(mal_pcm_rb* pRB)
return mal_rb_get_subbuffer_stride(&pRB->rb) / mal_pcm_rb_get_bpf(pRB);
return mal_rb_get_subbuffer_stride(&pRB->rb) / mal_pcm_rb_get_bpf(pRB);
}
}
size_t mal_pcm_rb_get_subbuffer_offset(mal_pcm_rb* pRB,
size_t
subbufferIndex)
size_t mal_pcm_rb_get_subbuffer_offset(mal_pcm_rb* pRB,
mal_uint32
subbufferIndex)
{
{
if (pRB == NULL) {
if (pRB == NULL) {
return 0;
return 0;
...
@@ -28961,7 +29098,7 @@ size_t mal_pcm_rb_get_subbuffer_offset(mal_pcm_rb* pRB, size_t subbufferIndex)
...
@@ -28961,7 +29098,7 @@ size_t mal_pcm_rb_get_subbuffer_offset(mal_pcm_rb* pRB, size_t subbufferIndex)
return mal_rb_get_subbuffer_offset(&pRB->rb, subbufferIndex) / mal_pcm_rb_get_bpf(pRB);
return mal_rb_get_subbuffer_offset(&pRB->rb, subbufferIndex) / mal_pcm_rb_get_bpf(pRB);
}
}
void* mal_pcm_rb_get_subbuffer_ptr(mal_pcm_rb* pRB,
size_t
subbufferIndex, void* pBuffer)
void* mal_pcm_rb_get_subbuffer_ptr(mal_pcm_rb* pRB,
mal_uint32
subbufferIndex, void* pBuffer)
{
{
if (pRB == NULL) {
if (pRB == NULL) {
return NULL;
return NULL;
tests/mal_duplex.c
View file @
5b4b7fa2
...
@@ -6,6 +6,12 @@
...
@@ -6,6 +6,12 @@
#define DR_WAV_IMPLEMENTATION
#define DR_WAV_IMPLEMENTATION
#include "../extras/dr_wav.h"
#include "../extras/dr_wav.h"
#ifdef __EMSCRIPTEN__
void
main_loop__em
()
{
}
#endif
void
log_callback
(
mal_context
*
pContext
,
mal_device
*
pDevice
,
mal_uint32
logLevel
,
const
char
*
message
)
void
log_callback
(
mal_context
*
pContext
,
mal_device
*
pDevice
,
mal_uint32
logLevel
,
const
char
*
message
)
{
{
(
void
)
pContext
;
(
void
)
pContext
;
...
@@ -25,17 +31,20 @@ void data_callback(mal_device* pDevice, void* pOutput, const void* pInput, mal_u
...
@@ -25,17 +31,20 @@ void data_callback(mal_device* pDevice, void* pOutput, const void* pInput, mal_u
/* In this test the format and channel count are the same for both input and output which means we can just memcpy(). */
/* In this test the format and channel count are the same for both input and output which means we can just memcpy(). */
mal_copy_memory
(
pOutput
,
pInput
,
frameCount
*
mal_get_bytes_per_frame
(
pDevice
->
capture
.
format
,
pDevice
->
capture
.
channels
));
mal_copy_memory
(
pOutput
,
pInput
,
frameCount
*
mal_get_bytes_per_frame
(
pDevice
->
capture
.
format
,
pDevice
->
capture
.
channels
));
#if 0
/* Also write to a wav file for debugging. */
/* Also write to a wav file for debugging. */
drwav* pWav = (drwav*)pDevice->pUserData;
drwav* pWav = (drwav*)pDevice->pUserData;
mal_assert(pWav != NULL);
mal_assert(pWav != NULL);
drwav_write_pcm_frames(pWav, frameCount, pInput);
drwav_write_pcm_frames(pWav, frameCount, pInput);
#endif
}
}
int
main
(
int
argc
,
char
**
argv
)
int
main
(
int
argc
,
char
**
argv
)
{
{
mal_result
result
;
mal_result
result
;
#if 0
drwav_data_format wavFormat;
drwav_data_format wavFormat;
wavFormat.container = drwav_container_riff;
wavFormat.container = drwav_container_riff;
wavFormat.format = DR_WAVE_FORMAT_PCM;
wavFormat.format = DR_WAVE_FORMAT_PCM;
...
@@ -48,9 +57,10 @@ int main(int argc, char** argv)
...
@@ -48,9 +57,10 @@ int main(int argc, char** argv)
printf("Failed to initialize output file.\n");
printf("Failed to initialize output file.\n");
return -1;
return -1;
}
}
#endif
mal_backend
backend
=
mal_backend_
dsound
;
mal_backend
backend
=
mal_backend_
webaudio
;
mal_context_config
contextConfig
=
mal_context_config_init
();
mal_context_config
contextConfig
=
mal_context_config_init
();
contextConfig
.
logCallback
=
log_callback
;
contextConfig
.
logCallback
=
log_callback
;
...
@@ -74,7 +84,7 @@ int main(int argc, char** argv)
...
@@ -74,7 +84,7 @@ int main(int argc, char** argv)
deviceConfig
.
periods
=
2
;
deviceConfig
.
periods
=
2
;
deviceConfig
.
dataCallback
=
data_callback
;
deviceConfig
.
dataCallback
=
data_callback
;
deviceConfig
.
stopCallback
=
stop_callback
;
deviceConfig
.
stopCallback
=
stop_callback
;
deviceConfig
.
pUserData
=
&
wav
;
deviceConfig
.
pUserData
=
NULL
;
/*&wav;*/
mal_device
device
;
mal_device
device
;
result
=
mal_device_init
(
&
context
,
&
deviceConfig
,
&
device
);
result
=
mal_device_init
(
&
context
,
&
deviceConfig
,
&
device
);
...
@@ -82,13 +92,21 @@ int main(int argc, char** argv)
...
@@ -82,13 +92,21 @@ int main(int argc, char** argv)
return
result
;
return
result
;
}
}
#ifdef __EMSCRIPTEN__
getchar
();
#endif
mal_device_start
(
&
device
);
mal_device_start
(
&
device
);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop
(
main_loop__em
,
0
,
1
);
#else
printf
(
"Press Enter to quit...
\n
"
);
printf
(
"Press Enter to quit...
\n
"
);
getchar
();
getchar
();
#endif
mal_device_uninit
(
&
device
);
mal_device_uninit
(
&
device
);
drwav_uninit
(
&
wav
);
/*drwav_uninit(&wav);*/
(
void
)
argc
;
(
void
)
argc
;
(
void
)
argv
;
(
void
)
argv
;
...
...
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