-
-
Notifications
You must be signed in to change notification settings - Fork 487
Open
Description
First of all, thank you very much for providing such an excellent library.
My use case involves retrieving MP3 data from a WebSocket and then putting it into a queue (m_down_audio_queue).
My code is as follows
queue_t m_down_audio_queue;
ma_device m_ma_device;
ma_decoder m_ma_decoder;
uint32_t m_decoder_read_end_count = 0;
uint32_t m_pcm_read_end_count = 0;
bool m_pcm_empty = true;
ma_result DialogSystem::on_ma_decoder_read_proc(ma_decoder *pDecoder, void *pBufferOut, size_t bytesToRead,
size_t *pBytesRead)
{
DialogSystem *self = (DialogSystem *)pDecoder->pUserData;
// 0: get data directly without waiting
int ret = queue_get_data_with_timeout(&self->m_down_audio_queue, (uint8_t *)pBufferOut, bytesToRead, 0);
if (ret == -1)
{
USER_LOG_BASIC_WARN("decoder read failed. ret: {}, size: {}", ret,
queue_get_current_size(self->m_down_audio_queue));
*pBytesRead = 0;
return MA_AT_END;
}
if (ret == 0)
{
self->m_decoder_read_end_count++;
*pBytesRead = 0;
return MA_SUCCESS;
}
self->m_decoder_read_end_count = 0;
*pBytesRead = ret;
return MA_SUCCESS;
}
ma_result DialogSystem::on_ma_decoder_seek_proc(ma_decoder *pDecoder, ma_int64 byteOffset, ma_seek_origin origin)
{
// TODO: is it feasible to directly return MA_SUCCESS?
return MA_SUCCESS;
}
void DialogSystem::on_ma_device_data_proc(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount)
{
DialogSystem *self = (DialogSystem *)pDevice->pUserData;
ma_uint64 frames_read = 0;
ma_result ret = ma_decoder_read_pcm_frames(&self->m_ma_decoder, pOutput, frameCount, &frames_read);
if (ret == MA_AT_END)
{
self->m_pcm_read_end_count++;
self->m_pcm_empty = true;
}
else
{
self->m_pcm_read_end_count = 0;
self->m_pcm_empty = false;
}
}
void DialogSystem::play_audio_thread(void)
{
bool initialized = false;
uint8_t wait_count = 0;
while (true)
{
if (initialized)
{
uint32_t queue_current_size = queue_get_current_size(m_down_audio_queue);
if ((m_pcm_empty) && (queue_current_size != 0))
{
USER_LOG_BASIC_WARN("pcm empty is true, but down audio queue is not empty. queue size: {}, "
"decoder read end count: {}, pcm read end count: {}",
queue_current_size, m_decoder_read_end_count, m_pcm_read_end_count);
}
bool need_uninit = false;
if ((queue_current_size == 0) && (m_pcm_empty))
{
if (wait_count++ >= 5)
{
need_uninit = true;
}
}
if (need_uninit)
{
ma_device_uninit(&m_ma_device);
ma_decoder_uninit(&m_ma_decoder);
queue_clear(&m_down_audio_queue);
initialized = false;
USER_LOG_BASIC_INFO("uninit decoder and device success");
}
else
{
wait_count = 0;
}
}
else
{
if (queue_get_current_size(m_down_audio_queue) < 2048)
{
usleep(10 * 1000);
continue;
}
m_decoder_read_end_count = 0;
m_pcm_read_end_count = 0;
m_pcm_empty = false;
ma_decoder_config decoder_config = ma_decoder_config_init(ma_format_s16, 1, 16000);
ma_result ret = ma_decoder_init(&DialogSystem::on_ma_decoder_read_proc,
&DialogSystem::on_ma_decoder_seek_proc, this, &decoder_config,
&m_ma_decoder);
if (ret != MA_SUCCESS)
{
USER_LOG_BASIC_WARN("init decoder failed, will retry. ret: {}", (int)ret);
usleep(10 * 1000);
continue;
}
USER_LOG_BASIC_INFO("init decoder success");
ma_device_config device_config = ma_device_config_init(ma_device_type_playback);
device_config.playback.format = ma_format_s16;
device_config.playback.channels = 1;
device_config.sampleRate = 16000;
device_config.dataCallback = &DialogSystem::on_ma_device_data_proc;
device_config.pUserData = this;
ret = ma_device_init(NULL, &device_config, &m_ma_device);
if (ret != MA_SUCCESS)
{
USER_LOG_BASIC_WARN("init playback device failed, will retry. ret: {}", (int)ret);
ma_decoder_uninit(&m_ma_decoder);
usleep(10 * 1000);
continue;
}
ret = ma_device_start(&m_ma_device);
if (ret != MA_SUCCESS)
{
USER_LOG_BASIC_WARN("start playback device failed, will retry. ret: {}", (int)ret);
ma_device_uninit(&m_ma_device);
ma_decoder_uninit(&m_ma_decoder);
usleep(10 * 1000);
continue;
}
initialized = true;
USER_LOG_BASIC_INFO("init playback device success");
}
usleep(100 * 1000);
}
}I've noticed that sometimes the onRead callback function on_ma_decoder_read_proc() of ma_decoder_init() is not called.
I discovered the issue was caused by pMP3->atEnd=MA_TRUE in the ma_dr_mp3_decode_next_frame_ex__callbacks() function.
static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData)
{
ma_uint32 pcmFramesRead = 0;
MA_DR_MP3_ASSERT(pMP3 != NULL);
MA_DR_MP3_ASSERT(pMP3->onRead != NULL);
if (pMP3->atEnd) {
return 0;
}
for (;;) {
ma_dr_mp3dec_frame_info info;
if (pMP3->dataSize < MA_DR_MP3_MIN_DATA_CHUNK_SIZE) {
size_t bytesRead;
if (pMP3->pData != NULL) {
MA_DR_MP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
}
pMP3->dataConsumed = 0;
if (pMP3->dataCapacity < MA_DR_MP3_DATA_CHUNK_SIZE) {
ma_uint8* pNewData;
size_t newDataCap;
newDataCap = MA_DR_MP3_DATA_CHUNK_SIZE;
pNewData = (ma_uint8*)ma_dr_mp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
if (pNewData == NULL) {
return 0;
}
pMP3->pData = pNewData;
pMP3->dataCapacity = newDataCap;
}
bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
if (bytesRead == 0) {
if (pMP3->dataSize == 0) {
// TODO: Here, atEnd=MA_TRUE is set.
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx atEnd will is true\n");
pMP3->atEnd = MA_TRUE;
return 0;
}
}
pMP3->dataSize += bytesRead;
}
...
};
return pcmFramesRead;
}Some logs
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx atEnd will is true
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx atEnd is true
[2025-12-01 09:48:14.479] [W] [dialog_system.cpp:507] pcm empty is true, but down audio queue is not empty. queue size: 576, decoder read end count: 29, pcm read end count: 13My questions:
- Is there a problem with the
on_ma_decoder_seek_proc()function always returningMA_SUCCESSeven though it doesn't perform any operation? - Is it because the WebSocket data is too slow, and there isn't enough data in the queue (
m_down_audio_queue), causingma_dr_mp3_decode_next_frame_ex__callbacksto think there's no data and then setatEndtoMA_TRUE?
Metadata
Metadata
Assignees
Labels
No labels