119 lines
2.5 KiB
C
119 lines
2.5 KiB
C
|
/*
|
||
|
Copyright (C) 2010 bg <bg_one@mail.ru>
|
||
|
*/
|
||
|
#include "ast_config.h"
|
||
|
|
||
|
#include <asterisk/utils.h> /* ast_slinear_saturated_add() */
|
||
|
|
||
|
#include "mixbuffer.h"
|
||
|
|
||
|
#/* */
|
||
|
EXPORT_DEF void mixb_attach(struct mixbuffer * mb, struct mixstream * stream)
|
||
|
{
|
||
|
stream->entry.next = NULL;
|
||
|
stream->used = 0;
|
||
|
stream->write = mb->rb.read;
|
||
|
AST_LIST_INSERT_TAIL(&mb->streams, stream, entry);
|
||
|
mb->attached++;
|
||
|
}
|
||
|
|
||
|
#/* */
|
||
|
EXPORT_DEF void mixb_detach(struct mixbuffer * mb, struct mixstream * stream)
|
||
|
{
|
||
|
mb->attached--;
|
||
|
AST_LIST_REMOVE(&mb->streams, stream, entry);
|
||
|
}
|
||
|
|
||
|
#/* TODO: move up */
|
||
|
static void * saturated_sum(void* s1, const void *s2, size_t n)
|
||
|
{
|
||
|
short* s11 = s1;
|
||
|
short* s22 = (short*)s2;
|
||
|
|
||
|
/* FIXME: odd bytes */
|
||
|
for(n /= 2; n; n--, s11++, s22++)
|
||
|
ast_slinear_saturated_add(s11, s22);
|
||
|
|
||
|
return s1;
|
||
|
}
|
||
|
|
||
|
#/* function not update rb */
|
||
|
static inline size_t mixb_mix_write(struct mixbuffer * mb, struct mixstream * stream, const char * data, size_t len)
|
||
|
{
|
||
|
size_t rv;
|
||
|
/* save global state */
|
||
|
size_t save_write = mb->rb.write;
|
||
|
size_t save_used = mb->rb.used;
|
||
|
|
||
|
/* load local state */
|
||
|
mb->rb.write = stream->write;
|
||
|
mb->rb.used = stream->used;
|
||
|
|
||
|
rv = rb_write_core(&mb->rb, data, len, saturated_sum);
|
||
|
|
||
|
/* update local state */
|
||
|
stream->write = mb->rb.write;
|
||
|
stream->used = mb->rb.used;
|
||
|
|
||
|
/* restore global state */
|
||
|
mb->rb.used = save_used;
|
||
|
mb->rb.write = save_write;
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
#/* */
|
||
|
EXPORT_DEF size_t mixb_write(struct mixbuffer * mb, struct mixstream * stream, const char * data, size_t len)
|
||
|
{
|
||
|
/* local state: how many data you fit? */
|
||
|
size_t max_mix = mixb_free(mb, stream);
|
||
|
|
||
|
if(max_mix < len)
|
||
|
len = max_mix;
|
||
|
|
||
|
if(len > 0)
|
||
|
{
|
||
|
max_mix = mb->rb.used - stream->used;
|
||
|
if(len > max_mix)
|
||
|
{
|
||
|
/* optitional Mix followed by copy */
|
||
|
if(max_mix)
|
||
|
mixb_mix_write(mb, stream, data, max_mix);
|
||
|
rb_write(&mb->rb, data + max_mix, len - max_mix);
|
||
|
|
||
|
/* save local state */
|
||
|
stream->write = mb->rb.write;
|
||
|
stream->used = mb->rb.used;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Mix only */
|
||
|
mixb_mix_write(mb, stream, data, len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
#/* */
|
||
|
EXPORT_DEF size_t mixb_read_upd(struct mixbuffer * mb, size_t len)
|
||
|
{
|
||
|
struct mixstream * stream;
|
||
|
|
||
|
// NOTE: change used, read and also can change write
|
||
|
size_t rv = rb_read_upd(&mb->rb, len);
|
||
|
|
||
|
// all streams has one read but differ used
|
||
|
AST_LIST_TRAVERSE(&mb->streams, stream, entry) {
|
||
|
if(stream->used > len)
|
||
|
stream->used -= len;
|
||
|
else
|
||
|
stream->used = 0;
|
||
|
stream->write = mb->rb.read + stream->used;
|
||
|
if(stream->write >= mb->rb.size)
|
||
|
stream->write -= mb->rb.size;
|
||
|
}
|
||
|
|
||
|
return rv;
|
||
|
}
|