From 8458ec65f4b1972de101db9328596982ed4340b4 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Thu, 20 Aug 2026 21:53:08 +0300 Subject: [PATCH] =?UTF-8?q?libc/cbl:=20=D0=B4=D0=B2=D0=B5=20=D1=82=D0=BE?= =?UTF-8?q?=D1=87=D0=BA=D0=B8=20=D0=B2=D1=85=D0=BE=D0=B4=D0=B0=20=D0=B2?= =?UTF-8?q?=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20underrun=5Fmode=20=E2=80=94=20?= =?UTF-8?q?malloc=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=B2=20=D1=80=D0=B5=D0=B7=D0=B8=D0=B4=D0=B5=D0=BD=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Линкер тянет .rel целиком, поэтому malloc/free, стоявшие в мёртвой ветке CBL_UNDERRUN_SILENCE внутри cbl_open, приезжали в резидент КАЖДОМУ приложению — включая те, что льют тишину сами и кучей не пользуются. Разведено: cbl_open(freq, fmt, pump, fill) — ничего не аллоцирует; cbl_open_silence(freq, fmt, pump, fill) — аллоцирует буфер тишины; _cbl_open_raw(...) — общее тело. Параметр underrun_mode из публичного API убран: режим задаёт выбор функции. cbl_close больше не зовёт free — иначе malloc возвращался бы тем же путём. Буфер тишины живёт до выхода из программы и переиспользуется; его размер запоминается, иначе открытие 16-бит после 8-бит писало бы memset'ом мимо выделенного куска. _cbl_open_raw указатель на буфер не трогает вовсе — иначе cbl_open после cbl_open_silence терял бы уже выделенную память. В дереве режим SILENCE не использовал никто: все три вызова (cblwav, cblstream, PoP) передавали CBL_UNDERRUN_APP. Итог для PoP: _CODE 24329 -> 23716 (−613 Б), свободно в резиденте 129 -> 747 Б. make size-check чистый (67 программ), звук в MAME проверен — насос отработал 696 запросов, pop_snd_ok/want = 1/1. Co-Authored-By: Claude Opus 5 --- applications/PoP/roomtest/pop_sfx_cold.c | 9 +-- docs/libc-reference.md | 3 +- libc/cbl/_cbl.h | 6 ++ libc/cbl/_cbl_open_raw.c | 78 +++++++++++++++++++++ libc/cbl/cbl_close.c | 13 ++-- libc/cbl/cbl_open.c | 86 ++---------------------- libc/cbl/cbl_open_silence.c | 37 ++++++++++ libc/include/cbl.h | 42 ++++++++---- tests/cblstream/cblstream.c | 2 +- tests/cblwav/cblwav.c | 2 +- 10 files changed, 172 insertions(+), 106 deletions(-) create mode 100644 libc/cbl/_cbl_open_raw.c create mode 100644 libc/cbl/cbl_open_silence.c diff --git a/applications/PoP/roomtest/pop_sfx_cold.c b/applications/PoP/roomtest/pop_sfx_cold.c index cdecf55..8420bf5 100644 --- a/applications/PoP/roomtest/pop_sfx_cold.c +++ b/applications/PoP/roomtest/pop_sfx_cold.c @@ -48,16 +48,17 @@ int pop_sfx_init(void) __banked * * Параметры: 10 937,5 Гц, 8 бит моно — формат данных один в один * (sound_plan.md). OTIR, а не акселератор: тот нужен только для 16 бит. - * UNDERRUN_APP, а не SILENCE: тишину насос льёт СВОЮ (первый блок - * набора), и просить у libc буфер через malloc не надо — куча в - * резиденте W2 тесная, и её отказ ронял бы весь звук. */ + * cbl_open, а не cbl_open_silence: тишину насос льёт СВОЮ (первый блок + * набора), и просить у libc буфер через malloc не надо — куча в резиденте + * W2 тесная, и её отказ ронял бы весь звук. Заодно так malloc вообще не + * приезжает в резидент (275 Б, см. libc/cbl/_cbl_open_raw.c). */ int pop_sfx_start(void) __banked { if (pop_snd_ok) return 0; if (!pop_snd_want) return 0; /* выключено пользователем (Ctrl+S) */ if (!snd_blk) return -1; /* набор не загружен */ if (cbl_open(CBL_FREQ_10K9, CBL_FMT_MONO8, CBL_PUMP_OTIR, - CBL_UNDERRUN_APP, pop_sfx_fill) != 0) + pop_sfx_fill) != 0) return -1; pop_snd_ok = 1; return 0; diff --git a/docs/libc-reference.md b/docs/libc-reference.md index 58ae0ae..5be56e8 100644 --- a/docs/libc-reference.md +++ b/docs/libc-reference.md @@ -395,7 +395,8 @@ applications/PoP/docs/PORT_PLAN.md §2 — пользователь подтве | Сигнатура | Описание | |---|---| -| `int cbl_open(freq_code, fmt, pump_mode, underrun_mode, fill)` | включить CBL (`0x90\|fmt\|freq`), зарегистрировать callback; 0 / -1+errno (EBUSY повтор, EINVAL — freq/fmt/pump_mode/underrun_mode плохие или OTIR+16-бит, ENOMEM — буфер тишины) | +| `int cbl_open(freq_code, fmt, pump_mode, fill)` | включить CBL (`0x90\|fmt\|freq`), зарегистрировать callback; недолив — забота приложения; **malloc не тянет**; 0 / -1+errno (EBUSY повтор, EINVAL — freq/fmt/pump_mode плохие или OTIR+16-бит) | +| `int cbl_open_silence(freq_code, fmt, pump_mode, fill)` | то же, но тишину при недоливе шлёт libc из своего буфера; ТОЛЬКО этот вариант тянет malloc (+ENOMEM). Буфер не освобождается — живёт до выхода | | `void cbl_close(void)` | выключить CBL, снять хук, освободить буфер тишины (если был); висит на atexit | | `void cbl_push_otir(const void *src, uint16_t n)` | пропихнуть n байт через `otir` в порт 0x4F; звать ИЗ fill() | | `void cbl_push_accel(const void *src, uint16_t n)` | то же акселератором (страница EMM 0xFD@0xC000); единственный путь для 16-бит | diff --git a/libc/cbl/_cbl.h b/libc/cbl/_cbl.h index 20075ac..c69e050 100644 --- a/libc/cbl/_cbl.h +++ b/libc/cbl/_cbl.h @@ -55,6 +55,12 @@ extern uint8_t _cbl_port_refs; /* держатели bit7 помимо /* Запись в 16-битный порт управления 0x004E. */ void _cbl_ctrl(uint8_t v); +/* Общее тело обеих публичных точек входа (cbl_open / cbl_open_silence). + * Буфер тишины не трогает — им владеет cbl_open_silence.c; так malloc не + * приезжает в резидент приложениям, которые льют тишину сами. */ +int _cbl_open_raw(uint8_t freq_code, uint8_t fmt, uint8_t pump_mode, + uint8_t underrun_mode, cbl_fill_fn fill); + /* Залить весь аппаратный буфер (256 слотов) байтом тишины сразу после * включения — иначе первые 23 мс играет то, что лежало в буфере раньше. * Подробный разбор — в шапке _cbl_prime.c. */ diff --git a/libc/cbl/_cbl_open_raw.c b/libc/cbl/_cbl_open_raw.c new file mode 100644 index 0000000..690b872 --- /dev/null +++ b/libc/cbl/_cbl_open_raw.c @@ -0,0 +1,78 @@ +/* + * _cbl_open_raw — общее тело обеих точек входа CBL (cbl_open и + * cbl_open_silence). Проверяет параметры, вешает насос и включает железо. + * + * ПОЧЕМУ ТОЧЕК ВХОДА ДВЕ, а не один параметр underrun_mode. Линкер тянет + * .rel ЦЕЛИКОМ, поэтому malloc/free, стоящие в ветке CBL_UNDERRUN_SILENCE, + * приезжали в резидент КАЖДОМУ приложению — даже тому, которое льёт тишину + * само и кучей не пользуется вовсе. Это 275 Б кода плюс вся область кучи; + * в huge-режиме, где под резидент отведено 0x4100..0xBB00, такая мелочь + * заметна (у PoP оставалось 129 Б свободных). Разведя аллокацию в отдельный + * публичный модуль, мы отдаём выбор линкеру: зовёшь cbl_open — malloc не + * приезжает. + * + * Указатель на буфер тишины (_cbl_silence) здесь НЕ ТРОГАЕТСЯ: им владеет + * cbl_open_silence.c, который его и аллоцирует. В режиме APP насос на него + * не смотрит вовсе (условие в _cbl_pump_*), а обнуляй мы его тут — cbl_open + * после cbl_open_silence терял бы уже выделенный буфер, и следующая + * silence-сессия аллоцировала бы второй. + */ + +#include +#include +#include "_cbl.h" +#include "../irq/_irq.h" + +int _cbl_open_raw(uint8_t freq_code, uint8_t fmt, uint8_t pump_mode, + uint8_t underrun_mode, cbl_fill_fn fill) +{ + if (_irq_cbl_hook) { errno = EBUSY; return -1; } + if (freq_code < CBL_FREQ_7K8 || freq_code > CBL_FREQ_109K) { + errno = EINVAL; + return -1; + } + if (fmt & (uint8_t)~(CBL_FMT_MONO16 | CBL_FMT_STEREO8)) { + errno = EINVAL; /* биты вне 5/6 — неизвестный формат */ + return -1; + } + if (pump_mode != CBL_PUMP_OTIR && pump_mode != CBL_PUMP_ACCEL) { + errno = EINVAL; + return -1; + } + /* ЗАПРЕТ CBL_PUMP_OTIR + 16-бит (подтверждено чтением исходника MAME + * sprinter.cpp): порт данных 0x4F ВСЕГДА кладёт байт как есть в один + * слот, не собирая пару байт в 16-бит значение и не сверяясь с + * cbl_mode16() вообще — это умеет только акселераторный путь (спец- + * страница 0xFD, do_accel_block). Комбинация принципиально не может + * звучать правильно, поэтому запрещена. */ + if (pump_mode == CBL_PUMP_OTIR && (fmt & CBL_FMT_MONO16)) { + errno = EINVAL; + return -1; + } + + if (_irq_table_ref() != 0) return -1; + + _cbl_block = (fmt & CBL_FMT_MONO16) ? 256u : 128u; + _cbl_reqs = 0; + _cbl_undr = 0; + _cbl_fill = fill; + _cbl_underrun_mode = underrun_mode; + + static uint8_t atexit_armed; + if (!atexit_armed) { + atexit_armed = 1; + atexit(cbl_close); /* CBL обязан умолкнуть до шелла */ + } + + IRQ_DISABLE(); + _irq_cbl_hook = (pump_mode == CBL_PUMP_ACCEL) ? _cbl_pump_accel : _cbl_pump_otir; + _cbl_ctrl((uint8_t)(0x90 | fmt | freq_code)); /* on + int + формат + частота */ + /* ...и НЕМЕДЛЕННО забить буфер тишиной: железо пускает воспроизведение + * с нулевого слота той же записью в порт управления, а буфер хранит + * старое содержимое — без этого первые 23 мс уходит мусор. Заливка + * обязана быть внутри той же DI-скобки и сразу за включением (разбор — + * _cbl_prime.c). */ + _cbl_prime((uint8_t)((fmt & CBL_FMT_MONO16) ? 0x00 : 0x80)); + IRQ_ENABLE(); + return 0; +} diff --git a/libc/cbl/cbl_close.c b/libc/cbl/cbl_close.c index 87dce09..1e700d2 100644 --- a/libc/cbl/cbl_close.c +++ b/libc/cbl/cbl_close.c @@ -1,7 +1,11 @@ /* - * cbl_close — выключить CBL, снять хук насоса, освободить буфер - * тишины (если был аллоцирован под CBL_UNDERRUN_SILENCE) и отпустить - * IM2-таблицу. Идемпотентно; вызывается и из atexit. + * cbl_close — выключить CBL, снять хук насоса и отпустить IM2-таблицу. + * Идемпотентно; вызывается и из atexit. + * + * БУФЕР ТИШИНЫ НЕ ОСВОБОЖДАЕТСЯ. Раньше здесь стоял free(_cbl_silence), и + * он один тянул malloc/free в резидент КАЖДОМУ приложению — включая те, что + * cbl_open_silence() не зовут вовсе. Буфер живёт до выхода из программы и + * переиспользуется при повторном открытии (см. cbl_open_silence.c). * * Порт 0x004E не гасится напрямую — вместо этого _cbl_port_sync() * пересчитывает нужное значение: если gfx_wait_vsync() ещё держит @@ -9,7 +13,6 @@ * синхронизации; иначе порт гасится полностью. */ -#include #include "_cbl.h" #include "../irq/_irq.h" @@ -20,7 +23,5 @@ void cbl_close(void) _irq_cbl_hook = 0; IRQ_ENABLE(); _cbl_port_sync(); - free(_cbl_silence); - _cbl_silence = 0; _irq_table_unref(); } diff --git a/libc/cbl/cbl_open.c b/libc/cbl/cbl_open.c index d58e71c..3e9ccf8 100644 --- a/libc/cbl/cbl_open.c +++ b/libc/cbl/cbl_open.c @@ -1,89 +1,15 @@ /* - * cbl_open — включить CBL, зарегистрировать fill()-callback и один - * из ISR-насосов. + * cbl_open — включить CBL, когда тишину при недоливе льёт САМО ПРИЛОЖЕНИЕ + * (режим CBL_UNDERRUN_APP). Буфера не просит, поэтому НЕ ТЯНЕТ malloc — + * ради этого точки входа и разведены (см. шапку _cbl_open_raw.c). * - * Управляющее слово: bit7 (CBL on) + bit4 (int enable) + fmt (bit6 - * stereo, bit5 16-бит) + freq_code. Размер блока/буфер тишины - * зависят от fmt и underrun_mode (см. cbl.h). cbl_close вешается на - * atexit. - * - * ЗАПРЕТ CBL_PUMP_OTIR + 16-бит (подтверждено чтением исходника MAME - * sprinter.cpp): порт данных 0x4F ВСЕГДА кладёт байт как есть в один - * слот, не собирая пару байт в 16-бит значение и не сверяясь с - * cbl_mode16() вообще — это умеет только акселераторный путь (спец- - * страница 0xFD, do_accel_block). Комбинация принципиально не может - * звучать правильно, поэтому запрещена (EINVAL). Для 16-бит — - * CBL_PUMP_ACCEL. + * Если тишина нужна от libc — cbl_open_silence() в соседнем модуле. */ -#include -#include -#include -#include #include "_cbl.h" -#include "../irq/_irq.h" int cbl_open(uint8_t freq_code, uint8_t fmt, uint8_t pump_mode, - uint8_t underrun_mode, cbl_fill_fn fill) + cbl_fill_fn fill) { - if (_irq_cbl_hook) { errno = EBUSY; return -1; } - if (freq_code < CBL_FREQ_7K8 || freq_code > CBL_FREQ_109K) { - errno = EINVAL; - return -1; - } - if (fmt & (uint8_t)~(CBL_FMT_MONO16 | CBL_FMT_STEREO8)) { - errno = EINVAL; /* биты вне 5/6 — неизвестный формат */ - return -1; - } - if (pump_mode != CBL_PUMP_OTIR && pump_mode != CBL_PUMP_ACCEL) { - errno = EINVAL; - return -1; - } - if (pump_mode == CBL_PUMP_OTIR && (fmt & CBL_FMT_MONO16)) { - errno = EINVAL; /* OTIR не может собрать 16-бит сэмпл — только ACCEL */ - return -1; - } - if (underrun_mode != CBL_UNDERRUN_APP && underrun_mode != CBL_UNDERRUN_SILENCE) { - errno = EINVAL; - return -1; - } - - uint16_t block = (fmt & CBL_FMT_MONO16) ? 256u : 128u; - - uint8_t *silence = 0; - if (underrun_mode == CBL_UNDERRUN_SILENCE) { - silence = malloc(block); - if (!silence) { errno = ENOMEM; return -1; } - memset(silence, (fmt & CBL_FMT_MONO16) ? 0x00 : 0x80, block); - } - - if (_irq_table_ref() != 0) { - free(silence); - return -1; - } - - _cbl_block = block; - _cbl_reqs = 0; - _cbl_undr = 0; - _cbl_fill = fill; - _cbl_underrun_mode = underrun_mode; - _cbl_silence = silence; - - static uint8_t atexit_armed; - if (!atexit_armed) { - atexit_armed = 1; - atexit(cbl_close); /* CBL обязан умолкнуть до шелла */ - } - - IRQ_DISABLE(); - _irq_cbl_hook = (pump_mode == CBL_PUMP_ACCEL) ? _cbl_pump_accel : _cbl_pump_otir; - _cbl_ctrl((uint8_t)(0x90 | fmt | freq_code)); /* on + int + формат + частота */ - /* ...и НЕМЕДЛЕННО забить буфер тишиной: железо пускает воспроизведение - * с нулевого слота той же записью в порт управления, а буфер хранит - * старое содержимое — без этого первые 23 мс уходит мусор. Заливка - * обязана быть внутри той же DI-скобки и сразу за включением (разбор — - * _cbl_prime.c). */ - _cbl_prime((uint8_t)((fmt & CBL_FMT_MONO16) ? 0x00 : 0x80)); - IRQ_ENABLE(); - return 0; + return _cbl_open_raw(freq_code, fmt, pump_mode, CBL_UNDERRUN_APP, fill); } diff --git a/libc/cbl/cbl_open_silence.c b/libc/cbl/cbl_open_silence.c new file mode 100644 index 0000000..fb36a65 --- /dev/null +++ b/libc/cbl/cbl_open_silence.c @@ -0,0 +1,37 @@ +/* + * cbl_open_silence — то же, что cbl_open, но при недоливе тишину шлёт САМА + * libc: буфер под неё аллоцируется здесь. Именно этот модуль тянет malloc, + * поэтому приложения на cbl_open() за него не платят. + * + * БУФЕР НЕ ОСВОБОЖДАЕТСЯ. cbl_close() его не трогает намеренно: free() + * в cbl_close вернул бы malloc в резидент всем подряд — ровно то, от чего + * уходили. Потеря невелика (128 или 256 байт), а при повторном открытии + * буфер переиспользуется; окончательно память возвращает выход из + * программы. + */ + +#include +#include +#include +#include "_cbl.h" + +/* Сколько байт под буфером сейчас лежит. Помнить обязательно: у 8-бит + * формата блок 128, у 16-бит — 256, и открытие 16-бит ПОСЛЕ 8-бит писало бы + * memset'ом мимо выделенного куска. */ +static uint16_t silence_cap; + +int cbl_open_silence(uint8_t freq_code, uint8_t fmt, uint8_t pump_mode, + cbl_fill_fn fill) +{ + uint16_t block = (fmt & CBL_FMT_MONO16) ? 256u : 128u; + uint8_t quiet = (fmt & CBL_FMT_MONO16) ? 0x00 : 0x80; + + if (silence_cap < block) { + uint8_t *p = malloc(block); + if (!p) { errno = ENOMEM; return -1; } + _cbl_silence = p; /* прежний кусок не освобождаем — см. шапку */ + silence_cap = block; + } + memset(_cbl_silence, quiet, block); + return _cbl_open_raw(freq_code, fmt, pump_mode, CBL_UNDERRUN_SILENCE, fill); +} diff --git a/libc/include/cbl.h b/libc/include/cbl.h index e8c134d..3c23ea5 100644 --- a/libc/include/cbl.h +++ b/libc/include/cbl.h @@ -44,13 +44,14 @@ * кладёт байт как есть в один слот, не собирая пару байт в 16-бит * значение — это умеет только акселераторный путь (страница 0xFD). * - * Поведение при недоливе — CBL_UNDERRUN_* (4-й параметр cbl_open): + * Поведение при недоливе задаётся ВЫБОРОМ ТОЧКИ ВХОДА (cbl_open / + * cbl_open_silence), а не параметром: * CBL_UNDERRUN_APP (по умолчанию, 0) — недолив не наша забота; * в CBL доигрывает то, что уже лежит в его буфере (никакого * буфера тишины не аллоцируется). * CBL_UNDERRUN_SILENCE (1) — насос сам пропихивает тишину при * недоливе; буфер тишины (128/256 Б по формату) аллоцируется - * malloc'ом ВНУТРИ cbl_open(), только в этом режиме. + * malloc'ом внутри cbl_open_silence(), только в этом режиме. * cbl_underruns() считает недоливы в ОБОИХ режимах — это диагностика, * поведение не меняет. * @@ -89,8 +90,10 @@ #define CBL_PUMP_ACCEL 1 /* cbl_push_accel() — единственный путь для 16-бит */ /* Поведение при недоливе (fill() вернул 0 или не задан). */ -#define CBL_UNDERRUN_APP 0 /* по умолчанию: не наша забота, буфер тишины не аллоцируется */ -#define CBL_UNDERRUN_SILENCE 1 /* насос сам шлёт тишину; буфер аллоцируется в cbl_open() */ +/* Внутренние коды режима недолива: приложение их не передаёт (режим задаёт + * выбор cbl_open / cbl_open_silence), но насос по ним и различает поведение. */ +#define CBL_UNDERRUN_APP 0 /* не наша забота, буфер тишины не аллоцируется */ +#define CBL_UNDERRUN_SILENCE 1 /* насос сам шлёт тишину из буфера libc */ /* fill(n): пропихнуть n байт (через cbl_push_otir/accel) прямо из * данных приложения. Вызывается ИЗ ISR — обязан быть быстрым (без @@ -98,17 +101,30 @@ * данных сейчас (недолив). */ typedef int (*cbl_fill_fn)(uint16_t n); -/* Включить CBL с частотой CBL_FREQ_*, форматом CBL_FMT_*, способом - * выдачи CBL_PUMP_* и поведением при недоливе CBL_UNDERRUN_*; fill — - * callback, зовущийся из ISR за новым блоком (может быть NULL, тогда - * недолив — на каждом запросе). 0 или -1 + errno (EBUSY — уже - * открыт; EINVAL — плохой код частоты/формат/pump/underrun_mode, или - * не-W2 режим; ENOMEM — не хватило памяти под буфер тишины). */ +/* Включить CBL с частотой CBL_FREQ_*, форматом CBL_FMT_* и способом выдачи + * CBL_PUMP_*; fill — callback, зовущийся из ISR за новым блоком (может быть + * NULL, тогда недолив — на каждом запросе). Недолив НЕ наша забота + * (CBL_UNDERRUN_APP): железо доиграет по кругу неактивную половину, и если + * это слышно — приложение обязано отдавать тишину само. + * + * 0 или -1 + errno (EBUSY — уже открыт; EINVAL — плохой код частоты, формат, + * pump, или не-W2 режим). + * + * ТОЧКИ ВХОДА ДВЕ, и это не косметика: cbl_open() не аллоцирует ничего и + * потому НЕ ТЯНЕТ malloc в резидент. За тишиной от libc — cbl_open_silence() + * ниже, и malloc приезжает только тому, кто её позвал. */ int cbl_open(uint8_t freq_code, uint8_t fmt, uint8_t pump_mode, - uint8_t underrun_mode, cbl_fill_fn fill); + cbl_fill_fn fill); -/* Выключить CBL, отпустить IM2-таблицу, освободить буфер тишины (если - * был). Идемпотентно. */ +/* То же, но при недоливе тишину шлёт САМА libc (CBL_UNDERRUN_SILENCE): + * буфер под неё аллоцируется здесь. Добавляет ENOMEM к кодам ошибок. + * Буфер живёт до конца программы и переиспользуется при повторном открытии + * — cbl_close() его не освобождает намеренно (иначе free вернул бы malloc + * в резидент всем подряд). */ +int cbl_open_silence(uint8_t freq_code, uint8_t fmt, uint8_t pump_mode, + cbl_fill_fn fill); + +/* Выключить CBL и отпустить IM2-таблицу. Идемпотентно. */ void cbl_close(void); /* Пропихнуть n байт из src прямо в CBL (звать ИЗ fill()). */ diff --git a/tests/cblstream/cblstream.c b/tests/cblstream/cblstream.c index 959ae85..1284999 100644 --- a/tests/cblstream/cblstream.c +++ b/tests/cblstream/cblstream.c @@ -100,7 +100,7 @@ int main(void) } if (cbl_open(CBL_FREQ_21K9, CBL_FMT_MONO8, CBL_PUMP_OTIR, - CBL_UNDERRUN_APP, fill_stream) != 0) { + fill_stream) != 0) { printf("cbl_open failed: errno=%d\n", errno); close(fd); return 1; diff --git a/tests/cblwav/cblwav.c b/tests/cblwav/cblwav.c index bbbee5c..db2b0c7 100644 --- a/tests/cblwav/cblwav.c +++ b/tests/cblwav/cblwav.c @@ -113,7 +113,7 @@ int main(void) done = 0; if (cbl_open(CBL_FREQ_21K9, CBL_FMT_MONO8, CBL_PUMP_OTIR, - CBL_UNDERRUN_APP, fill_speech) != 0) { + fill_speech) != 0) { printf("cbl_open failed: errno=%d\n", errno); mem_free_block(blk); return 1;