cplay_SOURCES = cplay.c wave.c
crecord_SOURCES = crecord.c wave.c
-sofprobeclient_SOURCES = sofprobeclient.c wave.c
+sofprobeclient_SOURCES = sofprobeclient.c probes_demux.c
cplay_CFLAGS = -I$(top_srcdir)/include
crecord_CFLAGS = -I$(top_srcdir)/include
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2022 Intel Corporation. All rights reserved.
+ *
+ * Local copy of ipc/probe_dma_frame.h with MASK defined inline
+ * so it can be built without SOF RTOS headers.
+ */
+
+#ifndef __PROBE_DMA_FRAME_H__
+#define __PROBE_DMA_FRAME_H__
+
+#include <stdint.h>
+
+#ifndef MASK
+#define MASK(b_hi, b_lo) \
+ (((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL) << (b_lo))
+#endif
+
+/**
+ * Header for data packets sent via compressed PCM from extraction probes
+ */
+struct probe_data_packet {
+ uint32_t sync_word; /**< PROBE_EXTRACT_SYNC_WORD */
+ uint32_t buffer_id; /**< Buffer ID from which data was extracted */
+ uint32_t format; /**< Encoded data format */
+ uint32_t timestamp_low; /**< Low 32 bits of timestamp in us */
+ uint32_t timestamp_high; /**< High 32 bits of timestamp in us */
+ uint32_t data_size_bytes; /**< Size of following audio data */
+ uint8_t data[]; /**< Audio data extracted from buffer */
+} __attribute__((packed, aligned(4)));
+
+#define PROBE_EXTRACT_SYNC_WORD 0xBABEBEBA
+
+/**
+ * \brief Definitions of shifts and masks for format encoding in probe
+ * extraction stream
+ *
+ * Audio format from extraction probes is encoded as 32 bit value. Following
+ * graphic explains encoding.
+ *
+ * A|BBBB|CCCC|DDDD|EEEEE|FF|GG|H|I|J|XXXXXXX
+ * A - 1 bit - Specifies Type Encoding - 1 for Standard encoding
+ * B - 4 bits - Specify Standard Type - 0 for Audio
+ * C - 4 bits - Specify Audio format - 0 for PCM
+ * D - 4 bits - Specify Sample Rate - value enumerating standard sample rates:
+ * 8000 Hz = 0x0
+ * 11025 Hz = 0x1
+ * 12000 Hz = 0x2
+ * 16000 Hz = 0x3
+ * 22050 Hz = 0x4
+ * 24000 Hz = 0x5
+ * 32000 Hz = 0x6
+ * 44100 Hz = 0x7
+ * 48000 Hz = 0x8
+ * 64000 Hz = 0x9
+ * 88200 Hz = 0xA
+ * 96000 Hz = 0xB
+ * 128000 Hz = 0xC
+ * 176400 Hz = 0xD
+ * 192000 Hz = 0xE
+ * none of the above = 0xF
+ * E - 5 bits - Specify Number of Channels minus 1
+ * F - 2 bits - Specify Sample Size, number of valid sample bytes minus 1
+ * G - 2 bits - Specify Container Size, number of container bytes minus 1
+ * H - 1 bit - Specifies Sample Format - 0 for Integer, 1 for Floating point
+ * I - 1 bit - Specifies Sample Endianness - 0 for LE
+ * J - 1 bit - Specifies Interleaving - 1 for Sample Interleaving
+ */
+
+#define PROBE_SHIFT_FMT_TYPE 31
+#define PROBE_SHIFT_STANDARD_TYPE 27
+#define PROBE_SHIFT_AUDIO_FMT 23
+#define PROBE_SHIFT_SAMPLE_RATE 19
+#define PROBE_SHIFT_NB_CHANNELS 14
+#define PROBE_SHIFT_SAMPLE_SIZE 12
+#define PROBE_SHIFT_CONTAINER_SIZE 10
+#define PROBE_SHIFT_SAMPLE_FMT 9
+#define PROBE_SHIFT_SAMPLE_END 8
+#define PROBE_SHIFT_INTERLEAVING_ST 7
+
+#define PROBE_MASK_FMT_TYPE MASK(31, 31)
+#define PROBE_MASK_STANDARD_TYPE MASK(30, 27)
+#define PROBE_MASK_AUDIO_FMT MASK(26, 23)
+#define PROBE_MASK_SAMPLE_RATE MASK(22, 19)
+#define PROBE_MASK_NB_CHANNELS MASK(18, 14)
+#define PROBE_MASK_SAMPLE_SIZE MASK(13, 12)
+#define PROBE_MASK_CONTAINER_SIZE MASK(11, 10)
+#define PROBE_MASK_SAMPLE_FMT MASK(9, 9)
+#define PROBE_MASK_SAMPLE_END MASK(8, 8)
+#define PROBE_MASK_INTERLEAVING_ST MASK(7, 7)
+
+#endif /* __PROBE_DMA_FRAME_H__ */
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Author: Adrian Bonislawski <adrian.bonislawski@intel.com>
+// Jyri Sarha <jyri.sarha@intel.com> (restructured and moved to this file)
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "probe_dma_frame.h"
+
+#include "probes_wave.h"
+
+#define APP_NAME "sof-probes"
+
+#define PACKET_MAX_SIZE 4096 /**< Size limit for probe data packet */
+#define DATA_READ_LIMIT 4096 /**< Data limit for file read */
+#define FILES_LIMIT 32 /**< Maximum num of probe output files */
+#define FILE_PATH_LIMIT 128 /**< Path limit for probe output files */
+
+struct wave_files {
+ FILE *fd;
+ uint32_t buffer_id;
+ uint32_t fmt;
+ uint32_t size;
+ struct wave header;
+};
+
+enum p_state {
+ READY = 0, /**< At this stage app is looking for a SYNC word */
+ SYNC, /**< SYNC received, copying data */
+ CHECK /**< Check crc and save packet if valid */
+};
+
+struct dma_frame_parser {
+ bool log_to_stdout;
+ enum p_state state;
+ struct probe_data_packet *packet;
+ size_t packet_size;
+ uint8_t *w_ptr; /* Write pointer to copy data to */
+ uint32_t total_data_to_copy; /* Total bytes left to copy */
+ int start; /* Start of unfilled data */
+ int len; /* Data buffer fill level */
+ uint8_t data[DATA_READ_LIMIT];
+ struct wave_files files[FILES_LIMIT];
+};
+
+static uint32_t sample_rate[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
+ 48000, 64000, 88200, 96000, 128000, 176400, 192000
+};
+
+int get_buffer_file(struct wave_files *files, uint32_t buffer_id)
+{
+ int i;
+
+ for (i = 0; i < FILES_LIMIT; i++) {
+ if (files[i].fd != NULL && files[i].buffer_id == buffer_id)
+ return i;
+ }
+ return -1;
+}
+
+int get_buffer_file_free(struct wave_files *files)
+{
+ int i;
+
+ for (i = 0; i < FILES_LIMIT; i++) {
+ if (files[i].fd == NULL)
+ return i;
+ }
+ return -1;
+}
+
+bool is_audio_format(uint32_t format)
+{
+ return (format & PROBE_MASK_FMT_TYPE) != 0 && (format & PROBE_MASK_AUDIO_FMT) == 0;
+}
+
+int init_wave(struct dma_frame_parser *p, uint32_t buffer_id, uint32_t format)
+{
+ bool audio = is_audio_format(format);
+ char path[FILE_PATH_LIMIT];
+ int i;
+
+ i = get_buffer_file_free(p->files);
+ if (i == -1) {
+ fprintf(stderr, "error: too many buffers\n");
+ exit(0);
+ }
+
+ sprintf(path, "buffer_%d.%s", buffer_id, audio ? "wav" : "bin");
+
+ fprintf(stderr, "%s:\t Creating file %s\n", APP_NAME, path);
+
+ if (!audio && p->log_to_stdout) {
+ p->files[i].fd = stdout;
+ } else {
+ p->files[i].fd = fopen(path, "wb");
+ if (!p->files[i].fd) {
+ fprintf(stderr, "error: unable to create file %s, error %d\n",
+ path, errno);
+ exit(0);
+ }
+ }
+
+ p->files[i].buffer_id = buffer_id;
+ p->files[i].fmt = format;
+
+ if (!audio)
+ return i;
+
+ p->files[i].header.riff.chunk_id = HEADER_RIFF;
+ p->files[i].header.riff.format = HEADER_WAVE;
+ p->files[i].header.fmt.subchunk_id = HEADER_FMT;
+ p->files[i].header.fmt.subchunk_size = 16;
+ p->files[i].header.fmt.audio_format = 1;
+ p->files[i].header.fmt.num_channels = ((format & PROBE_MASK_NB_CHANNELS) >> PROBE_SHIFT_NB_CHANNELS) + 1;
+ p->files[i].header.fmt.sample_rate = sample_rate[(format & PROBE_MASK_SAMPLE_RATE) >> PROBE_SHIFT_SAMPLE_RATE];
+ p->files[i].header.fmt.bits_per_sample = (((format & PROBE_MASK_CONTAINER_SIZE) >> PROBE_SHIFT_CONTAINER_SIZE) + 1) * 8;
+ p->files[i].header.fmt.byte_rate = p->files[i].header.fmt.sample_rate *
+ p->files[i].header.fmt.num_channels *
+ p->files[i].header.fmt.bits_per_sample / 8;
+ p->files[i].header.fmt.block_align = p->files[i].header.fmt.num_channels *
+ p->files[i].header.fmt.bits_per_sample / 8;
+ p->files[i].header.data.subchunk_id = HEADER_DATA;
+
+ fwrite(&p->files[i].header, sizeof(struct wave), 1, p->files[i].fd);
+
+ return i;
+}
+
+void finalize_wave_files(struct dma_frame_parser *p)
+{
+ struct wave_files *files = p->files;
+ uint32_t i, chunk_size;
+
+ /* fill the header at the beginning of each file */
+ /* and close all opened files */
+ /* check wave struct to understand the offsets */
+ for (i = 0; i < FILES_LIMIT; i++) {
+ if (!is_audio_format(files[i].fmt))
+ continue;
+
+ if (files[i].fd) {
+ chunk_size = files[i].size + sizeof(struct wave) -
+ offsetof(struct riff_chunk, format);
+
+ fseek(files[i].fd, sizeof(uint32_t), SEEK_SET);
+ fwrite(&chunk_size, sizeof(uint32_t), 1, files[i].fd);
+ fseek(files[i].fd, sizeof(struct wave) -
+ offsetof(struct data_subchunk, subchunk_size),
+ SEEK_SET);
+ fwrite(&files[i].size, sizeof(uint32_t), 1, files[i].fd);
+
+ fclose(files[i].fd);
+ }
+ }
+}
+
+int validate_data_packet(struct probe_data_packet *packet)
+{
+ uint64_t *checksump;
+ uint64_t sum;
+
+ sum = (uint32_t) (packet->sync_word +
+ packet->buffer_id +
+ packet->format +
+ packet->timestamp_high +
+ packet->timestamp_low +
+ packet->data_size_bytes);
+
+ checksump = (uint64_t *) (packet->data + packet->data_size_bytes);
+
+ if (sum != *checksump) {
+ fprintf(stderr, "Checksum error 0x%016" PRIx64 " != 0x%016" PRIx64 "\n",
+ sum, *checksump);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int process_sync(struct dma_frame_parser *p)
+{
+ struct probe_data_packet *temp_packet;
+
+ /* request to copy data_size from probe packet and 64-bit checksum */
+ p->total_data_to_copy = p->packet->data_size_bytes + sizeof(uint64_t);
+
+ if (sizeof(struct probe_data_packet) + p->total_data_to_copy >
+ p->packet_size) {
+ p->packet_size = sizeof(struct probe_data_packet) +
+ p->total_data_to_copy;
+
+ temp_packet = realloc(p->packet, p->packet_size);
+
+ if (!temp_packet)
+ return -ENOMEM;
+
+ p->packet = temp_packet;
+ }
+
+ p->w_ptr = (uint8_t *)p->packet->data;
+
+ return 0;
+}
+
+struct dma_frame_parser *parser_init(void)
+{
+ struct dma_frame_parser *p = malloc(sizeof(*p));
+ if (!p) {
+ fprintf(stderr, "error: allocation failed, err %d\n",
+ errno);
+ return NULL;
+ }
+ memset(p, 0, sizeof(*p));
+ p->packet = malloc(PACKET_MAX_SIZE);
+ if (!p) {
+ fprintf(stderr, "error: allocation failed, err %d\n",
+ errno);
+ free(p);
+ return NULL;
+ }
+ memset(p->packet, 0, PACKET_MAX_SIZE);
+ p->packet_size = PACKET_MAX_SIZE;
+ return p;
+}
+
+void parser_free(struct dma_frame_parser *p)
+{
+ free(p->packet);
+ free(p);
+}
+
+void parser_log_to_stdout(struct dma_frame_parser *p)
+{
+ p->log_to_stdout = true;
+}
+
+void parser_fetch_free_buffer(struct dma_frame_parser *p, uint8_t **d, size_t *len)
+{
+ *d = &p->data[p->start];
+ *len = sizeof(p->data) - p->start;
+}
+
+int parser_parse_data(struct dma_frame_parser *p, size_t d_len)
+{
+ uint i = 0;
+
+ p->len = p->start + d_len;
+ /* processing all loaded bytes */
+ while (i < p->len) {
+ if (p->total_data_to_copy == 0) {
+ switch (p->state) {
+ case READY:
+ /* check for SYNC */
+ if (p->len - i < sizeof(p->packet->sync_word)) {
+ p->start = p->len - i;
+ memmove(&p->data[0], &p->data[i], p->start);
+ i += p->start;
+ } else if (*((uint32_t *)&p->data[i]) ==
+ PROBE_EXTRACT_SYNC_WORD) {
+ memset(p->packet, 0, p->packet_size);
+ /* request to copy full data packet */
+ p->total_data_to_copy =
+ sizeof(struct probe_data_packet);
+ p->w_ptr = (uint8_t *)p->packet;
+ p->state = SYNC;
+ p->start = 0;
+ } else {
+ i++;
+ }
+ break;
+ case SYNC:
+ /* SYNC -> CHECK */
+ if (process_sync(p) < 0) {
+ fprintf(stderr, "OOM, quitting\n");
+ return -ENOMEM;
+ }
+ p->state = CHECK;
+ break;
+ case CHECK:
+ /* CHECK -> READY */
+ /* find corresponding file and save data if valid */
+ if (validate_data_packet(p->packet) == 0) {
+ int file = get_buffer_file(p->files,
+ p->packet->buffer_id);
+
+ if (file < 0)
+ file = init_wave(p, p->packet->buffer_id,
+ p->packet->format);
+
+ if (file < 0) {
+ fprintf(stderr,
+ "unable to open file for %u\n",
+ p->packet->buffer_id);
+ return -EIO;
+ }
+
+ fwrite(p->packet->data, 1,
+ p->packet->data_size_bytes,
+ p->files[file].fd);
+ p->files[file].size += p->packet->data_size_bytes;
+ }
+ p->state = READY;
+ break;
+ }
+ }
+ /* data copying section */
+ if (p->total_data_to_copy > 0) {
+ uint data_to_copy;
+
+ /* check if there is enough bytes loaded */
+ /* or copy partially if not */
+ if (i + p->total_data_to_copy > p->len) {
+ data_to_copy = p->len - i;
+ p->total_data_to_copy -= data_to_copy;
+ } else {
+ data_to_copy = p->total_data_to_copy;
+ p->total_data_to_copy = 0;
+ }
+ memcpy(p->w_ptr, &p->data[i], data_to_copy);
+ p->w_ptr += data_to_copy;
+ i += data_to_copy;
+ }
+ }
+ return 0;
+}
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Author: Jyri Sarha <jyri.sarha@intel.com>
+//
+
+#ifndef _PROBES_DEMUX_H_
+#define _PROBES_DEMUX_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+struct dma_frame_parser;
+
+struct dma_frame_parser *parser_init(void);
+
+void parser_log_to_stdout(struct dma_frame_parser *p);
+
+void parser_free(struct dma_frame_parser *p);
+
+void parser_fetch_free_buffer(struct dma_frame_parser *p, uint8_t **d, size_t *len);
+
+int parser_parse_data(struct dma_frame_parser *p, size_t d_len);
+
+void finalize_wave_files(struct dma_frame_parser *p);
+
+#endif
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2019 Intel Corporation. All rights reserved.
+ *
+ * Author: Adrian Bonislawski <adrian.bonislawski@intel.com>
+ */
+
+#ifndef __WAVE_H__
+#define __WAVE_H__
+
+#define HEADER_RIFF 0x46464952 /**< ASCII "RIFF" */
+#define HEADER_WAVE 0x45564157 /**< ASCII "WAVE" */
+#define HEADER_FMT 0x20746d66 /**< ASCII "fmt " */
+#define HEADER_DATA 0x61746164 /**< ASCII "data" */
+
+struct riff_chunk {
+ uint32_t chunk_id;
+ uint32_t chunk_size;
+ uint32_t format;
+};
+
+struct fmt_subchunk {
+ uint32_t subchunk_id;
+ uint32_t subchunk_size;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate;
+ uint16_t block_align;
+ uint16_t bits_per_sample;
+};
+
+struct data_subchunk {
+ uint32_t subchunk_id;
+ uint32_t subchunk_size;
+ uint32_t data[];
+};
+
+struct wave {
+ struct riff_chunk riff;
+ struct fmt_subchunk fmt;
+ struct data_subchunk data;
+};
+
+#endif /* __WAVE_H__ */
#include "sound/compress_params.h"
#include "sound/compress_offload.h"
#include "tinycompress/tinycompress.h"
-#include "tinycompress/tinywave.h"
+
+#include "probes_demux.h"
static int verbose;
-static int file;
static FILE *finfo;
-static bool streamed;
static const unsigned int DEFAULT_CHANNELS = 4;
static const unsigned int DEFAULT_RATE = 48000;
static const unsigned int DEFAULT_FORMAT = SNDRV_PCM_FORMAT_S32_LE;
static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM;
-static const struct {
- const char *name;
- unsigned int id;
-} codec_ids[] = {
- { "PCM", SND_AUDIOCODEC_PCM },
- { "MP3", SND_AUDIOCODEC_MP3 },
- { "AMR", SND_AUDIOCODEC_AMR },
- { "AMRWB", SND_AUDIOCODEC_AMRWB },
- { "AMRWBPLUS", SND_AUDIOCODEC_AMRWBPLUS },
- { "AAC", SND_AUDIOCODEC_AAC },
- { "WMA", SND_AUDIOCODEC_WMA },
- { "REAL", SND_AUDIOCODEC_REAL },
- { "VORBIS", SND_AUDIOCODEC_VORBIS },
- { "FLAC", SND_AUDIOCODEC_FLAC },
- { "IEC61937", SND_AUDIOCODEC_IEC61937 },
- { "G723_1", SND_AUDIOCODEC_G723_1 },
- { "G729", SND_AUDIOCODEC_G729 },
-/* BESPOKE isn't defined on older kernels */
-#ifdef SND_AUDIOCODEC_BESPOKE
- { "BESPOKE", SND_AUDIOCODEC_BESPOKE },
-#endif
-};
-#define CREC_NUM_CODEC_IDS (sizeof(codec_ids) / sizeof(codec_ids[0]))
-
-static const char *codec_name_from_id(unsigned int id)
-{
- static char hexname[12];
- int i;
-
- for (i = 0; i < CREC_NUM_CODEC_IDS; ++i) {
- if (codec_ids[i].id == id)
- return codec_ids[i].name;
- }
-
- snprintf(hexname, sizeof(hexname), "0x%x", id);
- return hexname; /* a static is safe because we're single-threaded */
-}
+static struct dma_frame_parser *parser;
static void usage(void)
{
- int i;
-
- fprintf(stderr, "usage: sofprobeclient [OPTIONS] [filename.wav]\n"
- "-c\tcard number\n"
- "-d\tdevice node\n"
- "-b\tbuffer size\n"
- "-f\tfragments\n"
+ fprintf(stderr, "usage: sofprobeclient [OPTIONS]\n"
+ "-c\tcard number (default 3)\n"
+ "-d\tdevice node (default 0)\n"
+ "-b\tbuffer size (default 8192)\n"
+ "-f\tfragments (default 4)\n"
"-v\tverbose mode\n"
- "-l\tlength of record in seconds\n"
+ "-l\tlength of record in seconds (0 = unlimited)\n"
"-h\tPrints this help list\n\n"
"-C\tSpecify the number of channels (default %u)\n"
"-R\tSpecify the sample rate (default %u)\n"
- "-F\tSpecify the format: S16_LE, S32_LE (default S16_LE)\n"
- "-I\tSpecify codec ID (default %s)\n\n"
- "If filename.wav is not given the output is written to stdout\n"
- "Only PCM data can be written to a WAV file.\n\n"
+ "-F\tSpecify the format: S16_LE, S32_LE (default S32_LE)\n\n"
+ "Captured probe data is parsed in real time.\n"
+ "Log output (non-audio probes) is written to stdout.\n"
+ "Audio probe data is written to buffer_<id>.wav files\n"
+ "in the current directory.\n\n"
"Example:\n"
- "\tsofprobeclient -c 1 -d 2 test.wav\n"
- "\tsofprobeclient -f 5 test.wav\n"
- "\tsofprobeclient -I BESPOKE >raw.bin\n\n"
- "Valid codec IDs:\n",
- DEFAULT_CHANNELS, DEFAULT_RATE,
- codec_name_from_id(DEFAULT_CODEC_ID));
-
- for (i = 0; i < CREC_NUM_CODEC_IDS; ++i)
- fprintf(stderr, "%s%c", codec_ids[i].name,
- ((i + 1) % 8) ? ' ' : '\n');
-
- fprintf(stderr, "\nor the value in decimal or hex\n");
+ "\tsofprobeclient\n"
+ "\tsofprobeclient -c 1 -d 2\n",
+ DEFAULT_CHANNELS, DEFAULT_RATE);
exit(EXIT_FAILURE);
}
return 0;
}
-static int finish_record(void)
-{
- struct wave_header header;
- int ret;
- size_t nread, written;
-
- if (!file)
- return -ENOENT;
-
- /* can't rewind if streaming to stdout */
- if (streamed)
- return 0;
-
- /* Get amount of data written to file */
- ret = lseek(file, 0, SEEK_END);
- if (ret < 0)
- return -errno;
-
- written = ret;
- if (written < sizeof(header))
- return -ENOENT;
- written -= sizeof(header);
-
- /* Sync file header from file */
- ret = lseek(file, 0, SEEK_SET);
- if (ret < 0)
- return -errno;
-
- nread = read(file, &header, sizeof(header));
- if (nread != sizeof(header))
- return -errno;
-
- /* Update file header */
- ret = lseek(file, 0, SEEK_SET);
- if (ret < 0)
- return -errno;
-
- size_wave_header(&header, written);
-
- written = write(file, &header, sizeof(header));
- if (written != sizeof(header))
- return -errno;
-
- return 0;
-}
-
-static void capture_samples(char *name, unsigned int card, unsigned int device,
- unsigned long buffer_size, unsigned int frag,
- unsigned int length, unsigned int rate,
- unsigned int channels, unsigned int format,
- unsigned int codec_id)
+static void capture_and_parse(unsigned int card, unsigned int device,
+ unsigned long buffer_size, unsigned int frag,
+ unsigned int length, unsigned int rate,
+ unsigned int channels, unsigned int format)
{
struct compr_config config;
struct snd_codec codec;
struct compress *compress;
- struct wave_header header;
char *buffer;
- size_t written;
int read, ret;
unsigned int size, total_read = 0;
unsigned int samplebits;
+ uint8_t *parse_buf;
+ size_t parse_len;
switch (format) {
case SNDRV_PCM_FORMAT_S32_LE:
if (verbose)
fprintf(finfo, "%s: entry, reading %u bytes\n", __func__, length);
- if (!name) {
- file = STDOUT_FILENO;
- } else {
- file = open(name, O_RDWR | O_CREAT,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
- if (file == -1) {
- fprintf(stderr, "Unable to open file '%s'\n", name);
- exit(EXIT_FAILURE);
- }
- }
-
- /* Write a header, will update with size once record is complete */
- if (!streamed) {
- init_wave_header(&header, channels, rate, samplebits);
- written = write(file, &header, sizeof(header));
- if (written != sizeof(header)) {
- fprintf(stderr, "Error writing output file header: %s\n",
- strerror(errno));
- goto file_exit;
- }
- }
memset(&codec, 0, sizeof(codec));
memset(&config, 0, sizeof(config));
- codec.id = codec_id;
+ codec.id = DEFAULT_CODEC_ID;
codec.ch_in = channels;
codec.ch_out = channels;
codec.sample_rate = rate;
if (!codec.sample_rate) {
fprintf(stderr, "invalid sample rate %d\n", rate);
- goto file_exit;
+ return;
}
codec.format = format;
if ((buffer_size != 0) && (frag != 0)) {
fprintf(stderr, "Unable to open Compress device %d:%d\n",
card, device);
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
- goto file_exit;
+ return;
};
if (verbose)
goto comp_exit;
}
- fprintf(finfo, "Recording file %s On Card %u device %u, with buffer of %u bytes\n",
- name, card, device, size);
+ fprintf(finfo, "Capturing probes on Card %u device %u, buffer %u bytes\n",
+ card, device, size);
fprintf(finfo, "Codec %u Format %u Channels %u, %u Hz\n",
codec.id, codec.format, codec.ch_out, rate);
compress_start(compress);
if (verbose)
- fprintf(finfo, "%s: Capturing audio NOW!!!\n", __func__);
+ fprintf(finfo, "%s: Capturing probe data NOW!!!\n", __func__);
do {
read = compress_read(compress, buffer, size);
if (read > 0) {
total_read += read;
- written = write(file, buffer, read);
- if (written != (size_t)read) {
- fprintf(stderr, "Error writing output file: %s\n",
- strerror(errno));
+ /* Feed captured data into the probe parser */
+ parser_fetch_free_buffer(parser, &parse_buf, &parse_len);
+ if ((size_t)read > parse_len) {
+ fprintf(stderr, "Warning: read %d > parser buffer %zu, truncating\n",
+ read, parse_len);
+ read = parse_len;
+ }
+ memcpy(parse_buf, buffer, read);
+ ret = parser_parse_data(parser, read);
+ if (ret < 0) {
+ fprintf(stderr, "Parser error %d, stopping\n", ret);
goto buf_exit;
}
+
if (verbose) {
print_time(compress);
fprintf(finfo, "%s: read %d\n", __func__, read);
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
}
- ret = finish_record();
- if (ret < 0) {
- fprintf(stderr, "Failed to finish header: %s\n", strerror(ret));
- goto buf_exit;
- }
+ /* Finalize any open wave files */
+ finalize_wave_files(parser);
if (verbose)
fprintf(finfo, "%s: exit success\n", __func__);
free(buffer);
- close(file);
- file = 0;
-
compress_close(compress);
return;
free(buffer);
comp_exit:
compress_close(compress);
-file_exit:
- close(file);
if (verbose)
fprintf(finfo, "%s: exit failure\n", __func__);
static void sig_handler(int signum __attribute__ ((unused)))
{
- finish_record();
-
- if (file)
- close(file);
+ /* Finalize wave files on signal */
+ if (parser)
+ finalize_wave_files(parser);
_exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
- char *file;
unsigned long buffer_size = 8192;
- int c, i;
+ int c;
unsigned int card = 3, device = 0, frag = 4, length = 0;
unsigned int rate = DEFAULT_RATE, channels = DEFAULT_CHANNELS;
unsigned int format = DEFAULT_FORMAT;
- unsigned int codec_id = DEFAULT_CODEC_ID;
if (signal(SIGINT, sig_handler) == SIG_ERR) {
fprintf(stderr, "Error registering signal handler\n");
exit(EXIT_FAILURE);
}
- if (argc < 1)
- usage();
+ /* Initialize the probe parser with log-to-stdout */
+ parser = parser_init();
+ if (!parser) {
+ fprintf(stderr, "Failed to initialize probe parser\n");
+ exit(EXIT_FAILURE);
+ }
+ parser_log_to_stdout(parser);
verbose = 0;
- while ((c = getopt(argc, argv, "hvl:R:C:F:I:b:f:c:d:")) != -1) {
+ finfo = stderr;
+
+ while ((c = getopt(argc, argv, "hvl:R:C:F:b:f:c:d:")) != -1) {
switch (c) {
case 'h':
usage();
usage();
}
break;
- case 'I':
- if (optarg[0] == '0') {
- codec_id = strtol(optarg, NULL, 0);
- } else {
- for (i = 0; i < CREC_NUM_CODEC_IDS; ++i) {
- if (strcmp(optarg,
- codec_ids[i].name) == 0) {
- codec_id = codec_ids[i].id;
- break;
- }
- }
-
- if (i == CREC_NUM_CODEC_IDS) {
- fprintf(stderr, "Unrecognised ID: %s\n",
- optarg);
- usage();
- }
- }
- break;
default:
exit(EXIT_FAILURE);
}
}
- if (optind >= argc) {
- file = NULL;
- finfo = fopen("/dev/null", "w");
- streamed = true;
- } else if (codec_id == SND_AUDIOCODEC_PCM) {
- file = argv[optind];
- finfo = stdout;
- streamed = false;
- } else {
- fprintf(stderr, "ERROR: Only PCM can be written to a WAV file\n");
- exit(EXIT_FAILURE);
- }
-
- capture_samples(file, card, device, buffer_size, frag, length,
- rate, channels, format, codec_id);
+ capture_and_parse(card, device, buffer_size, frag, length,
+ rate, channels, format);
fprintf(finfo, "Finish capturing... Close Normally\n");
+ parser_free(parser);
exit(EXIT_SUCCESS);
}