| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 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 | |
|---|
| 46 | int should_exit = FALSE; |
|---|
| 47 | char *c_addr, *token, *token_e; |
|---|
| 48 | |
|---|
| 49 | #ifndef WIN32 |
|---|
| 50 | static void |
|---|
| 51 | signal_handler(int signal) |
|---|
| 52 | { |
|---|
| 53 | debug_msg("Caught signal %d\n", signal); |
|---|
| 54 | exit(-1); |
|---|
| 55 | } |
|---|
| 56 | #endif |
|---|
| 57 | |
|---|
| 58 | #define MBUS_ADDR_ENGINE "(media:audio module:engine app:rat instance:%u)" |
|---|
| 59 | |
|---|
| 60 | static void parse_args(int argc, char *argv[]) |
|---|
| 61 | { |
|---|
| 62 | int i; |
|---|
| 63 | |
|---|
| 64 | if (argc != 5) { |
|---|
| 65 | printf("Usage: %s -ctrl <addr> -token <token>\n", argv[0]); |
|---|
| 66 | exit(1); |
|---|
| 67 | } |
|---|
| 68 | for (i = 1; i < argc; i++) { |
|---|
| 69 | if (strcmp(argv[i], "-ctrl") == 0) { |
|---|
| 70 | c_addr = xstrdup(argv[++i]); |
|---|
| 71 | } else if (strcmp(argv[i], "-token") == 0) { |
|---|
| 72 | token = xstrdup(argv[++i]); |
|---|
| 73 | token_e = mbus_encode_str(token); |
|---|
| 74 | } else { |
|---|
| 75 | printf("Unknown argument \"%s\"\n", argv[i]); |
|---|
| 76 | abort(); |
|---|
| 77 | } |
|---|
| 78 | } |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | static void |
|---|
| 82 | mbus_error_handler(int seqnum, int reason) |
|---|
| 83 | { |
|---|
| 84 | debug_msg("mbus message failed (%d:%d)\n", seqnum, reason); |
|---|
| 85 | if (should_exit == FALSE) { |
|---|
| 86 | abort(); |
|---|
| 87 | } |
|---|
| 88 | UNUSED(seqnum); |
|---|
| 89 | UNUSED(reason); |
|---|
| 90 | |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | int main(int argc, char *argv[]) |
|---|
| 94 | { |
|---|
| 95 | uint32_t cur_time = 0, ntp_time = 0; |
|---|
| 96 | int seed, elapsed_time, alc = 0, scnt = 0; |
|---|
| 97 | session_t *sp; |
|---|
| 98 | struct timeval time; |
|---|
| 99 | struct timeval timeout; |
|---|
| 100 | uint8_t j; |
|---|
| 101 | |
|---|
| 102 | #ifdef WIN32 |
|---|
| 103 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); |
|---|
| 104 | #else |
|---|
| 105 | signal(SIGINT, signal_handler); |
|---|
| 106 | debug_set_core_dir(argv[0]); |
|---|
| 107 | #endif |
|---|
| 108 | |
|---|
| 109 | |
|---|
| 110 | |
|---|
| 111 | |
|---|
| 112 | seed = (gethostid() << 8) | (getpid() & 0xff); |
|---|
| 113 | srand48(seed); |
|---|
| 114 | lbl_srandom(seed); |
|---|
| 115 | converters_init(); |
|---|
| 116 | audio_init_interfaces(); |
|---|
| 117 | parse_args(argc, argv); |
|---|
| 118 | |
|---|
| 119 | |
|---|
| 120 | sp = (session_t *) xmalloc(sizeof(session_t)); |
|---|
| 121 | session_init(sp); |
|---|
| 122 | audio_device_get_safe_config(&sp->new_config); |
|---|
| 123 | audio_device_reconfigure(sp); |
|---|
| 124 | sp->cur_ts = ts_seq32_in(&sp->decode_sequencer, get_freq(sp->device_clock), 0); |
|---|
| 125 | assert(audio_device_is_open(sp->audio_device)); |
|---|
| 126 | settings_load_early(sp); |
|---|
| 127 | |
|---|
| 128 | |
|---|
| 129 | sp->mbus_engine = mbus_init(mbus_engine_rx, mbus_error_handler); |
|---|
| 130 | sp->mbus_engine_addr = (char *) xmalloc(strlen(MBUS_ADDR_ENGINE) + 3); |
|---|
| 131 | sprintf(sp->mbus_engine_addr, MBUS_ADDR_ENGINE, (uint32_t) getpid()); |
|---|
| 132 | mbus_addr(sp->mbus_engine, sp->mbus_engine_addr); |
|---|
| 133 | |
|---|
| 134 | |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | debug_msg("Waiting to validate address %s\n", c_addr); |
|---|
| 138 | while (!mbus_addr_valid(sp->mbus_engine, c_addr)) { |
|---|
| 139 | timeout.tv_sec = 0; |
|---|
| 140 | timeout.tv_usec = 250000; |
|---|
| 141 | mbus_recv(sp->mbus_engine, NULL, &timeout); |
|---|
| 142 | mbus_send(sp->mbus_engine); |
|---|
| 143 | mbus_heartbeat(sp->mbus_engine, 1); |
|---|
| 144 | mbus_retransmit(sp->mbus_engine); |
|---|
| 145 | } |
|---|
| 146 | debug_msg("Address %s is valid\n", c_addr); |
|---|
| 147 | |
|---|
| 148 | |
|---|
| 149 | |
|---|
| 150 | |
|---|
| 151 | debug_msg("Waiting for mbus.waiting(%s) from controller...\n", token); |
|---|
| 152 | mbus_rendezvous_go(sp->mbus_engine, token, (void *) sp); |
|---|
| 153 | debug_msg("...got it\n"); |
|---|
| 154 | |
|---|
| 155 | |
|---|
| 156 | |
|---|
| 157 | debug_msg("Waiting for mbus.go(%s) from controller...\n", token); |
|---|
| 158 | mbus_rendezvous_waiting(sp->mbus_engine, c_addr, token, (void *) sp); |
|---|
| 159 | debug_msg("...got it\n"); |
|---|
| 160 | assert(sp->rtp_session[0] != NULL); |
|---|
| 161 | |
|---|
| 162 | if (pdb_create(&sp->pdb) == FALSE) { |
|---|
| 163 | debug_msg("Failed to create persistent database\n"); |
|---|
| 164 | abort(); |
|---|
| 165 | } |
|---|
| 166 | pdb_item_create(sp->pdb, sp->clock, (uint16_t)get_freq(sp->device_clock), rtp_my_ssrc(sp->rtp_session[0])); |
|---|
| 167 | settings_load_late(sp); |
|---|
| 168 | |
|---|
| 169 | ui_initial_settings(sp); |
|---|
| 170 | ui_update(sp); |
|---|
| 171 | network_process_mbus(sp); |
|---|
| 172 | |
|---|
| 173 | audio_drain(sp->audio_device); |
|---|
| 174 | if (tx_is_sending(sp->tb)) { |
|---|
| 175 | tx_start(sp->tb); |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | session_validate(sp); |
|---|
| 179 | xdoneinit(); |
|---|
| 180 | |
|---|
| 181 | while (!should_exit) { |
|---|
| 182 | elapsed_time = 0; |
|---|
| 183 | |
|---|
| 184 | |
|---|
| 185 | elapsed_time = audio_rw_process(sp, sp, sp->ms); |
|---|
| 186 | cur_time = get_time(sp->device_clock); |
|---|
| 187 | ntp_time = ntp_time32(); |
|---|
| 188 | sp->cur_ts = ts_seq32_in(&sp->decode_sequencer, get_freq(sp->device_clock), cur_time); |
|---|
| 189 | |
|---|
| 190 | if (tx_is_sending(sp->tb)) { |
|---|
| 191 | tx_process_audio(sp->tb); |
|---|
| 192 | tx_send(sp->tb); |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | |
|---|
| 196 | timeout.tv_sec = 0; |
|---|
| 197 | timeout.tv_usec = 0; |
|---|
| 198 | for (j = 0; j < sp->rtp_session_count; j++) { |
|---|
| 199 | while(rtp_recv(sp->rtp_session[j], &timeout, cur_time)); |
|---|
| 200 | rtp_send_ctrl(sp->rtp_session[j], cur_time, NULL); |
|---|
| 201 | rtp_update(sp->rtp_session[j]); |
|---|
| 202 | } |
|---|
| 203 | |
|---|
| 204 | |
|---|
| 205 | timeout.tv_sec = 0; |
|---|
| 206 | timeout.tv_usec = 0; |
|---|
| 207 | mbus_recv(sp->mbus_engine, (void *) sp, &timeout); |
|---|
| 208 | mbus_heartbeat(sp->mbus_engine, 1); |
|---|
| 209 | mbus_retransmit(sp->mbus_engine); |
|---|
| 210 | mbus_send(sp->mbus_engine); |
|---|
| 211 | |
|---|
| 212 | |
|---|
| 213 | elapsed_time += audio_rw_process(sp, sp, sp->ms); |
|---|
| 214 | cur_time = get_time(sp->device_clock); |
|---|
| 215 | ntp_time = ntp_time32(); |
|---|
| 216 | sp->cur_ts = ts_seq32_in(&sp->decode_sequencer, get_freq(sp->device_clock), cur_time); |
|---|
| 217 | |
|---|
| 218 | if (tx_is_sending(sp->tb)) { |
|---|
| 219 | tx_process_audio(sp->tb); |
|---|
| 220 | tx_send(sp->tb); |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | |
|---|
| 224 | if (sp->playing_audio) { |
|---|
| 225 | struct s_source *s; |
|---|
| 226 | int sidx; |
|---|
| 227 | ts_t cush_ts; |
|---|
| 228 | |
|---|
| 229 | session_validate(sp); |
|---|
| 230 | cush_ts = ts_map32(get_freq(sp->device_clock), cushion_get_size(sp->cushion)); |
|---|
| 231 | cush_ts = ts_add(sp->cur_ts, cush_ts); |
|---|
| 232 | scnt = (int)source_list_source_count(sp->active_sources); |
|---|
| 233 | for(sidx = 0; sidx < scnt; sidx++) { |
|---|
| 234 | s = source_list_get_source_no(sp->active_sources, sidx); |
|---|
| 235 | if (source_relevant(s, sp->cur_ts)) { |
|---|
| 236 | pdb_entry_t *e; |
|---|
| 237 | ts_t two_secs, delta; |
|---|
| 238 | source_check_buffering(s); |
|---|
| 239 | source_process(sp, s, sp->ms, sp->render_3d, sp->repair, sp->cur_ts, cush_ts); |
|---|
| 240 | source_audit(s); |
|---|
| 241 | |
|---|
| 242 | pdb_item_get(sp->pdb, source_get_ssrc(s), &e); |
|---|
| 243 | delta = ts_sub(sp->cur_ts, e->last_ui_update); |
|---|
| 244 | two_secs = ts_map32(8000, 16000); |
|---|
| 245 | if (ts_gt(delta, two_secs)) { |
|---|
| 246 | ui_update_stats(sp, e->ssrc); |
|---|
| 247 | e->last_ui_update = sp->cur_ts; |
|---|
| 248 | } |
|---|
| 249 | } else { |
|---|
| 250 | |
|---|
| 251 | uint32_t ssrc; |
|---|
| 252 | ssrc = source_get_ssrc(s); |
|---|
| 253 | ui_info_deactivate(sp, ssrc); |
|---|
| 254 | source_remove(sp->active_sources, s); |
|---|
| 255 | sidx--; |
|---|
| 256 | scnt--; |
|---|
| 257 | } |
|---|
| 258 | } |
|---|
| 259 | } |
|---|
| 260 | |
|---|
| 261 | |
|---|
| 262 | |
|---|
| 263 | session_validate(sp); |
|---|
| 264 | if (sp->echo_suppress) { |
|---|
| 265 | if (scnt > 0) { |
|---|
| 266 | if (tx_is_sending(sp->tb)) { |
|---|
| 267 | tx_stop(sp->tb); |
|---|
| 268 | sp->echo_tx_active = TRUE; |
|---|
| 269 | debug_msg("Echo suppressor (disabling tx)\n"); |
|---|
| 270 | } |
|---|
| 271 | } else if (sp->echo_tx_active) { |
|---|
| 272 | |
|---|
| 273 | |
|---|
| 274 | if (tx_is_sending(sp->tb) == FALSE) { |
|---|
| 275 | tx_start(sp->tb); |
|---|
| 276 | debug_msg("Echo suppressor (enabling tx)\n"); |
|---|
| 277 | } |
|---|
| 278 | sp->echo_tx_active = FALSE; |
|---|
| 279 | } |
|---|
| 280 | } |
|---|
| 281 | |
|---|
| 282 | if (alc >= 50) { |
|---|
| 283 | if (!sp->lecture && tx_is_sending(sp->tb) && sp->auto_lecture != 0) { |
|---|
| 284 | gettimeofday(&time, NULL); |
|---|
| 285 | if (time.tv_sec - sp->auto_lecture > 120) { |
|---|
| 286 | sp->auto_lecture = 0; |
|---|
| 287 | debug_msg("Dummy lecture mode\n"); |
|---|
| 288 | } |
|---|
| 289 | } |
|---|
| 290 | alc = 0; |
|---|
| 291 | } else { |
|---|
| 292 | alc++; |
|---|
| 293 | } |
|---|
| 294 | |
|---|
| 295 | if (sp->audio_device && elapsed_time != 0) { |
|---|
| 296 | ui_periodic_updates(sp, elapsed_time); |
|---|
| 297 | } |
|---|
| 298 | if (sp->new_config != NULL) { |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | |
|---|
| 302 | network_process_mbus(sp); |
|---|
| 303 | if (audio_device_reconfigure(sp)) { |
|---|
| 304 | |
|---|
| 305 | |
|---|
| 306 | |
|---|
| 307 | source_list_clear(sp->active_sources); |
|---|
| 308 | ui_update(sp); |
|---|
| 309 | } |
|---|
| 310 | } |
|---|
| 311 | |
|---|
| 312 | |
|---|
| 313 | if (!audio_is_ready(sp->audio_device)) { |
|---|
| 314 | audio_wait_for(sp->audio_device, 20); |
|---|
| 315 | } |
|---|
| 316 | |
|---|
| 317 | |
|---|
| 318 | session_validate(sp); |
|---|
| 319 | } |
|---|
| 320 | |
|---|
| 321 | settings_save(sp); |
|---|
| 322 | tx_stop(sp->tb); |
|---|
| 323 | if (sp->in_file != NULL) snd_read_close (&sp->in_file); |
|---|
| 324 | if (sp->out_file != NULL) snd_write_close(&sp->out_file); |
|---|
| 325 | audio_device_release(sp, sp->audio_device); |
|---|
| 326 | pdb_destroy(&sp->pdb); |
|---|
| 327 | |
|---|
| 328 | |
|---|
| 329 | mbus_qmsgf(sp->mbus_engine, "()", FALSE, "mbus.bye", ""); |
|---|
| 330 | mbus_send(sp->mbus_engine); |
|---|
| 331 | do { |
|---|
| 332 | struct timeval timeout; |
|---|
| 333 | mbus_send(sp->mbus_engine); |
|---|
| 334 | mbus_retransmit(sp->mbus_engine); |
|---|
| 335 | timeout.tv_sec = 0; |
|---|
| 336 | timeout.tv_usec = 20000; |
|---|
| 337 | mbus_recv(sp->mbus_engine, sp, &timeout); |
|---|
| 338 | } while (!mbus_sent_all(sp->mbus_engine)); |
|---|
| 339 | mbus_exit(sp->mbus_engine); |
|---|
| 340 | |
|---|
| 341 | for (j = 0; j < sp->rtp_session_count; j++) { |
|---|
| 342 | rtp_send_bye(sp->rtp_session[j]); |
|---|
| 343 | rtp_done(sp->rtp_session[j]); |
|---|
| 344 | rtp_callback_exit(sp->rtp_session[j]); |
|---|
| 345 | } |
|---|
| 346 | |
|---|
| 347 | session_validate(sp); |
|---|
| 348 | session_exit(sp); |
|---|
| 349 | converters_free(); |
|---|
| 350 | audio_free_interfaces(); |
|---|
| 351 | xmemdmp(); |
|---|
| 352 | return 0; |
|---|
| 353 | } |
|---|