Merge pull request #123 from padenot/latency-frames

Latency numbers should be in frames
This commit is contained in:
Paul Adenot 2016-07-12 19:45:25 +02:00 коммит произвёл GitHub
Родитель 9d28cd3133 9bb6846d03
Коммит 240d20604b
16 изменённых файлов: 151 добавлений и 119 удалений

Просмотреть файл

@ -32,10 +32,10 @@ extern "C" {
cubeb_init(&app_ctx, "Example Application");
int rv;
int rate;
int latency_ms;
int latency_frames;
uint64_t ts;
rv = cubeb_get_min_latency(app_ctx, output_params, &latency_ms);
rv = cubeb_get_min_latency(app_ctx, output_params, &latency_frames);
if (rv != CUBEB_OK) {
fprintf(stderr, "Could not get minimum latency");
return rv;
@ -61,7 +61,7 @@ extern "C" {
rv = cubeb_stream_init(app_ctx, &stm, "Example Stream 1",
NULL, input_params,
NULL, output_params,
latency_ms,
latency_frames,
data_cb, state_cb,
NULL);
if (rv != CUBEB_OK) {
@ -284,8 +284,8 @@ typedef struct {
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; /**< Lowest possible latency in frames. */
unsigned int latency_hi; /**< Higest possible latency in frames. */
} cubeb_device_info;
/** Device collection. */
@ -363,19 +363,20 @@ char const * cubeb_get_backend_id(cubeb * context);
@retval CUBEB_ERROR */
int cubeb_get_max_channel_count(cubeb * context, uint32_t * max_channels);
/** Get the minimal latency value, in milliseconds, that is guaranteed to work
/** Get the minimal latency value, in frames, that is guaranteed to work
when creating a stream for the specified sample rate. This is platform,
hardware and backend dependant.
@param context A pointer to the cubeb context.
@param params On some backends, the minimum achievable latency depends on
the characteristics of the stream.
@param latency_ms The latency value, in ms, to pass to cubeb_stream_init.
@param latency_frames The latency value, in frames, to pass to
cubeb_stream_init.
@retval CUBEB_OK
@retval CUBEB_ERROR_INVALID_PARAMETER
@retval CUBEB_ERROR_NOT_SUPPORTED */
int cubeb_get_min_latency(cubeb * context,
cubeb_stream_params params,
uint32_t * latency_ms);
uint32_t * latency_frames);
/** Get the preferred sample rate for this backend: this is hardware and
platform dependant, and can avoid resampling, and/or trigger fastpaths.
@ -404,8 +405,8 @@ void cubeb_destroy(cubeb * context);
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 latency Stream latency in frames. Valid range
is [1, 96000].
@param data_callback Will be called to preroll data before playback is
started by cubeb_stream_start.
@param state_callback A pointer to a state callback.
@ -422,7 +423,7 @@ int cubeb_stream_init(cubeb * context,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void * user_ptr);

Просмотреть файл

@ -107,7 +107,7 @@ validate_stream_params(cubeb_stream_params * input_stream_params,
int
validate_latency(int latency)
{
if (latency < 1 || latency > 2000) {
if (latency < 1 || latency > 96000) {
return CUBEB_ERROR_INVALID_PARAMETER;
}
return CUBEB_OK;

Просмотреть файл

@ -774,7 +774,7 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
void * user_ptr)
{
@ -782,6 +782,8 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
int r;
snd_pcm_format_t format;
snd_pcm_uframes_t period_size;
int latency_us = 0;
assert(ctx && stream);
@ -845,16 +847,19 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
r = snd_pcm_nonblock(stm->pcm, 1);
assert(r == 0);
latency_us = latency_frames * 1e6 / stm->params.rate;
/* Ugly hack: the PA ALSA plugin allows buffer configurations that can't
possibly work. See https://bugzilla.mozilla.org/show_bug.cgi?id=761274.
Only resort to this hack if the handle_underrun workaround failed. */
if (!ctx->local_config && ctx->is_pa) {
latency = latency < 500 ? 500 : latency;
const int min_latency = 5e5;
latency_us = latency_us < min_latency ? min_latency: latency_us;
}
r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED,
stm->params.channels, stm->params.rate, 1,
latency * 1000);
latency_us);
if (r < 0) {
alsa_stream_destroy(stm);
return CUBEB_ERROR_INVALID_FORMAT;
@ -999,11 +1004,11 @@ alsa_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) {
}
static int
alsa_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
alsa_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
/* This is found to be an acceptable minimum, even on a super low-end
/* 40ms is found to be an acceptable minimum, even on a super low-end
* machine. */
*latency_ms = 40;
*latency_frames = 40 * params.rate / 1000;
return CUBEB_OK;
}

