Streaming seems to load full file into memory #436
Replies: 5 comments 3 replies
-
Your sample code looks fine on the surface. Are you able to run the program below and let see if you get the same results? Pass in the file path via the command line. May need to adjust the location of the miniaudio.h include based on your setup. Could you also let me know what the #define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
ma_data_source_read_pcm_frames((ma_data_source*)pDevice->pUserData, pOutput, frameCount, NULL);
(void)pInput;
}
int main(int argc, char** argv)
{
ma_result result;
ma_device_config deviceConfig;
ma_device device;
ma_resource_manager_config resourceManagerConfig;
ma_resource_manager resourceManager;
ma_resource_manager_data_source dataSource;
if (argc < 2) {
printf("No input file.");
return -1;
}
/* We'll initialize the device first. */
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = &dataSource; /* <-- We'll be reading from this in the data callback. */
result = ma_device_init(NULL, &deviceConfig, &device);
if (result != MA_SUCCESS) {
printf("Failed to initialize device.");
return -1;
}
/*
We have the device so now we want to initialize the resource manager. We'll use the resource manager to load a
sound based on the command line.
*/
resourceManagerConfig = ma_resource_manager_config_init();
resourceManagerConfig.decodedFormat = device.playback.format;
resourceManagerConfig.decodedChannels = device.playback.channels;
resourceManagerConfig.decodedSampleRate = device.sampleRate;
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
if (result != MA_SUCCESS) {
ma_device_uninit(&device);
printf("Failed to initialize the resource manager.");
return -1;
}
/* Now that we have a resource manager we can load a sound. */
result = ma_resource_manager_data_source_init(&resourceManager, argv[1], MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM, NULL, &dataSource);
if (result != MA_SUCCESS) {
printf("Failed to load sound \"%s\".", argv[1]);
return -1;
}
/* Now that we have a sound we can start the device. */
result = ma_device_start(&device);
if (result != MA_SUCCESS) {
ma_device_uninit(&device);
printf("Failed to start device.");
return -1;
}
printf("Press Enter to quit...\n");
getchar();
/* Teardown. */
/* Uninitialize the device first to ensure the data callback is stopped and doesn't try to access any data. */
ma_device_uninit(&device);
/*
Before uninitializing the resource manager we need to uninitialize every data source. The data source is owned by
the caller which means you're responsible for uninitializing it.
*/
ma_resource_manager_data_source_uninit(&dataSource);
/* Uninitialize the resource manager after each data source. */
ma_resource_manager_uninit(&resourceManager);
return 0;
} |
Beta Was this translation helpful? Give feedback.
-
I swapped from using Qt creator's build system (qmake) to using a Makefile with g++, and everything seems to work fine now (when removing the drive, the sounds stop playing after a while, indicating it doesn't buffer everything. Thanks for the help! Regarding buffered memory, I misinterpreted the results, so please ignore the comments I made about it above. My data source flags are left default, as is done in the example you provided, printing them out gives 3 so I assume the flags
have been set (setting async doesn't change the results). |
Beta Was this translation helpful? Give feedback.
-
@mackron sorry to bother you again. Is it possible that decoded files are always buffered fully somewhere in memory? When I remove an USB drive containing the mp3 file playing, it continues playing the whole song, and it seems to take a while to decode as well. When I do the same thing using a .wav, the file stops playing after a few seconds. I am still using all the settings mentioned above and I've also tested this using the sample code you provided. Also where decoded data is written to or is it just put on heap? |
Beta Was this translation helpful? Give feedback.
-
No, that's not possible when loading a stream. When the if ((pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
return ma_resource_manager_data_stream_init_ex(pResourceManager, pConfig, &pDataSource->backend.stream);
} else {
return ma_resource_manager_data_buffer_init_ex(pResourceManager, pConfig, &pDataSource->backend.buffer);
} The only time the whole sound would be loaded into memory is if it happens to be shorter than two seconds (each page is 1 second, and there's 2 pages). It's unlikely this is the case for you. I've just tested with that sample program I posted above and it's certainly not fully loading it into memory: (That screenshot is from loading a ~3 minute long song) Make double sure you're specifying the When a stream is loaded, two pages are allocated on the heap, each being 1 second long: pageBufferSizeInBytes = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream) * 2 * ma_get_bytes_per_frame(pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels);
pDataStream->pPageData = ma_malloc(pageBufferSizeInBytes, &pResourceManager->config.allocationCallbacks); That's the only buffer being allocated for streams for the purpose of audio playback. It's impossible for the sound to be fully loaded into memory if it's being loaded as a stream. This would have been reported a long, long time ago if that was the case because that's the whole point of a stream. If that's happening it means your code is triggering it somewhere. |
Beta Was this translation helpful? Give feedback.
-
I think as you say most likely it's just the operating system doing some kind of buffering of the file. Maybe it knows you're reading from removable storage so it's being safe by moving it into cache or something, I don't know. |
Beta Was this translation helpful? Give feedback.
-
I have no doubt that I am doing something wrong, but please help me out here. Thanks in advance.
I am trying to play rather large music files so I'm swapping from using a regular decoder to using a resource manager using streaming instead.
When I use the top command in Linux terminal I seem to get very similar memory buffered for the miniaudio PID regardless of whether I use streaming or not. More concretely when I play a long file from a USB drive and remove it mid way, streaming should stop right? (which it doesn't) As it can't continue paging.
I initialize the resource manager data source like this:
And use the following callback for the device (playback type):
And the resource manager like this:
Beta Was this translation helpful? Give feedback.
All reactions