TEEM
2014-06-26
We're developing an experimental interface called "TEEM" at the moment. This is intended for streaming immersive 3D audio in a simple way that lets programs collaborate easily. We're hoping to make it "open".
TEEM supports sound objects with dynamic 3D positional information, and static multichannel beds including ambisonic beds. It has similarities to OpenAL, but is much simpler because it focusses only on 3D spatialisation (e.g. for cinema) and does not attempt to handle many rendering features needed for games (environmental modelling, effects, dynamic sample rate conversion and so on). That said, a game could render such features itself and then feed audio to a TEEM-compatible renderer or network stream for 3D spatialisation.
TEEM itself is a simple software interface (see below) that allows two TEEM-compatible software components to talk to each other in a standard way. We've also written a software development kit ("libteem"), which includes a lossless packet and file format and an example renderer, but you don't need this to use the TEEM interface itself.
We're still working out exactly what we should do with TEEM, partly because there is work happening in standards bodies with which we'd like to be compatible, many "object" concepts are in flux, and it is possible to have too many standards. To help the debate, we thought we'd give you a sneak peek at the technical core of the interface. What do you think? Please get in touch and let us know what we've broken or missed...
Possible Uses
We can see a lot of possible uses for this sort of thing. The interface itself can act as glue connecting components together. For instance, TEEM-compatible digital audio workstations or other audio and A/V packages could load or save TEEM-compatible data, using lossy or lossless coding formats, to aid cross-tool content creation. We could stream TEEM audio live or offline over a network, put it on disks, in audio files or embedded in A/V streams. TEEM audio could be rendered for playback on headphones for music, film, games, VR and more, using a wide variety of immersive audio rendering techniques, like traditional panning, VBAP, Wavefield synthesis or ambisonics. Of course, we could do this anyway, but by having a programming interface we massively increase the chance that when we (for instance) link a TEEM-compatible network receiver software component to (for instance) a TEEM-compatible Wavefield renderer, things will "just work".
The Technical Part - C/C++ Programmers Only!
The interface is specified as a C header file for direct compatibility with C and C++, and easy integration into other software. The lossless packet and file format in the SDK can be used for interchange, but other formats (e.g. lossy) would also work, if they follow the interface.
THE INTERFACE IS NOT FINAL - THIS IS JUST PRESENTED HERE FOR COMMENT. Please don't write any software using this just yet. Because it's not finished and we may yet make incompatible changes, we've not made it open yet (see the license below).
Here's the current header file:
/** @file teem.h
Main C/C++ interface for TEEM streams.
Copyright (C) 2014 Blue Ripple Sound Limited
Permission is hereby granted, free of charge, to the person to
whom a copy of this software and associated documentation files is
provided by Blue Ripple Sound Limited (the "Software"), to view
and use the Software for the purpose only of assessing the quality
and functionality of the Software and providing feedback on the
same to Blue Ripple Sound Limited.
No other rights are granted in respect of the Software and for the
avoidance of doubt the following rights are hereby expressly
excluded: the right to copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef TEEM_H_INCLUDED
#define TEEM_H_INCLUDED
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************/
/** Correct behaviour should not be expected if interacting with code
with a different major number. */
#define TEEM_API_VERSION_NUMBER_MAJOR 3
/** New backwards-compatible features, functions, metadata and audio
types may be added in minor versions. */
#define TEEM_API_VERSION_NUMBER_MINOR 0
/*****************************************************************************/
/** Indicates the type of metadata being transmitted. Values are
reserved. The value zero is not allowed. Other values under 1000
will not be allocated and may be used for development purposes
(only). */
typedef uint32_t TEEMMetadataType;
/*****************************************************************************/
/** TEEM object handles refer to audio, sources, beds or mixes. */
typedef void * TEEMObject;
/*****************************************************************************/
/** Timestamp, in samples, relative to some unspecified start point
(NOT necessarily zero). Divide by the sample rate to find the
sample index in seconds. Wrapping around back to zero is not
defined behaviour. */
typedef uint64_t TEEMSampleIndex;
/** Sometimes end timestamps for objects are not known. In these
cases, this symbol may be used instead until the information
becomes available. */
#define TEEM_SAMPLE_INDEX_UNKNOWN (uint64_t(-1))
/*****************************************************************************/
/** Position in space, relative to a central position. +X is to the
front, +Y is left, +Z is up. Units are metres. */
typedef struct {
/** Positive values are to the front, negative values are to the
back. Units are metres. */
float atX;
/** Positive values are to the left, negative values are to the
right. Units are metres. */
float atY;
/** Positive values are upwards, negative values are
downwards. Units are metres. */
float atZ;
} TEEMVector;
/*****************************************************************************/
/** Return codes from the TEEM functions. TR_SUCCESS indicates
success. Generally calls that fail can be assumed to leave data in
the state they were in before the call, however this is not
guaranteed for the TR_ALLOCATION_FAILED, TR_SYSTEM_ERROR or
TR_UNKNOWN_ERROR cases. */
typedef enum {
/** This return code generally means all has gone as intended. */
TR_SUCCESS = 0,
/** This indicates that the operation cannot yet complete, but the
same operation may be possible in the future. */
TR_NOT_READY = 1,
/** An error has occurred, but its type is unclear. */
TR_UNKNOWN_ERROR = 2,
/** A system call has failed. */
TR_SYSTEM_ERROR = 3,
/** A memory or other resource allocation has failed. */
TR_ALLOCATION_FAILED = 4,
/** A parameter passed to the called routine was not valid. */
TR_BAD_PARAMETER = 5,
/** Data state is not well-defined. */
TR_BAD_STATE = 6,
/** Data is not compatible with the software in use. */
TR_INCOMPATIBLE = 7,
/** No more data in the stream or file. */
TR_END_OF_STREAM = 8,
/** Operation cannot be completed because of configuration. */
TR_NOT_ALLOWED = 9
} TEEMResult;
/*****************************************************************************/
/** Audio types describe how the channels of an audio object should be
interpreted (audio objects are used for both sources and
beds). Examples of audio types are mono, stereo and 5.1. The type
must correspond to the channel count present. This enumeration is
expected to be extended in future versions of the API, so
pass-through of unknown values is encouraged where possible. */
typedef enum {
/** Mono audio. The channel count must be one. This is the only
audio type which may be used with source objects. Beds may use
any audio type.
When used in a bed, mono audio provides the TEEM level
reference. The word "level" is used here in a flexible
way. Equal level would ideally constrain the sound pressure
amplitude, intensity and other acoustic metrics around all
listeners in the audience. In practice, this is not achieved (or
generally desirable) and implementations manage level in
different ways.
To provide the TEEM level reference, mono bed audio is assumed
to be presented to the listener from a position 1m directly in
front of the head, without proximity effects such as wavefront
curvature.
In stereo rendering, mono bed audio might be scaled by -3dB and
presented to both speakers, although some renderers may wish to
handle even this differently, for instance for mono
compatibility. */
TAT_MONO = 0,
/** Mono Low Frequency Effect audio. The channel count must be
one. Audio is sent to an LFE ("Low Frequency Effect") channel if
one is present.
If no LFE speaker is present, it is usual to discard this rather
than mix it into other channels. If this is not desired,
TAT_MONO may be appropriate. */
TAT_LFE = 1,
/** Stereo audio. The channel count must be two (in order: left,
right). TMT_STANDARD_STEREO and/or other metadata can be used to
provide further information on handling.
A sound presented to exactly one of the channels should sound at
a similar level to TAT_MONO use. */
TAT_STEREO = 2,
/** Quadraphonic audio. The channel count must be four (in order:
front left, front right, back left, back right).
A sound presented to exactly one of the channels should sound at
a similar level to TAT_MONO use. */
TAT_QUAD = 3,
/** 5.1 audio. The channel count must be six (in order: front left,
front right, front centre, LFE, surround left, surround
right). TMT_STANDARD_5_1 or other metadata can be used to
provide further handling information.
A sound presented to exactly one of the channels should sound at
a similar level to TAT_MONO use. */
TAT_5_1 = 4,
/** 7.1 audio. The channel count must be eight (in order: front
left, front right, front centre, LFE, back left, back right,
surround left, surround right).
A sound presented to exactly one of the channels should sound at
a similar level to TAT_MONO use. */
TAT_7_1 = 5,
/** Auro-3D audio. The channel count must be 10, 11 or 12,
corresponding to Auro-3D 9.1, 10.1 or 11.1 (in
order: front left, front right, front centre, LFE, surround
left, surround right, height front left, height front right,
height surround left, height surround right, top ceiling, height
front centre).
A sound presented to exactly one of the channels should sound at
a similar level to TAT_MONO use. */
TAT_AURO_3D = 6,
/** 22.2 audio. The channel count must be 24 (in order: FL, FR, FC,
LFE1, BL, BR, FLc, FRc, BC, LFE2, SiL, SiR, TpFL, TpFR, TpFC,
TpC, TpBL, TpBR, TpSiL, TpSiR, TpBC, BtFC, BtFL, BtFR).
A sound presented to exactly one of the channels should sound at
a similar level to TAT_MONO use. */
TAT_22_2 = 7,
/** Ambisonic audio using FuMa encoding. The channel count is used
to infer the order (or mixed order). The following channel
sequences (and channel counts) are supported: W (1), WXY (3),
WXYZ (4), WXYUV (5), WXYZUV (6), WXYUVPQ (7), WXYZUVPQ (8),
WXYZRSTUV (9), WXYZRSTUVPQ (11), WXYZRSTUVKLMNOPQ (16).
Playback should be at a level which ensures a source panned
using the usual equations has a similar level to TAT_MONO
use. */
TAT_AMBISONIC_BFORMAT_FUMA = 8,
/** Ambisonic audio using N3D encoding. The channel count is used to
infer the order using (order+1)*(order+1)=count, and other
channel counts are disallowed. ACN channel ordering and
expressions are used.
Playback should be at a level which ensures a source panned
using the usual equations has a similar level to TAT_MONO
use. */
TAT_AMBISONIC_BFORMAT_N3D = 9
} TEEMAudioType;
/*****************************************************************************/
/** Source properties form a bitmask describing the various properties
of a source. See TEEMSourceDetails. */
typedef enum {
/** Nothing defined. */
TSP_NONE = 0,
/** The source should be considered non-diegetic rather than part of
the main sound scene. This typically applies to "HUD" sounds,
narration, and background music. */
TSP_NDG = 0x01,
/** The source is part of a mutually dependent group of sources,
from which it should not be separated. This is typically used
where the objects have been reduced by lossy compression with an
expectation of later masking, which also suggests that overly
precise spatial rendering may be a bad idea. */
TSP_DEPENDENT_GROUP = 0x02
} TEEMSourceProperties;
/*****************************************************************************/
/** Bed properties form a bitmask describing the various properties of
a bed. See TEEMBedDetails. */
typedef enum {
/** Nothing defined. */
TBP_NONE = 0,
/** The bed should be considered non-diegetic rather than part of
the main sound scene. This typically applies to "HUD" sounds,
narration, and background music. */
TBP_NDG = 0x01
} TEEMBedProperties;
/*****************************************************************************/
/** Mix properties form a bitmask of properties defined for a mix. */
typedef enum {
/** Nothing defined. */
TMP_NONE = 0,
/** This mix includes commentary audio. */
TMP_COMMENTARY = 0x01,
/** This mix includes audio descriptive material. */
TMP_AUDIO_DESCRIPTIVE = 0x02
} TEEMMixProperties;
/*****************************************************************************/
/** Fixed (non-varying) data for a source. */
typedef struct {
/** The audio object which will provide an audio stream for the
source. The audio object type must be of type TAT_MONO. Note
that if the linked audio object ends then the source will
too. */
TEEMObject audio;
/** Bitmap of properties applying to the source. */
TEEMSourceProperties properties;
} TEEMSourceDetails;
/*****************************************************************************/
/** Fixed (non-varying) data for a bed. */
typedef struct {
/** The audio object which will provide an audio stream for the
bed. Note that if the linked audio object ends then the bed will
too. */
TEEMObject audio;
/** Bitmap of properties applying to the bed. */
TEEMBedProperties properties;
} TEEMBedDetails;
/*****************************************************************************/
/** Fixed (non-varying) data for a mix. */
typedef struct {
/** Bitmap of properties applying to a mix. */
TEEMMixProperties properties;
/** The language code for this mix as a zero-terminated string, or
an empty string if there is no language associated. Uses ISO
639-2 (three character lower case) codes. */
char language[4];
/** Ordering number used to decide between mixes, overriding other
information. Values are normally between 0 and 10, and large
numbers go first. */
uint8_t majorPreference;
/** Ordering number used to decide between mixes in the absence of
other information. Values are normally between 0 and 10, and
large numbers go first. */
uint8_t minorPreference;
} TEEMMixDetails;
/*****************************************************************************/
/** A source step describes how a source moves to a position in space,
potentially over a period in time.
Steps are defined over a time interval and the values here are
defined for the end of that interval. During the interval, values
are interpolated from preceding ones. */
typedef struct {
/** The position from which the audio should ideally seem to
come. This is specified in 3D Cartesian coordinates, in metres,
with X forward, Y left and Z upwards, relative to the
listener. Interpreting positions where multiple listeners are
present is left to the discretion of the renderer.
It is assumed that major distance cues are embedded in the audio
data upstream. For instance, distant sources may be delayed and
attenuated. Therefore, renderers might use only the position’s
direction and not its distance.
Positions are interpolated linearly in space. */
TEEMVector position;
/** The size of the source at the end timestamp, in metres, with 0
indicating a point source. Changing the radius should not change
the source's overall level.
Radii are interpolated linearly. */
float radius;
/** Sources can be made diffuse, without losing their directivity or
changing in overall level. This is most relevant for sources
with larger radii and results in sound components from different
directions arriving with reduced correlation. Values are between
zero and one and a value of zero indicates no diffuseness.
Diffuseness values are interpolated linearly. */
float diffuseness;
/** The non-negative scalar control gain of the source at the end
timestamp.
Control gains are interpolated linearly.
Note that audio is represented using integers, and this gain
needs to contain an appropriate scalar to take those integers
down to a sensible level. Typically, the mix peak amplitude
should be under 1. For instance, if 16bit audio (-32768 to
+32767) is to be presented at -6dB (0.5) relative to its normal
full level, this control gain might be 0.5/32768. */
float controlGain;
} TEEMSourceStep;
/*****************************************************************************/
/** A bed step includes information about how a bed should be
rendered.
Steps are defined over a time interval and the values here are
defined for the end of that interval. During the interval, values
are interpolated from preceding ones. */
typedef struct {
/** The non-negative scalar control gain of the bed at the end
timestamp.
Control gains are interpolated linearly.
Note that audio is represented using integers, and this gain
needs to contain an appropriate scalar to take those integers
down to a sensible level. Typically, the mix peak amplitude
should be under 1. For instance, if 16bit audio (-32768 to
+32767) is to be presented at -6dB (0.5) relative to its normal
full level, this control gain might be 0.5/32768. */
float controlGain;
} TEEMBedStep;
/*****************************************************************************/
/** Main stream handle. */
typedef struct TEEMStreamFunctionsStruct * TEEMStream;
/*****************************************************************************/
/** Streams control the overall state of an audio stream and the
objects within it. Basic usage is for the 'upstream' code to call
the routines provided here to maintain the objects and update the
audio which they are linked to, and then to call flush() to push
all the data 'downstream'. Object data is carried forward from
block to block (although it can be restated regularly or
irregularly for recovery purposes), and audio is read from memory
during each flush() call (only).
The downstream component is responsible for audio synchronisation
and so provides the sample rate and current timestamp (sample
index).
This interface controls operation of the stream but not how it is
initialised or cleaned up. It is assumed that some other function
calls or interface(s) are used to manage this in a way which
depends on the stream implementation. */
typedef struct TEEMStreamFunctionsStruct {
/* Stream-Level Calls:
------------------- */
/** Get the version of the TEEM application programming interface
(API) that the stream implementation is using. The major and
minor version numbers are written at the pointers provided. A
difference in major version indicates that streaming should not
proceed as the interface may not be directly compatible.
@param stream A handle to the stream in use.
@param majorVersion A difference in major version indicates that
versions are not compatible.
@param minorVersion A difference in minor version indicates that
not all features may be fully supported. */
TEEMResult (*getAPIVersion)(TEEMStream stream,
uint32_t * majorVersion,
uint32_t * minorVersion);
/** Get the sample rate, in Hz. The sample rate is written at the
pointer provided.
@param stream A handle to the stream in use.
@param sampleRate On success, (*sampleRate) contains the sample
rate, in Hz. */
TEEMResult (*getSampleRate)(TEEMStream stream,
float * sampleRate);
/** Get the index of the current sample index, as calculated by the
downstream component. The result is written at the pointer
provided. Note that the sample index start point is determined
by the downstream component and may not necessarily start at
zero.
@param stream A handle to the stream in use.
@param sampleIndex On success, (*sampleIndex) contains the
current sample index. */
TEEMResult (*getSampleIndex)(TEEMStream stream,
TEEMSampleIndex * sampleIndex);
/** Flush all data downstream for the current block. Returns an
error code on failure, or TR_SUCCESS on success. This call
releases all objects downstream and is the (only) point at which
audio is read from memory. This call may have real-time
dependencies and in practice may take a while and even
block. After this, the current sample index (as returned by
getSampleIndex()) will move forward by the block size provided.
@param stream A handle to the stream in use.
@param blockSize The block size, in samples, between 1 and
65535. This determines how many samples of audio are read from
each audio channel. It also determines how far the sample index
is moved along. */
TEEMResult (*flush)(TEEMStream stream,
uint16_t blockSize);
/* Audio:
------ */
/** Declare an audio object for future use. Audio objects carry one
or more channels of audio PCM data. They need to be linked to
sources or beds for actual playback.
The object is not well-defined until connectAudio() has been
called successfully for it. After that point, full buffers of
audio will be expected during flush() calls until the object has
been destroyed. */
TEEMResult (*declareAudio)(TEEMStream stream,
TEEMAudioType audioType,
uint16_t channelCount,
TEEMObject * audio);
/** Connect the audio object to a memory location pointing to an
array of channel pointers, each of which indicates an array of
integer PCM samples for one channel.
During a stream flush operation, the samples address is
dereferenced and a number of samples are read from each of the
channels.
The number of samples is given by the flush block size only and
is <em>not</em> affected by the end time of any objects. In
other words, after calling this method you must provide a full
buffer of audio for every block until the scheduled end time for
the audio object is less than or equal to the current block's
sample index. (Of course, some of the block(s) of audio may be
silent.)
Note that the connection indicates just one memory location, so
the indirect channel pointers (e.g. address samples[0]) may be
changed upstream without another call to connectAudio() and must
not be referenced downstream except during flush() calls. */
TEEMResult (*connectAudio)(TEEMStream stream,
TEEMObject audio,
int32_t ** samples);
/** Schedule the end-point for the audio object. The audio object
can be well-defined without this. The audio object, and any
linked beds or sources, will end when this time is reached.
The timestamp may or may not be exactly on a block boundary. An
object is destroyed when its end timestamp is on or before the
current block start. This can occur either through scheduling a
new end timestamp or through time moving forward. Immediately
after this happens (i.e. not only at flush points), the object's
handle may become invalid and should not be used by upstream
code. Further, no audio may be read in flush phases. Note that
this means that an object can effectively be deleted immediately
at any time. Regardless of the exact timing of object
destruction, if the object ends within the current block, audio
will not be heard after the end timestamp, although it may be
before. However, a full block of audio must still be present in
this case during the flush() call.
This call may be used to add data, or to restate data that
downstream should already have. When restating, it is an error
to send a later value, but equal or earlier values are allowed. */
TEEMResult (*scheduleAudioEnd)(TEEMStream stream,
TEEMObject audio,
TEEMSampleIndex timestamp);
/* Sources:
-------- */
/** Declare a source for future use, and set its basic details. A
source is a virtual sound-producing agent placed somewhere in 3D
space. It presents a mono sound stream.
The source is not well-defined (and will not play) until the
sample at which it has a valid source step and well-defined
audio. */
TEEMResult (*declareSource)(TEEMStream stream,
const TEEMSourceDetails * details,
TEEMObject * source);
/** Schedule a change to the source settings. The startTimestamp
must be less than or equal to the endTimestamp. Steps must all
have distinct end timestamps and may not overlap (although the
end timestamp of one event may match the start timestamp of
another).
This call may be used to add data, or to restate data that
downstream should already have. When restating, it is an error
to send different values. */
TEEMResult (*scheduleSourceStep)(TEEMStream stream,
TEEMObject source,
TEEMSampleIndex startTimestamp,
TEEMSampleIndex endTimestamp,
const TEEMSourceStep * step);
/** Schedule the end time for the source object. The source can be
well-defined without this. The source will end when this time is
reached.
The timestamp may or may not be exactly on a block boundary. An
object is destroyed when its end timestamp is on or before the
current block start. This can occur either through scheduling a
new end timestamp or through time moving forward. Immediately
after this happens (i.e. not only at flush points), the object's
handle may become invalid and should not be used by upstream
code. Note that this means that an object can effectively be
deleted immediately at any time. Regardless of the exact timing
of object destruction, if the object ends within the current
block, audio will not be heard after the end timestamp, although
it may be before.
This call may be used to add data, or to restate data that
downstream should already have. When restating, it is an error
to send a later value, but equal or earlier values are allowed. */
TEEMResult (*scheduleSourceEnd)(TEEMStream stream,
TEEMObject source,
TEEMSampleIndex timestamp);
/* Beds:
----- */
/** Declare a bed for future use, and set its basic details. A bed
presents (typically) pre-rendered multichannel audio
(e.g. stereo or 5.1) into the virtual space in a specially
defined way, not using the 3D spatialisation features of source
objects.
The bed is not well-defined (and will not play) until the sample
at which it has a valid bed step and well-defined audio. */
TEEMResult (*declareBed)(TEEMStream stream,
const TEEMBedDetails * details,
TEEMObject * bed);
/** Schedule a change to the bed settings. The startTimestamp must
be less than or equal to the endTimestamp. Steps must all have
distinct end timestamps and may not overlap (although the end
timestamp of one event may match the start timestamp of
another).
This call may be used to add data, or to restate data that
downstream should already have. When restating, it is an error
to send different values. */
TEEMResult (*scheduleBedStep)(TEEMStream stream,
TEEMObject bed,
TEEMSampleIndex startTimestamp,
TEEMSampleIndex endTimestamp,
const TEEMBedStep * step);
/** Schedule the end time for the bed object. The bed can be
well-defined without this. The bed will end when this time is
reached.
The timestamp may or may not be exactly on a block boundary. An
object is destroyed when its end timestamp is on or before the
current block start. This can occur either through scheduling a
new end timestamp or through time moving forward. Immediately
after this happens (i.e. not only at flush points), the object's
handle may become invalid and should not be used by upstream
code. Note that this means that an object can effectively be
deleted immediately at any time. Regardless of the exact timing
of object destruction, if the object ends within the current
block, audio will not be heard after the end timestamp, although
it may be before.
This call may be used to add data, or to restate data that
downstream should already have. When restating, it is an error
to send a later value, but equal or earlier values are
allowed. */
TEEMResult (*scheduleBedEnd)(TEEMStream stream,
TEEMObject bed,
TEEMSampleIndex timestamp);
/* Mixes:
----- */
/** Declare a mix for future use, and set its basic details. A mix
selects a particular collection of sound objects (sources and
beds) all of which are to be played at once.
The mix is not well-defined (and will not play) until the sample
at which it has a valid mix content (which may be empty). If no
mix is well-defined then a default mix is used, containing all
source and bed objects. */
TEEMResult (*declareMix)(TEEMStream stream,
const TEEMMixDetails * details,
TEEMObject * mix);
/** Schedule a change to the mix settings. Changes must all have
distinct timestamps.
Objects may be sources or beds. They may not be audio objects
directly. Note that sources and beds may appear in any number of
mixes and may share audio objects.
The mix is well-defined once it has content, even if some of the
objects provided are not well-defined themselves. Only the
well-defined objects within the mix will sound. Also, the mix is
still well-defined if some or all of these objects end.
This call may be used to add data, or to restate data that
downstream should already have. When restating, it is an error
to send different values. */
TEEMResult (*scheduleMixContent)(TEEMStream stream,
TEEMObject mix,
TEEMSampleIndex timestamp,
TEEMObject * objects,
uint32_t objectCount);
/** Schedule the end time for the mix object. The mix can be
well-defined without this. The mix will end when this time is
reached. Objects within the mix are not destroyed.
The timestamp may or may not be exactly on a block boundary. An
object is destroyed when its end timestamp is on or before the
current block start. This can occur either through scheduling a
new end timestamp or through time moving forward. Immediately
after this happens (i.e. not only at flush points), the object's
handle may become invalid and should not be used by upstream
code. Note that this means that an object can effectively be
deleted immediately at any time. Regardless of the exact timing
of object destruction, if the object ends within the current
block, audio will not be heard after the end timestamp, although
it may be before.
This call may be used to add data, or to restate data that
downstream should already have. When restating, it is an error
to send a later value, but equal or earlier values are
allowed. */
TEEMResult (*scheduleMixEnd)(TEEMStream stream,
TEEMObject mix,
TEEMSampleIndex timestamp);
/* Metadata:
--------- */
/** Schedule a change in metadata at a particular point in time. Use
a size of zero to make the metadata undefined from that
point. Metadata can be applied to audio, source, bed or mix
objects.
This call may be used to add data, or to restate data that
downstream should already have. When restating, it is an error
to send different values. */
TEEMResult (*scheduleMetadata)(TEEMStream stream,
TEEMObject object,
TEEMMetadataType metadataType,
TEEMSampleIndex timestamp,
const void * data,
uint32_t dataSize);
} TEEMStreamFunctions;
/*****************************************************************************/
#ifdef __cplusplus
}
#endif
#endif
/* EOF */
