blob: b61be89bd3be0668cac9ffa1a65d0fd83e9bb636 [file] [log] [blame]
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +01001/* Processing Queue Management */
2
3/*
4 * This file is part of gapk (GSM Audio Pocket Knife).
5 *
6 * gapk is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * gapk is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with gapk. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <errno.h>
21#include <stdint.h>
22#include <stdlib.h>
23
24#include <gapk/procqueue.h>
25
Harald Welte59128482017-05-28 10:20:54 +020026#define VAR_BUF_SIZE 320
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +010027#define MAX_PQ_ITEMS 8
28
29struct pq {
30 int n_items;
31 struct pq_item* items[MAX_PQ_ITEMS];
32 void * buffers[MAX_PQ_ITEMS+1];
33};
34
35
Harald Weltef3d2ad62017-05-27 16:42:14 +020036/* crate a new (empty) processing queue */
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +010037struct pq *
38pq_create(void)
39{
40 return (struct pq *) calloc(1, sizeof(struct pq));
41}
42
Harald Weltef3d2ad62017-05-27 16:42:14 +020043/*! destroy a processing queue, calls exit() callback of each item
44 * \param[in] pq Processing Queue to be destroyed */
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +010045void
46pq_destroy(struct pq *pq)
47{
48 int i;
49
50 if (!pq)
51 return;
52
53 for (i=0; i<pq->n_items; i++) {
54 if (!pq->items[i])
55 continue;
56 if (pq->items[i]->exit)
57 pq->items[i]->exit(pq->items[i]->state);
58 free(pq->items[i]);
59 }
60
61 for (i=0; i<pq->n_items-1; i++)
62 free(pq->buffers[i]); /* free is NULL safe */
63
64 free(pq);
65}
66
Harald Weltef3d2ad62017-05-27 16:42:14 +020067/*! allocate + add an item to a processing queue; return new item
68 * \param[in] pq Processing Queue to which item is added
69 * \returns new PQ item; NULL on error */
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +010070struct pq_item *
71pq_add_item(struct pq *pq)
72{
73 struct pq_item *item;
74
Harald Welte495c6942017-05-28 12:25:59 +020075 if (pq->n_items == MAX_PQ_ITEMS) {
76 fprintf(stderr, "Processing Queue cannot handle more than %u items\n",
77 MAX_PQ_ITEMS);
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +010078 return NULL;
Harald Welte495c6942017-05-28 12:25:59 +020079 }
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +010080
81 item = calloc(1, sizeof(struct pq_item));
82 if (!item)
83 return NULL;
84
85 pq->items[pq->n_items++] = item;
86
87 return item;
88}
89
Harald Weltef3d2ad62017-05-27 16:42:14 +020090/*! prepare a processing queue; allocates buffers; checks lengths
91 * \param[in] pq Processing Queue to be prepared
92 * \returns 0 on succcess; negative on error */
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +010093int
94pq_prepare(struct pq *pq)
95{
96 int i;
97 unsigned int len_prev;
98
99 len_prev = 0;
100
101 for (i=0; i<pq->n_items; i++) {
102 struct pq_item *item = pq->items[i];
103
Harald Welte495c6942017-05-28 12:25:59 +0200104 if (item->len_in && item->len_in != len_prev) {
105 fprintf(stderr, "PQ item requires input size %u, but previous output is %u\n",
106 item->len_in, len_prev);
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100107 return -EINVAL;
Harald Welte495c6942017-05-28 12:25:59 +0200108 }
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100109
110 if (i < (pq->n_items-1)) {
Harald Welte59128482017-05-28 10:20:54 +0200111 unsigned int buf_size = item->len_out;
112 /* variable-length codec output, use maximum
113 * known buffer size */
114 if (!buf_size)
115 buf_size = VAR_BUF_SIZE;
116 pq->buffers[i] = malloc(buf_size);
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100117 if (!pq->buffers[i])
118 return -ENOMEM;
119 } else{
120 if (item->len_out)
121 return -EINVAL;
122 }
123
124 len_prev = item->len_out;
125 }
126
127 return 0;
128}
129
Harald Weltef3d2ad62017-05-27 16:42:14 +0200130/*! execute a processing queue; iterate over processing elements
131 * \param[in] pq Processing Queue to be executed
132 * \returns 0 on success; negative on error (if any item returns negative) */
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100133int
134pq_execute(struct pq *pq)
135{
136 int i;
137 void *buf_prev, *buf;
Harald Welte59128482017-05-28 10:20:54 +0200138 unsigned int len_prev;
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100139
140 buf_prev = NULL;
Harald Welte59128482017-05-28 10:20:54 +0200141 len_prev = 0;
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100142
143 for (i=0; i<pq->n_items; i++) {
144 int rv;
145 struct pq_item *item = pq->items[i];
146
147 buf = i < (pq->n_items-1) ? pq->buffers[i] : NULL;
148
Harald Welte59128482017-05-28 10:20:54 +0200149 rv = item->proc(item->state, buf, buf_prev, len_prev);
150 if (rv < 0) {
151 fprintf(stderr, "pq_execute(): abort, item returned %d\n", rv);
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100152 return rv;
Harald Welte59128482017-05-28 10:20:54 +0200153 }
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100154
155 buf_prev = buf;
Harald Welte59128482017-05-28 10:20:54 +0200156 len_prev = rv;
Sylvain Munaut3c0a4fb2010-11-11 20:40:29 +0100157 }
158
159 return 0;
160}