58 lines
3.0 KiB
C
58 lines
3.0 KiB
C
/* 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");
|
|
}
|