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
3bcdf394
Commit
3bcdf394
authored
Jul 22, 2020
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a resource manager example.
parent
681d26a5
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
184 additions
and
0 deletions
+184
-0
research/_examples/resource_manager.c
research/_examples/resource_manager.c
+184
-0
No files found.
research/_examples/resource_manager.c
0 → 100644
View file @
3bcdf394
/*
Demonstrates how you can use the resource manager to manage loaded sounds.
The resource manager can be used to create a data source whose resources are managed internally by miniaudio. The data
sources can then be read just like any other data source such as decoders and audio buffers.
In this example we use the resource manager independently of the `ma_engine` API so that we can demonstrate how it can
be used by itself without getting it confused with `ma_engine`. Audio data is mixed using the `ma_mixer` API, but you
can also use data sources with `ma_data_source_read_pcm_frames()` in the same way we do in the simple_looping example.
The main feature of the resource manager is the ability to decode and stream audio data asynchronously. Asynchronicity
is achieved with a job system. The resource manager will issue jobs which are processed by a configurable number of job
threads. You can also implement your own custom job threads which this example also demonstrates.
In this example we show how you can create a data source, mix them with other data sources, configure the number of job
threads to manage internally and how to implement your own custom job thread.
*/
#define MA_NO_ENGINE
/* We're intentionally not using the ma_engine API here. */
#define MA_IMPLEMENTATION
#include "../../miniaudio.h"
#include "../ma_engine.h"
static
ma_mixer
g_mixer
;
static
ma_resource_manager_data_source
g_dataSources
[
16
];
static
ma_uint32
g_dataSourceCount
;
void
data_callback
(
ma_device
*
pDevice
,
void
*
pOutput
,
const
void
*
pInput
,
ma_uint32
frameCount
)
{
/* In this example we're just going to play our data sources layered on top of each other. */
ma_uint32
framesProcessed
=
0
;
while
(
framesProcessed
<
frameCount
)
{
ma_uint64
frameCountIn
;
ma_uint64
frameCountOut
=
(
frameCount
-
framesProcessed
);
ma_mixer_begin
(
&
g_mixer
,
NULL
,
&
frameCountOut
,
&
frameCountIn
);
{
size_t
iDataSource
;
for
(
iDataSource
=
0
;
iDataSource
<
g_dataSourceCount
;
iDataSource
+=
1
)
{
ma_mixer_mix_data_source
(
&
g_mixer
,
&
g_dataSources
[
iDataSource
],
frameCountIn
,
1
,
NULL
,
MA_TRUE
);
}
}
ma_mixer_end
(
&
g_mixer
,
NULL
,
ma_offset_ptr
(
pOutput
,
framesProcessed
*
ma_get_bytes_per_frame
(
pDevice
->
playback
.
format
,
pDevice
->
playback
.
channels
)));
framesProcessed
+=
(
ma_uint32
)
frameCountOut
;
/* Safe cast. */
}
(
void
)
pInput
;
}
static
ma_thread_result
MA_THREADCALL
custom_job_thread
(
void
*
pUserData
)
{
ma_resource_manager
*
pResourceManager
=
(
ma_resource_manager
*
)
pUserData
;
MA_ASSERT
(
pResourceManager
!=
NULL
);
for
(;;)
{
ma_result
result
;
ma_job
job
;
result
=
ma_resource_manager_next_job
(
pResourceManager
,
&
job
);
if
(
result
!=
MA_SUCCESS
)
{
break
;
}
/* Terminate if we got a quit message. */
if
(
job
.
toc
.
code
==
MA_JOB_QUIT
)
{
printf
(
"CUSTOM JOB THREAD TERMINATING... "
);
break
;
}
printf
(
"PROCESSING IN CUSTOM JOB THREAD: %d
\n
"
,
job
.
toc
.
code
);
ma_resource_manager_process_job
(
pResourceManager
,
&
job
);
}
printf
(
"TERMINATED
\n
"
);
return
(
ma_thread_result
)
0
;
}
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_mixer_config
mixerConfig
;
ma_thread
jobThread
;
int
iFile
;
deviceConfig
=
ma_device_config_init
(
ma_device_type_playback
);
deviceConfig
.
dataCallback
=
data_callback
;
deviceConfig
.
pUserData
=
NULL
;
result
=
ma_device_init
(
NULL
,
&
deviceConfig
,
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to initialize device."
);
return
-
1
;
}
/*
Before starting the device we'll need to initialize the mixer. If we don't do this first, the data callback will be
fired and will try to use the mixer without it being initialized.
*/
mixerConfig
=
ma_mixer_config_init
(
device
.
playback
.
format
,
device
.
playback
.
channels
,
1024
,
NULL
,
NULL
);
result
=
ma_mixer_init
(
&
mixerConfig
,
&
g_mixer
);
if
(
result
!=
MA_SUCCESS
)
{
ma_device_uninit
(
&
device
);
printf
(
"Failed to initialize mixer."
);
return
-
1
;
}
/* We can start the device before loading any sounds. We'll just end up outputting silence. */
result
=
ma_device_start
(
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
ma_device_uninit
(
&
device
);
printf
(
"Failed to start device."
);
return
-
1
;
}
/*
We have the device so now we want to initialize the resource manager. We'll use the resource manager to load some
sounds based on the command line.
*/
resourceManagerConfig
=
ma_resource_manager_config_init
(
device
.
playback
.
format
,
device
.
playback
.
channels
,
device
.
sampleRate
,
NULL
);
/* Create this number of job threads to be managed internally. Set this to 0 if you want to self-manage your job threads */
resourceManagerConfig
.
jobThreadCount
=
4
;
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 set up our custom job thread. */
ma_thread_create
(
&
jobThread
,
ma_thread_priority_default
,
0
,
custom_job_thread
,
&
resourceManager
);
/* Create each data source from the resource manager. Note that the caller is the owner. */
for
(
iFile
=
0
;
iFile
<
ma_countof
(
g_dataSources
)
&&
iFile
<
argc
-
1
;
iFile
+=
1
)
{
result
=
ma_resource_manager_data_source_init
(
&
resourceManager
,
argv
[
iFile
+
1
],
MA_DATA_SOURCE_FLAG_DECODE
|
MA_DATA_SOURCE_FLAG_ASYNC
/*| MA_DATA_SOURCE_FLAG_STREAM*/
,
&
g_dataSources
[
iFile
]);
if
(
result
!=
MA_SUCCESS
)
{
break
;
}
g_dataSourceCount
+=
1
;
}
printf
(
"Press Enter to quit..."
);
getchar
();
/* Teardown. */
/* Uninitialize the device first to ensure the data callback is stopped and doesn't try to access any data sources. */
ma_device_uninit
(
&
device
);
/*
Before uninitializing the resource manager we need to make sure a quit event has been posted to ensure we can get out of our custom thread. The
call to ma_resource_manager_uninit() will also do this, but we need to call it explicitly so that our thread can exit naturally. You only need
to post a quit job if you're using that as the exit indicator. You can instead use whatever variable you want to terminate your job thread, but
since this example is using a quit job we need to post one.
*/
ma_resource_manager_post_job_quit
(
&
resourceManager
);
ma_thread_wait
(
&
jobThread
);
/* Wait for the custom job thread to finish before uninitializing the resource manager. */
/* Out data sources need to be explicitly uninitialized. ma_resource_manager_uninit() will not do it for us. */
for
(
iFile
=
0
;
(
size_t
)
iFile
<
g_dataSourceCount
;
iFile
+=
1
)
{
ma_resource_manager_data_source_uninit
(
&
resourceManager
,
&
g_dataSources
[
iFile
]);
}
/* Uninitialize the resource manager after each data source. */
ma_resource_manager_uninit
(
&
resourceManager
);
/* We're uninitializing the mixer last, but it doesn't really when it's done, so long as it's after the device has been stopped/uninitialized. */
ma_mixer_uninit
(
&
g_mixer
);
return
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