add slinfactory object, and change app_chanspy to use it (bug #4724)
[asterisk/asterisk.git] / slinfactory.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * A machine to gather up arbitrary frames and convert them
5  * to raw slinear on demand.
6  * 
7  * Copyright (C) 2005, Anthony Minessale II.
8  *
9  * Anthony Minessale <anthmct@yahoo.com>
10  *
11  * This program is free software, distributed under the terms of
12  * the GNU General Public License
13  */
14
15 #include "asterisk/slinfactory.h"
16 #include "asterisk/file.h"
17 #include "asterisk/logger.h"
18 #include "asterisk/channel.h"
19 #include "asterisk/pbx.h"
20 #include "asterisk/module.h"
21 #include "asterisk/lock.h"
22 #include "asterisk/cli.h"
23 #include "asterisk/options.h"
24 #include "asterisk/app.h"
25 #include "asterisk/translate.h"
26
27
28 void ast_slinfactory_init(struct ast_slinfactory *sf) 
29 {
30         memset(sf, 0, sizeof(struct ast_slinfactory));
31         sf->offset = sf->hold;
32         sf->queue = NULL;
33 }
34
35 void ast_slinfactory_destroy(struct ast_slinfactory *sf) 
36 {
37         struct ast_frame *f;
38
39         if (sf->trans) {
40                 ast_translator_free_path(sf->trans);
41                 sf->trans = NULL;
42         }
43
44         while((f = sf->queue)) {
45                 sf->queue = f->next;
46                 ast_frfree(f);
47         }
48 }
49
50 int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
51 {
52         struct ast_frame *frame, *frame_ptr;
53
54         if (!f) {
55                 return 0;
56         }
57
58         if (f->subclass != AST_FORMAT_SLINEAR) {
59                 if (sf->trans && f->subclass != sf->format) {
60                         ast_translator_free_path(sf->trans);
61                         sf->trans = NULL;
62                 }
63                 if (!sf->trans) {
64                         if ((sf->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, f->subclass)) == NULL) {
65                                 ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(f->subclass));
66                                 return 0;
67                         } else {
68                                 sf->format = f->subclass;
69                         }
70                 }
71         }
72
73         if (sf->trans) {
74                 frame = ast_translate(sf->trans, f, 0);
75         } else {
76                 frame = ast_frdup(f);
77         }
78
79         if (frame) {
80                 int x = 0;
81                 for (frame_ptr = sf->queue; frame_ptr && frame_ptr->next; frame_ptr=frame_ptr->next) {
82                         x++;
83                 }
84                 if (frame_ptr) {
85                         frame_ptr->next = frame;
86                 } else {
87                         sf->queue = frame;
88                 }
89                 frame->next = NULL;
90                 sf->size += frame->datalen;     
91                 return x;
92         }
93
94         return 0;
95         
96 }
97
98 int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t bytes) 
99 {
100         struct ast_frame *frame_ptr;
101         int sofar = 0, ineed, remain;
102         short *frame_data, *offset = buf;
103
104         while (sofar < bytes) {
105                 ineed = bytes - sofar;
106
107                 if (sf->holdlen) {
108                         if ((sofar + sf->holdlen) <= ineed) {
109                                 memcpy(offset, sf->hold, sf->holdlen);
110                                 sofar += sf->holdlen;
111                                 offset += (sf->holdlen / sizeof(short));
112                                 sf->holdlen = 0;
113                                 sf->offset = sf->hold;
114                         } else {
115                                 remain = sf->holdlen - ineed;
116                                 memcpy(offset, sf->offset, ineed);
117                                 sofar += ineed;
118                                 sf->offset += (ineed / sizeof(short));
119                                 sf->holdlen = remain;
120                         }
121                         continue;
122                 }
123                 
124                 if ((frame_ptr = sf->queue)) {
125                         sf->queue = frame_ptr->next;
126                         frame_data = frame_ptr->data;
127                         
128                         if ((sofar + frame_ptr->datalen) <= ineed) {
129                                 memcpy(offset, frame_data, frame_ptr->datalen);
130                                 sofar += frame_ptr->datalen;
131                                 offset += (frame_ptr->datalen / sizeof(short));
132                         } else {
133                                 remain = frame_ptr->datalen - ineed;
134                                 memcpy(offset, frame_data, ineed);
135                                 sofar += ineed;
136                                 frame_data += (ineed / sizeof(short));
137                                 memcpy(sf->hold, frame_data, remain);
138                                 sf->holdlen = remain;
139                         }
140                         ast_frfree(frame_ptr);
141                 } else {
142                         break;
143                 }
144         }
145
146         sf->size -= sofar;
147         return sofar;
148 }
149
150
151
152