diff --git a/CMakeLists.txt b/CMakeLists.txt index 428ce14..5411361 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,16 @@ else() set(LIBUVC_INCLUDE_DIRS "" CACHE STRING "manual libuvc includepath") endif() +if(PKG_CONFIG_FOUND) + pkg_check_modules(LIBFLAC flac IMPORTED_TARGET) + if(LIBFLAC_LINK_LIBRARIES) + set(LIBFLAC_LIBRARIES "${LIBFLAC_LINK_LIBRARIES}") + endif() +else() + set(LIBFLAC_LIBRARIES "" CACHE STRING "manual FLAC path") + set(LIBFLAC_INCLUDE_DIRS "" CACHE STRING "manual FLAC includepath") +endif() + if(MSVC) set(THREADS_PTHREADS_LIBRARY "" CACHE STRING "manual pthread-win32 path") set(THREADS_PTHREADS_INCLUDE_DIR "" CACHE STRING "manual pthread-win32 includepath") @@ -102,6 +112,9 @@ endif() if(PKG_CONFIG_FOUND AND NOT LIBUVC_FOUND) message(FATAL_ERROR "LibUVC required to compile hsdaoh") endif() +if(PKG_CONFIG_FOUND AND NOT LIBFLAC_FOUND) + message(FATAL_ERROR "LibFLAC required to compile hsdaoh") +endif() if(NOT THREADS_FOUND) message(FATAL_ERROR "pthreads(-win32) required to compile hsdaoh") endif() @@ -165,6 +178,14 @@ FOREACH(lib ${LIBUVC_LIBRARY_DIRS}) LIST(APPEND hsdaoh_PC_LIBS "-L${lib}") ENDFOREACH(lib) +FOREACH(inc ${LIBFLAC_INCLUDEDIR}) + LIST(APPEND hsdaoh_PC_CFLAGS "-I${inc}") +ENDFOREACH(inc) + +FOREACH(lib ${LIBFLAC_LIBRARY_DIRS}) + LIST(APPEND hsdaoh_PC_LIBS "-L${lib}") +ENDFOREACH(lib) + # use space-separation format for the pc file STRING(REPLACE ";" " " hsdaoh_PC_CFLAGS "${hsdaoh_PC_CFLAGS}") STRING(REPLACE ";" " " hsdaoh_PC_LIBS "${hsdaoh_PC_LIBS}") diff --git a/README.md b/README.md index f3d5411..d88d71c 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ There is one additional dependency to abstract the video input however (libuvc). To install the build dependencies on a distribution based on Debian (e.g. Ubuntu), run the following command: - sudo apt-get install build-essential cmake pkgconf libusb-1.0-0-dev libuvc-dev + sudo apt-get install build-essential cmake pkgconf libusb-1.0-0-dev libuvc-dev libflac-dev To build hsdaoh: @@ -80,7 +80,7 @@ pacman -Suy # Install the required dependencies: pacman -S git zip mingw-w64-x86_64-libusb mingw-w64-x86_64-libwinpthread mingw-w64-x86_64-cc \ -mingw-w64-x86_64-gcc-libs mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja +mingw-w64-x86_64-gcc-libs mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-flac ``` #### Build libuvc @@ -88,7 +88,7 @@ mingw-w64-x86_64-gcc-libs mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja # Clone the repository: git clone https://github.com/steve-m/libuvc.git mkdir libuvc/build && cd libuvc/build -cmake ../ -DCMAKE_INSTALL_PREFIX:PATH=/mingw64 +cmake ../ -DCMAKE_POLICY_VERSION_MINIMUM=3.10 -DCMAKE_INSTALL_PREFIX:PATH=/mingw64 cmake --build . cmake --install . ``` @@ -101,7 +101,7 @@ mkdir hsdaoh/build && cd hsdaoh/build cmake ../ cmake --build . # Gather all files required for release -zip -j hsdaoh_win_release.zip src/*.exe src/*.dll /mingw64/bin/libusb-1.0.dll /mingw64/bin/libuvc.dll /mingw64/bin/libwinpthread-1.dll +zip -j hsdaoh_win_release.zip src/*.exe src/*.dll /mingw64/bin/libusb-1.0.dll /mingw64/bin/libuvc.dll /mingw64/bin/libwinpthread-1.dll /mingw64/bin/libFLAC.dll /mingw64/bin/libogg-0.dll ``` ### Mac OS X diff --git a/cmake/hsdaohConfig.cmake b/cmake/hsdaohConfig.cmake index 4c0199d..51b4cd9 100644 --- a/cmake/hsdaohConfig.cmake +++ b/cmake/hsdaohConfig.cmake @@ -1,6 +1,7 @@ include(FindPkgConfig) pkg_check_modules(LIBUSB libusb-1.0 IMPORTED_TARGET) pkg_check_modules(LIBUVC libuvc IMPORTED_TARGET) +pkg_check_modules(LIBFLAC flac IMPORTED_TARGET) get_filename_component(HSDAOH_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) diff --git a/include/hsdaoh.h b/include/hsdaoh.h index 49a5038..caf5a11 100644 --- a/include/hsdaoh.h +++ b/include/hsdaoh.h @@ -41,6 +41,11 @@ typedef struct hsdaoh_data_info { unsigned char *buf; size_t len; /* buffer length */ uint16_t stream_id; + uint32_t srate; + uint8_t nchans; + uint8_t bits_per_samp; + bool is_signed; + bool is_float; bool device_error; /* device error happened, terminate application */ } hsdaoh_data_info_t; diff --git a/include/hsdaoh_private.h b/include/hsdaoh_private.h index cbdccf1..2279aff 100644 --- a/include/hsdaoh_private.h +++ b/include/hsdaoh_private.h @@ -12,6 +12,7 @@ struct llist { size_t len; uint16_t sid; uint16_t format; + uint32_t srate; struct llist *next; }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 81c65e3..e92737c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -85,6 +85,7 @@ add_executable(hsdaoh_test hsdaoh_test.c) set(INSTALL_TARGETS hsdaoh hsdaoh_static hsdaoh_file hsdaoh_tcp hsdaoh_test) target_link_libraries(hsdaoh_file hsdaoh + ${LIBFLAC_LIBRARIES} # ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) diff --git a/src/format_convert.c b/src/format_convert.c index e251d75..26e2a69 100644 --- a/src/format_convert.c +++ b/src/format_convert.c @@ -53,6 +53,10 @@ static inline void hsdaoh_16bit_to_float(hsdaoh_dev_t *dev, hsdaoh_data_info_t * data_info->buf = (uint8_t *)floats; data_info->len = j * sizeof(float); + data_info->bits_per_samp = 32; + data_info->nchans = 1; + data_info->is_signed = true; + data_info->is_float = true; dev->cb(data_info); free(floats); @@ -81,6 +85,11 @@ void hsdaoh_unpack_pio_12bit(hsdaoh_dev_t *dev, hsdaoh_data_info_t *data_info) } else { data_info->buf = (uint8_t *)out; data_info->len = j * sizeof(uint16_t); + data_info->bits_per_samp = 12; + data_info->nchans = 1; + data_info->is_signed = false; + data_info->is_float = false; + dev->cb(data_info); } @@ -112,11 +121,18 @@ void hsdaoh_unpack_pio_12bit_dual(hsdaoh_dev_t *dev, hsdaoh_data_info_t *data_in out16_2[i] = out[i] & 0x0fff; } + data_info->bits_per_samp = 12; + data_info->nchans = 1; + if (dev->output_float) { hsdaoh_16bit_to_float(dev, data_info, out16_1, i, 2047.5, true); } else { data_info->buf = (uint8_t *)out16_1; data_info->len = i * sizeof(uint16_t); + data_info->bits_per_samp = 12; + data_info->nchans = 1; + data_info->is_signed = false; + data_info->is_float = false; dev->cb(data_info); } @@ -157,6 +173,10 @@ void hsdaoh_unpack_pio_8bit_iq(hsdaoh_dev_t *dev, hsdaoh_data_info_t *data_info) } else { data_info->buf = (uint8_t *)in; data_info->len = inlen; + data_info->bits_per_samp = 8; + data_info->nchans = 2; + data_info->is_signed = false; + data_info->is_float = false; dev->cb(data_info); } @@ -202,6 +222,10 @@ void hsdaoh_unpack_pio_10bit_iq(hsdaoh_dev_t *dev, hsdaoh_data_info_t *data_info } else { data_info->buf = (uint8_t *)iq_samps; data_info->len = out_samps * sizeof(uint16_t); + data_info->bits_per_samp = 10; + data_info->nchans = 2; + data_info->is_signed = false; + data_info->is_float = false; dev->cb(data_info); } @@ -215,14 +239,24 @@ void hsdaoh_unpack_pio_pcm1802_audio(hsdaoh_dev_t *dev, hsdaoh_data_info_t *data uint32_t *in = (uint32_t *)data_info->buf; size_t inlen = data_info->len / sizeof(uint32_t); - /* convert from S24LE to S32LE */ - for (unsigned int i = 0; i < inlen; i++) - in[i] <<= 8; + /* output as S24_3LE */ + uint8_t *out = malloc(inlen * 3); + int j = 0; - data_info->buf = (uint8_t *)in; - data_info->len = inlen * sizeof(uint32_t); + for (unsigned int i = 0; i < inlen; i++) { + out[j++] = in[i] & 0xff; + out[j++] = (in[i] >> 8) & 0xff; + out[j++] = (in[i] >> 16) & 0xff; + } + data_info->buf = (uint8_t *)out; + data_info->len = j; + data_info->bits_per_samp = 24; + data_info->nchans = 2; + data_info->is_signed = true; + data_info->is_float = false; dev->cb(data_info); + free(out); } void hsdaoh_unpack_fpga_12bit_dual(hsdaoh_dev_t *dev, hsdaoh_data_info_t *data_info) @@ -250,6 +284,10 @@ void hsdaoh_unpack_fpga_12bit_dual(hsdaoh_dev_t *dev, hsdaoh_data_info_t *data_i } else { data_info->buf = (uint8_t *)out16_1; data_info->len = j * sizeof(uint16_t); + data_info->bits_per_samp = 12; + data_info->nchans = 1; + data_info->is_signed = false; + data_info->is_float = false; dev->cb(data_info); } diff --git a/src/hsdaoh_file.c b/src/hsdaoh_file.c index 7309f8a..719fe09 100644 --- a/src/hsdaoh_file.c +++ b/src/hsdaoh_file.c @@ -35,15 +35,23 @@ #define usleep(t) Sleep((t)/1000) #endif +#include "FLAC/metadata.h" +#include "FLAC/stream_encoder.h" + #include "hsdaoh.h" #define FD_NUMS 4 -static int do_exit = 0; +static bool do_exit = false; static hsdaoh_dev_t *dev = NULL; +static uint32_t flac_level = 5; +static uint32_t flac_nthreads = 4; typedef struct file_ctx { FILE *files[FD_NUMS]; + bool use_flac[FD_NUMS]; + FLAC__StreamEncoder *encoder[FD_NUMS]; + FLAC__StreamMetadata *seektable[FD_NUMS]; } file_ctx_t; void usage(void) @@ -52,9 +60,14 @@ void usage(void) "hsdaoh_file, HDMI data acquisition tool\n\n" "Usage:\n" "\t[-d device_index (default: 0)]\n" - "\t[-b maximum number of buffers (default: 16)]\n" - "\t[-0 to -3 filename of steam 0 to stream 3 (a '-' dumps samples to stdout)]\n" - "\tfilename (of stream 0) (a '-' dumps samples to stdout)\n\n"); + "\t[-b maximum number of buffers (default: 96)]\n" + "\t[-l FLAC compression level (default: 5)]\n" +#ifdef FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK + "\t[-t number of threads for FLAC encoding (default: 4)]\n" +#endif + "\t[-0 to -3 filename of stream 0 to stream 3 (a '-' dumps samples to stdout)]\n" + "\tfilename (of stream 0) (a '-' dumps samples to stdout)\n\n" + "\tFilenames with the extension .flac will enable FLAC encoding\n\n"); exit(1); } @@ -64,7 +77,7 @@ sighandler(int signum) { if (CTRL_C_EVENT == signum) { fprintf(stderr, "Signal caught, exiting!\n"); - do_exit = 1; + do_exit = true; hsdaoh_stop_stream(dev); return TRUE; } @@ -75,7 +88,7 @@ static void sighandler(int signum) { signal(SIGPIPE, SIG_IGN); fprintf(stderr, "Signal caught, exiting!\n"); - do_exit = 1; + do_exit = true; hsdaoh_stop_stream(dev); } #endif @@ -97,13 +110,110 @@ static void hsdaoh_callback(hsdaoh_data_info_t *data_info) if (!file) return; - while (nbytes < len) { - nbytes += fwrite(data_info->buf + nbytes, 1, len - nbytes, file); + FLAC__StreamEncoder *encoder = f->encoder[data_info->stream_id]; + /* allocate FLAC encoder if required */ + if (f->use_flac[data_info->stream_id] && !encoder) { + FLAC__bool ret = true; + FLAC__StreamEncoderInitStatus init_status; - if (ferror(file)) { - fprintf(stderr, "Error writing file, samples lost, exiting!\n"); + if ((encoder = FLAC__stream_encoder_new()) == NULL) { + fprintf(stderr, "ERROR: failed allocating FLAC encoder\n"); + do_exit = true; + return; + } + + ret &= FLAC__stream_encoder_set_verify(encoder, false); + ret &= FLAC__stream_encoder_set_compression_level(encoder, flac_level); + ret &= FLAC__stream_encoder_set_sample_rate(encoder, + data_info->srate > FLAC__MAX_SAMPLE_RATE ? + data_info->srate/1000 : data_info->srate); + + ret &= FLAC__stream_encoder_set_channels(encoder, data_info->nchans); + ret &= FLAC__stream_encoder_set_bits_per_sample(encoder, data_info->bits_per_samp); + ret &= FLAC__stream_encoder_set_total_samples_estimate(encoder, 0); + ret &= FLAC__stream_encoder_set_streamable_subset(encoder, false); + +#ifdef FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK + if (FLAC__stream_encoder_set_num_threads(encoder, flac_nthreads) != FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK) + ret = false; +#endif + + if (!ret) { + fprintf(stderr, "ERROR: failed initializing FLAC encoder\n"); + do_exit = true; + return; + } + + init_status = FLAC__stream_encoder_init_FILE(encoder, f->files[data_info->stream_id], NULL, NULL); + if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { + fprintf(stderr, "ERROR: failed initializing FLAC encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]); + do_exit = true; + return; + } + + f->encoder[data_info->stream_id] = encoder; + } + + if (f->use_flac[data_info->stream_id]) { + /* write FLAC output */ + FLAC__bool ok = false; + FLAC__int32 offset = data_info->is_signed ? 0 : 1 << (data_info->bits_per_samp - 1); + int bytes_per_samp = ((data_info->bits_per_samp - 1) / 8) + 1; + int nsamps = len / bytes_per_samp; + FLAC__int32 *out = malloc(nsamps * sizeof(FLAC__int32)); + int i = 0; + + if (bytes_per_samp == 1) { + /* data encoded in uint8 */ + uint8_t *dat = (uint8_t *)data_info->buf; + + for (; i < nsamps; i++) + out[i] = dat[i] - offset; + } else if (bytes_per_samp == 2) { + /* data encoded in uint16 */ + uint16_t *dat = (uint16_t *)data_info->buf; + + for (; i < nsamps; i++) + out[i] = dat[i] - offset; + } else if (bytes_per_samp == 3) { + /* data encoded in 3 * uint8 */ + uint8_t *dat = (uint8_t *)data_info->buf; + int j = 0; + + for (; i < nsamps; i++) { + /* convert S24_3LE and take care of sign extension */ + FLAC__int32 samp = (FLAC__int32)((dat[j+2] << 24) | (dat[j+1] << 16) | (dat[j] << 8)); + //samp /= 256; + samp >>= (32 - data_info->bits_per_samp); + j += 3; + out[i] = samp - offset; + } + } else { + /* data encoded in uint32 */ + uint32_t *dat = (uint32_t *)data_info->buf; + + for (; i < nsamps; i++) + out[i] = dat[i] - offset; + } + + ok = FLAC__stream_encoder_process_interleaved(f->encoder[data_info->stream_id], out, nsamps / data_info->nchans); + free(out); + + if (!ok && encoder) { + fprintf(stderr, "ERROR: () FLAC encoder could not process data: %s\n", + FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder)]); hsdaoh_stop_stream(dev); - break; + } + } else { + /* write raw file output */ + while (nbytes < len) { + nbytes += fwrite(data_info->buf + nbytes, 1, len - nbytes, file); + + if (ferror(file)) { + fprintf(stderr, "Error writing file, samples lost, exiting!\n"); + hsdaoh_stop_stream(dev); + break; + } } } } @@ -116,13 +226,13 @@ int main(int argc, char **argv) char *filenames[FD_NUMS] = { NULL, }; int n_read; int r, opt; - file_ctx_t f; + file_ctx_t f = { 0 }; int dev_index = 0; unsigned int num_bufs = 0; bool fname0_used = false; bool have_file = false; - while ((opt = getopt(argc, argv, "0:1:2:3:d:b:")) != -1) { + while ((opt = getopt(argc, argv, "0:1:2:3:d:b:l:t:")) != -1) { switch (opt) { case 'd': dev_index = (uint32_t)atoi(optarg); @@ -130,6 +240,12 @@ int main(int argc, char **argv) case 'b': num_bufs = (unsigned int)atoi(optarg); break; + case 'l': + flac_level = atoi(optarg); + break; + case 't': + flac_nthreads = atoi(optarg); + break; case '0': fname0_used = true; have_file = true; @@ -184,6 +300,7 @@ int main(int argc, char **argv) for (int i = 0; i < FD_NUMS; i++) { f.files[i] = NULL; + f.encoder[i] = NULL; if (!filenames[i]) continue; @@ -199,24 +316,36 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to open %s\n", filenames[i]); goto out; } + + char *dot = strrchr(filenames[i], '.'); + if (dot && !strcmp(dot, ".flac")) + f.use_flac[i] = true; + else + f.use_flac[i] = false; } } r = hsdaoh_start_stream(dev, hsdaoh_callback, (void *)&f, num_bufs); - while (!do_exit) { + while (!do_exit) usleep(50000); - } - - if (do_exit) - fprintf(stderr, "\nUser cancel, exiting...\n"); - else - fprintf(stderr, "\nLibrary error %d, exiting...\n", r); + fprintf(stderr, "\nUser cancel, exiting...\n"); hsdaoh_close(dev); for (int i = 0; i < FD_NUMS; i++) { - if (f.files[i] && (f.files[i] != stdout)) + if (!f.files[i]) + continue; + + if (f.use_flac[i] && f.encoder[i]) { + FLAC__bool ret = FLAC__stream_encoder_finish(f.encoder[i]); + + if (!ret) + fprintf(stderr, "ERROR: FLAC encoder did not finish correctly: %s\n", + FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(f.encoder[i])]); + + FLAC__stream_encoder_delete(f.encoder[i]); + } else if (f.files[i] != stdout) fclose(f.files[i]); } diff --git a/src/libhsdaoh.c b/src/libhsdaoh.c index f54b837..f81991b 100644 --- a/src/libhsdaoh.c +++ b/src/libhsdaoh.c @@ -52,7 +52,7 @@ #include #include -#define DEFAULT_BUFFERS 16 +#define DEFAULT_BUFFERS 96 typedef struct hsdaoh_adapter { uint16_t vid; @@ -531,8 +531,6 @@ int hsdaoh_close(hsdaoh_dev_t *dev) return 0; } -// maybe rename to preferred output format -// and add real output format to data_info_t int hsdaoh_set_output_format(hsdaoh_dev_t *dev, hsdaoh_output_format_t format) { if (!dev) @@ -542,13 +540,14 @@ int hsdaoh_set_output_format(hsdaoh_dev_t *dev, hsdaoh_output_format_t format) return 0; } -void hsdaoh_output(hsdaoh_dev_t *dev, uint16_t sid, int format, uint8_t *data, size_t len) +void hsdaoh_output(hsdaoh_dev_t *dev, uint16_t sid, int format, uint32_t srate, uint8_t *data, size_t len) { hsdaoh_data_info_t data_info; data_info.ctx = dev->cb_ctx; data_info.stream_id = sid; data_info.buf = data; data_info.len = len; + data_info.srate = srate; switch (format) { case PIO_8BIT_IQ: @@ -604,7 +603,7 @@ static void *hsdaoh_output_worker(void *arg) pthread_mutex_unlock(&dev->ll_mutex); while (curelem != NULL) { - hsdaoh_output(dev, curelem->sid, curelem->format, curelem->data, curelem->len); + hsdaoh_output(dev, curelem->sid, curelem->format, curelem->srate, curelem->data, curelem->len); prev = curelem; curelem = curelem->next; @@ -614,7 +613,7 @@ static void *hsdaoh_output_worker(void *arg) } } -void hsdaoh_enqueue_data(hsdaoh_dev_t *dev, uint16_t sid, int format, uint8_t *data, size_t len) +void hsdaoh_enqueue_data(hsdaoh_dev_t *dev, uint16_t sid, int format, uint32_t srate, uint8_t *data, size_t len) { if (dev->async_status != HSDAOH_RUNNING) { free(data); @@ -626,6 +625,7 @@ void hsdaoh_enqueue_data(hsdaoh_dev_t *dev, uint16_t sid, int format, uint8_t *d rpt->len = len; rpt->sid = sid; rpt->format = format; + rpt->srate = srate; rpt->next = NULL; pthread_mutex_lock(&dev->ll_mutex); @@ -721,6 +721,11 @@ void hsdaoh_process_frame(hsdaoh_dev_t *dev, uint8_t *data, int size) uint16_t stream0_format = 0; uint8_t *stream0_data = malloc(dev->width-1 * dev->height * 2); + if (!stream0_data) { + fprintf(stderr, "Out of memory, frame skipped!\n"); + return; + } + for (unsigned int i = 0; i < dev->height; i++) { uint8_t *line_dat = data + (dev->width * sizeof(uint16_t) * i); @@ -745,6 +750,7 @@ void hsdaoh_process_frame(hsdaoh_dev_t *dev, uint8_t *data, int size) fprintf(stderr, "Invalid payload length: %d\n", payload_len); /* discard frame */ + free(stream0_data); return; } @@ -770,14 +776,15 @@ void hsdaoh_process_frame(hsdaoh_dev_t *dev, uint8_t *data, int size) stream0_format = format; } else { uint8_t *out_data = malloc(out_len); + uint32_t srate = stream_id < DEFAULT_MAX_STREAMS ? meta.stream_info[stream_id].srate : 0; memcpy(out_data, line_dat, out_len); - hsdaoh_enqueue_data(dev, stream_id, format, out_data, out_len); + hsdaoh_enqueue_data(dev, stream_id, format, srate, out_data, out_len); } } } if (dev->stream_synced && stream0_payload_bytes) - hsdaoh_enqueue_data(dev, 0, stream0_format, stream0_data, stream0_payload_bytes); + hsdaoh_enqueue_data(dev, 0, stream0_format, meta.stream_info[0].srate, stream0_data, stream0_payload_bytes); else free(stream0_data); @@ -788,7 +795,7 @@ void hsdaoh_process_frame(hsdaoh_dev_t *dev, uint8_t *data, int size) dev->frames_since_error++; if (!dev->stream_synced && !frame_errors && (dev->in_order_cnt > 4)) { - fprintf(stderr, "Syncronized to HDMI input stream\n"); + fprintf(stderr, "Synchronized to HDMI input stream\n"); dev->stream_synced = true; } } @@ -839,7 +846,7 @@ int hsdaoh_start_stream(hsdaoh_dev_t *dev, hsdaoh_read_cb_t cb, void *ctx, unsig // dev->output_float = true; /* initialize with a threshold */ - dev->highest_numq = 9; + dev->highest_numq = DEFAULT_BUFFERS/2; dev->llbuf_num = (buf_num == 0) ? DEFAULT_BUFFERS : buf_num; pthread_mutex_init(&dev->ll_mutex, NULL);