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