1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 	a_events.c - Internal Event System
4 ---------------------------------------------------------------------------
5  * Copyright (C) 2002, David Olofson
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22 #define	EVDBG(x)
23 
24 #include <stdlib.h>
25 
26 #include "kobolog.h"
27 #include "a_events.h"
28 
29 #define	EVENTS_PER_BLOCK	256
30 
31 /*----------------------------------------------------------
32 	The global event timestamp time base
33 ----------------------------------------------------------*/
34 Uint16 aev_timer = 0;
35 
36 
37 /*----------------------------------------------------------
38 	Event pool management
39 ----------------------------------------------------------*/
40 
41 aev_event_t		*aev_event_pool = NULL;
42 
43 #ifdef	AEV_TRACKING
44 int aev_event_counter = 0;
45 int aev_event_counter_max = 0;
46 const char *aev_current_client = "Unknown";
47 #endif
48 
49 
50 typedef struct evblock_t
51 {
52 	struct evblock_t	*next;
53 	aev_event_t		events[EVENTS_PER_BLOCK];
54 } evblock_t;
55 
56 static evblock_t *blocks = NULL;
57 
58 
_aev_refill_pool(void)59 int _aev_refill_pool(void)
60 {
61 	/*
62 	 * We can't refill in real time context on some
63 	 * platforms - and it would be a bad idea anyway...
64 	 */
65 	log_printf(ELOG, "Audio event pool exhausted!\n");
66 	return -1;
67 }
68 
69 
70 /*
71  * A job for a future butler thread. For now, we only use
72  * this during initialization.
73  */
refill_pool(void)74 static int refill_pool(void)
75 {
76 	int i;
77 	evblock_t *eb = calloc(1, sizeof(evblock_t));
78 	if(!eb)
79 		return -1;
80 
81 	/* Add to block list */
82 	eb->next = blocks;
83 	blocks = eb;
84 
85 	/* Add the events to the pool */
86 	for(i = 0; i < EVENTS_PER_BLOCK; ++i)
87 	{
88 		eb->events[i].type = AEV_ET_FREE;
89 		aev_free(&eb->events[i]);
90 	}
91 
92 	return 0;
93 }
94 
95 
96 /*----------------------------------------------------------
97 	Event Input Port
98 ----------------------------------------------------------*/
aev_insert(aev_port_t * evp,aev_event_t * ev)99 void aev_insert(aev_port_t *evp, aev_event_t *ev)
100 {
101 EVDBG(log_printf(D2LOG, "aev_insert:\n");)
102 	if(!evp->first)
103 	{
104 EVDBG(log_printf(D2LOG, "  empty list\n");)
105 		ev->next = NULL;
106 		evp->first = evp->last = ev;
107 	}
108 	else if((Sint16)(evp->last->frame - ev->frame) <= 0)
109 	{
110 EVDBG(log_printf(D2LOG, "  last\n");)
111 		ev->next = NULL;
112 		evp->last->next = ev;
113 		evp->last = ev;
114 	}
115 	else
116 	{
117 		aev_event_t *e_prev = NULL;
118 		aev_event_t *e = evp->first;
119 EVDBG(log_printf(D2LOG, " scanning...\n");)
120 		while((Sint16)(e->frame - ev->frame) <= 0)
121 		{
122 EVDBG(log_printf(D2LOG, "e->frame = %d, ev->frame = %d\n", e->frame, ev->frame);)
123 			e_prev = e;
124 			e = e->next;
125 		}
126 		ev->next = e;
127 		if(e_prev)
128 		{
129 EVDBG(log_printf(D2LOG, "  insert\n");)
130 			e_prev->next = ev;
131 		}
132 		else
133 		{
134 EVDBG(log_printf(D2LOG, "  first\n");)
135 			evp->first = ev;
136 		}
137 	}
138 #ifdef AEV_TRACKING
139 	ev->port = evp;
140 #endif
141 }
142 
143 
144 /*----------------------------------------------------------
145 	Open/Close
146 ----------------------------------------------------------*/
147 
aev_open(int pool_size)148 int aev_open(int pool_size)
149 {
150 	while(pool_size > 0)
151 	{
152 		if(refill_pool() < 0)
153 		{
154 			aev_close();
155 			return -1;	/* OOM! */
156 		}
157 		pool_size -= EVENTS_PER_BLOCK;
158 	}
159 #if 0
160 	{
161 		aev_evport_t port;
162 		int i;
163 		aev_evport_init(&port, "testport");
164 		aev_timer = 0;
165 		aev_event_client(42);
166 		for(i = 0; i < 5; ++i)
167 			aev_put0(&port, 20+i*20, 42);
168 		for(i = 0; i < 5; ++i)
169 			aev_put0(&port, 100-i*20, 43);
170 		i = 0;
171 		aev_timer = 0;
172 		while(i < 200)
173 		{
174 			unsigned int frames;
175 			log_printf(D2LOG, "aev_timer = %d\n", aev_timer);
176 			while(!(frames = aev_next(&port, 0)))
177 			{
178 				aev_event_t *ev = aev_read(&port);
179 				log_printf(D2LOG, "  event.frame = %d, type = %d\n",
180 						ev->frame, ev->type);
181 				aev_free(ev);
182 			}
183 			if(frames > 5)
184 				frames = 5;
185 			aev_timer += frames;
186 			i += frames;
187 		}
188 	}
189 #endif
190 #ifdef	AEV_TRACKING
191 	aev_event_counter = 0;
192 	aev_event_counter_max = 0;
193 #endif
194 	return 0;
195 }
196 
197 
aev_close(void)198 void aev_close(void)
199 {
200 	log_printf(DLOG, "aev_close(): max events used: %d\n",
201 				aev_event_counter_max);
202 #ifdef	AEV_TRACKING
203 	if(aev_event_counter)
204 	{
205 		evblock_t *eb = blocks;
206 		log_printf(ELOG, "INTERNAL ERROR: Closing audio event system"
207 				" system with %d events in use!"
208 				" (Memory leaked.)\n",
209 				aev_event_counter);
210 		while(eb)
211 		{
212 			int i;
213 			for(i = 0; i < EVENTS_PER_BLOCK; ++i)
214 			{
215 				if(eb->events[i].type == AEV_ET_FREE)
216 					continue;
217 				log_printf(ELOG, "  Event %p, "
218 						"sent from client \"%s\", "
219 						"to port \"%s\".\n",
220 						eb->events + i,
221 						eb->events[i].client,
222 						eb->events[i].port->name );
223 			}
224 			eb = eb->next;
225 		}
226 	}
227 	else
228 #endif
229 		while(blocks)
230 		{
231 			evblock_t *eb = blocks;
232 			blocks = eb->next;
233 			free(eb);
234 		}
235 
236 	blocks = NULL;
237 	aev_event_pool = NULL;
238 #ifdef	AEV_TRACKING
239 	aev_event_counter = 0;
240 	aev_event_counter_max = 0;
241 #endif
242 }
243