Просмотреть файл

@ -250,9 +250,6 @@ audiotrack_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * l
return CUBEB_ERROR;
}
/* Convert to milliseconds. */
*latency_ms = *latency_ms * 1000 / params.rate;
return CUBEB_OK;
}

Просмотреть файл

@ -705,7 +705,7 @@ audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
}
static int
audiounit_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
audiounit_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
#if TARGET_OS_IPHONE
//TODO: [[AVAudioSession sharedInstance] inputLatency]
@ -716,7 +716,7 @@ audiounit_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * la
return CUBEB_ERROR;
}
*latency_ms = ceil((latency_range.mMinimum * 1000 ) / params.rate);
*latency_frames = latency_range.mMinimum;
#endif
return CUBEB_OK;
@ -906,7 +906,7 @@ audiounit_stream_init(cubeb * context,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void * user_ptr)
@ -1127,7 +1127,7 @@ audiounit_stream_init(cubeb * context,
// Setting the latency doesn't work well for USB headsets (eg. plantronics).
// Keep the default latency for now.
#if 0
buffer_size = latency / 1000.0 * ss.mSampleRate;
buffer_size = latency;
/* Get the range of latency this particular device can work with, and clamp
* the requested latency to this acceptable range. */
@ -1768,11 +1768,11 @@ audiounit_create_device_from_hwdev(AudioObjectID devid, cubeb_device_type type)
adr.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
size = sizeof(AudioValueRange);
if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &range) == noErr) {
ret->latency_lo_ms = ((latency + range.mMinimum) * 1000) / ret->default_rate;
ret->latency_hi_ms = ((latency + range.mMaximum) * 1000) / ret->default_rate;
ret->latency_lo = latency + range.mMinimum;
ret->latency_hi = latency + range.mMaximum;
} else {
ret->latency_lo_ms = 10; /* Default to 10ms */
ret->latency_hi_ms = 100; /* Default to 100ms */
ret->latency_lo = 10 * ret->default_rate / 1000; /* Default to 10ms */
ret->latency_hi = 100 * ret->default_rate / 1000; /* Default to 100ms */
}
return ret;

Просмотреть файл

@ -85,8 +85,8 @@ extern "C"
}
static char const * cbjack_get_backend_id(cubeb * context);
static int cbjack_get_max_channel_count(cubeb * ctx, uint32_t * max_channels);
static int cbjack_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms);
static int cbjack_get_latency(cubeb_stream * stm, unsigned int * latency_ms);
static int cbjack_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames);
static int cbjack_get_latency(cubeb_stream * stm, unsigned int * latency_frames);
static int cbjack_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate);
static void cbjack_destroy(cubeb * context);
static void cbjack_interleave_capture(cubeb_stream * stream, float **in, jack_nframes_t nframes, bool format_mismatch);
@ -102,7 +102,7 @@ static int cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char cons
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void * user_ptr);
@ -307,10 +307,8 @@ cbjack_graph_order_callback(void * arg)
max_latency = 128;
}
if (cbjack_get_preferred_sample_rate(ctx, &rate) == CUBEB_ERROR)
ctx->jack_latency = (max_latency * 1000) / 48000;
else
ctx->jack_latency = (max_latency * 1000) / rate;
ctx->jack_latency = max_latency;
return 0;
}
@ -705,7 +703,7 @@ cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void * user_ptr)
@ -999,8 +997,8 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
context->devinfo[i]->min_rate = rate;
context->devinfo[i]->max_rate = rate;
context->devinfo[i]->default_rate = rate;
context->devinfo[i]->latency_lo_ms = 1;
context->devinfo[i]->latency_hi_ms = 10;
context->devinfo[i]->latency_lo = 0;
context->devinfo[i]->latency_hi = 0;
i++;
}
@ -1020,8 +1018,8 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
context->devinfo[i]->min_rate = rate;
context->devinfo[i]->max_rate = rate;
context->devinfo[i]->default_rate = rate;
context->devinfo[i]->latency_lo_ms = 1;
context->devinfo[i]->latency_hi_ms = 10;
context->devinfo[i]->latency_lo = 0;
context->devinfo[i]->latency_hi = 0;
i++;
}

