HelenOS sources
This source file includes following definitions.
- audio_data_create
- audio_data_addref
- audio_data_unref
- audio_data_link_list_instance
- audio_data_link_create
- audio_data_link_destroy
- audio_data_link_start
- audio_data_link_remain_size
- audio_data_link_available_frames
- audio_pipe_init
- audio_pipe_fini
- audio_pipe_push
- audio_pipe_pop
- audio_pipe_mix_data
#include <macros.h>
#include <stdlib.h>
#include "audio_data.h"
#include "log.h"
audio_data_t *audio_data_create(void *data, size_t size,
pcm_format_t format)
{
audio_data_t *adata = malloc(sizeof(audio_data_t) + size);
if (adata) {
unsigned overflow = size % pcm_format_frame_size(&format);
if (overflow)
log_warning("Data not a multiple of frame size, "
"clipping.");
adata->data = data;
adata->size = size - overflow;
adata->format = format;
refcount_init(&adata->refcount);
}
return adata;
}
void audio_data_addref(audio_data_t *adata)
{
assert(adata);
refcount_up(&adata->refcount);
}
void audio_data_unref(audio_data_t *adata)
{
assert(adata);
if (refcount_down(&adata->refcount)) {
free(adata->data);
free(adata);
}
}
typedef struct {
link_t link;
audio_data_t *adata;
size_t position;
} audio_data_link_t;
static inline audio_data_link_t *audio_data_link_list_instance(link_t *l)
{
return l ? list_get_instance(l, audio_data_link_t, link) : NULL;
}
static audio_data_link_t *audio_data_link_create(audio_data_t *adata)
{
assert(adata);
audio_data_link_t *link = malloc(sizeof(audio_data_link_t));
if (link) {
audio_data_addref(adata);
link->adata = adata;
link->position = 0;
}
return link;
}
static void audio_data_link_destroy(audio_data_link_t *link)
{
assert(link);
assert(!link_in_use(&link->link));
audio_data_unref(link->adata);
free(link);
}
static inline const void *audio_data_link_start(audio_data_link_t *alink)
{
assert(alink);
assert(alink->adata);
return alink->adata->data + alink->position;
}
static inline size_t audio_data_link_remain_size(audio_data_link_t *alink)
{
assert(alink);
assert(alink->adata);
assert(alink->position <= alink->adata->size);
return alink->adata->size - alink->position;
}
static inline size_t audio_data_link_available_frames(audio_data_link_t *alink)
{
assert(alink);
assert(alink->adata);
return pcm_format_size_to_frames(audio_data_link_remain_size(alink),
&alink->adata->format);
}
void audio_pipe_init(audio_pipe_t *pipe)
{
assert(pipe);
list_initialize(&pipe->list);
fibril_mutex_initialize(&pipe->guard);
pipe->frames = 0;
pipe->bytes = 0;
}
void audio_pipe_fini(audio_pipe_t *pipe)
{
assert(pipe);
while (!list_empty(&pipe->list)) {
audio_data_t *adata = audio_pipe_pop(pipe);
audio_data_unref(adata);
}
}
errno_t audio_pipe_push(audio_pipe_t *pipe, audio_data_t *data)
{
assert(pipe);
assert(data);
audio_data_link_t *alink = audio_data_link_create(data);
if (!alink)
return ENOMEM;
fibril_mutex_lock(&pipe->guard);
list_append(&alink->link, &pipe->list);
pipe->bytes += audio_data_link_remain_size(alink);
pipe->frames += audio_data_link_available_frames(alink);
fibril_mutex_unlock(&pipe->guard);
return EOK;
}
audio_data_t *audio_pipe_pop(audio_pipe_t *pipe)
{
assert(pipe);
fibril_mutex_lock(&pipe->guard);
audio_data_t *adata = NULL;
link_t *l = list_first(&pipe->list);
if (l) {
audio_data_link_t *alink = audio_data_link_list_instance(l);
list_remove(&alink->link);
pipe->bytes -= audio_data_link_remain_size(alink);
pipe->frames -= audio_data_link_available_frames(alink);
adata = alink->adata;
audio_data_addref(adata);
audio_data_link_destroy(alink);
}
fibril_mutex_unlock(&pipe->guard);
return adata;
}
size_t audio_pipe_mix_data(audio_pipe_t *pipe, void *data,
size_t size, const pcm_format_t *f)
{
assert(pipe);
const size_t dst_frame_size = pcm_format_frame_size(f);
size_t needed_frames = pcm_format_size_to_frames(size, f);
size_t copied_size = 0;
fibril_mutex_lock(&pipe->guard);
while (needed_frames > 0 && !list_empty(&pipe->list)) {
link_t *l = list_first(&pipe->list);
audio_data_link_t *alink = audio_data_link_list_instance(l);
const size_t src_frame_size =
pcm_format_frame_size(&alink->adata->format);
const size_t available_frames =
audio_data_link_available_frames(alink);
const size_t copy_frames = min(available_frames, needed_frames);
const size_t dst_copy_size = copy_frames * dst_frame_size;
const size_t src_copy_size = copy_frames * src_frame_size;
assert(src_copy_size <= audio_data_link_remain_size(alink));
pcm_format_convert_and_mix(data, dst_copy_size,
audio_data_link_start(alink), src_copy_size,
&alink->adata->format, f);
needed_frames -= copy_frames;
copied_size += dst_copy_size;
data += dst_copy_size;
alink->position += src_copy_size;
pipe->bytes -= src_copy_size;
pipe->frames -= copy_frames;
if (audio_data_link_remain_size(alink) == 0) {
list_remove(&alink->link);
audio_data_link_destroy(alink);
} else {
assert(needed_frames == 0);
}
}
fibril_mutex_unlock(&pipe->guard);
return copied_size;
}
HelenOS homepage, sources at GitHub