You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
57 lines
3.0 KiB
57 lines
3.0 KiB
/* PA snapshot без сервера: несколько converter callbacks принадлежат одному physical PCM-блоку. */ |
|
#define MA_DATA_CONVERTER_STACK_BUFFER_SIZE 128 |
|
#include "../transport/miniaudio_impl.c" |
|
#include <assert.h> |
|
#include <stdio.h> |
|
static int64_t times[64]; |
|
static unsigned counts[64], seen; |
|
static int capture_missing; |
|
static int fake_latency(const void* stream, uint64_t* latency, int* negative) { |
|
(void)stream; *latency = 100000; *negative = 0; return 0; |
|
} |
|
static void observe(ma_device* device, void* output, const void* input, ma_uint32 frames) { |
|
(void)output; (void)input; |
|
int measured = 0; |
|
assert(seen < 64); |
|
times[seen] = audio_stream_frame_time(device, frames, &measured); |
|
counts[seen++] = frames; |
|
assert(measured && seen < 64); |
|
assert(audio_stream_capture_missing(device) == capture_missing); |
|
} |
|
static int64_t time_us(void) { |
|
struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); |
|
return now.tv_sec * INT64_C(1000000) + now.tv_nsec / 1000; |
|
} |
|
int main(void) { |
|
/* Только dispatch/converter: backend union не подменяется у живого null-device. */ |
|
ma_context context = {0}; ma_device device = {0}; |
|
device.pContext = &context; device.type = ma_device_type_capture; |
|
device.sampleRate = 48000; device.noFixedSizedCallback = MA_TRUE; device.onData = observe; |
|
device.capture.format = ma_format_s16; device.capture.channels = 1; |
|
device.capture.internalFormat = ma_format_f32; device.capture.internalChannels = 2; |
|
assert(ma_device_set_master_volume(&device, 1) == MA_SUCCESS); |
|
ma_data_converter_config converter = ma_data_converter_config_init(ma_format_f32, ma_format_s16, 2, 1, 48000, 48000); |
|
assert(ma_data_converter_init(&converter, NULL, &device.capture.converter) == MA_SUCCESS); |
|
device.capture.internalSampleRate = 48000; |
|
context.backend = ma_backend_pulseaudio; |
|
context.pulse.pa_stream_get_latency = (ma_proc)fake_latency; |
|
device.pulse.pStreamCapture = (void*)1; |
|
float input[180 * 2] = {0}; |
|
int64_t now = time_us(); |
|
assert(ma_device_handle_backend_data_callback(&device, NULL, input, 180) == MA_SUCCESS); |
|
int64_t after = time_us(); |
|
assert(seen == 3 && counts[0] == 64 && counts[1] == 64 && counts[2] == 52); |
|
assert(times[0] >= now - 100000 && times[0] <= after - 100000); |
|
for (unsigned i = 1; i < seen; ++i) { |
|
int64_t difference = times[i] - times[0] - (int64_t)i * 64 * 1000000 / 48000; |
|
assert(difference >= -1 && difference <= 1); |
|
} |
|
capture_missing = 1; seen = 0; audio_capture_hole(120); |
|
now = time_us(); |
|
assert(ma_device_handle_backend_data_callback(&device, NULL, input, 64) == MA_SUCCESS); |
|
after = time_us(); |
|
assert(seen == 1 && times[0] >= now - 100000 + 2500 && times[0] <= after - 100000 + 2500); |
|
assert(!audio_stream_capture_missing(&device)); // Hint действует только внутри dispatch. |
|
ma_data_converter_uninit(&device.capture.converter, NULL); |
|
puts("audio timing: capture read index, converter offsets, explicit hole PASS"); |
|
}
|
|
|