root/rat/trunk/main_engine.c @ 3008

Revision 3008, 11.4 KB (checked in by ucaccsp, 15 years ago)

Cleanup exit routines - shouldn't core dump when quiting anymore. I think
we're about ready for another release....?

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:    main-engine.c
3 * PROGRAM: RAT
4 * AUTHOR:  Colin Perkins
5 *
6 * $Revision$
7 * $Date$
8 *
9 * Copyright (c) 1995-99 University College London
10 * All rights reserved.
11 *
12 */
13
14#include "config_unix.h"
15#include "config_win32.h"
16#include "debug.h"
17#include "memory.h"
18#include "audio_types.h"
19#include "codec_types.h"
20#include "codec.h"
21#include "channel_types.h"
22#include "session.h"
23#include "audio.h"
24#include "auddev.h"
25#include "cushion.h"
26#include "converter.h"
27#include "tcltk.h"
28#include "pdb.h"
29#include "ui.h"
30#include "net.h"
31#include "timers.h"
32#include "parameters.h"
33#include "transmit.h"
34#include "source.h"
35#include "mix.h"
36#include "sndfile.h"
37#include "mbus.h"
38#include "mbus_ui.h"
39#include "mbus_engine.h"
40#include "crypt_random.h"
41#include "net_udp.h"
42#include "settings.h"
43#include "rtp.h"
44#include "rtp_callback.h"
45
46int should_exit = FALSE;
47int thread_pri  = 2; /* Time Critical */
48
49#ifndef WIN32
50static void
51signal_handler(int signal)
52{
53        debug_msg("Caught signal %d\n", signal);
54        exit(-1);
55}
56#endif
57
58char    *c_addr, *token, *token_e;
59
60#define MBUS_ADDR_ENGINE "(media:audio module:engine app:rat instance:%5u)"
61
62static void parse_args(int argc, char *argv[])
63{
64        int     i;
65
66        if (argc != 5) {
67                printf("Usage: %s -ctrl <addr> -token <token>\n", argv[0]);
68                exit(1);
69        }
70        for (i = 1; i < argc; i++) {
71                if (strcmp(argv[i], "-ctrl") == 0) {
72                        c_addr = xstrdup(argv[++i]);
73                } else if (strcmp(argv[i], "-token") == 0) {
74                        token   = xstrdup(argv[++i]);
75                        token_e = mbus_encode_str(token);
76                } else {
77                        printf("Unknown argument \"%s\"\n", argv[i]);
78                        abort();
79                }
80        }
81}
82
83static void 
84mbus_error_handler(int seqnum, int reason)
85{
86        debug_msg("mbus message failed (%d:%d)\n", seqnum, reason);
87        if (should_exit == FALSE) {
88                abort();
89        }
90        UNUSED(seqnum);
91        UNUSED(reason);
92        /* Ignore error we're closing down anyway */
93}
94
95int main(int argc, char *argv[])
96{
97        uint32_t         cur_time = 0, ntp_time = 0;
98        int              seed, elapsed_time, alc = 0, scnt = 0;
99        session_t       *sp;
100        struct timeval   time;
101        struct timeval   timeout;
102        uint8_t          j;
103
104#ifndef WIN32
105        signal(SIGINT, signal_handler);
106#endif
107
108        debug_set_core_dir(argv[0]);
109
110        seed = (gethostid() << 8) | (getpid() & 0xff);
111        srand48(seed);
112        lbl_srandom(seed);
113
114        sp = (session_t *) xmalloc(sizeof(session_t));
115        session_init(sp);
116        converters_init();
117        audio_init_interfaces();
118        audio_device_get_safe_config(&sp->new_config);
119        audio_device_reconfigure(sp);
120        sp->cur_ts = ts_seq32_in(&sp->decode_sequencer,
121                                 get_freq(sp->device_clock), 0);
122        assert(audio_device_is_open(sp->audio_device));
123        settings_load_early(sp);
124        parse_args(argc, argv);
125
126        /* Initialise our mbus interface... once this is done we can talk to our controller */
127        sp->mbus_engine = mbus_init(mbus_engine_rx, mbus_error_handler);
128        sp->mbus_engine_addr = (char *) xmalloc(strlen(MBUS_ADDR_ENGINE) + 3);
129        sprintf(sp->mbus_engine_addr, MBUS_ADDR_ENGINE, (uint32_t) getpid());
130        mbus_addr(sp->mbus_engine, sp->mbus_engine_addr);
131
132        /* The first stage is to wait until we hear from our controller. The address of the */
133        /* controller is passed to us via a command line parameter, and we just wait until  */
134        /* we get an mbus.hello() from that address.                                        */
135        debug_msg("Waiting to validate address %s\n", c_addr);
136        while (!mbus_addr_valid(sp->mbus_engine, c_addr)) {
137                timeout.tv_sec  = 0;
138                timeout.tv_usec = 250000;
139                mbus_recv(sp->mbus_engine, NULL, &timeout);
140                mbus_send(sp->mbus_engine);
141                mbus_heartbeat(sp->mbus_engine, 1);
142                mbus_retransmit(sp->mbus_engine);
143        }
144        debug_msg("Address %s is valid\n", c_addr);
145
146        /* Next, we signal to the controller that we are ready to go. It should be sending  */
147        /* us an mbus.waiting(foo) where "foo" is the same as the "-token" argument we were */
148        /* passed on startup. We respond with mbus.go(foo) sent reliably to the controller. */
149        debug_msg("Waiting for mbus.waiting(%s) from controller...\n", token);
150        mbus_rendezvous_go(sp->mbus_engine, token, (void *) sp->mbus_engine);
151        debug_msg("...got it\n");
152
153        /* At this point we know the mbus address of our controller, and have conducted */
154        /* a successful rendezvous with it. It will now send us configuration commands. */
155        debug_msg("Waiting for mbus.go(%s) from controller...\n", token);
156        mbus_rendezvous_waiting(sp->mbus_engine, c_addr, token, (void *) sp);
157        debug_msg("...got it\n");
158        assert(sp->rtp_session[0] != NULL);
159
160        if (pdb_create(&sp->pdb) == FALSE) {
161                debug_msg("Failed to create persistent database\n");
162                abort();
163        }
164        pdb_item_create(sp->pdb, sp->clock, (uint16_t)get_freq(sp->device_clock), rtp_my_ssrc(sp->rtp_session[0]));
165        settings_load_late(sp);
166
167        ui_controller_init(sp);
168        ui_initial_settings(sp);
169        ui_update(sp);
170        network_process_mbus(sp);
171       
172#ifdef NDEF
173        if (sp->new_config != NULL) {
174                network_process_mbus(sp);
175                audio_device_reconfigure(sp);
176                network_process_mbus(sp);
177        }
178#endif
179
180#ifdef NDEF
181        ui_final_settings(sp);
182        network_process_mbus(sp);
183#endif
184        audio_drain(sp->audio_device);
185        if (tx_is_sending(sp->tb)) {
186                tx_start(sp->tb);
187        }
188
189        xdoneinit();
190
191        while (!should_exit) {
192                elapsed_time = 0;
193
194                /* Process audio */
195                elapsed_time = audio_rw_process(sp, sp, sp->ms);
196                cur_time = get_time(sp->device_clock);
197                ntp_time = ntp_time32();
198                sp->cur_ts   = ts_seq32_in(&sp->decode_sequencer, get_freq(sp->device_clock), cur_time);
199
200                if (tx_is_sending(sp->tb)) {
201                        tx_process_audio(sp->tb);
202                        tx_send(sp->tb);
203                }
204
205                /* Process RTP/RTCP packets */
206                timeout.tv_sec  = 0;
207                timeout.tv_usec = 0;
208                for (j = 0; j < sp->rtp_session_count; j++) {
209                        while(rtp_recv(sp->rtp_session[j], &timeout, cur_time));
210                        rtp_send_ctrl(sp->rtp_session[j], cur_time, NULL);
211                        rtp_update(sp->rtp_session[j]);
212                }
213
214                /* Process mbus */
215                timeout.tv_sec  = 0;
216                timeout.tv_usec = 0;
217                mbus_send(sp->mbus_engine);
218                mbus_recv(sp->mbus_engine, (void *) sp, &timeout);
219                mbus_retransmit(sp->mbus_engine);
220                mbus_heartbeat(sp->mbus_engine, 1);
221
222                /* Process audio */
223                elapsed_time += audio_rw_process(sp, sp, sp->ms);
224                cur_time = get_time(sp->device_clock);
225                ntp_time = ntp_time32();
226                sp->cur_ts   = ts_seq32_in(&sp->decode_sequencer, get_freq(sp->device_clock), cur_time);
227
228                if (tx_is_sending(sp->tb)) {
229                        tx_process_audio(sp->tb);
230                        tx_send(sp->tb);
231                }
232
233                /* Process and mix active sources */
234                if (sp->playing_audio) {
235                        struct s_source *s;
236                        int sidx;
237                        ts_t cush_ts;
238                        cush_ts = ts_map32(get_freq(sp->device_clock), cushion_get_size(sp->cushion));
239                        cush_ts = ts_add(sp->cur_ts, cush_ts);
240                        scnt = (int)source_list_source_count(sp->active_sources);
241                        for(sidx = 0; sidx < scnt; sidx++) {
242                                s = source_list_get_source_no(sp->active_sources, sidx);
243                                if (source_relevant(s, sp->cur_ts)) {
244                                        pdb_entry_t *e;
245                                        ts_t         two_secs, delta;
246                                        source_check_buffering(s);
247                                        source_process(sp, s, sp->ms, sp->render_3d, sp->repair, sp->cur_ts, cush_ts);
248                                        source_audit(s);
249                                        /* Check for UI update necessary, updating once per 2 secs */
250                                        pdb_item_get(sp->pdb, source_get_ssrc(s), &e);
251                                        delta    = ts_sub(sp->cur_ts, e->last_ui_update);
252                                        two_secs = ts_map32(8000, 16000);
253                                        if (ts_gt(delta, two_secs)) {
254                                                ui_update_stats(sp, e->ssrc);
255                                                e->last_ui_update = sp->cur_ts;
256                                        }
257                                } else {
258                                        /* Remove source as stopped */
259                                        uint32_t ssrc;
260                                        ssrc = source_get_ssrc(s);
261                                        ui_info_deactivate(sp, ssrc);
262                                        source_remove(sp->active_sources, s);
263                                        sidx--;
264                                        scnt--;
265                                }
266                        }
267                }
268
269                /* Echo Suppression - cut off transmitter when receiving     */
270                /* audio, enable when stop receiving.                        */
271
272                if (sp->echo_suppress) {
273                        if (scnt > 0) {
274                                if (tx_is_sending(sp->tb)) {
275                                        tx_stop(sp->tb);
276                                        sp->echo_tx_active = TRUE;
277                                        debug_msg("Echo suppressor (disabling tx)\n");
278                                }
279                        } else if (sp->echo_tx_active) {
280                                /* Transmitter was stopped because we were   */
281                                /* playing out audio.  Restart it.           */
282                                if (tx_is_sending(sp->tb) == FALSE) {
283                                        tx_start(sp->tb);
284                                        debug_msg("Echo suppressor (enabling tx)\n");
285                                }
286                                sp->echo_tx_active = FALSE;
287                        }
288                }
289                /* Lecture Mode */
290                if (alc >= 50) {
291                        if (!sp->lecture && tx_is_sending(sp->tb) && sp->auto_lecture != 0) {
292                                gettimeofday(&time, NULL);
293                                if (time.tv_sec - sp->auto_lecture > 120) {
294                                        sp->auto_lecture = 0;
295                                        debug_msg("Dummy lecture mode\n");
296                                }
297                        }
298                        alc = 0;
299                } else {
300                        alc++;
301                }
302
303                if (sp->audio_device && elapsed_time != 0) {
304                        ui_periodic_updates(sp, elapsed_time);
305                }
306                if (sp->new_config != NULL) {
307                        /* wait for mbus messages - closing audio device
308                         * can timeout unprocessed messages as some drivers
309                         * pause to drain before closing.
310                         */
311                        network_process_mbus(sp);
312                        if (audio_device_reconfigure(sp)) {
313                                /* Device reconfigured so
314                                 * decode paths of all sources
315                                 * are misconfigured.  Delete
316                                 * and incoming data will
317                                 * drive correct new path */
318                                source_list_clear(sp->active_sources);
319                        }
320                }
321               
322                /* Choke CPU usage */
323                if (!audio_is_ready(sp->audio_device)) {
324                        audio_wait_for(sp->audio_device, 20);
325                }
326        }
327
328        settings_save(sp);
329        tx_stop(sp->tb);
330        if (sp->in_file  != NULL) snd_read_close (&sp->in_file);
331        if (sp->out_file != NULL) snd_write_close(&sp->out_file);
332        audio_device_release(sp, sp->audio_device);
333        pdb_destroy(&sp->pdb);
334
335        /* Inform other processes that we're about to quit... */
336        mbus_qmsgf(sp->mbus_engine, "()", FALSE, "mbus.bye", "");
337        mbus_send(sp->mbus_engine);
338        do {
339                struct timeval   timeout;
340                mbus_send(sp->mbus_engine);
341                mbus_retransmit(sp->mbus_engine);
342                timeout.tv_sec  = 0;
343                timeout.tv_usec = 20000;
344                mbus_recv(sp->mbus_engine, sp, &timeout);
345        } while (!mbus_sent_all(sp->mbus_engine));
346        mbus_exit(sp->mbus_engine);
347        sp->mbus_engine = NULL;
348
349        for (j = 0; j < sp->rtp_session_count; j++) {
350                rtp_send_bye(sp->rtp_session[j]);
351                rtp_done(sp->rtp_session[j]);
352                rtp_callback_exit(sp->rtp_session[j]);
353        }
354
355        session_exit(sp);
356        xfree(sp);
357
358        converters_free();
359        audio_free_interfaces();
360
361        xmemdmp();
362        return 0;
363}
Note: See TracBrowser for help on using the browser.