BuildSystem: Remove unused variables.
[asterisk/asterisk.git] / main / smoother.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Frame smoother manipulation routines
22  *
23  * \author Mark Spencer <markster@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/_private.h"
33 #include "asterisk/frame.h"
34 #include "asterisk/astobj2.h"
35 #include "asterisk/time.h"
36 #include "asterisk/utils.h"
37 #include "asterisk/format.h"
38 #include "asterisk/codec.h"
39 #include "asterisk/smoother.h"
40
41 #define SMOOTHER_SIZE 8000
42
43 struct ast_smoother {
44         int size;
45         struct ast_format *format;
46         int flags;
47         float samplesperbyte;
48         unsigned int opt_needs_swap:1;
49         struct ast_frame f;
50         struct timeval delivery;
51         char data[SMOOTHER_SIZE];
52         char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
53         struct ast_frame *opt;
54         int len;
55 };
56
57 static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
58 {
59         if (s->flags & AST_SMOOTHER_FLAG_G729) {
60                 if (s->len % 10) {
61                         ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
62                         return 0;
63                 }
64         }
65         if (swap) {
66                 ast_swapcopy_samples(s->data + s->len, f->data.ptr, f->samples);
67         } else {
68                 memcpy(s->data + s->len, f->data.ptr, f->datalen);
69         }
70         /* If either side is empty, reset the delivery time */
71         if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) {    /* XXX really ? */
72                 s->delivery = f->delivery;
73         }
74         s->len += f->datalen;
75
76         return 0;
77 }
78
79 void ast_smoother_reset(struct ast_smoother *s, int bytes)
80 {
81         ao2_cleanup(s->format);
82         memset(s, 0, sizeof(*s));
83         s->size = bytes;
84 }
85
86 void ast_smoother_reconfigure(struct ast_smoother *s, int bytes)
87 {
88         /* if there is no change, then nothing to do */
89         if (s->size == bytes) {
90                 return;
91         }
92         /* set the new desired output size */
93         s->size = bytes;
94         /* if there is no 'optimized' frame in the smoother,
95          *   then there is nothing left to do
96          */
97         if (!s->opt) {
98                 return;
99         }
100         /* there is an 'optimized' frame here at the old size,
101          * but it must now be put into the buffer so the data
102          * can be extracted at the new size
103          */
104         smoother_frame_feed(s, s->opt, s->opt_needs_swap);
105         s->opt = NULL;
106 }
107
108 struct ast_smoother *ast_smoother_new(int size)
109 {
110         struct ast_smoother *s;
111         if (size < 1)
112                 return NULL;
113         if ((s = ast_calloc(1, sizeof(*s))))
114                 ast_smoother_reset(s, size);
115         return s;
116 }
117
118 int ast_smoother_get_flags(struct ast_smoother *s)
119 {
120         return s->flags;
121 }
122
123 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
124 {
125         s->flags = flags;
126 }
127
128 int ast_smoother_test_flag(struct ast_smoother *s, int flag)
129 {
130         return (s->flags & flag);
131 }
132
133 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
134 {
135         if (f->frametype != AST_FRAME_VOICE) {
136                 ast_log(LOG_WARNING, "Huh?  Can't smooth a non-voice frame!\n");
137                 return -1;
138         }
139         if (!s->format) {
140                 s->format = ao2_bump(f->subclass.format);
141                 s->samplesperbyte = (float)f->samples / (float)f->datalen;
142         } else if (ast_format_cmp(s->format, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
143                 ast_log(LOG_WARNING, "Smoother was working on %s format frames, now trying to feed %s?\n",
144                         ast_format_get_name(s->format), ast_format_get_name(f->subclass.format));
145                 return -1;
146         }
147         if (s->len + f->datalen > SMOOTHER_SIZE) {
148                 ast_log(LOG_WARNING, "Out of smoother space\n");
149                 return -1;
150         }
151         if (((f->datalen == s->size) ||
152              ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) &&
153             !s->opt &&
154             !s->len &&
155             (f->offset >= AST_MIN_OFFSET)) {
156                 /* Optimize by sending the frame we just got
157                    on the next read, thus eliminating the douple
158                    copy */
159                 if (swap)
160                         ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples);
161                 s->opt = f;
162                 s->opt_needs_swap = swap ? 1 : 0;
163                 return 0;
164         }
165
166         return smoother_frame_feed(s, f, swap);
167 }
168
169 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
170 {
171         struct ast_frame *opt;
172         int len;
173
174         /* IF we have an optimization frame, send it */
175         if (s->opt) {
176                 if (s->opt->offset < AST_FRIENDLY_OFFSET)
177                         ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n",
178                                                         s->opt->offset);
179                 opt = s->opt;
180                 s->opt = NULL;
181                 return opt;
182         }
183
184         /* Make sure we have enough data */
185         if (s->len < s->size) {
186                 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
187                 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->len % 10)))
188                         return NULL;
189         }
190         len = s->size;
191         if (len > s->len)
192                 len = s->len;
193         /* Make frame */
194         s->f.frametype = AST_FRAME_VOICE;
195         s->f.subclass.format = s->format;
196         s->f.data.ptr = s->framedata + AST_FRIENDLY_OFFSET;
197         s->f.offset = AST_FRIENDLY_OFFSET;
198         s->f.datalen = len;
199         /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
200         s->f.samples = len * s->samplesperbyte; /* XXX rounding */
201         s->f.delivery = s->delivery;
202         /* Fill Data */
203         memcpy(s->f.data.ptr, s->data, len);
204         s->len -= len;
205         /* Move remaining data to the front if applicable */
206         if (s->len) {
207                 /* In principle this should all be fine because if we are sending
208                    G.729 VAD, the next timestamp will take over anyawy */
209                 memmove(s->data, s->data + len, s->len);
210                 if (!ast_tvzero(s->delivery)) {
211                         /* If we have delivery time, increment it, otherwise, leave it at 0 */
212                         s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples,
213                                 ast_format_get_sample_rate(s->format)));
214                 }
215         }
216         /* Return frame */
217         return &s->f;
218 }
219
220 void ast_smoother_free(struct ast_smoother *s)
221 {
222         ao2_cleanup(s->format);
223         ast_free(s);
224 }