HelenOS sources
This source file includes following definitions.
- record_initialize
- device_event_callback
- record_fragment
- drecord
#include <assert.h>
#include <errno.h>
#include <fibril.h>
#include <str_error.h>
#include <audio_pcm_iface.h>
#include <pcm/format.h>
#include <stdio.h>
#include <as.h>
#include <inttypes.h>
#include <str.h>
#include "wave.h"
#include "drec.h"
#define BUFFER_PARTS 16
static const pcm_format_t format = {
.sampling_rate = 44100,
.channels = 2,
.sample_format = PCM_SAMPLE_SINT16_LE,
};
typedef struct {
struct {
void *base;
size_t size;
unsigned id;
void *position;
} buffer;
FILE *file;
audio_pcm_sess_t *device;
} record_t;
static void record_initialize(record_t *rec, audio_pcm_sess_t *sess)
{
assert(sess);
assert(rec);
rec->buffer.base = NULL;
rec->buffer.size = 0;
rec->buffer.position = NULL;
rec->file = NULL;
rec->device = sess;
}
static void device_event_callback(ipc_call_t *icall, void *arg)
{
record_t *rec = arg;
const size_t buffer_part = rec->buffer.size / BUFFER_PARTS;
bool record = true;
while (record) {
ipc_call_t call;
async_get_call(&call);
switch (ipc_get_imethod(&call)) {
case PCM_EVENT_CAPTURE_TERMINATED:
printf("Recording terminated\n");
record = false;
break;
case PCM_EVENT_FRAMES_CAPTURED:
printf("%" PRIun " frames\n", ipc_get_arg1(&call));
break;
default:
printf("Unknown event %" PRIun ".\n", ipc_get_imethod(&call));
async_answer_0(&call, ENOTSUP);
continue;
}
if (!record) {
async_answer_0(&call, EOK);
break;
}
const size_t bytes = fwrite(rec->buffer.position,
sizeof(uint8_t), buffer_part, rec->file);
printf("%zu ", bytes);
rec->buffer.position += buffer_part;
if (rec->buffer.position >= (rec->buffer.base + rec->buffer.size))
rec->buffer.position = rec->buffer.base;
async_answer_0(&call, EOK);
}
}
static void record_fragment(record_t *rec, pcm_format_t f)
{
assert(rec);
assert(rec->device);
errno_t ret = audio_pcm_register_event_callback(rec->device,
device_event_callback, rec);
if (ret != EOK) {
printf("Failed to register for events: %s.\n", str_error(ret));
return;
}
rec->buffer.position = rec->buffer.base;
printf("Recording: %dHz, %s, %d channel(s).\n", f.sampling_rate,
pcm_sample_format_str(f.sample_format), f.channels);
const unsigned frames =
pcm_format_size_to_frames(rec->buffer.size / BUFFER_PARTS, &f);
ret = audio_pcm_start_capture_fragment(rec->device,
frames, f.channels, f.sampling_rate, f.sample_format);
if (ret != EOK) {
printf("Failed to start recording: %s.\n", str_error(ret));
return;
}
getchar();
printf("\n");
audio_pcm_stop_capture(rec->device);
printf("Delay before playback termination\n");
fibril_usleep(1000000);
printf("Terminate playback\n");
}
int drecord(const char *device, const char *file)
{
errno_t ret = EOK;
audio_pcm_sess_t *session = NULL;
sysarg_t val;
if (str_cmp(device, "default") == 0) {
session = audio_pcm_open_default();
} else {
session = audio_pcm_open(device);
}
if (!session) {
printf("Failed to connect to device %s.\n", device);
return 1;
}
printf("Recording on device: %s.\n", device);
ret = audio_pcm_query_cap(session, AUDIO_CAP_CAPTURE, &val);
if (ret != EOK || !val) {
printf("Device %s does not support recording\n", device);
ret = ENOTSUP;
goto close_session;
}
char *info = NULL;
ret = audio_pcm_get_info_str(session, &info);
if (ret != EOK) {
printf("Failed to get PCM info.\n");
goto close_session;
}
printf("Capturing on %s.\n", info);
free(info);
record_t rec;
record_initialize(&rec, session);
ret = audio_pcm_get_buffer(rec.device, &rec.buffer.base,
&rec.buffer.size);
if (ret != EOK) {
printf("Failed to get PCM buffer: %s.\n", str_error(ret));
goto close_session;
}
printf("Buffer: %p %zu.\n", rec.buffer.base, rec.buffer.size);
rec.file = fopen(file, "w");
if (rec.file == NULL) {
ret = ENOENT;
printf("Failed to open file: %s.\n", file);
goto cleanup;
}
wave_header_t header;
fseek(rec.file, sizeof(header), SEEK_SET);
if (ret != EOK) {
printf("Error parsing wav header\n");
goto cleanup;
}
ret = audio_pcm_query_cap(rec.device, AUDIO_CAP_INTERRUPT, &val);
if (ret == EOK && val)
record_fragment(&rec, format);
else
printf("Recording method is not supported");
wav_init_header(&header, format, ftell(rec.file) - sizeof(header));
fseek(rec.file, 0, SEEK_SET);
fwrite(&header, sizeof(header), 1, rec.file);
cleanup:
fclose(rec.file);
as_area_destroy(rec.buffer.base);
audio_pcm_release_buffer(rec.device);
close_session:
audio_pcm_close(session);
return ret == EOK ? 0 : 1;
}
HelenOS homepage, sources at GitHub