Просмотреть файл

@ -241,7 +241,7 @@ kai_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency)
{
/* We have at least two buffers. One is being played, the other one is being
filled. So there is as much latency as one buffer. */
*latency = FRAME_SIZE * 1000 / params.rate;
*latency = FRAME_SIZE;
return CUBEB_OK;
}

Просмотреть файл

@ -425,7 +425,7 @@ opensl_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
}
static int
opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
/* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
* We don't want to deal with JNI here (and we don't have Java on b2g anyways),
@ -475,7 +475,7 @@ opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
/* To get a fast track in Android's mixer, we need to be at the native
* samplerate, which is device dependant. Some devices might be able to
* resample when playing a fast track, but it's pretty rare. */
*latency_ms = NBUFS * primary_buffer_size / (primary_sampling_rate / 1000);
*latency_frames = NBUFS * primary_buffer_size;
dlclose(libmedia);
@ -502,7 +502,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
void * user_ptr)
{
@ -517,11 +517,6 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
*stream = NULL;
if (output_stream_params->channels < 1 || output_stream_params->channels > 32 ||
latency < 1 || latency > 2000) {
return CUBEB_ERROR_INVALID_FORMAT;
}
SLDataFormat_PCM format;
format.formatType = SL_DATAFORMAT_PCM;
@ -627,7 +622,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
stm->outputrate = preferred_sampling_rate;
stm->bytespersec = stm->outputrate * stm->framesize;
stm->queuebuf_len = (stm->bytespersec * latency) / (1000 * NBUFS);
stm->queuebuf_len = stm->framesize * latency / NBUFS;
// round up to the next multiple of stm->framesize, if needed.
if (stm->queuebuf_len % stm->framesize) {
stm->queuebuf_len += stm->framesize - (stm->queuebuf_len % stm->framesize);

Просмотреть файл

@ -582,10 +582,10 @@ pulse_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
}
static int
pulse_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
pulse_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
// According to PulseAudio developers, this is a safe minimum.
*latency_ms = 25;
*latency_frames = 25 * params.rate / 1000;
return CUBEB_OK;
}
@ -670,12 +670,12 @@ create_pa_stream(cubeb_stream * stm,
}
static pa_buffer_attr
set_buffering_attribute(unsigned int latency, pa_sample_spec * sample_spec)
set_buffering_attribute(unsigned int latency_frames, 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.tlength = latency_frames * WRAP(pa_frame_size)(sample_spec);
battr.minreq = battr.tlength / 4;
battr.fragsize = battr.minreq;
@ -693,7 +693,7 @@ pulse_stream_init(cubeb * context,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void * user_ptr)
@ -734,7 +734,7 @@ pulse_stream_init(cubeb * context,
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);
battr = set_buffering_attribute(latency_frames, &stm->output_sample_spec);
WRAP(pa_stream_connect_playback)(stm->output_stream,
output_device,
&battr,
@ -757,7 +757,7 @@ pulse_stream_init(cubeb * context,
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);
battr = set_buffering_attribute(latency_frames, &stm->input_sample_spec);
WRAP(pa_stream_connect_record)(stm->input_stream,
input_device,
&battr,
@ -1056,8 +1056,8 @@ pulse_sink_info_cb(pa_context * context, const pa_sink_info * info,
devinfo->max_rate = PA_RATE_MAX;
devinfo->default_rate = info->sample_spec.rate;
devinfo->latency_lo_ms = 25;
devinfo->latency_hi_ms = 400;
devinfo->latency_lo = 0;
devinfo->latency_hi = 0;
pulse_ensure_dev_list_data_list_size (list_data);
list_data->devinfo[list_data->count++] = devinfo;
@ -1116,8 +1116,8 @@ pulse_source_info_cb(pa_context * context, const pa_source_info * info,
devinfo->max_rate = PA_RATE_MAX;
devinfo->default_rate = info->sample_spec.rate;
devinfo->latency_lo_ms = 1;
devinfo->latency_hi_ms = 10;
devinfo->latency_lo = 0;
devinfo->latency_hi = 0;
pulse_ensure_dev_list_data_list_size (list_data);
list_data->devinfo[list_data->count++] = devinfo;

Просмотреть файл

@ -177,7 +177,7 @@ sndio_stream_init(cubeb * context,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void *user_ptr)
@ -222,7 +222,7 @@ sndio_stream_init(cubeb * context,
}
wpar.rate = output_stream_params->rate;
wpar.pchan = output_stream_params->channels;
wpar.appbufsz = latency * wpar.rate / 1000;
wpar.appbufsz = latency_frames;
if (!sio_setpar(s->hdl, &wpar) || !sio_getpar(s->hdl, &rpar)) {
sio_close(s->hdl);
free(s);
@ -290,7 +290,7 @@ static int
sndio_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
{
// XXX Not yet implemented.
*latency_ms = 40;
*latency = 2048;
return CUBEB_OK;
}

Просмотреть файл

@ -62,23 +62,6 @@ DEFINE_PROPERTYKEY(PKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e
(sizeof(array_) / sizeof(array_[0]))
namespace {
uint32_t
ms_to_hns(uint32_t ms)
{
return ms * 10000;
}
uint32_t
hns_to_ms(REFERENCE_TIME hns)
{
return static_cast<uint32_t>(hns / 10000);
}
double
hns_to_s(REFERENCE_TIME hns)
{
return static_cast<double>(hns) / 10000000;
}
void
SafeRelease(HANDLE handle)
@ -240,7 +223,7 @@ struct cubeb_stream
/* The input and output device, or NULL for default. */
cubeb_devid input_device;
cubeb_devid output_device;
/* The latency initially requested for this stream. */
/* The latency initially requested for this stream, in frames. */
unsigned latency;
cubeb_state_callback state_callback;
cubeb_data_callback data_callback;
@ -438,6 +421,50 @@ double stream_to_mix_samplerate_ratio(cubeb_stream_params & stream, cubeb_stream
return double(stream.rate) / mixer.rate;
}
uint32_t
get_rate(cubeb_stream * stm)
{
return has_input(stm) ? stm->input_stream_params.rate
: stm->output_stream_params.rate;
}
uint32_t
ms_to_hns(uint32_t ms)
{
return ms * 10000;
}
uint32_t
hns_to_ms(REFERENCE_TIME hns)
{
return static_cast<uint32_t>(hns / 10000);
}
double
hns_to_s(REFERENCE_TIME hns)
{
return static_cast<double>(hns) / 10000000;
}
uint32_t
hns_to_frames(cubeb_stream * stm, REFERENCE_TIME hns)
{
return hns_to_ms(hns * get_rate(stm)) / 1000;
}
uint32_t
hns_to_frames(uint32_t rate, REFERENCE_TIME hns)
{
return hns_to_ms(hns * rate) / 1000;
}
REFERENCE_TIME
frames_to_hns(cubeb_stream * stm, uint32_t frames)
{
return frames * 1000 / get_rate(stm);
}
/* Upmix function, copies a mono channel into L and R */
template<typename T>
void
@ -1244,7 +1271,7 @@ wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
}
int
wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
HRESULT hr;
IAudioClient * client;
@ -1287,7 +1314,8 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
/* According to the docs, the best latency we can achieve is by synchronizing
the stream and the engine.
http://msdn.microsoft.com/en-us/library/windows/desktop/dd370871%28v=vs.85%29.aspx */
*latency_ms = hns_to_ms(default_period);
*latency_frames = hns_to_frames(params.rate, default_period);
SafeRelease(client);
@ -1476,7 +1504,7 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
hr = (*audio_client)->Initialize(AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
AUDCLNT_STREAMFLAGS_NOPERSIST,
ms_to_hns(stm->latency),
frames_to_hns(stm, stm->latency),
0,
mix_format,
NULL);
@ -1642,7 +1670,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency, cubeb_data_callback data_callback,
unsigned int latency_frames, cubeb_data_callback data_callback,
cubeb_state_callback state_callback, void * user_ptr)
{
HRESULT hr;
@ -1652,7 +1680,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
return CUBEB_ERROR;
}
XASSERT(context && stream);
XASSERT(context && stream && (input_stream_params || output_stream_params));
if (output_stream_params && output_stream_params->format != CUBEB_SAMPLE_FLOAT32NE ||
input_stream_params && input_stream_params->format != CUBEB_SAMPLE_FLOAT32NE) {
@ -1676,7 +1704,8 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
stm->output_stream_params = *output_stream_params;
stm->output_device = output_device;
}
stm->latency = latency;
stm->latency = latency_frames;
stm->volume = 1.0;
stm->stream_reset_lock = new owned_critical_section();
@ -1947,8 +1976,7 @@ int wasapi_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
if (FAILED(hr)) {
return CUBEB_ERROR;
}
double latency_s = hns_to_s(latency_hns);
*latency = static_cast<uint32_t>(latency_s * stm->output_stream_params.rate);
*latency = hns_to_frames(stm, latency_hns);
return CUBEB_OK;
}
@ -2141,11 +2169,11 @@ wasapi_create_device(IMMDeviceEnumerator * enumerator, IMMDevice * dev)
if (SUCCEEDED(dev->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&client)) &&
SUCCEEDED(client->GetDevicePeriod(&def_period, &min_period))) {
ret->latency_lo_ms = hns_to_ms(min_period);
ret->latency_hi_ms = hns_to_ms(def_period);
ret->latency_lo = hns_to_frames(ret->default_rate, min_period);
ret->latency_hi = hns_to_frames(ret->default_rate, def_period);
} else {
ret->latency_lo_ms = 0;
ret->latency_hi_ms = 0;
ret->latency_lo = 0;
ret->latency_hi = 0;
}
SafeRelease(client);

Просмотреть файл

@ -89,7 +89,7 @@ struct cubeb {
PSLIST_HEADER work;
CRITICAL_SECTION lock;
unsigned int active_streams;
unsigned int minimum_latency;
unsigned int minimum_latency_ms;
};
struct cubeb_stream {
@ -336,7 +336,7 @@ winmm_init(cubeb ** context, char const * context_name)
InitializeCriticalSection(&ctx->lock);
ctx->active_streams = 0;
ctx->minimum_latency = calculate_minimum_latency();
ctx->minimum_latency_ms = calculate_minimum_latency();
*context = ctx;
@ -384,7 +384,7 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void * user_ptr)
@ -467,11 +467,13 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
stm->user_ptr = user_ptr;
stm->written = 0;
if (latency < context->minimum_latency) {
latency = context->minimum_latency;
uint32_t latency_ms = latency_frames * 1000 / output_stream_params->rate;
if (latency_ms < context->minimum_latency_ms) {
latency_ms = context->minimum_latency_ms;
}
bufsz = (size_t) (stm->params.rate / 1000.0 * latency * bytes_per_frame(stm->params) / NBUFS);
bufsz = (size_t) (stm->params.rate / 1000.0 * latency_ms * bytes_per_frame(stm->params) / NBUFS);
if (bufsz % bytes_per_frame(stm->params) != 0) {
bufsz += bytes_per_frame(stm->params) - (bufsz % bytes_per_frame(stm->params));
}
@ -600,7 +602,7 @@ static int
winmm_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency)
{
// 100ms minimum, if we are not in a bizarre configuration.
*latency = ctx->minimum_latency;
*latency = ctx->minimum_latency_ms * params.rate / 1000;
return CUBEB_OK;
}
@ -854,8 +856,8 @@ winmm_create_device_from_outcaps2(LPWAVEOUTCAPS2A caps, UINT devid)
&ret->format, &ret->default_format);
/* Hardcoed latency estimates... */
ret->latency_lo_ms = 100;
ret->latency_hi_ms = 200;
ret->latency_lo = 100 * ret->default_rate / 1000;
ret->latency_hi = 200 * ret->default_rate / 1000;
return ret;
}
@ -885,8 +887,8 @@ winmm_create_device_from_outcaps(LPWAVEOUTCAPSA caps, UINT devid)
&ret->format, &ret->default_format);
/* Hardcoed latency estimates... */
ret->latency_lo_ms = 100;
ret->latency_hi_ms = 200;
ret->latency_lo = 100 * ret->default_rate / 1000;
ret->latency_hi = 200 * ret->default_rate / 1000;
return ret;
}
@ -935,8 +937,8 @@ winmm_create_device_from_incaps2(LPWAVEINCAPS2A caps, UINT devid)
&ret->format, &ret->default_format);
/* Hardcoed latency estimates... */
ret->latency_lo_ms = 100;
ret->latency_hi_ms = 200;
ret->latency_lo = 100 * ret->default_rate / 1000;
ret->latency_hi = 200 * ret->default_rate / 1000;
return ret;
}
@ -966,8 +968,8 @@ winmm_create_device_from_incaps(LPWAVEINCAPSA caps, UINT devid)
&ret->format, &ret->default_format);
/* Hardcoed latency estimates... */
ret->latency_lo_ms = 100;
ret->latency_hi_ms = 200;
ret->latency_lo = 100 * ret->default_rate / 1000;
ret->latency_hi = 200 * ret->default_rate / 1000;
return ret;
}

