forked from bg111/asterisk-chan-dongle
-
Notifications
You must be signed in to change notification settings - Fork 105
/
mixbuffer.c
118 lines (96 loc) · 2.49 KB
/
mixbuffer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
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;
}