11
edits
| Line 264: | Line 264: | ||
return NULL; | return NULL; | ||
} | } | ||
</pre> | |||
=====Switching to Low Power (Silence)===== | |||
Callback Mode: While an application is performing audio output, it will receive callbacks at a regular interval. If an application needs to enter a state where audio output isn't required, it may wish to suppress the callback to save power and/or CPU cycles. The application can suppress the audio callback in two ways: 1) It can shutdown the audio context, and at a later time, when the application needs to resume audio output, it can re-initialize a new audio context. This approach may have long latency. 2) If setStateContext(npp, NPAudioContextStateCallback, NPAudioCallbackStop) is invoked on the NPAPI thread, callbacks will be suspended and the implicit audio thread will go into a sleep state. To resume audio playback and callbacks, the NPAPI thread should invoke setStateContext(npp,NPAudioContextStateCallback, NPAudioCallbackStop), which will resume callbacks in a low latency time frame. | |||
Push Mode: In the blocking push model, flushContext() will block (sleep) until the audio context is ready to consume another chunk of sample data. If the audio thread does not call flushContext() within a short period of time (the duration of which depends on the sample frame count and sample frequency), the audio context will automatically emit silience. Normally, an audio thread will continuously make calls to the blocking flushContext() call to emit long continuous periods of audio output. If the application enters a state where no audio output is needed for an extended duration and it wishes to reduce CPU load, the application has one of two options. 1) Shutdown the audio context and exit the audio thread. When audio playback needs to resume, it can re-spawn the audio thread and re-initialize an audio context. This approach may have a long latency. 2) The application can sleep the audio thread during long periods of silence by waiting on a pthread cond_var. When the main thread is ready to resume audio playback, it can signal the condition variable to wake up the sleeping audio thread. This approach is expected to resume audio output in a low latency time frame. | |||
=====Basic API===== | |||
The basic Pepper API consists of: queryCapability, queryConfig, initializeContext, setStateContext, getStateContext, flushContext, and destroyContext. | |||
<pre> | |||
/* min & max sample frame count */ | |||
static const int32 NPAudioMinSampleFrameCount = 64; | |||
static const int32 NPAudioMaxSampleFrameCount = 32768; | |||
/* supported sample rates */ | |||
static const int32 NPAudioSampleRate44100Hz = 44100; | |||
static const int32 NPAudioSampleRate48000Hz = 48000; | |||
static const int32 NPAudioSampleRate96000Hz = 96000; | |||
/* supported sample formats */ | |||
static const int32 NPAudioSampleTypeInt16 = 0; | |||
static const int32 NPAudioSampleTypeFloat32 = 1; | |||
/* supported channel layouts */ | |||
static const int32 NPAudioChannelNone = 0; | |||
static const int32 NPAudioChannelMono = 1; | |||
static const int32 NPAudioChannelStereo = 2; | |||
static const int32 NPAudioChannelThree = 3; | |||
static const int32 NPAudioChannelFour = 4; | |||
static const int32 NPAudioChannelFive = 5; | |||
static const int32 NPAudioChannelFiveOne = 6; | |||
static const int32 NPAudioChannelSeven = 7; | |||
static const int32 NPAudioChannelSevenOne = 8; | |||
/* audio context states */ | |||
static const int32 NPAudioContextStateCallback = 0; | |||
static const int32 NPAudioContextStateUnderrunCounter = 1; | |||
/* audio context state values */ | |||
static const int32 NPAudioCallbackStop = 0; | |||
static const int32 NPAudioCallbackStart = 1; | |||
/* audio query capabilities */ | |||
static const int32 NPAudioCapabilitySampleRate = 0; | |||
static const int32 NPAudioCapabilitySampleType = 1; | |||
static const int32 NPAudioCapabilitySampleFrameCount = 2; | |||
static const int32 NPAudioCapabilitySampleFrameCount44100Hz = 3; | |||
static const int32 NPAudioCapabilitySampleFrameCount48000Hz = 4; | |||
static const int32 NPAudioCapabilitySampleFrameCount96000Hz = 5; | |||
static const int32 NPAudioCapabilityOutputChannelMap = 6; | |||
static const int32 NPAudioCapabilityInputChannelMap = 7; | |||
/* forward decls */ | |||
typedef struct NPAudioContext NPAudioContext; | |||
typedef struct NPAudioConfig NPAudioConfig; | |||
/* user supplied callback function */ | |||
typedef void (*NPAudioCallback)(const NPAudioContext *context); | |||
/* Audio config structure */ | |||
struct NPAudioConfig { | |||
int32 sampleRate; | |||
int32 sampleType; | |||
int32 outputChannelMap; | |||
int32 inputChannelMap; | |||
int32 sampleFrameCount; | |||
uint32 flags; | |||
NPAudioCallback callback; | |||
void *userData; | |||
}; | |||
/* Audio context structure */ | |||
struct NPAudioContext { | |||
NPP npp; | |||
NPAudioConfig config; | |||
void *outBuffer; | |||
void *inBuffer; | |||
void *private; | |||
}; | |||
</pre> | |||
'''NPError queryCapability(NPP npp, int32 query, int32 *value)''' | |||
<pre> | |||
inputs: | |||
NPP npp | |||
Plug-in instance npp | |||
NPDeviceCapability query | |||
NPAudioCapabilitySampleRate | |||
NPAudioCapabilitySampleType | |||
NPAudioCapabilitySampleFrameCount | |||
NPAudioCapabilitySampleFrameCount44100Hz | |||
NPAudioCapabilitySampleFrameCount48000Hz | |||
NPAudioCapabilitySampleFrameCount96000Hz | |||
NPAudioCapabilityOutputChannelMap | |||
NPAudioCapabilityInputChannelMap | |||
outputs: | |||
*value | |||
Value based on input query. See section "NPAudioCapability | |||
Details" for input & output values. | |||
returns: | |||
NPERR_NO_ERROR | |||
NPERR_INVALID_PARAM | |||
</pre> | |||
'''NPError queryConfig(NPP npp, NPAudioConfig *request, NPAudioConfig *obtain)''' | |||
<pre> | |||
inputs: | |||
NPP npp | |||
Plug-in instance npp | |||
NPAudioConfig *request | |||
A requested configuration, which is a set of capabilities | |||
outputs: | |||
NPAudioConfig *obtain | |||
The set of capabilities obtained, which may or may not match | |||
request input. | |||
returns: | |||
NPERR_NO_ERROR | |||
NPERR_INVALID_PARAM | |||
notes: | |||
Okay if request & obtain pointers are the same. | |||
</pre> | |||
'''NPError initializeContext(NPP npp, const NPAudioConfig *config, | |||
NPAudioContext *context)''' | |||
<pre> | |||
inputs: | |||
NPP npp | |||
Plug-in instance npp | |||
NPAudioConfig *config - a structure with which to configure the | |||
audio device | |||
int32 sampleRate | |||
Both NPAudioSampleRate44100Hz and | |||
NPAudioSampleRate48000Hz will always be supported. | |||
int32 sampleType | |||
Size and format of audio sample. | |||
NPAudioSampleTypeInt16 will always be supported. | |||
int32 outputChannelMap | |||
Describes output channel mapping. | |||
NPAudioChannelStereo will always be supported, regardless | |||
of the physical speaker configuration. | |||
NPAudioChannelNone describes no output will occur and | |||
out_buffer on the callback will be NULL. | |||
int32 inputChannelMap | |||
Describes input channel layout. | |||
NPAudioChannelNone describes no input will occur and | |||
inBuffer on the callback will be NULL. | |||
int32 sampleFrameCount | |||
Requested sample frame count ranging from | |||
NPAudioMinSampleFrameCount..NPAudioMaxSampleFrameCount. | |||
The sample frame count will determine sample buffer size | |||
and overall latency. Count value is in sample frames, | |||
which are independent of the number of audio channels -- | |||
a single sample frame on a stereo device means one value | |||
for the left channel and one value for the right channel. | |||
int32 flags: | |||
Reserved, set to 0. | |||
callback | |||
Pointer to application supplied callback function. | |||
NULL: Audio context is initialized in blocking push | |||
mode. | |||
!NULL: Audio context is initialized in callback | |||
mode. | |||
void *userData | |||
pointer to user data for callback. Can be NULL. | |||
outputs: | |||
NPAudioContext *context | |||
Filled in, used to identify audio context. | |||
returns: | |||
NPERR_NO_ERROR | |||
NPERR_INVALID_PARAM | |||
notes: | |||
Callable only from the NPAPI thread. | |||
An application is free to always select either 44.1kHz or 48kHz. | |||
In callback mode: | |||
Audio context is initialized in the stopped state. Use | |||
setStateContext(npp, NPAudioContextStateCallback, | |||
NPAudioCallbackStart) to begin callbacks. Repeated callbacks | |||
will occur until either setStateContext(npp, | |||
NPAudioContextStateCallback, NPAudioCallbackStop) or | |||
destroyContext(npp, context) is issued on the NPAPI thread. | |||
In blocking push mode: | |||
From a thread dedicated to audio, use flushContext(npp, | |||
context) to push the contents of context->outBuffer and | |||
context->inBuffer to and from the audio device. | |||
</pre> | |||
'''NPError setStateContext(NPP npp, NPAudioContext *context, int32 state, int32 value)''' | |||
<pre> | |||
inputs: | |||
NPP npp | |||
Plug-in instance npp | |||
NPAudioContext *context | |||
audio context to apply state | |||
int32 state | |||
NPAudioContextStateCallback | |||
Start & Stop playback when in callback mode. Audio | |||
device will emit silence and callbacks will be suspended. | |||
int32 value | |||
returns: | |||
NPERR_NO_ERROR | |||
NPERR_INVALID_PARAM | |||
NPERR_GENERIC_ERROR | |||
notes: | |||
Callable only from the NPAPI thread. | |||
Use setStateContext(npp, context, NPAudioContextStateCallback, | |||
NPAudioCallbackStart) to resume stopped playback. | |||
When stopping, after a successful return value, no callbacks should | |||
occur. If a pending callback is taking too long, this function | |||
will fail with a return value of NPERR_GENERIC_ERROR. | |||
After initialization in callback mode, an audio context will be in | |||
the NPAudioCallbackStop state. | |||
</pre> | |||
'''NPError getStateContext(NPP npp, NPAudioContext *context, int32 state, int32 *value)''' | |||
<pre> | |||
inputs: | |||
NPP npp | |||
Plug-in instance npp | |||
NPAudioContext *context | |||
audio context to apply state | |||
int32 state | |||
new state value | |||
NPAudioContextStateCallback | |||
Get current state of callback. | |||
NPAudioContextStateUnderrunCounter | |||
Get current detectable underrun count since | |||
initialization. | |||
output: | |||
int32 *value | |||
returns: | |||
NPERR_NO_ERROR | |||
NPERR_INVALID_PARAM | |||
notes: | |||
Callable only from the NPAPI thread. | |||
</pre> | |||
'''NPError flushContext(NPP npp, NPAudioContext *context)''' | |||
<pre> | |||
inputs: | |||
NPP npp | |||
For audio, this function is invoked from a non-NPAPI thread, | |||
so npp is ignored. | |||
NPAudioContext *context | |||
context->outBuffer | |||
pointer to output data. If this field is NULL, no output | |||
(or silence) will occur. | |||
context->inBuffer | |||
pointer to input data. If this field is NULL, no input | |||
will occur. | |||
returns: | |||
NPERR_NO_ERROR | |||
NPERR_INVALID_PARAM | |||
NPERR_GENERIC_ERROR | |||
notes: | |||
This is a blocking call. Data in context->outBuffer is streamed to | |||
the audio device. The call then blocks until the audio device is | |||
ready to receive the next buffer payload. If the audio device does | |||
not receive data within a certain time frame, it will begin to emit | |||
silence. For an application to emit continuous audio without gaps | |||
of silence, it will need to perform a minimal amount of computation | |||
between consecutive flushDevice() calls on a priority boosted | |||
dedicated audio thread. If the audio device is initialized with | |||
both input channel(s) and output channel(s), audio can stream | |||
isochronously on the same flushContext() call. | |||
In the case of audio, it is highly recommend not to make this call | |||
from the NPAPI thread. | |||
If the audio device was initialized in callback mode, | |||
flushContext() will do nothing and return NPERR_GENERIC_ERROR | |||
If the audio device is in blocking push mode and | |||
destroyContext(npp, context) is performed in the NPAPI thread, | |||
pending blocking flushContext calls will return with | |||
NPERR_GENERIC_ERROR. | |||
</pre> | |||
'''NPError destroyContext(NPP npp, NPAudioContext *context)''' | |||
<pre> | |||
inputs: | |||
NPP npp | |||
Plug-in instance npp | |||
NPAudioContext context | |||
audio context to shutdown | |||
returns: | |||
NPERR_NO_ERROR | |||
NPERR_INVALID_PARAM | |||
notes: | |||
callback mode: | |||
Waits for pending callback (if applicable) to complete (or | |||
times out) Upon return from shutdown, no further callbacks | |||
will occur. | |||
blocking push mode: | |||
Does _not_ automatically terminate pending blocking | |||
flushContext() calls occuring other threads. It is highly | |||
recommended that other threads suspend calls to flushContext() | |||
_before_ invoking destroyContext(npp, context). | |||
other: | |||
Callable only from the NPAPI thread. Application's | |||
responsibility to cleanly bring down audio before Shutdown to | |||
avoid clicks / pops. | |||
</pre> | |||
'''void (NPAudioCallback *)(NPAudioContext *context);''' | |||
<pre> | |||
inputs: | |||
NPAudioContext context | |||
Audio context that generated this callback. Fields within the | |||
context | |||
context->config.sampleFrameCount | |||
Number of sample frames to write into buffers. This will | |||
always be the obtained sample frame count returned at | |||
initialization. An application should never write more | |||
than sample_frame_count sample frames. An application | |||
should avoid writing fewer than sample_frame_count sample | |||
frames. Sample frame count is independent of the number | |||
of channels. A sample frame count of 1 on a stereo | |||
device means write one left channel sample, and one right | |||
channel sample. | |||
context->outBuffer | |||
Pointer to output sample buffer, channels are | |||
interleaved. | |||
For a stereo int16 configuration: | |||
int16 *buffer16 = (int16 *)buffer; | |||
buffer16[0] is the first left channel sample | |||
buffer16[1] is the first right channel sample | |||
buffer16[2] is the second left channel sample | |||
buffer16[3] is the second right channel sample | |||
Data will always be in the native endian format of | |||
the platform. | |||
context->inBuffer | |||
audio input data, NULL if no input. | |||
in_buffer and out_buffer will have the same sample rate, | |||
sample type, and sample frame count. Only the number of | |||
channels can differ (note that the channel format | |||
determines how data is interleaved.) | |||
context->userData | |||
Void pointer to user data (same pointer supplied during | |||
initialization) Can be NULL. | |||
notes: | |||
Callbacks occur on thread(s) other than the NPAPI thread. Deliver | |||
audio data to the buffer(s) in a timely fashion to avoid | |||
underruns. Do not make NPAPI calls from the callback function. | |||
Avoid calling functions that might cause the OS scheduler to | |||
transfer execution, such as sleep(). Callbacks will not occur | |||
after return from Shutdown. If the audio device is initialized | |||
with both input channel(s) and output channel(s), audio can stream | |||
isochronously on the same callback. | |||
</pre> | </pre> | ||
edits