зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1241476: Update libcubeb from upstream rs=padenot
Import from libcubeb git commit b364f9ce2f8f7c392055b94c350ce600892ce7bc --HG-- extra : commitid : 49ZDL6OsQel
This commit is contained in:
Родитель
41fa341197
Коммит
ef9e20cf89
|
@ -6,3 +6,10 @@ David Richards <drichards@mozilla.com>
|
|||
Sebastien Alaiwan <sebastien.alaiwan@gmail.com>
|
||||
KO Myung-Hun <komh@chollian.net>
|
||||
Haakon Sporsheim <haakon.sporsheim@telenordigital.com>
|
||||
Alex Chronopoulos <achronop@gmail.com>
|
||||
Jan Beich <jbeich@FreeBSD.org>
|
||||
Vito Caputo <vito.caputo@coreos.com>
|
||||
Landry Breuil <landry@openbsd.org>
|
||||
Jacek Caban <jacek@codeweavers.com>
|
||||
Paul Hancock <Paul.Hancock.17041993@live.com>
|
||||
Ted Mielczarek <ted@mielczarek.org>
|
||||
|
|
|
@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
|
|||
|
||||
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
|
||||
|
||||
The git commit ID used was 23a17cb4f9ed2de78a0df5ecdfefbbe47dc83c35.
|
||||
The git commit ID used was b364f9ce2f8f7c392055b94c350ce600892ce7bc.
|
||||
|
|
|
@ -118,6 +118,10 @@ typedef enum {
|
|||
} cubeb_stream_type;
|
||||
#endif
|
||||
|
||||
/** An opaque handle used to refer a particular input or output device
|
||||
* across calls. */
|
||||
typedef void * cubeb_devid;
|
||||
|
||||
/** Stream format initialization parameters. */
|
||||
typedef struct {
|
||||
cubeb_sample_format format; /**< Requested sample format. One of
|
||||
|
@ -149,41 +153,61 @@ enum {
|
|||
CUBEB_ERROR = -1, /**< Unclassified error. */
|
||||
CUBEB_ERROR_INVALID_FORMAT = -2, /**< Unsupported #cubeb_stream_params requested. */
|
||||
CUBEB_ERROR_INVALID_PARAMETER = -3, /**< Invalid parameter specified. */
|
||||
CUBEB_ERROR_NOT_SUPPORTED = -4 /**< Optional function not implemented in current backend. */
|
||||
CUBEB_ERROR_NOT_SUPPORTED = -4, /**< Optional function not implemented in current backend. */
|
||||
CUBEB_ERROR_DEVICE_UNAVAILABLE = -5 /**< Device specified by #cubeb_devid not available. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether a particular device is an input device (e.g. a microphone), or an
|
||||
* output device (e.g. headphones). */
|
||||
typedef enum {
|
||||
CUBEB_DEVICE_TYPE_UNKNOWN,
|
||||
CUBEB_DEVICE_TYPE_INPUT,
|
||||
CUBEB_DEVICE_TYPE_OUTPUT
|
||||
} cubeb_device_type;
|
||||
|
||||
/**
|
||||
* The state of a device.
|
||||
*/
|
||||
typedef enum {
|
||||
CUBEB_DEVICE_STATE_DISABLED,
|
||||
CUBEB_DEVICE_STATE_UNPLUGGED,
|
||||
CUBEB_DEVICE_STATE_ENABLED
|
||||
CUBEB_DEVICE_STATE_DISABLED, /**< The device has been disabled at the system level. */
|
||||
CUBEB_DEVICE_STATE_UNPLUGGED, /**< The device is enabled, but nothing is plugged into it. */
|
||||
CUBEB_DEVICE_STATE_ENABLED /**< The device is enabled. */
|
||||
} cubeb_device_state;
|
||||
|
||||
typedef void * cubeb_devid;
|
||||
|
||||
/**
|
||||
* Architecture specific sample type.
|
||||
*/
|
||||
typedef enum {
|
||||
CUBEB_DEVICE_FMT_S16LE = 0x0010,
|
||||
CUBEB_DEVICE_FMT_S16BE = 0x0020,
|
||||
CUBEB_DEVICE_FMT_F32LE = 0x1000,
|
||||
CUBEB_DEVICE_FMT_F32BE = 0x2000
|
||||
CUBEB_DEVICE_FMT_S16LE = 0x0010, /**< 16-bit integers, Little Endian. */
|
||||
CUBEB_DEVICE_FMT_S16BE = 0x0020, /**< 16-bit integers, Big Endian. */
|
||||
CUBEB_DEVICE_FMT_F32LE = 0x1000, /**< 32-bit floating point, Little Endian. */
|
||||
CUBEB_DEVICE_FMT_F32BE = 0x2000 /**< 32-bit floating point, Big Endian. */
|
||||
} cubeb_device_fmt;
|
||||
|
||||
#if defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__)
|
||||
/** 16-bit integers, native endianess, when on a Big Endian environment. */
|
||||
#define CUBEB_DEVICE_FMT_S16NE CUBEB_DEVICE_FMT_S16BE
|
||||
/** 32-bit floating points, native endianess, when on a Big Endian environment. */
|
||||
#define CUBEB_DEVICE_FMT_F32NE CUBEB_DEVICE_FMT_F32BE
|
||||
#else
|
||||
/** 16-bit integers, native endianess, when on a Little Endian environment. */
|
||||
#define CUBEB_DEVICE_FMT_S16NE CUBEB_DEVICE_FMT_S16LE
|
||||
/** 32-bit floating points, native endianess, when on a Little Endian
|
||||
* environment. */
|
||||
#define CUBEB_DEVICE_FMT_F32NE CUBEB_DEVICE_FMT_F32LE
|
||||
#endif
|
||||
/** All the 16-bit integers types. */
|
||||
#define CUBEB_DEVICE_FMT_S16_MASK (CUBEB_DEVICE_FMT_S16LE | CUBEB_DEVICE_FMT_S16BE)
|
||||
/** All the 32-bit floating points types. */
|
||||
#define CUBEB_DEVICE_FMT_F32_MASK (CUBEB_DEVICE_FMT_F32LE | CUBEB_DEVICE_FMT_F32BE)
|
||||
/** All the device formats types. */
|
||||
#define CUBEB_DEVICE_FMT_ALL (CUBEB_DEVICE_FMT_S16_MASK | CUBEB_DEVICE_FMT_F32_MASK)
|
||||
|
||||
/** Channel type for a `cubeb_stream`. Depending on the backend and platform
|
||||
* used, this can control inter-stream interruption, ducking, and volume
|
||||
* control.
|
||||
*/
|
||||
typedef enum {
|
||||
CUBEB_DEVICE_PREF_NONE = 0x00,
|
||||
CUBEB_DEVICE_PREF_MULTIMEDIA = 0x01,
|
||||
|
@ -192,26 +216,30 @@ typedef enum {
|
|||
CUBEB_DEVICE_PREF_ALL = 0x0F
|
||||
} cubeb_device_pref;
|
||||
|
||||
/** This structure holds the characteristics
|
||||
* of an input or output audio device. It can be obtained using
|
||||
* `cubeb_enumerate_devices`, and must be destroyed using
|
||||
* `cubeb_device_info_destroy`. */
|
||||
typedef struct {
|
||||
cubeb_devid devid; /* Device identifier handle */
|
||||
char * device_id; /* Device identifier which might be presented in a UI */
|
||||
char * friendly_name; /* Friendly device name which might be presented in a UI */
|
||||
char * group_id; /* Two devices have the same group identifier if they belong to the same physical device; for example a headset and microphone. */
|
||||
char * vendor_name; /* Optional vendor name, may be NULL */
|
||||
cubeb_devid devid; /**< Device identifier handle. */
|
||||
char * device_id; /**< Device identifier which might be presented in a UI. */
|
||||
char * friendly_name; /**< Friendly device name which might be presented in a UI. */
|
||||
char * group_id; /**< Two devices have the same group identifier if they belong to the same physical device; for example a headset and microphone. */
|
||||
char * vendor_name; /**< Optional vendor name, may be NULL. */
|
||||
|
||||
cubeb_device_type type; /* Type of device (Input/Output) */
|
||||
cubeb_device_state state; /* State of device disabled/enabled/unplugged */
|
||||
cubeb_device_pref preferred;/* Preferred device */
|
||||
cubeb_device_type type; /**< Type of device (Input/Output). */
|
||||
cubeb_device_state state; /**< State of device disabled/enabled/unplugged. */
|
||||
cubeb_device_pref preferred;/**< Preferred device. */
|
||||
|
||||
cubeb_device_fmt format; /* Sample format supported */
|
||||
cubeb_device_fmt default_format;
|
||||
unsigned int max_channels; /* Channels */
|
||||
unsigned int default_rate; /* Default/Preferred sample rate */
|
||||
unsigned int max_rate; /* Maximum sample rate supported */
|
||||
unsigned int min_rate; /* Minimum sample rate supported */
|
||||
cubeb_device_fmt format; /**< Sample format supported. */
|
||||
cubeb_device_fmt default_format; /**< The default sample format for this device. */
|
||||
unsigned int max_channels; /**< Channels. */
|
||||
unsigned int default_rate; /**< Default/Preferred sample rate. */
|
||||
unsigned int max_rate; /**< Maximum sample rate supported. */
|
||||
unsigned int min_rate; /**< Minimum sample rate supported. */
|
||||
|
||||
unsigned int latency_lo_ms; /* Lowest possible latency in milliseconds */
|
||||
unsigned int latency_hi_ms; /* Higest possible latency in milliseconds */
|
||||
unsigned int latency_lo_ms; /**< Lowest possible latency in milliseconds. */
|
||||
unsigned int latency_hi_ms; /**< Higest possible latency in milliseconds. */
|
||||
} cubeb_device_info;
|
||||
|
||||
/** Device collection. */
|
||||
|
@ -221,17 +249,21 @@ typedef struct {
|
|||
} cubeb_device_collection;
|
||||
|
||||
/** User supplied data callback.
|
||||
@param stream
|
||||
@param user_ptr
|
||||
@param buffer
|
||||
@param nframes
|
||||
@retval Number of frames written to buffer, which must equal nframes except
|
||||
at end of stream.
|
||||
@param stream The stream for which this callback fired
|
||||
@param user_ptr The pointer passed to cubeb_stream_create
|
||||
@param input_buffer A pointer containing the input data, or nullptr
|
||||
if this is an output-only stream.
|
||||
@param output_buffer A pointer containing the output data, or nullptr
|
||||
if this is an input -only stream.
|
||||
@param nframes The number of frames of the two buffer.
|
||||
@retval Number of frames written to the output buffer, which must equal
|
||||
nframes except at end of stream.
|
||||
@retval CUBEB_ERROR on error, in which case the data callback will stop
|
||||
and the stream will enter a shutdown state. */
|
||||
typedef long (* cubeb_data_callback)(cubeb_stream * stream,
|
||||
void * user_ptr,
|
||||
void * buffer,
|
||||
const void * input_buffer,
|
||||
void * output_buffer,
|
||||
long nframes);
|
||||
|
||||
/** User supplied state callback.
|
||||
|
@ -306,7 +338,14 @@ void cubeb_destroy(cubeb * context);
|
|||
@param context
|
||||
@param stream
|
||||
@param stream_name
|
||||
@param stream_params
|
||||
@param input_device Device for the input side of the stream. If NULL
|
||||
default input device is used.
|
||||
@param input_stream_params Parameters for the input side of the stream, or
|
||||
NULL if this stream is output only.
|
||||
@param output_device Device for the output side of the stream. If NULL
|
||||
default output device is used.
|
||||
@param output_stream_params Parameters for the output side of the stream, or
|
||||
NULL if this stream is input only.
|
||||
@param latency Approximate stream latency in milliseconds. Valid range
|
||||
is [1, 2000].
|
||||
@param data_callback Will be called to preroll data before playback is
|
||||
|
@ -315,11 +354,15 @@ void cubeb_destroy(cubeb * context);
|
|||
@param user_ptr
|
||||
@retval CUBEB_OK
|
||||
@retval CUBEB_ERROR
|
||||
@retval CUBEB_ERROR_INVALID_FORMAT */
|
||||
@retval CUBEB_ERROR_INVALID_FORMAT
|
||||
@retval CUBEB_ERROR_DEVICE_UNAVAILABLE */
|
||||
int cubeb_stream_init(cubeb * context,
|
||||
cubeb_stream ** stream,
|
||||
char const * stream_name,
|
||||
cubeb_stream_params stream_params,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback,
|
||||
cubeb_state_callback state_callback,
|
||||
|
@ -422,7 +465,7 @@ int cubeb_enumerate_devices(cubeb * context,
|
|||
cubeb_device_type devtype,
|
||||
cubeb_device_collection ** collection);
|
||||
|
||||
/** Destroy a cubeb_device_collection.
|
||||
/** Destroy a cubeb_device_collection, and its `cubeb_device_info`.
|
||||
@param collection collection to destroy
|
||||
@retval CUBEB_OK
|
||||
@retval CUBEB_ERROR_INVALID_PARAMETER if collection is an invalid pointer */
|
||||
|
|
|
@ -22,8 +22,14 @@ struct cubeb_ops {
|
|||
int (* enumerate_devices)(cubeb * context, cubeb_device_type type,
|
||||
cubeb_device_collection ** collection);
|
||||
void (* destroy)(cubeb * context);
|
||||
int (* stream_init)(cubeb * context, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
int (* stream_init)(cubeb * context,
|
||||
cubeb_stream ** stream,
|
||||
char const * stream_name,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback,
|
||||
cubeb_state_callback state_callback,
|
||||
void * user_ptr);
|
||||
|
|
|
@ -61,15 +61,36 @@ int audiotrack_init(cubeb ** context, char const * context_name);
|
|||
int kai_init(cubeb ** context, char const * context_name);
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
validate_stream_params(cubeb_stream_params stream_params)
|
||||
validate_stream_params(cubeb_stream_params * input_stream_params,
|
||||
cubeb_stream_params * output_stream_params)
|
||||
{
|
||||
if (stream_params.rate < 1000 || stream_params.rate > 192000 ||
|
||||
stream_params.channels < 1 || stream_params.channels > 8) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
if (output_stream_params) {
|
||||
if (output_stream_params->rate < 1000 || output_stream_params->rate > 192000 ||
|
||||
output_stream_params->channels < 1 || output_stream_params->channels > 8) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
}
|
||||
if (input_stream_params) {
|
||||
if (input_stream_params->rate < 1000 || input_stream_params->rate > 192000 ||
|
||||
input_stream_params->channels < 1 || input_stream_params->channels > 8) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
}
|
||||
// Rate and sample format must be the same for input and output, if using a
|
||||
// duplex stream
|
||||
if (input_stream_params && output_stream_params) {
|
||||
if (input_stream_params->rate != output_stream_params->rate ||
|
||||
input_stream_params->format != output_stream_params->format) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
}
|
||||
|
||||
switch (stream_params.format) {
|
||||
cubeb_stream_params * params = input_stream_params ?
|
||||
input_stream_params : output_stream_params;
|
||||
|
||||
switch (params->format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
case CUBEB_SAMPLE_S16BE:
|
||||
case CUBEB_SAMPLE_FLOAT32LE:
|
||||
|
@ -80,6 +101,8 @@ validate_stream_params(cubeb_stream_params stream_params)
|
|||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
validate_latency(int latency)
|
||||
{
|
||||
|
@ -218,7 +241,11 @@ cubeb_destroy(cubeb * context)
|
|||
|
||||
int
|
||||
cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback,
|
||||
cubeb_state_callback state_callback,
|
||||
void * user_ptr)
|
||||
|
@ -229,13 +256,17 @@ cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
|
|||
return CUBEB_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((r = validate_stream_params(stream_params)) != CUBEB_OK ||
|
||||
if ((r = validate_stream_params(input_stream_params, output_stream_params)) != CUBEB_OK ||
|
||||
(r = validate_latency(latency)) != CUBEB_OK) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return context->ops->stream_init(context, stream, stream_name,
|
||||
stream_params, latency,
|
||||
input_device,
|
||||
input_stream_params,
|
||||
output_device,
|
||||
output_stream_params,
|
||||
latency,
|
||||
data_callback,
|
||||
state_callback,
|
||||
user_ptr);
|
||||
|
|
|
@ -306,7 +306,7 @@ alsa_refill_stream(cubeb_stream * stm)
|
|||
assert(p);
|
||||
|
||||
pthread_mutex_unlock(&stm->mutex);
|
||||
got = stm->data_callback(stm, stm->user_ptr, p, avail);
|
||||
got = stm->data_callback(stm, stm->user_ptr, NULL, p, avail);
|
||||
pthread_mutex_lock(&stm->mutex);
|
||||
if (got < 0) {
|
||||
pthread_mutex_unlock(&stm->mutex);
|
||||
|
@ -781,7 +781,11 @@ static void alsa_stream_destroy(cubeb_stream * stm);
|
|||
|
||||
static int
|
||||
alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
|
||||
void * user_ptr)
|
||||
{
|
||||
|
@ -792,9 +796,15 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
|
|||
|
||||
assert(ctx && stream);
|
||||
|
||||
assert(!input_stream_params && "not supported.");
|
||||
if (input_device || output_device) {
|
||||
/* Device selection not yet implemented. */
|
||||
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
*stream = NULL;
|
||||
|
||||
switch (stream_params.format) {
|
||||
switch (output_stream_params->format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
format = SND_PCM_FORMAT_S16_LE;
|
||||
break;
|
||||
|
@ -826,7 +836,7 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
|
|||
stm->data_callback = data_callback;
|
||||
stm->state_callback = state_callback;
|
||||
stm->user_ptr = user_ptr;
|
||||
stm->params = stream_params;
|
||||
stm->params = *output_stream_params;
|
||||
stm->state = INACTIVE;
|
||||
stm->volume = 1.0;
|
||||
|
||||
|
@ -933,7 +943,7 @@ alsa_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
|
|||
|
||||
assert(ctx);
|
||||
|
||||
r = alsa_stream_init(ctx, &stm, "", params, 100, NULL, NULL, NULL);
|
||||
r = alsa_stream_init(ctx, &stm, "", NULL, NULL, NULL, ¶ms, 100, NULL, NULL, NULL);
|
||||
if (r != CUBEB_OK) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
|
|
@ -99,12 +99,11 @@ audiotrack_refill(int event, void* user, void* info)
|
|||
return;
|
||||
}
|
||||
|
||||
got = stream->data_callback(stream, stream->user_ptr, b->raw, b->frameCount);
|
||||
got = stream->data_callback(stream, stream->user_ptr, NULL, b->raw, b->frameCount);
|
||||
|
||||
stream->written += got;
|
||||
|
||||
if (got != (long)b->frameCount) {
|
||||
uint32_t p;
|
||||
stream->draining = 1;
|
||||
/* set a marker so we are notified when the are done draining, that is,
|
||||
* when every frame has been played by android. */
|
||||
|
@ -279,7 +278,11 @@ audiotrack_destroy(cubeb * context)
|
|||
|
||||
int
|
||||
audiotrack_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback,
|
||||
cubeb_state_callback state_callback,
|
||||
void * user_ptr)
|
||||
|
@ -290,12 +293,18 @@ audiotrack_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_
|
|||
|
||||
assert(ctx && stream);
|
||||
|
||||
if (stream_params.format == CUBEB_SAMPLE_FLOAT32LE ||
|
||||
stream_params.format == CUBEB_SAMPLE_FLOAT32BE) {
|
||||
assert(!input_stream_params && "not supported");
|
||||
if (input_device || output_device) {
|
||||
/* Device selection not yet implemented. */
|
||||
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (output_stream_params->format == CUBEB_SAMPLE_FLOAT32LE ||
|
||||
output_stream_params->format == CUBEB_SAMPLE_FLOAT32BE) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
if (audiotrack_get_min_frame_count(ctx, &stream_params, (int *)&min_frame_count)) {
|
||||
if (audiotrack_get_min_frame_count(ctx, output_stream_params, (int *)&min_frame_count)) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
|
@ -306,7 +315,7 @@ audiotrack_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_
|
|||
stm->data_callback = data_callback;
|
||||
stm->state_callback = state_callback;
|
||||
stm->user_ptr = user_ptr;
|
||||
stm->params = stream_params;
|
||||
stm->params = *output_stream_params;
|
||||
|
||||
stm->instance = calloc(SIZE_AUDIOTRACK_INSTANCE, 1);
|
||||
(*(uint32_t*)((intptr_t)stm->instance + SIZE_AUDIOTRACK_INSTANCE - 4)) = 0xbaadbaad;
|
||||
|
|
|
@ -136,7 +136,7 @@ audiounit_output_callback(void * user_ptr, AudioUnitRenderActionFlags * flags,
|
|||
}
|
||||
|
||||
pthread_mutex_unlock(&stm->mutex);
|
||||
got = stm->data_callback(stm, stm->user_ptr, buf, nframes);
|
||||
got = stm->data_callback(stm, stm->user_ptr, NULL, buf, nframes);
|
||||
pthread_mutex_lock(&stm->mutex);
|
||||
if (got < 0) {
|
||||
/* XXX handle this case. */
|
||||
|
@ -539,7 +539,11 @@ static void audiounit_stream_destroy(cubeb_stream * stm);
|
|||
|
||||
static int
|
||||
audiounit_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
|
||||
void * user_ptr)
|
||||
{
|
||||
|
@ -558,13 +562,19 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream, char const * stre
|
|||
UInt32 size;
|
||||
AudioValueRange latency_range;
|
||||
|
||||
assert(!input_stream_params && "not supported");
|
||||
if (input_device || output_device) {
|
||||
/* Device selection not yet implemented. */
|
||||
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
assert(context);
|
||||
*stream = NULL;
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
ss.mFormatFlags = 0;
|
||||
|
||||
switch (stream_params.format) {
|
||||
switch (output_stream_params->format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
ss.mBitsPerChannel = 16;
|
||||
ss.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
|
||||
|
@ -589,8 +599,8 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream, char const * stre
|
|||
|
||||
ss.mFormatID = kAudioFormatLinearPCM;
|
||||
ss.mFormatFlags |= kLinearPCMFormatFlagIsPacked;
|
||||
ss.mSampleRate = stream_params.rate;
|
||||
ss.mChannelsPerFrame = stream_params.channels;
|
||||
ss.mSampleRate = output_stream_params->rate;
|
||||
ss.mChannelsPerFrame = output_stream_params->channels;
|
||||
|
||||
ss.mBytesPerFrame = (ss.mBitsPerChannel / 8) * ss.mChannelsPerFrame;
|
||||
ss.mFramesPerPacket = 1;
|
||||
|
|
|
@ -120,7 +120,7 @@ bufferqueue_callback(SLBufferQueueItf caller, void * user_ptr)
|
|||
pthread_mutex_unlock(&stm->mutex);
|
||||
|
||||
if (!draining) {
|
||||
written = cubeb_resampler_fill(stm->resampler, buf,
|
||||
written = cubeb_resampler_fill(stm->resampler, NULL, buf,
|
||||
stm->queuebuf_len / stm->framesize);
|
||||
if (written < 0 || written * stm->framesize > stm->queuebuf_len) {
|
||||
(*stm->play)->SetPlayState(stm->play, SL_PLAYSTATE_PAUSED);
|
||||
|
@ -465,17 +465,26 @@ static void opensl_stream_destroy(cubeb_stream * stm);
|
|||
|
||||
static int
|
||||
opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
|
||||
void * user_ptr)
|
||||
{
|
||||
cubeb_stream * stm;
|
||||
|
||||
assert(ctx);
|
||||
assert(!input_stream_params && "not supported");
|
||||
if (input_device || output_device) {
|
||||
/* Device selection not yet implemented. */
|
||||
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
*stream = NULL;
|
||||
|
||||
if (stream_params.channels < 1 || stream_params.channels > 32 ||
|
||||
if (output_stream_params->channels < 1 || output_stream_params->channels > 32 ||
|
||||
latency < 1 || latency > 2000) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
@ -483,16 +492,16 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
|
|||
SLDataFormat_PCM format;
|
||||
|
||||
format.formatType = SL_DATAFORMAT_PCM;
|
||||
format.numChannels = stream_params.channels;
|
||||
format.numChannels = output_stream_params->channels;
|
||||
// samplesPerSec is in milliHertz
|
||||
format.samplesPerSec = stream_params.rate * 1000;
|
||||
format.samplesPerSec = output_stream_params->rate * 1000;
|
||||
format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
|
||||
format.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
|
||||
format.channelMask = stream_params.channels == 1 ?
|
||||
format.channelMask = output_stream_params->channels == 1 ?
|
||||
SL_SPEAKER_FRONT_CENTER :
|
||||
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
|
||||
|
||||
switch (stream_params.format) {
|
||||
switch (output_stream_params->format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
format.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
break;
|
||||
|
@ -511,10 +520,10 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
|
|||
stm->state_callback = state_callback;
|
||||
stm->user_ptr = user_ptr;
|
||||
|
||||
stm->inputrate = stream_params.rate;
|
||||
stm->inputrate = output_stream_params->rate;
|
||||
stm->latency = latency;
|
||||
stm->stream_type = stream_params.stream_type;
|
||||
stm->framesize = stream_params.channels * sizeof(int16_t);
|
||||
stm->stream_type = output_stream_params->stream_type;
|
||||
stm->framesize = output_stream_params->channels * sizeof(int16_t);
|
||||
stm->lastPosition = -1;
|
||||
stm->lastPositionTimeStamp = 0;
|
||||
stm->lastCompensativePosition = -1;
|
||||
|
@ -575,7 +584,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
|
|||
stm->queuebuf_len += stm->framesize - (stm->queuebuf_len % stm->framesize);
|
||||
}
|
||||
|
||||
stm->resampler = cubeb_resampler_create(stm, stream_params,
|
||||
stm->resampler = cubeb_resampler_create(stm, *output_stream_params,
|
||||
preferred_sampling_rate,
|
||||
data_callback,
|
||||
stm->queuebuf_len / stm->framesize,
|
||||
|
@ -594,7 +603,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
|
|||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
SLuint32 stream_type = convert_stream_type_to_sl_stream(stream_params.stream_type);
|
||||
SLuint32 stream_type = convert_stream_type_to_sl_stream(output_stream_params->stream_type);
|
||||
if (stream_type != 0xFFFFFFFF) {
|
||||
SLAndroidConfigurationItf playerConfig;
|
||||
res = (*stm->playerObj)->GetInterface(stm->playerObj,
|
||||
|
|
|
@ -70,12 +70,27 @@
|
|||
X(pa_threaded_mainloop_unlock) \
|
||||
X(pa_threaded_mainloop_wait) \
|
||||
X(pa_usec_to_bytes) \
|
||||
X(pa_stream_set_read_callback) \
|
||||
X(pa_stream_connect_record) \
|
||||
X(pa_stream_readable_size) \
|
||||
X(pa_stream_peek) \
|
||||
X(pa_stream_drop) \
|
||||
X(pa_stream_get_buffer_attr) \
|
||||
|
||||
#define MAKE_TYPEDEF(x) static typeof(x) * cubeb_##x;
|
||||
LIBPULSE_API_VISIT(MAKE_TYPEDEF);
|
||||
#undef MAKE_TYPEDEF
|
||||
#endif
|
||||
|
||||
//#define LOGGING_ENABLED
|
||||
#ifdef LOGGING_ENABLED
|
||||
#define LOG(...) do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} while(0)
|
||||
#else
|
||||
#define LOG(...)
|
||||
#endif
|
||||
|
||||
static struct cubeb_ops const pulse_ops;
|
||||
|
||||
struct cubeb {
|
||||
|
@ -90,12 +105,14 @@ struct cubeb {
|
|||
|
||||
struct cubeb_stream {
|
||||
cubeb * context;
|
||||
pa_stream * stream;
|
||||
pa_stream * output_stream;
|
||||
pa_stream * input_stream;
|
||||
cubeb_data_callback data_callback;
|
||||
cubeb_state_callback state_callback;
|
||||
void * user_ptr;
|
||||
pa_time_event * drain_timer;
|
||||
pa_sample_spec sample_spec;
|
||||
pa_sample_spec output_sample_spec;
|
||||
pa_sample_spec input_sample_spec;
|
||||
int shutdown;
|
||||
float volume;
|
||||
};
|
||||
|
@ -113,6 +130,7 @@ sink_info_callback(pa_context * context, const pa_sink_info * info, int eol, voi
|
|||
{
|
||||
cubeb * ctx = u;
|
||||
if (!eol) {
|
||||
free(ctx->default_sink_info);
|
||||
ctx->default_sink_info = malloc(sizeof(pa_sink_info));
|
||||
memcpy(ctx->default_sink_info, info, sizeof(pa_sink_info));
|
||||
}
|
||||
|
@ -170,46 +188,46 @@ stream_state_callback(pa_stream * s, void * u)
|
|||
}
|
||||
|
||||
static void
|
||||
stream_request_callback(pa_stream * s, size_t nbytes, void * u)
|
||||
trigger_user_callback(pa_stream * s, void const * input_data, size_t nbytes, cubeb_stream * stm)
|
||||
{
|
||||
cubeb_stream * stm;
|
||||
void * buffer;
|
||||
size_t size;
|
||||
int r;
|
||||
long got;
|
||||
size_t towrite;
|
||||
size_t towrite, read_offset;
|
||||
size_t frame_size;
|
||||
|
||||
stm = u;
|
||||
|
||||
if (stm->shutdown)
|
||||
return;
|
||||
|
||||
frame_size = WRAP(pa_frame_size)(&stm->sample_spec);
|
||||
|
||||
frame_size = WRAP(pa_frame_size)(&stm->output_sample_spec);
|
||||
assert(nbytes % frame_size == 0);
|
||||
|
||||
towrite = nbytes;
|
||||
|
||||
read_offset = 0;
|
||||
while (towrite) {
|
||||
size = towrite;
|
||||
r = WRAP(pa_stream_begin_write)(s, &buffer, &size);
|
||||
// Note: this has failed running under rr on occassion - needs investigation.
|
||||
assert(r == 0);
|
||||
assert(size > 0);
|
||||
assert(size % frame_size == 0);
|
||||
|
||||
got = stm->data_callback(stm, stm->user_ptr, buffer, size / frame_size);
|
||||
LOG("Trigger user callback with output buffer size=%zd, read_offset=%zd\n", size, read_offset);
|
||||
got = stm->data_callback(stm, stm->user_ptr, (uint8_t const *)input_data + read_offset, buffer, size / frame_size);
|
||||
if (got < 0) {
|
||||
WRAP(pa_stream_cancel_write)(s);
|
||||
stm->shutdown = 1;
|
||||
return;
|
||||
}
|
||||
// If more iterations move offset of read buffer
|
||||
if (input_data) {
|
||||
size_t in_frame_size = WRAP(pa_frame_size)(&stm->input_sample_spec);
|
||||
read_offset += (size / frame_size) * in_frame_size;
|
||||
}
|
||||
|
||||
if (stm->volume != PULSE_NO_GAIN) {
|
||||
uint32_t samples = size * stm->sample_spec.channels / frame_size ;
|
||||
uint32_t samples = size * stm->output_sample_spec.channels / frame_size ;
|
||||
|
||||
if (stm->sample_spec.format == PA_SAMPLE_S16BE ||
|
||||
stm->sample_spec.format == PA_SAMPLE_S16LE) {
|
||||
if (stm->output_sample_spec.format == PA_SAMPLE_S16BE ||
|
||||
stm->output_sample_spec.format == PA_SAMPLE_S16LE) {
|
||||
short * b = buffer;
|
||||
for (uint32_t i = 0; i < samples; i++) {
|
||||
b[i] *= stm->volume;
|
||||
|
@ -246,6 +264,81 @@ stream_request_callback(pa_stream * s, size_t nbytes, void * u)
|
|||
assert(towrite == 0);
|
||||
}
|
||||
|
||||
static int
|
||||
read_from_input(pa_stream * s, void const ** buffer, size_t * size)
|
||||
{
|
||||
size_t readable_size = WRAP(pa_stream_readable_size)(s);
|
||||
if (readable_size > 0) {
|
||||
if (WRAP(pa_stream_peek)(s, buffer, size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return readable_size;
|
||||
}
|
||||
|
||||
static void
|
||||
stream_write_callback(pa_stream * s, size_t nbytes, void * u)
|
||||
{
|
||||
LOG("Output callback to be written buffer size %zd\n", nbytes);
|
||||
cubeb_stream * stm = u;
|
||||
if (stm->shutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stm->input_stream){
|
||||
// Output/playback only operation.
|
||||
// Write directly to output
|
||||
assert(!stm->input_stream && stm->output_stream);
|
||||
trigger_user_callback(s, NULL, nbytes, stm);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stream_read_callback(pa_stream * s, size_t nbytes, void * u)
|
||||
{
|
||||
LOG("Input callback buffer size %zd\n", nbytes);
|
||||
cubeb_stream * stm = u;
|
||||
if (stm->shutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: this has failed running under rr on occassion - needs investigation.
|
||||
assert(stm->input_stream && stm->input_sample_spec.rate != 0);
|
||||
|
||||
void const * read_data = NULL;
|
||||
size_t read_size;
|
||||
while (read_from_input(s, &read_data, &read_size) > 0) {
|
||||
/* read_data can be NULL in case of a hole. */
|
||||
if (read_data) {
|
||||
size_t in_frame_size = WRAP(pa_frame_size)(&stm->input_sample_spec);
|
||||
size_t read_frames = read_size / in_frame_size;
|
||||
|
||||
if (stm->output_stream) {
|
||||
// input/capture + output/playback operation
|
||||
size_t out_frame_size = WRAP(pa_frame_size)(&stm->output_sample_spec);
|
||||
size_t write_size = read_frames * out_frame_size;
|
||||
// Offer full duplex data for writing
|
||||
trigger_user_callback(stm->output_stream, read_data, write_size, stm);
|
||||
} else {
|
||||
// input/capture only operation. Call callback directly
|
||||
long got = stm->data_callback(stm, stm->user_ptr, read_data, NULL, read_frames);
|
||||
if (got < 0 || (size_t) got != read_frames) {
|
||||
WRAP(pa_stream_cancel_write)(s);
|
||||
stm->shutdown = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (read_size > 0) {
|
||||
WRAP(pa_stream_drop)(s);
|
||||
}
|
||||
|
||||
if (stm->shutdown) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
wait_until_context_ready(cubeb * ctx)
|
||||
{
|
||||
|
@ -261,15 +354,32 @@ wait_until_context_ready(cubeb * ctx)
|
|||
}
|
||||
|
||||
static int
|
||||
wait_until_stream_ready(cubeb_stream * stm)
|
||||
wait_until_io_stream_ready(pa_stream * stream, pa_threaded_mainloop * mainloop)
|
||||
{
|
||||
if (!stream || !mainloop){
|
||||
return -1;
|
||||
}
|
||||
for (;;) {
|
||||
pa_stream_state_t state = WRAP(pa_stream_get_state)(stm->stream);
|
||||
pa_stream_state_t state = WRAP(pa_stream_get_state)(stream);
|
||||
if (!PA_STREAM_IS_GOOD(state))
|
||||
return -1;
|
||||
if (state == PA_STREAM_READY)
|
||||
break;
|
||||
WRAP(pa_threaded_mainloop_wait)(stm->context->mainloop);
|
||||
WRAP(pa_threaded_mainloop_wait)(mainloop);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wait_until_stream_ready(cubeb_stream * stm)
|
||||
{
|
||||
if (stm->output_stream &&
|
||||
wait_until_io_stream_ready(stm->output_stream, stm->context->mainloop) == -1) {
|
||||
return -1;
|
||||
}
|
||||
if(stm->input_stream &&
|
||||
wait_until_io_stream_ready(stm->input_stream, stm->context->mainloop) == -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -290,16 +400,25 @@ operation_wait(cubeb * ctx, pa_stream * stream, pa_operation * o)
|
|||
}
|
||||
|
||||
static void
|
||||
stream_cork(cubeb_stream * stm, enum cork_state state)
|
||||
cork_io_stream(cubeb_stream * stm, pa_stream * io_stream, enum cork_state state)
|
||||
{
|
||||
pa_operation * o;
|
||||
|
||||
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
|
||||
o = WRAP(pa_stream_cork)(stm->stream, state & CORK, stream_success_callback, stm);
|
||||
if (!io_stream) {
|
||||
return;
|
||||
}
|
||||
o = WRAP(pa_stream_cork)(io_stream, state & CORK, stream_success_callback, stm);
|
||||
if (o) {
|
||||
operation_wait(stm->context, stm->stream, o);
|
||||
operation_wait(stm->context, io_stream, o);
|
||||
WRAP(pa_operation_unref)(o);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stream_cork(cubeb_stream * stm, enum cork_state state)
|
||||
{
|
||||
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
|
||||
cork_io_stream(stm, stm->output_stream, state);
|
||||
cork_io_stream(stm, stm->input_stream, state);
|
||||
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
|
||||
|
||||
if (state & NOTIFY) {
|
||||
|
@ -308,6 +427,33 @@ stream_cork(cubeb_stream * stm, enum cork_state state)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
stream_update_timing_info(cubeb_stream * stm)
|
||||
{
|
||||
int r = -1;
|
||||
pa_operation * o = NULL;
|
||||
if (stm->output_stream) {
|
||||
o = WRAP(pa_stream_update_timing_info)(stm->output_stream, stream_success_callback, stm);
|
||||
if (o) {
|
||||
r = operation_wait(stm->context, stm->output_stream, o);
|
||||
WRAP(pa_operation_unref)(o);
|
||||
}
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (stm->input_stream) {
|
||||
o = WRAP(pa_stream_update_timing_info)(stm->input_stream, stream_success_callback, stm);
|
||||
if (o) {
|
||||
r = operation_wait(stm->context, stm->input_stream, o);
|
||||
WRAP(pa_operation_unref)(o);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void pulse_context_destroy(cubeb * ctx);
|
||||
static void pulse_destroy(cubeb * ctx);
|
||||
|
||||
|
@ -485,88 +631,145 @@ pulse_destroy(cubeb * ctx)
|
|||
|
||||
static void pulse_stream_destroy(cubeb_stream * stm);
|
||||
|
||||
pa_sample_format_t
|
||||
cubeb_to_pulse_format(cubeb_sample_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
return PA_SAMPLE_S16LE;
|
||||
case CUBEB_SAMPLE_S16BE:
|
||||
return PA_SAMPLE_S16BE;
|
||||
case CUBEB_SAMPLE_FLOAT32LE:
|
||||
return PA_SAMPLE_FLOAT32LE;
|
||||
case CUBEB_SAMPLE_FLOAT32BE:
|
||||
return PA_SAMPLE_FLOAT32BE;
|
||||
default:
|
||||
return PA_SAMPLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pulse_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
|
||||
create_pa_stream(cubeb_stream * stm,
|
||||
pa_stream ** pa_stm,
|
||||
cubeb_stream_params * stream_params,
|
||||
char const * stream_name)
|
||||
{
|
||||
assert(stm && stream_params);
|
||||
*pa_stm = NULL;
|
||||
pa_sample_spec ss;
|
||||
ss.format = cubeb_to_pulse_format(stream_params->format);
|
||||
if (ss.format == PA_SAMPLE_INVALID)
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
ss.rate = stream_params->rate;
|
||||
ss.channels = stream_params->channels;
|
||||
|
||||
*pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, NULL);
|
||||
return (*pa_stm == NULL) ? CUBEB_ERROR : CUBEB_OK;
|
||||
}
|
||||
|
||||
static pa_buffer_attr
|
||||
set_buffering_attribute(unsigned int latency, pa_sample_spec * sample_spec)
|
||||
{
|
||||
pa_buffer_attr battr;
|
||||
battr.maxlength = -1;
|
||||
battr.prebuf = -1;
|
||||
battr.tlength = WRAP(pa_usec_to_bytes)(latency * PA_USEC_PER_MSEC, sample_spec);
|
||||
battr.minreq = battr.tlength / 4;
|
||||
battr.fragsize = battr.minreq;
|
||||
|
||||
LOG("Requested buffer attributes maxlength %u, tlength %u, prebuf %u, minreq %u, fragsize %u\n",
|
||||
battr.maxlength, battr.tlength, battr.prebuf, battr.minreq, battr.fragsize);
|
||||
|
||||
return battr;
|
||||
}
|
||||
|
||||
static int
|
||||
pulse_stream_init(cubeb * context,
|
||||
cubeb_stream ** stream,
|
||||
char const * stream_name,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback,
|
||||
cubeb_state_callback state_callback,
|
||||
void * user_ptr)
|
||||
{
|
||||
pa_sample_spec ss;
|
||||
cubeb_stream * stm;
|
||||
pa_operation * o;
|
||||
pa_buffer_attr battr;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
|
||||
*stream = NULL;
|
||||
|
||||
switch (stream_params.format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
ss.format = PA_SAMPLE_S16LE;
|
||||
break;
|
||||
case CUBEB_SAMPLE_S16BE:
|
||||
ss.format = PA_SAMPLE_S16BE;
|
||||
break;
|
||||
case CUBEB_SAMPLE_FLOAT32LE:
|
||||
ss.format = PA_SAMPLE_FLOAT32LE;
|
||||
break;
|
||||
case CUBEB_SAMPLE_FLOAT32BE:
|
||||
ss.format = PA_SAMPLE_FLOAT32BE;
|
||||
break;
|
||||
default:
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
// If the connection failed for some reason, try to reconnect
|
||||
if (context->error == 1 && pulse_context_init(context) != 0) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
ss.rate = stream_params.rate;
|
||||
ss.channels = stream_params.channels;
|
||||
*stream = NULL;
|
||||
|
||||
stm = calloc(1, sizeof(*stm));
|
||||
assert(stm);
|
||||
|
||||
stm->context = context;
|
||||
|
||||
stm->data_callback = data_callback;
|
||||
stm->state_callback = state_callback;
|
||||
stm->user_ptr = user_ptr;
|
||||
|
||||
stm->sample_spec = ss;
|
||||
stm->volume = PULSE_NO_GAIN;
|
||||
|
||||
battr.maxlength = -1;
|
||||
battr.tlength = WRAP(pa_usec_to_bytes)(latency * PA_USEC_PER_MSEC, &stm->sample_spec);
|
||||
battr.prebuf = -1;
|
||||
battr.minreq = battr.tlength / 4;
|
||||
battr.fragsize = -1;
|
||||
|
||||
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
|
||||
stm->stream = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, NULL);
|
||||
if (!stm->stream) {
|
||||
pulse_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
if (output_stream_params) {
|
||||
r = create_pa_stream(stm, &stm->output_stream, output_stream_params, stream_name);
|
||||
if (r != CUBEB_OK) {
|
||||
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
|
||||
pulse_stream_destroy(stm);
|
||||
return r;
|
||||
}
|
||||
|
||||
stm->output_sample_spec = *(WRAP(pa_stream_get_sample_spec)(stm->output_stream));
|
||||
|
||||
WRAP(pa_stream_set_state_callback)(stm->output_stream, stream_state_callback, stm);
|
||||
WRAP(pa_stream_set_write_callback)(stm->output_stream, stream_write_callback, stm);
|
||||
|
||||
battr = set_buffering_attribute(latency, &stm->output_sample_spec);
|
||||
WRAP(pa_stream_connect_playback)(stm->output_stream,
|
||||
output_device,
|
||||
&battr,
|
||||
PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
|
||||
PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY,
|
||||
NULL, NULL);
|
||||
}
|
||||
WRAP(pa_stream_set_state_callback)(stm->stream, stream_state_callback, stm);
|
||||
WRAP(pa_stream_set_write_callback)(stm->stream, stream_request_callback, stm);
|
||||
WRAP(pa_stream_connect_playback)(stm->stream, NULL, &battr,
|
||||
|
||||
// Set up input stream
|
||||
if (input_stream_params) {
|
||||
r = create_pa_stream(stm, &stm->input_stream, input_stream_params, stream_name);
|
||||
if (r != CUBEB_OK) {
|
||||
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
|
||||
pulse_stream_destroy(stm);
|
||||
return r;
|
||||
}
|
||||
|
||||
stm->input_sample_spec = *(WRAP(pa_stream_get_sample_spec)(stm->input_stream));
|
||||
|
||||
WRAP(pa_stream_set_state_callback)(stm->input_stream, stream_state_callback, stm);
|
||||
WRAP(pa_stream_set_read_callback)(stm->input_stream, stream_read_callback, stm);
|
||||
|
||||
battr = set_buffering_attribute(latency, &stm->input_sample_spec);
|
||||
WRAP(pa_stream_connect_record)(stm->input_stream,
|
||||
input_device,
|
||||
&battr,
|
||||
PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
|
||||
PA_STREAM_START_CORKED,
|
||||
NULL, NULL);
|
||||
PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY);
|
||||
}
|
||||
|
||||
r = wait_until_stream_ready(stm);
|
||||
if (r == 0) {
|
||||
/* force a timing update now, otherwise timing info does not become valid
|
||||
until some point after initialization has completed. */
|
||||
o = WRAP(pa_stream_update_timing_info)(stm->stream, stream_success_callback, stm);
|
||||
if (o) {
|
||||
r = operation_wait(stm->context, stm->stream, o);
|
||||
WRAP(pa_operation_unref)(o);
|
||||
}
|
||||
r = stream_update_timing_info(stm);
|
||||
}
|
||||
|
||||
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
|
||||
|
||||
if (r != 0) {
|
||||
|
@ -574,6 +777,22 @@ pulse_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
#ifdef LOGGING_ENABLED
|
||||
if (output_stream_params){
|
||||
const pa_buffer_attr * output_att;
|
||||
output_att = WRAP(pa_stream_get_buffer_attr)(stm->output_stream);
|
||||
LOG("Output buffer attributes maxlength %u, tlength %u, prebuf %u, minreq %u, fragsize %u\n",output_att->maxlength, output_att->tlength,
|
||||
output_att->prebuf, output_att->minreq, output_att->fragsize);
|
||||
}
|
||||
|
||||
if (input_stream_params){
|
||||
const pa_buffer_attr * input_att;
|
||||
input_att = WRAP(pa_stream_get_buffer_attr)(stm->input_stream);
|
||||
LOG("Input buffer attributes maxlength %u, tlength %u, prebuf %u, minreq %u, fragsize %u\n",input_att->maxlength, input_att->tlength,
|
||||
input_att->prebuf, input_att->minreq, input_att->fragsize);
|
||||
}
|
||||
#endif
|
||||
|
||||
*stream = stm;
|
||||
|
||||
return CUBEB_OK;
|
||||
|
@ -582,22 +801,28 @@ pulse_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
|
|||
static void
|
||||
pulse_stream_destroy(cubeb_stream * stm)
|
||||
{
|
||||
if (stm->stream) {
|
||||
stream_cork(stm, CORK);
|
||||
stream_cork(stm, CORK);
|
||||
|
||||
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
|
||||
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
|
||||
if (stm->output_stream) {
|
||||
|
||||
if (stm->drain_timer) {
|
||||
/* there's no pa_rttime_free, so use this instead. */
|
||||
WRAP(pa_threaded_mainloop_get_api)(stm->context->mainloop)->time_free(stm->drain_timer);
|
||||
}
|
||||
|
||||
WRAP(pa_stream_set_state_callback)(stm->stream, NULL, NULL);
|
||||
WRAP(pa_stream_disconnect)(stm->stream);
|
||||
WRAP(pa_stream_unref)(stm->stream);
|
||||
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
|
||||
WRAP(pa_stream_set_state_callback)(stm->output_stream, NULL, NULL);
|
||||
WRAP(pa_stream_disconnect)(stm->output_stream);
|
||||
WRAP(pa_stream_unref)(stm->output_stream);
|
||||
}
|
||||
|
||||
if (stm->input_stream) {
|
||||
WRAP(pa_stream_set_state_callback)(stm->input_stream, NULL, NULL);
|
||||
WRAP(pa_stream_disconnect)(stm->input_stream);
|
||||
WRAP(pa_stream_unref)(stm->input_stream);
|
||||
}
|
||||
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
|
||||
|
||||
free(stm);
|
||||
}
|
||||
|
||||
|
@ -622,12 +847,16 @@ pulse_stream_get_position(cubeb_stream * stm, uint64_t * position)
|
|||
pa_usec_t r_usec;
|
||||
uint64_t bytes;
|
||||
|
||||
if (!stm || !stm->output_stream) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
in_thread = WRAP(pa_threaded_mainloop_in_thread)(stm->context->mainloop);
|
||||
|
||||
if (!in_thread) {
|
||||
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
|
||||
}
|
||||
r = WRAP(pa_stream_get_time)(stm->stream, &r_usec);
|
||||
r = WRAP(pa_stream_get_time)(stm->output_stream, &r_usec);
|
||||
if (!in_thread) {
|
||||
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
|
||||
}
|
||||
|
@ -636,8 +865,8 @@ pulse_stream_get_position(cubeb_stream * stm, uint64_t * position)
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
bytes = WRAP(pa_usec_to_bytes)(r_usec, &stm->sample_spec);
|
||||
*position = bytes / WRAP(pa_frame_size)(&stm->sample_spec);
|
||||
bytes = WRAP(pa_usec_to_bytes)(r_usec, &stm->output_sample_spec);
|
||||
*position = bytes / WRAP(pa_frame_size)(&stm->output_sample_spec);
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
@ -648,17 +877,17 @@ pulse_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
|
|||
pa_usec_t r_usec;
|
||||
int negative, r;
|
||||
|
||||
if (!stm) {
|
||||
if (!stm || !stm->output_stream) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
r = WRAP(pa_stream_get_latency)(stm->stream, &r_usec, &negative);
|
||||
r = WRAP(pa_stream_get_latency)(stm->output_stream, &r_usec, &negative);
|
||||
assert(!negative);
|
||||
if (r) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
*latency = r_usec * stm->sample_spec.rate / PA_USEC_PER_SEC;
|
||||
*latency = r_usec * stm->output_sample_spec.rate / PA_USEC_PER_SEC;
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
|
@ -678,6 +907,10 @@ pulse_stream_set_volume(cubeb_stream * stm, float volume)
|
|||
pa_cvolume cvol;
|
||||
const pa_sample_spec * ss;
|
||||
|
||||
if (!stm->output_stream) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
|
||||
|
||||
while (!stm->context->default_sink_info) {
|
||||
|
@ -689,18 +922,18 @@ pulse_stream_set_volume(cubeb_stream * stm, float volume)
|
|||
if (stm->context->default_sink_info->flags & PA_SINK_FLAT_VOLUME) {
|
||||
stm->volume = volume;
|
||||
} else {
|
||||
ss = WRAP(pa_stream_get_sample_spec)(stm->stream);
|
||||
ss = WRAP(pa_stream_get_sample_spec)(stm->output_stream);
|
||||
|
||||
vol = WRAP(pa_sw_volume_from_linear)(volume);
|
||||
WRAP(pa_cvolume_set)(&cvol, ss->channels, vol);
|
||||
|
||||
index = WRAP(pa_stream_get_index)(stm->stream);
|
||||
index = WRAP(pa_stream_get_index)(stm->output_stream);
|
||||
|
||||
op = WRAP(pa_context_set_sink_input_volume)(stm->context->context,
|
||||
index, &cvol, volume_success,
|
||||
stm);
|
||||
if (op) {
|
||||
operation_wait(stm->context, stm->stream, op);
|
||||
operation_wait(stm->context, stm->output_stream, op);
|
||||
WRAP(pa_operation_unref)(op);
|
||||
}
|
||||
}
|
||||
|
@ -716,7 +949,11 @@ pulse_stream_set_panning(cubeb_stream * stream, float panning)
|
|||
const pa_channel_map * map;
|
||||
pa_cvolume vol;
|
||||
|
||||
map = WRAP(pa_stream_get_channel_map)(stream->stream);
|
||||
if (!stream->output_stream) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
map = WRAP(pa_stream_get_channel_map)(stream->output_stream);
|
||||
|
||||
if (!WRAP(pa_channel_map_can_balance)(map)) {
|
||||
return CUBEB_ERROR;
|
||||
|
@ -926,11 +1163,13 @@ pulse_enumerate_devices(cubeb * context, cubeb_device_type type,
|
|||
}
|
||||
|
||||
*collection = malloc(sizeof(cubeb_device_collection) +
|
||||
sizeof(cubeb_device_info*) * (user_data.count > 0 ? user_data.count - 1 : 0));
|
||||
sizeof(cubeb_device_info *) * (user_data.count > 0 ? user_data.count - 1 : 0));
|
||||
(*collection)->count = user_data.count;
|
||||
for (i = 0; i < user_data.count; i++)
|
||||
(*collection)->device[i] = user_data.devinfo[i];
|
||||
|
||||
free(user_data.default_sink_name);
|
||||
free(user_data.default_source_name);
|
||||
free(user_data.devinfo);
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
|
|
@ -170,10 +170,14 @@ sndio_destroy(cubeb *context)
|
|||
}
|
||||
|
||||
static int
|
||||
sndio_stream_init(cubeb *context,
|
||||
cubeb_stream **stream,
|
||||
char const *stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
sndio_stream_init(cubeb * context,
|
||||
cubeb_stream ** stream,
|
||||
char const * stream_name,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback,
|
||||
cubeb_state_callback state_callback,
|
||||
void *user_ptr)
|
||||
|
@ -183,6 +187,12 @@ sndio_stream_init(cubeb *context,
|
|||
DPR("sndio_stream_init(%s)\n", stream_name);
|
||||
size_t size;
|
||||
|
||||
assert(!input_stream_params && "not supported.");
|
||||
if (input_device || output_device) {
|
||||
/* Device selection not yet implemented. */
|
||||
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
s = malloc(sizeof(cubeb_stream));
|
||||
if (s == NULL)
|
||||
return CUBEB_ERROR;
|
||||
|
@ -196,7 +206,7 @@ sndio_stream_init(cubeb *context,
|
|||
sio_initpar(&wpar);
|
||||
wpar.sig = 1;
|
||||
wpar.bits = 16;
|
||||
switch (stream_params.format) {
|
||||
switch (output_stream_params->format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
wpar.le = 1;
|
||||
break;
|
||||
|
@ -210,8 +220,8 @@ sndio_stream_init(cubeb *context,
|
|||
DPR("sndio_stream_init() unsupported format\n");
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
wpar.rate = stream_params.rate;
|
||||
wpar.pchan = stream_params.channels;
|
||||
wpar.rate = output_stream_params->rate;
|
||||
wpar.pchan = output_stream_params->channels;
|
||||
wpar.appbufsz = latency * wpar.rate / 1000;
|
||||
if (!sio_setpar(s->hdl, &wpar) || !sio_getpar(s->hdl, &rpar)) {
|
||||
sio_close(s->hdl);
|
||||
|
@ -237,7 +247,7 @@ sndio_stream_init(cubeb *context,
|
|||
s->arg = user_ptr;
|
||||
s->mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
s->rdpos = s->wrpos = 0;
|
||||
if (stream_params.format == CUBEB_SAMPLE_FLOAT32LE) {
|
||||
if (output_stream_params->format == CUBEB_SAMPLE_FLOAT32LE) {
|
||||
s->conv = 1;
|
||||
size = rpar.round * rpar.pchan * sizeof(float);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013 Mozilla Foundation
|
||||
* Copyright © 2013 Mozilla Foundation
|
||||
*
|
||||
* This program is made available under an ISC-style license. See the
|
||||
* accompanying file LICENSE for details.
|
||||
|
@ -472,7 +472,7 @@ refill(cubeb_stream * stm, float * data, long frames_needed)
|
|||
dest = data;
|
||||
}
|
||||
|
||||
long out_frames = cubeb_resampler_fill(stm->resampler, dest, frames_needed);
|
||||
long out_frames = cubeb_resampler_fill(stm->resampler, NULL, dest, frames_needed);
|
||||
/* TODO: Report out_frames < 0 as an error via the API. */
|
||||
XASSERT(out_frames >= 0);
|
||||
|
||||
|
@ -1201,7 +1201,11 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
|
||||
int
|
||||
wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
||||
char const * stream_name, cubeb_stream_params stream_params,
|
||||
char const * stream_name,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency, cubeb_data_callback data_callback,
|
||||
cubeb_state_callback state_callback, void * user_ptr)
|
||||
{
|
||||
|
@ -1212,9 +1216,15 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
XASSERT(!input_stream_params && "not supported.");
|
||||
if (input_device || output_device) {
|
||||
/* Device selection not yet implemented. */
|
||||
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
XASSERT(context && stream);
|
||||
|
||||
if (stream_params.format != CUBEB_SAMPLE_FLOAT32NE) {
|
||||
if (output_stream_params->format != CUBEB_SAMPLE_FLOAT32NE) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
|
@ -1226,7 +1236,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
stm->data_callback = data_callback;
|
||||
stm->state_callback = state_callback;
|
||||
stm->user_ptr = user_ptr;
|
||||
stm->stream_params = stream_params;
|
||||
stm->stream_params = *output_stream_params;
|
||||
stm->draining = false;
|
||||
stm->latency = latency;
|
||||
stm->volume = 1.0;
|
||||
|
|
|
@ -179,7 +179,7 @@ winmm_refill_stream(cubeb_stream * stm)
|
|||
/* It is assumed that the caller is holding this lock. It must be dropped
|
||||
during the callback to avoid deadlocks. */
|
||||
LeaveCriticalSection(&stm->lock);
|
||||
got = stm->data_callback(stm, stm->user_ptr, hdr->lpData, wanted);
|
||||
got = stm->data_callback(stm, stm->user_ptr, NULL, hdr->lpData, wanted);
|
||||
EnterCriticalSection(&stm->lock);
|
||||
if (got < 0) {
|
||||
LeaveCriticalSection(&stm->lock);
|
||||
|
@ -380,7 +380,11 @@ static void winmm_stream_destroy(cubeb_stream * stm);
|
|||
|
||||
static int
|
||||
winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
cubeb_devid input_device,
|
||||
cubeb_stream_params * input_stream_params,
|
||||
cubeb_devid output_device,
|
||||
cubeb_stream_params * output_stream_params,
|
||||
unsigned int latency,
|
||||
cubeb_data_callback data_callback,
|
||||
cubeb_state_callback state_callback,
|
||||
void * user_ptr)
|
||||
|
@ -394,26 +398,32 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
|
|||
XASSERT(context);
|
||||
XASSERT(stream);
|
||||
|
||||
XASSERT(input_stream_params && "not supported.");
|
||||
if (input_device || output_device) {
|
||||
/* Device selection not yet implemented. */
|
||||
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
*stream = NULL;
|
||||
|
||||
memset(&wfx, 0, sizeof(wfx));
|
||||
if (stream_params.channels > 2) {
|
||||
if (output_stream_params->channels > 2) {
|
||||
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
wfx.Format.cbSize = sizeof(wfx) - sizeof(wfx.Format);
|
||||
} else {
|
||||
wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
if (stream_params.format == CUBEB_SAMPLE_FLOAT32LE) {
|
||||
if (output_stream_params->format == CUBEB_SAMPLE_FLOAT32LE) {
|
||||
wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
}
|
||||
wfx.Format.cbSize = 0;
|
||||
}
|
||||
wfx.Format.nChannels = stream_params.channels;
|
||||
wfx.Format.nSamplesPerSec = stream_params.rate;
|
||||
wfx.Format.nChannels = output_stream_params->channels;
|
||||
wfx.Format.nSamplesPerSec = output_stream_params->rate;
|
||||
|
||||
/* XXX fix channel mappings */
|
||||
wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
|
||||
switch (stream_params.format) {
|
||||
switch (output_stream_params->format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
wfx.Format.wBitsPerSample = 16;
|
||||
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
|
@ -446,7 +456,7 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
|
|||
|
||||
stm->context = context;
|
||||
|
||||
stm->params = stream_params;
|
||||
stm->params = *output_stream_params;
|
||||
|
||||
stm->data_callback = data_callback;
|
||||
stm->state_callback = state_callback;
|
||||
|
|
|
@ -73,10 +73,10 @@ void synth_run_float(synth_state* synth, float* audiobuffer, long nframes)
|
|||
}
|
||||
}
|
||||
|
||||
long data_cb_float(cubeb_stream *stream, void *user, void *buffer, long nframes)
|
||||
long data_cb_float(cubeb_stream *stream, void *user, const void * inputbuffer, void *outputbuffer, long nframes)
|
||||
{
|
||||
synth_state *synth = (synth_state *)user;
|
||||
synth_run_float(synth, (float*)buffer, nframes);
|
||||
synth_run_float(synth, (float*)outputbuffer, nframes);
|
||||
return nframes;
|
||||
}
|
||||
|
||||
|
@ -92,10 +92,10 @@ void synth_run_16bit(synth_state* synth, short* audiobuffer, long nframes)
|
|||
}
|
||||
}
|
||||
|
||||
long data_cb_short(cubeb_stream *stream, void *user, void *buffer, long nframes)
|
||||
long data_cb_short(cubeb_stream *stream, void *user, const void * inputbuffer, void *outputbuffer, long nframes)
|
||||
{
|
||||
synth_state *synth = (synth_state *)user;
|
||||
synth_run_16bit(synth, (short*)buffer, nframes);
|
||||
synth_run_16bit(synth, (short*)outputbuffer, nframes);
|
||||
return nframes;
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ int run_test(int num_channels, int sampling_rate, int is_float)
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "test tone", params,
|
||||
r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, ¶ms,
|
||||
100, is_float ? data_cb_float : data_cb_short, state_cb, synth);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb stream: %d\n", r);
|
||||
|
@ -212,7 +212,7 @@ int run_panning_volume_test(int is_float)
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "test tone", params,
|
||||
r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, ¶ms,
|
||||
100, is_float ? data_cb_float : data_cb_short, state_cb, synth);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb stream: %d\n", r);
|
||||
|
|
|
@ -40,13 +40,14 @@ static uint64_t total_frames_written;
|
|||
static int delay_callback;
|
||||
|
||||
static long
|
||||
test_data_callback(cubeb_stream * stm, void * user_ptr, void * p, long nframes)
|
||||
test_data_callback(cubeb_stream * stm, void * user_ptr, const void * inputbuffer, void * outputbuffer, long nframes)
|
||||
{
|
||||
assert(stm && user_ptr == &dummy && p && nframes > 0);
|
||||
assert(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
|
||||
memset(outputbuffer, 0, nframes * sizeof(short));
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
memset(p, 0, nframes * sizeof(float));
|
||||
memset(outputbuffer, 0, nframes * sizeof(float));
|
||||
#else
|
||||
memset(p, 0, nframes * sizeof(short));
|
||||
memset(outputbuffer, 0, nframes * sizeof(short));
|
||||
#endif
|
||||
|
||||
total_frames_written += nframes;
|
||||
|
@ -158,7 +159,7 @@ test_init_destroy_stream(void)
|
|||
params.rate = STREAM_RATE;
|
||||
params.channels = STREAM_CHANNELS;
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
|
||||
r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, ¶ms, STREAM_LATENCY,
|
||||
test_data_callback, test_state_callback, &dummy);
|
||||
assert(r == 0 && stream);
|
||||
|
||||
|
@ -187,7 +188,7 @@ test_init_destroy_multiple_streams(void)
|
|||
params.channels = STREAM_CHANNELS;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
|
||||
r = cubeb_stream_init(ctx, &stream[i], "test", params, STREAM_LATENCY,
|
||||
r = cubeb_stream_init(ctx, &stream[i], "test", NULL, NULL, NULL, ¶ms, STREAM_LATENCY,
|
||||
test_data_callback, test_state_callback, &dummy);
|
||||
assert(r == 0);
|
||||
assert(stream[i]);
|
||||
|
@ -219,7 +220,7 @@ test_configure_stream(void)
|
|||
params.rate = STREAM_RATE;
|
||||
params.channels = 2; // panning
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
|
||||
r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, ¶ms, STREAM_LATENCY,
|
||||
test_data_callback, test_state_callback, &dummy);
|
||||
assert(r == 0 && stream);
|
||||
|
||||
|
@ -253,7 +254,7 @@ test_init_start_stop_destroy_multiple_streams(int early, int delay_ms)
|
|||
params.channels = STREAM_CHANNELS;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
|
||||
r = cubeb_stream_init(ctx, &stream[i], "test", params, STREAM_LATENCY,
|
||||
r = cubeb_stream_init(ctx, &stream[i], "test", NULL, NULL, NULL, ¶ms, STREAM_LATENCY,
|
||||
test_data_callback, test_state_callback, &dummy);
|
||||
assert(r == 0);
|
||||
assert(stream[i]);
|
||||
|
@ -317,7 +318,7 @@ test_init_destroy_multiple_contexts_and_streams(void)
|
|||
assert(r == 0 && ctx[i]);
|
||||
|
||||
for (j = 0; j < streams_per_ctx; ++j) {
|
||||
r = cubeb_stream_init(ctx[i], &stream[i * streams_per_ctx + j], "test", params, STREAM_LATENCY,
|
||||
r = cubeb_stream_init(ctx[i], &stream[i * streams_per_ctx + j], "test", NULL, NULL, NULL, ¶ms, STREAM_LATENCY,
|
||||
test_data_callback, test_state_callback, &dummy);
|
||||
assert(r == 0);
|
||||
assert(stream[i * streams_per_ctx + j]);
|
||||
|
@ -352,7 +353,7 @@ test_basic_stream_operations(void)
|
|||
params.rate = STREAM_RATE;
|
||||
params.channels = STREAM_CHANNELS;
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
|
||||
r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, ¶ms, STREAM_LATENCY,
|
||||
test_data_callback, test_state_callback, &dummy);
|
||||
assert(r == 0 && stream);
|
||||
|
||||
|
@ -401,7 +402,7 @@ test_stream_position(void)
|
|||
params.rate = STREAM_RATE;
|
||||
params.channels = STREAM_CHANNELS;
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
|
||||
r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, ¶ms, STREAM_LATENCY,
|
||||
test_data_callback, test_state_callback, &dummy);
|
||||
assert(r == 0 && stream);
|
||||
|
||||
|
@ -474,16 +475,16 @@ static int do_drain;
|
|||
static int got_drain;
|
||||
|
||||
static long
|
||||
test_drain_data_callback(cubeb_stream * stm, void * user_ptr, void * p, long nframes)
|
||||
test_drain_data_callback(cubeb_stream * stm, void * user_ptr, const void * inputbuffer, void * outputbuffer, long nframes)
|
||||
{
|
||||
assert(stm && user_ptr == &dummy && p && nframes > 0);
|
||||
assert(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
|
||||
if (do_drain == 1) {
|
||||
do_drain = 2;
|
||||
return 0;
|
||||
}
|
||||
/* once drain has started, callback must never be called again */
|
||||
assert(do_drain != 2);
|
||||
memset(p, 0, nframes * sizeof(short));
|
||||
memset(outputbuffer, 0, nframes * sizeof(short));
|
||||
total_frames_written += nframes;
|
||||
return nframes;
|
||||
}
|
||||
|
@ -517,7 +518,7 @@ test_drain(void)
|
|||
params.rate = STREAM_RATE;
|
||||
params.channels = STREAM_CHANNELS;
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
|
||||
r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, ¶ms, STREAM_LATENCY,
|
||||
test_drain_data_callback, test_drain_state_callback, &dummy);
|
||||
assert(r == 0 && stream);
|
||||
|
||||
|
|
|
@ -34,13 +34,13 @@ struct cb_user_data {
|
|||
long position;
|
||||
};
|
||||
|
||||
long data_cb(cubeb_stream *stream, void *user, void *buffer, long nframes)
|
||||
long data_cb(cubeb_stream *stream, void *user, const void* inputbuffer, void *outputbuffer, long nframes)
|
||||
{
|
||||
struct cb_user_data *u = (struct cb_user_data *)user;
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
float *b = (float *)buffer;
|
||||
float *b = (float *)outputbuffer;
|
||||
#else
|
||||
short *b = (short *)buffer;
|
||||
short *b = (short *)outputbuffer;
|
||||
#endif
|
||||
float t1, t2;
|
||||
int i;
|
||||
|
@ -127,7 +127,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
user_data->position = 0;
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "Cubeb tone (mono)", params,
|
||||
r = cubeb_stream_init(ctx, &stream, "Cubeb tone (mono)", NULL, NULL, NULL, ¶ms,
|
||||
250, data_cb, state_cb, user_data);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb stream\n");
|
||||
|
|
Загрузка…
Ссылка в новой задаче