BuildSystem: Remove unused variables.
[asterisk/asterisk.git] / main / frame.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 and codec 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/lock.h"
34 #include "asterisk/frame.h"
35 #include "asterisk/format_cache.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/cli.h"
38 #include "asterisk/term.h"
39 #include "asterisk/utils.h"
40 #include "asterisk/threadstorage.h"
41 #include "asterisk/linkedlists.h"
42 #include "asterisk/translate.h"
43 #include "asterisk/dsp.h"
44 #include "asterisk/file.h"
45
46 #if !defined(LOW_MEMORY)
47 static void frame_cache_cleanup(void *data);
48
49 /*! \brief A per-thread cache of frame headers */
50 AST_THREADSTORAGE_CUSTOM(frame_cache, NULL, frame_cache_cleanup);
51
52 /*!
53  * \brief Maximum ast_frame cache size
54  *
55  * In most cases where the frame header cache will be useful, the size
56  * of the cache will stay very small.  However, it is not always the case that
57  * the same thread that allocates the frame will be the one freeing them, so
58  * sometimes a thread will never have any frames in its cache, or the cache
59  * will never be pulled from.  For the latter case, we limit the maximum size.
60  */
61 #define FRAME_CACHE_MAX_SIZE    10
62
63 /*! \brief This is just so ast_frames, a list head struct for holding a list of
64  *  ast_frame structures, is defined. */
65 AST_LIST_HEAD_NOLOCK(ast_frames, ast_frame);
66
67 struct ast_frame_cache {
68         struct ast_frames list;
69         size_t size;
70 };
71 #endif
72
73 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
74
75 static struct ast_frame *ast_frame_header_new(void)
76 {
77         struct ast_frame *f;
78
79 #if !defined(LOW_MEMORY)
80         struct ast_frame_cache *frames;
81
82         if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
83                 if ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) {
84                         size_t mallocd_len = f->mallocd_hdr_len;
85
86                         memset(f, 0, sizeof(*f));
87                         f->mallocd_hdr_len = mallocd_len;
88                         frames->size--;
89                         return f;
90                 }
91         }
92         if (!(f = ast_calloc_cache(1, sizeof(*f))))
93                 return NULL;
94 #else
95         if (!(f = ast_calloc(1, sizeof(*f))))
96                 return NULL;
97 #endif
98
99         f->mallocd_hdr_len = sizeof(*f);
100
101         return f;
102 }
103
104 #if !defined(LOW_MEMORY)
105 static void frame_cache_cleanup(void *data)
106 {
107         struct ast_frame_cache *frames = data;
108         struct ast_frame *f;
109
110         while ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list)))
111                 ast_free(f);
112
113         ast_free(frames);
114 }
115 #endif
116
117 static void __frame_free(struct ast_frame *fr, int cache)
118 {
119         if (!fr->mallocd)
120                 return;
121
122 #if !defined(LOW_MEMORY)
123         if (fr->mallocd == AST_MALLOCD_HDR
124                 && cache
125                 && ast_opt_cache_media_frames) {
126                 /* Cool, only the header is malloc'd, let's just cache those for now
127                  * to keep things simple... */
128                 struct ast_frame_cache *frames;
129
130                 frames = ast_threadstorage_get(&frame_cache, sizeof(*frames));
131                 if (frames && frames->size < FRAME_CACHE_MAX_SIZE) {
132                         if (fr->frametype == AST_FRAME_VOICE
133                                 || fr->frametype == AST_FRAME_VIDEO
134                                 || fr->frametype == AST_FRAME_IMAGE) {
135                                 ao2_cleanup(fr->subclass.format);
136                         }
137
138                         AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
139                         frames->size++;
140                         return;
141                 }
142         }
143 #endif
144
145         if (fr->mallocd & AST_MALLOCD_DATA) {
146                 if (fr->data.ptr) {
147                         ast_free(fr->data.ptr - fr->offset);
148                 }
149         }
150         if (fr->mallocd & AST_MALLOCD_SRC) {
151                 ast_free((void *) fr->src);
152         }
153         if (fr->mallocd & AST_MALLOCD_HDR) {
154                 if (fr->frametype == AST_FRAME_VOICE
155                         || fr->frametype == AST_FRAME_VIDEO
156                         || fr->frametype == AST_FRAME_IMAGE) {
157                         ao2_cleanup(fr->subclass.format);
158                 }
159
160                 ast_free(fr);
161         } else {
162                 fr->mallocd = 0;
163         }
164 }
165
166
167 void ast_frame_free(struct ast_frame *frame, int cache)
168 {
169         struct ast_frame *next;
170
171         while (frame) {
172                 next = AST_LIST_NEXT(frame, frame_list);
173                 __frame_free(frame, cache);
174                 frame = next;
175         }
176 }
177
178 void ast_frame_dtor(struct ast_frame *f)
179 {
180         ast_frfree(f);
181 }
182
183 /*!
184  * \brief 'isolates' a frame by duplicating non-malloc'ed components
185  * (header, src, data).
186  * On return all components are malloc'ed
187  */
188 struct ast_frame *ast_frisolate(struct ast_frame *fr)
189 {
190         struct ast_frame *out;
191         void *newdata;
192
193         /* if none of the existing frame is malloc'd, let ast_frdup() do it
194            since it is more efficient
195         */
196         if (fr->mallocd == 0) {
197                 return ast_frdup(fr);
198         }
199
200         /* if everything is already malloc'd, we are done */
201         if ((fr->mallocd & (AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA)) ==
202             (AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA)) {
203                 return fr;
204         }
205
206         if (!(fr->mallocd & AST_MALLOCD_HDR)) {
207                 /* Allocate a new header if needed */
208                 if (!(out = ast_frame_header_new())) {
209                         return NULL;
210                 }
211                 out->frametype = fr->frametype;
212                 out->subclass = fr->subclass;
213                 if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
214                         (fr->frametype == AST_FRAME_IMAGE)) {
215                         ao2_bump(out->subclass.format);
216                 }
217                 out->datalen = fr->datalen;
218                 out->samples = fr->samples;
219                 out->mallocd = AST_MALLOCD_HDR;
220                 out->offset = fr->offset;
221                 /* Copy the timing data */
222                 ast_copy_flags(out, fr, AST_FLAGS_ALL);
223                 if (ast_test_flag(fr, AST_FRFLAG_HAS_TIMING_INFO)) {
224                         out->ts = fr->ts;
225                         out->len = fr->len;
226                         out->seqno = fr->seqno;
227                 }
228                 out->stream_num = fr->stream_num;
229         } else {
230                 out = fr;
231         }
232
233         if (fr->src) {
234                 /* The original frame has a source string */
235                 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
236                         /*
237                          * The original frame has a non-malloced source string.
238                          *
239                          * Duplicate the string and put it into the isolated frame
240                          * which may also be the original frame.
241                          */
242                         newdata = ast_strdup(fr->src);
243                         if (!newdata) {
244                                 if (out != fr) {
245                                         ast_frame_free(out, 0);
246                                 }
247                                 return NULL;
248                         }
249                         out->src = newdata;
250                         out->mallocd |= AST_MALLOCD_SRC;
251                 } else if (out != fr) {
252                         /* Steal the source string from the original frame. */
253                         out->src = fr->src;
254                         fr->src = NULL;
255                         fr->mallocd &= ~AST_MALLOCD_SRC;
256                         out->mallocd |= AST_MALLOCD_SRC;
257                 }
258         }
259
260         if (!(fr->mallocd & AST_MALLOCD_DATA))  {
261                 /* The original frame has a non-malloced data buffer. */
262                 if (!fr->datalen) {
263                         /* Actually it's just an int so we can simply copy it. */
264                         out->data.uint32 = fr->data.uint32;
265                         return out;
266                 }
267                 /*
268                  * Duplicate the data buffer and put it into the isolated frame
269                  * which may also be the original frame.
270                  */
271                 newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET);
272                 if (!newdata) {
273                         if (out != fr) {
274                                 ast_frame_free(out, 0);
275                         }
276                         return NULL;
277                 }
278                 newdata += AST_FRIENDLY_OFFSET;
279                 out->offset = AST_FRIENDLY_OFFSET;
280                 memcpy(newdata, fr->data.ptr, fr->datalen);
281                 out->data.ptr = newdata;
282                 out->mallocd |= AST_MALLOCD_DATA;
283         } else if (out != fr) {
284                 /* Steal the data buffer from the original frame. */
285                 out->data = fr->data;
286                 memset(&fr->data, 0, sizeof(fr->data));
287                 fr->mallocd &= ~AST_MALLOCD_DATA;
288                 out->mallocd |= AST_MALLOCD_DATA;
289         }
290
291         return out;
292 }
293
294 struct ast_frame *ast_frdup(const struct ast_frame *f)
295 {
296         struct ast_frame *out = NULL;
297         int len, srclen = 0;
298         void *buf = NULL;
299
300 #if !defined(LOW_MEMORY)
301         struct ast_frame_cache *frames;
302 #endif
303
304         /* Start with standard stuff */
305         len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
306         /* If we have a source, add space for it */
307         /*
308          * XXX Watch out here - if we receive a src which is not terminated
309          * properly, we can be easily attacked. Should limit the size we deal with.
310          */
311         if (f->src)
312                 srclen = strlen(f->src);
313         if (srclen > 0)
314                 len += srclen + 1;
315
316 #if !defined(LOW_MEMORY)
317         if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
318                 AST_LIST_TRAVERSE_SAFE_BEGIN(&frames->list, out, frame_list) {
319                         if (out->mallocd_hdr_len >= len) {
320                                 size_t mallocd_len = out->mallocd_hdr_len;
321
322                                 AST_LIST_REMOVE_CURRENT(frame_list);
323                                 memset(out, 0, sizeof(*out));
324                                 out->mallocd_hdr_len = mallocd_len;
325                                 buf = out;
326                                 frames->size--;
327                                 break;
328                         }
329                 }
330                 AST_LIST_TRAVERSE_SAFE_END;
331         }
332 #endif
333
334         if (!buf) {
335                 if (!(buf = ast_calloc_cache(1, len)))
336                         return NULL;
337                 out = buf;
338                 out->mallocd_hdr_len = len;
339         }
340
341         out->frametype = f->frametype;
342         out->subclass = f->subclass;
343         if ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO) ||
344                 (f->frametype == AST_FRAME_IMAGE)) {
345                 ao2_bump(out->subclass.format);
346         }
347         out->datalen = f->datalen;
348         out->samples = f->samples;
349         out->delivery = f->delivery;
350         /* Even though this new frame was allocated from the heap, we can't mark it
351          * with AST_MALLOCD_HDR, AST_MALLOCD_DATA and AST_MALLOCD_SRC, because that
352          * would cause ast_frfree() to attempt to individually free each of those
353          * under the assumption that they were separately allocated. Since this frame
354          * was allocated in a single allocation, we'll only mark it as if the header
355          * was heap-allocated; this will result in the entire frame being properly freed.
356          */
357         out->mallocd = AST_MALLOCD_HDR;
358         out->offset = AST_FRIENDLY_OFFSET;
359         if (out->datalen) {
360                 out->data.ptr = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
361                 memcpy(out->data.ptr, f->data.ptr, out->datalen);
362         } else {
363                 out->data.uint32 = f->data.uint32;
364         }
365         if (srclen > 0) {
366                 /* This may seem a little strange, but it's to avoid a gcc (4.2.4) compiler warning */
367                 char *src;
368                 out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
369                 src = (char *) out->src;
370                 /* Must have space since we allocated for it */
371                 strcpy(src, f->src);
372         }
373         ast_copy_flags(out, f, AST_FLAGS_ALL);
374         out->ts = f->ts;
375         out->len = f->len;
376         out->seqno = f->seqno;
377         out->stream_num = f->stream_num;
378         return out;
379 }
380
381 void ast_swapcopy_samples(void *dst, const void *src, int samples)
382 {
383         int i;
384         unsigned short *dst_s = dst;
385         const unsigned short *src_s = src;
386
387         for (i = 0; i < samples; i++)
388                 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
389 }
390
391 void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, char *moreinfo, size_t mlen)
392 {
393         switch(f->frametype) {
394         case AST_FRAME_DTMF_BEGIN:
395                 if (slen > 1) {
396                         subclass[0] = f->subclass.integer;
397                         subclass[1] = '\0';
398                 }
399                 break;
400         case AST_FRAME_DTMF_END:
401                 if (slen > 1) {
402                         subclass[0] = f->subclass.integer;
403                         subclass[1] = '\0';
404                 }
405                 break;
406         case AST_FRAME_CONTROL:
407                 switch (f->subclass.integer) {
408                 case AST_CONTROL_HANGUP:
409                         ast_copy_string(subclass, "Hangup", slen);
410                         break;
411                 case AST_CONTROL_RING:
412                         ast_copy_string(subclass, "Ring", slen);
413                         break;
414                 case AST_CONTROL_RINGING:
415                         ast_copy_string(subclass, "Ringing", slen);
416                         break;
417                 case AST_CONTROL_ANSWER:
418                         ast_copy_string(subclass, "Answer", slen);
419                         break;
420                 case AST_CONTROL_BUSY:
421                         ast_copy_string(subclass, "Busy", slen);
422                         break;
423                 case AST_CONTROL_TAKEOFFHOOK:
424                         ast_copy_string(subclass, "Take Off Hook", slen);
425                         break;
426                 case AST_CONTROL_OFFHOOK:
427                         ast_copy_string(subclass, "Line Off Hook", slen);
428                         break;
429                 case AST_CONTROL_CONGESTION:
430                         ast_copy_string(subclass, "Congestion", slen);
431                         break;
432                 case AST_CONTROL_FLASH:
433                         ast_copy_string(subclass, "Flash", slen);
434                         break;
435                 case AST_CONTROL_WINK:
436                         ast_copy_string(subclass, "Wink", slen);
437                         break;
438                 case AST_CONTROL_OPTION:
439                         ast_copy_string(subclass, "Option", slen);
440                         break;
441                 case AST_CONTROL_RADIO_KEY:
442                         ast_copy_string(subclass, "Key Radio", slen);
443                         break;
444                 case AST_CONTROL_RADIO_UNKEY:
445                         ast_copy_string(subclass, "Unkey Radio", slen);
446                         break;
447                 case AST_CONTROL_HOLD:
448                         ast_copy_string(subclass, "Hold", slen);
449                         break;
450                 case AST_CONTROL_UNHOLD:
451                         ast_copy_string(subclass, "Unhold", slen);
452                         break;
453                 case AST_CONTROL_T38_PARAMETERS: {
454                         char *message = "Unknown";
455                         if (f->datalen != sizeof(struct ast_control_t38_parameters)) {
456                                 message = "Invalid";
457                         } else {
458                                 struct ast_control_t38_parameters *parameters = f->data.ptr;
459                                 enum ast_control_t38 state = parameters->request_response;
460                                 if (state == AST_T38_REQUEST_NEGOTIATE)
461                                         message = "Negotiation Requested";
462                                 else if (state == AST_T38_REQUEST_TERMINATE)
463                                         message = "Negotiation Request Terminated";
464                                 else if (state == AST_T38_NEGOTIATED)
465                                         message = "Negotiated";
466                                 else if (state == AST_T38_TERMINATED)
467                                         message = "Terminated";
468                                 else if (state == AST_T38_REFUSED)
469                                         message = "Refused";
470                         }
471                         snprintf(subclass, slen, "T38_Parameters/%s", message);
472                         break;
473                 }
474                 case -1:
475                         ast_copy_string(subclass, "Stop generators", slen);
476                         break;
477                 default:
478                         snprintf(subclass, slen, "Unknown control '%d'", f->subclass.integer);
479                 }
480                 break;
481         case AST_FRAME_NULL:
482                 ast_copy_string(subclass, "N/A", slen);
483                 break;
484         case AST_FRAME_IAX:
485                 /* Should never happen */
486                 snprintf(subclass, slen, "IAX Frametype %d", f->subclass.integer);
487                 break;
488         case AST_FRAME_BRIDGE_ACTION:
489                 /* Should never happen */
490                 snprintf(subclass, slen, "Bridge Frametype %d", f->subclass.integer);
491                 break;
492         case AST_FRAME_BRIDGE_ACTION_SYNC:
493                 /* Should never happen */
494                 snprintf(subclass, slen, "Synchronous Bridge Frametype %d", f->subclass.integer);
495                 break;
496         case AST_FRAME_TEXT:
497                 ast_copy_string(subclass, "N/A", slen);
498                 if (moreinfo) {
499                         ast_copy_string(moreinfo, f->data.ptr, mlen);
500                 }
501                 break;
502         case AST_FRAME_IMAGE:
503                 snprintf(subclass, slen, "Image format %s\n", ast_format_get_name(f->subclass.format));
504                 break;
505         case AST_FRAME_HTML:
506                 switch (f->subclass.integer) {
507                 case AST_HTML_URL:
508                         ast_copy_string(subclass, "URL", slen);
509                         if (moreinfo) {
510                                 ast_copy_string(moreinfo, f->data.ptr, mlen);
511                         }
512                         break;
513                 case AST_HTML_DATA:
514                         ast_copy_string(subclass, "Data", slen);
515                         break;
516                 case AST_HTML_BEGIN:
517                         ast_copy_string(subclass, "Begin", slen);
518                         break;
519                 case AST_HTML_END:
520                         ast_copy_string(subclass, "End", slen);
521                         break;
522                 case AST_HTML_LDCOMPLETE:
523                         ast_copy_string(subclass, "Load Complete", slen);
524                         break;
525                 case AST_HTML_NOSUPPORT:
526                         ast_copy_string(subclass, "No Support", slen);
527                         break;
528                 case AST_HTML_LINKURL:
529                         ast_copy_string(subclass, "Link URL", slen);
530                         if (moreinfo) {
531                                 ast_copy_string(moreinfo, f->data.ptr, mlen);
532                         }
533                         break;
534                 case AST_HTML_UNLINK:
535                         ast_copy_string(subclass, "Unlink", slen);
536                         break;
537                 case AST_HTML_LINKREJECT:
538                         ast_copy_string(subclass, "Link Reject", slen);
539                         break;
540                 default:
541                         snprintf(subclass, slen, "Unknown HTML frame '%d'\n", f->subclass.integer);
542                         break;
543                 }
544                 break;
545         case AST_FRAME_MODEM:
546                 switch (f->subclass.integer) {
547                 case AST_MODEM_T38:
548                         ast_copy_string(subclass, "T.38", slen);
549                         break;
550                 case AST_MODEM_V150:
551                         ast_copy_string(subclass, "V.150", slen);
552                         break;
553                 default:
554                         snprintf(subclass, slen, "Unknown MODEM frame '%d'\n", f->subclass.integer);
555                         break;
556                 }
557                 break;
558         case AST_FRAME_RTCP:
559                 ast_copy_string(subclass, "RTCP", slen);
560         default:
561                 ast_copy_string(subclass, "Unknown Subclass", slen);
562                 break;
563         }
564 }
565
566 void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
567 {
568         switch (frame_type) {
569         case AST_FRAME_DTMF_BEGIN:
570                 ast_copy_string(ftype, "DTMF Begin", len);
571                 break;
572         case AST_FRAME_DTMF_END:
573                 ast_copy_string(ftype, "DTMF End", len);
574                 break;
575         case AST_FRAME_CONTROL:
576                 ast_copy_string(ftype, "Control", len);
577                 break;
578         case AST_FRAME_NULL:
579                 ast_copy_string(ftype, "Null Frame", len);
580                 break;
581         case AST_FRAME_IAX:
582                 /* Should never happen */
583                 ast_copy_string(ftype, "IAX Specific", len);
584                 break;
585         case AST_FRAME_BRIDGE_ACTION:
586                 /* Should never happen */
587                 ast_copy_string(ftype, "Bridge Specific", len);
588                 break;
589         case AST_FRAME_BRIDGE_ACTION_SYNC:
590                 /* Should never happen */
591                 ast_copy_string(ftype, "Bridge Specific", len);
592                 break;
593         case AST_FRAME_TEXT:
594                 ast_copy_string(ftype, "Text", len);
595                 break;
596         case AST_FRAME_IMAGE:
597                 ast_copy_string(ftype, "Image", len);
598                 break;
599         case AST_FRAME_HTML:
600                 ast_copy_string(ftype, "HTML", len);
601                 break;
602         case AST_FRAME_MODEM:
603                 ast_copy_string(ftype, "Modem", len);
604                 break;
605         case AST_FRAME_VOICE:
606                 ast_copy_string(ftype, "Voice", len);
607                 break;
608         case AST_FRAME_VIDEO:
609                 ast_copy_string(ftype, "Video", len);
610                 break;
611         case AST_FRAME_RTCP:
612                 ast_copy_string(ftype, "RTCP", len);
613                 break;
614         default:
615                 snprintf(ftype, len, "Unknown Frametype '%u'", frame_type);
616                 break;
617         }
618 }
619
620 /*! Dump a frame for debugging purposes */
621 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
622 {
623         const char noname[] = "unknown";
624         char ftype[40] = "Unknown Frametype";
625         char cft[80];
626         char subclass[40] = "Unknown Subclass";
627         char csub[80];
628         char moreinfo[40] = "";
629         char cn[60];
630         char cp[40];
631         char cmn[40];
632
633         if (!name) {
634                 name = noname;
635         }
636
637         if (!f) {
638                 ast_verb(-1, "%s [ %s (NULL) ] [%s]\n",
639                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
640                         term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
641                         term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
642                 return;
643         }
644         /* XXX We should probably print one each of voice and video when the format changes XXX */
645         if (f->frametype == AST_FRAME_VOICE) {
646                 return;
647         }
648         if (f->frametype == AST_FRAME_VIDEO) {
649                 return;
650         }
651         if (f->frametype == AST_FRAME_RTCP) {
652                 return;
653         }
654
655         ast_frame_type2str(f->frametype, ftype, sizeof(ftype));
656         ast_frame_subclass2str(f, subclass, sizeof(subclass), moreinfo, sizeof(moreinfo));
657
658         if (!ast_strlen_zero(moreinfo))
659                 ast_verb(-1, "%s [ TYPE: %s (%u) SUBCLASS: %s (%d) '%s' ] [%s]\n",
660                             term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
661                             term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
662                             f->frametype,
663                             term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
664                             f->subclass.integer,
665                             term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
666                             term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
667         else
668                 ast_verb(-1, "%s [ TYPE: %s (%u) SUBCLASS: %s (%d) ] [%s]\n",
669                             term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
670                             term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
671                             f->frametype,
672                             term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
673                             f->subclass.integer,
674                             term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
675 }
676
677 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
678 {
679         int count;
680         short *fdata = f->data.ptr;
681         short adjust_value = abs(adjustment);
682
683         if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_cache_is_slinear(f->subclass.format))) {
684                 return -1;
685         }
686
687         if (!adjustment) {
688                 return 0;
689         }
690
691         for (count = 0; count < f->samples; count++) {
692                 if (adjustment > 0) {
693                         ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
694                 } else if (adjustment < 0) {
695                         ast_slinear_saturated_divide(&fdata[count], &adjust_value);
696                 }
697         }
698
699         return 0;
700 }
701
702 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
703 {
704         int count;
705         short *data1, *data2;
706
707         if ((f1->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f1->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL))
708                 return -1;
709
710         if ((f2->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f2->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL))
711                 return -1;
712
713         if (f1->samples != f2->samples)
714                 return -1;
715
716         for (count = 0, data1 = f1->data.ptr, data2 = f2->data.ptr;
717              count < f1->samples;
718              count++, data1++, data2++)
719                 ast_slinear_saturated_add(data1, data2);
720
721         return 0;
722 }
723
724 int ast_frame_clear(struct ast_frame *frame)
725 {
726         struct ast_frame *next;
727
728         for (next = AST_LIST_NEXT(frame, frame_list);
729                  frame;
730                  frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {
731                 memset(frame->data.ptr, 0, frame->datalen);
732         }
733         return 0;
734 }