Просмотреть файл

@ -89,14 +89,14 @@ print_device_info(cubeb_device_info * info, FILE * f)
"\tCh: %u\n"
"\tFormat: %s (0x%x) (default: %s)\n"
"\tRate: %u - %u (default: %u)\n"
"\tLatency: lo %ums, hi %ums\n",
"\tLatency: lo %u frames, hi %u frames\n",
info->device_id, info->preferred ? " (PREFERRED)" : "",
info->friendly_name, info->group_id, info->vendor_name,
devtype, devstate, info->max_channels,
(devfmts[0] == ' ') ? &devfmts[1] : devfmts,
(unsigned int)info->format, devdeffmt,
info->min_rate, info->max_rate, info->default_rate,
info->latency_lo_ms, info->latency_hi_ms);
info->latency_lo, info->latency_hi);
}
static void
@ -125,6 +125,12 @@ run_enumerate_devices(void)
cubeb_get_backend_id(ctx));
r = cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_INPUT, &collection);
if (r == CUBEB_ERROR_NOT_SUPPORTED) {
fprintf(stderr, "Device enumeration not supported"
" for this backend, skipping this test.\n");
r = CUBEB_OK;
goto cleanup;
}
if (r != CUBEB_OK) {
fprintf(stderr, "Error enumerating devices %d\n", r);
goto cleanup;

Просмотреть файл

@ -101,7 +101,7 @@ int main(int argc, char *argv[])
cubeb_stream_params output_params;
int r;
user_state stream_state = { false };
uint32_t latency_ms = 0;
uint32_t latency_frames = 0;
r = cubeb_init(&ctx, "Cubeb duplex example");
if (r != CUBEB_OK) {
@ -123,7 +123,7 @@ int main(int argc, char *argv[])
output_params.rate = 48000;
output_params.channels = 2;
r = cubeb_get_min_latency(ctx, output_params, &latency_ms);
r = cubeb_get_min_latency(ctx, output_params, &latency_frames);
if (r != CUBEB_OK) {
fprintf(stderr, "Could not get minimal latency\n");
@ -132,7 +132,7 @@ int main(int argc, char *argv[])
r = cubeb_stream_init(ctx, &stream, "Cubeb duplex",
NULL, &input_params, NULL, &output_params,
latency_ms, data_cb, state_cb, &stream_state);
latency_frames, data_cb, state_cb, &stream_state);
if (r != CUBEB_OK) {
fprintf(stderr, "Error initializing cubeb stream\n");
return r;

Просмотреть файл

@ -21,7 +21,7 @@ int main(int argc, char * argv[])
int r;
uint32_t max_channels;
uint32_t preferred_rate;
uint32_t latency_ms;
uint32_t latency_frames;
LOG("latency_test start");
r = cubeb_init(&ctx, "Cubeb audio test");
@ -47,10 +47,10 @@ int main(int argc, char * argv[])
preferred_rate,
max_channels
};
r = cubeb_get_min_latency(ctx, params, &latency_ms);
r = cubeb_get_min_latency(ctx, params, &latency_frames);
assert(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
if (r == CUBEB_OK) {
assert(latency_ms > 0 && "Invalid minimal latency.");
assert(latency_frames > 0 && "Invalid minimal latency.");
LOG("cubeb_get_min_latency ok");
}

Просмотреть файл

@ -26,8 +26,8 @@
#define BEGIN_TEST fprintf(stderr, "START %s\n", __func__)
#define END_TEST fprintf(stderr, "END %s\n", __func__)
#define STREAM_LATENCY 100
#define STREAM_RATE 44100
#define STREAM_LATENCY 100 * STREAM_RATE / 1000
#define STREAM_CHANNELS 1
#if (defined(_WIN32) || defined(__WIN32__))
#define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE