CI: Various updates to buildAsterisk.sh
[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 && fr->frametype != AST_FRAME_TEXT) {
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         /* Make sure that empty text frames have a valid data.ptr */
360         if (out->datalen || f->frametype == AST_FRAME_TEXT) {
361                 out->data.ptr = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
362                 memcpy(out->data.ptr, f->data.ptr, out->datalen);
363         } else {
364                 out->data.uint32 = f->data.uint32;
365         }
366         if (srclen > 0) {
367                 /* This may seem a little strange, but it's to avoid a gcc (4.2.4) compiler warning */
368                 char *src;
369                 out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
370                 src = (char *) out->src;
371                 /* Must have space since we allocated for it */
372                 strcpy(src, f->src);
373         }
374         ast_copy_flags(out, f, AST_FLAGS_ALL);
375         out->ts = f->ts;
376         out->len = f->len;
377         out->seqno = f->seqno;
378         out->stream_num = f->stream_num;
379         return out;
380 }
381
382 void ast_swapcopy_samples(void *dst, const void *src, int samples)
383 {
384         int i;
385         unsigned short *dst_s = dst;
386         const unsigned short *src_s = src;
387
388         for (i = 0; i < samples; i++)
389                 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
390 }
391
392 void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, char *moreinfo, size_t mlen)
393 {
394         switch(f->frametype) {
395         case AST_FRAME_DTMF_BEGIN:
396                 if (slen > 1) {
397                         subclass[0] = f->subclass.integer;
398                         subclass[1] = '\0';
399                 }
400                 break;
401         case AST_FRAME_DTMF_END:
402                 if (slen > 1) {
403                         subclass[0] = f->subclass.integer;
404                         subclass[1] = '\0';
405                 }
406                 break;
407         case AST_FRAME_CONTROL:
408                 switch (f->subclass.integer) {
409                 case AST_CONTROL_HANGUP:
410                         ast_copy_string(subclass, "Hangup", slen);
411                         break;
412                 case AST_CONTROL_RING:
413                         ast_copy_string(subclass, "Ring", slen);
414                         break;
415                 case AST_CONTROL_RINGING:
416                         ast_copy_string(subclass, "Ringing", slen);
417                         break;
418                 case AST_CONTROL_ANSWER:
419                         ast_copy_string(subclass, "Answer", slen);
420                         break;
421                 case AST_CONTROL_BUSY:
422                         ast_copy_string(subclass, "Busy", slen);
423                         break;
424                 case AST_CONTROL_TAKEOFFHOOK:
425                         ast_copy_string(subclass, "Take Off Hook", slen);
426                         break;
427                 case AST_CONTROL_OFFHOOK:
428                         ast_copy_string(subclass, "Line Off Hook", slen);
429                         break;
430                 case AST_CONTROL_CONGESTION:
431                         ast_copy_string(subclass, "Congestion", slen);
432                         break;
433                 case AST_CONTROL_FLASH:
434                         ast_copy_string(subclass, "Flash", slen);
435                         break;
436                 case AST_CONTROL_WINK:
437                         ast_copy_string(subclass, "Wink", slen);
438                         break;
439                 case AST_CONTROL_OPTION:
440                         ast_copy_string(subclass, "Option", slen);
441                         break;
442                 case AST_CONTROL_RADIO_KEY:
443                         ast_copy_string(subclass, "Key Radio", slen);
444                         break;
445                 case AST_CONTROL_RADIO_UNKEY:
446                         ast_copy_string(subclass, "Unkey Radio", slen);
447                         break;
448                 case AST_CONTROL_HOLD:
449                         ast_copy_string(subclass, "Hold", slen);
450                         break;
451                 case AST_CONTROL_UNHOLD:
452                         ast_copy_string(subclass, "Unhold", slen);
453                         break;
454                 case AST_CONTROL_T38_PARAMETERS: {
455                         char *message = "Unknown";
456                         if (f->datalen != sizeof(struct ast_control_t38_parameters)) {
457                                 message = "Invalid";
458                         } else {
459                                 struct ast_control_t38_parameters *parameters = f->data.ptr;
460                                 enum ast_control_t38 state = parameters->request_response;
461                                 if (state == AST_T38_REQUEST_NEGOTIATE)
462                                         message = "Negotiation Requested";
463                                 else if (state == AST_T38_REQUEST_TERMINATE)
464                                         message = "Negotiation Request Terminated";
465                                 else if (state == AST_T38_NEGOTIATED)
466                                         message = "Negotiated";
467                                 else if (state == AST_T38_TERMINATED)
468                                         message = "Terminated";
469                                 else if (state == AST_T38_REFUSED)
470                                         message = "Refused";
471                         }
472                         snprintf(subclass, slen, "T38_Parameters/%s", message);
473                         break;
474                 }
475                 case -1:
476                         ast_copy_string(subclass, "Stop generators", slen);
477                         break;
478                 default:
479                         snprintf(subclass, slen, "Unknown control '%d'", f->subclass.integer);
480                 }
481                 break;
482         case AST_FRAME_NULL:
483                 ast_copy_string(subclass, "N/A", slen);
484                 break;
485         case AST_FRAME_IAX:
486                 /* Should never happen */
487                 snprintf(subclass, slen, "IAX Frametype %d", f->subclass.integer);
488                 break;
489         case AST_FRAME_BRIDGE_ACTION:
490                 /* Should never happen */
491                 snprintf(subclass, slen, "Bridge Frametype %d", f->subclass.integer);
492                 break;
493         case AST_FRAME_BRIDGE_ACTION_SYNC:
494                 /* Should never happen */
495                 snprintf(subclass, slen, "Synchronous Bridge Frametype %d", f->subclass.integer);
496                 break;
497         case AST_FRAME_TEXT:
498                 ast_copy_string(subclass, "N/A", slen);
499                 if (moreinfo) {
500                         ast_copy_string(moreinfo, f->data.ptr, mlen);
501                 }
502                 break;
503         case AST_FRAME_IMAGE:
504                 snprintf(subclass, slen, "Image format %s\n", ast_format_get_name(f->subclass.format));
505                 break;
506         case AST_FRAME_HTML:
507                 switch (f->subclass.integer) {
508                 case AST_HTML_URL:
509                         ast_copy_string(subclass, "URL", slen);
510                         if (moreinfo) {
511                                 ast_copy_string(moreinfo, f->data.ptr, mlen);
512                         }
513                         break;
514                 case AST_HTML_DATA:
515                         ast_copy_string(subclass, "Data", slen);
516                         break;
517                 case AST_HTML_BEGIN:
518                         ast_copy_string(subclass, "Begin", slen);
519                         break;
520                 case AST_HTML_END:
521                         ast_copy_string(subclass, "End", slen);
522                         break;
523                 case AST_HTML_LDCOMPLETE:
524                         ast_copy_string(subclass, "Load Complete", slen);
525                         break;
526                 case AST_HTML_NOSUPPORT:
527                         ast_copy_string(subclass, "No Support", slen);
528                         break;
529                 case AST_HTML_LINKURL:
530                         ast_copy_string(subclass, "Link URL", slen);
531                         if (moreinfo) {
532                                 ast_copy_string(moreinfo, f->data.ptr, mlen);
533                         }
534                         break;
535                 case AST_HTML_UNLINK:
536                         ast_copy_string(subclass, "Unlink", slen);
537                         break;
538                 case AST_HTML_LINKREJECT:
539                         ast_copy_string(subclass, "Link Reject", slen);
540                         break;
541                 default:
542                         snprintf(subclass, slen, "Unknown HTML frame '%d'\n", f->subclass.integer);
543                         break;
544                 }
545                 break;
546         case AST_FRAME_MODEM:
547                 switch (f->subclass.integer) {
548                 case AST_MODEM_T38:
549                         ast_copy_string(subclass, "T.38", slen);
550                         break;
551                 case AST_MODEM_V150:
552                         ast_copy_string(subclass, "V.150", slen);
553                         break;
554                 default:
555                         snprintf(subclass, slen, "Unknown MODEM frame '%d'\n", f->subclass.integer);
556                         break;
557                 }
558                 break;
559         case AST_FRAME_RTCP:
560                 ast_copy_string(subclass, "RTCP", slen);
561         default:
562                 ast_copy_string(subclass, "Unknown Subclass", slen);
563                 break;
564         }
565 }
566
567 void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
568 {
569         switch (frame_type) {
570         case AST_FRAME_DTMF_BEGIN:
571                 ast_copy_string(ftype, "DTMF Begin", len);
572                 break;
573         case AST_FRAME_DTMF_END:
574                 ast_copy_string(ftype, "DTMF End", len);
575                 break;
576         case AST_FRAME_CONTROL:
577                 ast_copy_string(ftype, "Control", len);
578                 break;
579         case AST_FRAME_NULL:
580                 ast_copy_string(ftype, "Null Frame", len);
581                 break;
582         case AST_FRAME_IAX:
583                 /* Should never happen */
584                 ast_copy_string(ftype, "IAX Specific", len);
585                 break;
586         case AST_FRAME_BRIDGE_ACTION:
587                 /* Should never happen */
588                 ast_copy_string(ftype, "Bridge Specific", len);
589                 break;
590         case AST_FRAME_BRIDGE_ACTION_SYNC:
591                 /* Should never happen */
592                 ast_copy_string(ftype, "Bridge Specific", len);
593                 break;
594         case AST_FRAME_TEXT:
595                 ast_copy_string(ftype, "Text", len);
596                 break;
597         case AST_FRAME_TEXT_DATA:
598                 ast_copy_string(ftype, "Text Data", len);
599                 break;
600         case AST_FRAME_IMAGE:
601                 ast_copy_string(ftype, "Image", len);
602                 break;
603         case AST_FRAME_HTML:
604                 ast_copy_string(ftype, "HTML", len);
605                 break;
606         case AST_FRAME_MODEM:
607                 ast_copy_string(ftype, "Modem", len);
608                 break;
609         case AST_FRAME_VOICE:
610                 ast_copy_string(ftype, "Voice", len);
611                 break;
612         case AST_FRAME_VIDEO:
613                 ast_copy_string(ftype, "Video", len);
614                 break;
615         case AST_FRAME_RTCP:
616                 ast_copy_string(ftype, "RTCP", len);
617                 break;
618         default:
619                 snprintf(ftype, len, "Unknown Frametype '%u'", frame_type);
620                 break;
621         }
622 }
623
624 /*! Dump a frame for debugging purposes */
625 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
626 {
627         const char noname[] = "unknown";
628         char ftype[40] = "Unknown Frametype";
629         char cft[80];
630         char subclass[40] = "Unknown Subclass";
631         char csub[80];
632         char moreinfo[40] = "";
633         char cn[60];
634         char cp[40];
635         char cmn[40];
636
637         if (!name) {
638                 name = noname;
639         }
640
641         if (!f) {
642                 ast_verb(-1, "%s [ %s (NULL) ] [%s]\n",
643                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
644                         term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
645                         term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
646                 return;
647         }
648         /* XXX We should probably print one each of voice and video when the format changes XXX */
649         if (f->frametype == AST_FRAME_VOICE) {
650                 return;
651         }
652         if (f->frametype == AST_FRAME_VIDEO) {
653                 return;
654         }
655         if (f->frametype == AST_FRAME_RTCP) {
656                 return;
657         }
658
659         ast_frame_type2str(f->frametype, ftype, sizeof(ftype));
660         ast_frame_subclass2str(f, subclass, sizeof(subclass), moreinfo, sizeof(moreinfo));
661
662         if (!ast_strlen_zero(moreinfo))
663                 ast_verb(-1, "%s [ TYPE: %s (%u) SUBCLASS: %s (%d) '%s' ] [%s]\n",
664                             term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
665                             term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
666                             f->frametype,
667                             term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
668                             f->subclass.integer,
669                             term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
670                             term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
671         else
672                 ast_verb(-1, "%s [ TYPE: %s (%u) SUBCLASS: %s (%d) ] [%s]\n",
673                             term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
674                             term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
675                             f->frametype,
676                             term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
677                             f->subclass.integer,
678                             term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
679 }
680
681 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
682 {
683         int count;
684         short *fdata = f->data.ptr;
685         short adjust_value = abs(adjustment);
686
687         if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_cache_is_slinear(f->subclass.format))) {
688                 return -1;
689         }
690
691         if (!adjustment) {
692                 return 0;
693         }
694
695         for (count = 0; count < f->samples; count++) {
696                 if (adjustment > 0) {
697                         ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
698                 } else if (adjustment < 0) {
699                         ast_slinear_saturated_divide(&fdata[count], &adjust_value);
700                 }
701         }
702
703         return 0;
704 }
705
706 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
707 {
708         int count;
709         short *data1, *data2;
710
711         if ((f1->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f1->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL))
712                 return -1;
713
714         if ((f2->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f2->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL))
715                 return -1;
716
717         if (f1->samples != f2->samples)
718                 return -1;
719
720         for (count = 0, data1 = f1->data.ptr, data2 = f2->data.ptr;
721              count < f1->samples;
722              count++, data1++, data2++)
723                 ast_slinear_saturated_add(data1, data2);
724
725         return 0;
726 }
727
728 int ast_frame_clear(struct ast_frame *frame)
729 {
730         struct ast_frame *next;
731
732         for (next = AST_LIST_NEXT(frame, frame_list);
733                  frame;
734                  frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {
735                 memset(frame->data.ptr, 0, frame->datalen);
736         }
737         return 0;
738 }