/* DESC: This script implements an audio voice dispatcher * Copyright (C) 2012 NetModule AG, Switzerland */ INTERVAL = 3; /* 3 seconds */ NUMBER = "+123456789"; /* number to call when DI1 = on */ template dispatcher { in1; audio; int dispatcher () { this.in1 = -1; endpoints = nb_voice_endpoint_list(); if (is_array(endpoints)) { for (i = 0; i < length(endpoints); i++) { ep = endpoints[i]; id = struct_get(ep, "id"); desc = struct_get(ep, "desc"); state = struct_get(ep, "state"); nb_syslog("%d: endpoint %d is in state %s (%s)", i, id, state, desc); /* record first audio endpoint */ if (is_void(aud) && left(desc, 6) == "aud://") { this.audio = ep; } } } if (is_void(this.audio)) { nb_syslog("no audio endpoint found"); return -1; } else { nb_syslog("using endpoint %s\n", struct_get(this.audio, "desc")); return 0; } } int checkdio () { in1 = nb_dio_get("in1"); if (in1 == this.in1) { /* no state change */ return -1; } else { /* update state */ nb_syslog("updating dio state"); this.in1 = in1; return in1; } } int handle_dio_event (int ev) { /* update endpoint first */ au = nb_voice_endpoint_get(d.audio); if (!is_struct(au)) { nb_syslog("updating audio endpoint failed"); return -1; } audesc = struct_get(au, "desc"); austate = struct_get(au, "state"); /* get list of currently active calls */ calls = nb_voice_call_list(); if (ev == 1) { nb_syslog("DI1 has been closed"); if (austate == "available") { /* initiate new call */ call = mkstruct("calling", audesc, "called", NUMBER); nb_syslog("initiating call to %s from %s", NUMBER, audesc); if (nb_voice_call_dial(call) == 0) { nb_syslog("unable to initate call to %s", NUMBER); } } else { nb_syslog("not calling %s as endpoint %s is not available", NUMBER, audesc); return -1; } } else { nb_syslog("DI1 has been opened"); /* terminate any active calls */ for (i = 0; i < length(calls); i++) { call = calls[i]; if (strstr(struct_get(call, "called"), desc)) { nb_syslog("hanging up call %d", struct_get(call, "id")); nb_voice_call_hangup(call); } } } return 0; } void handle_voice_event (struct event) { type = struct_get(event, "type"); call = struct_get(event, "call"); id = struct_get(call, "id"); nb_syslog("received voice event '%s' on call %d\n", type, id); /* update endpoint */ au = nb_voice_endpoint_get(d.audio); if (!is_struct(au)) { nb_syslog("updating audio endpoint failed"); return; } austate = struct_get(au, "state"); audesc = struct_get(au, "desc"); switch (type) { case "outgoing": /* don't touch any locally initiated calls */ break; case "incoming": nb_syslog("call %s: %s is calling %s", id, struct_get(call, "calling"), struct_get(call, "called")); /* route any incoming calls to audio device */ if (nb_voice_call_route(call, audesc) == 0) { nb_syslog("routing call %d to %s", id, audesc); } else { nb_syslog("unable to route call %d to %s", id, audesc); nb_voice_call_hangup(call); } break; case "dispatched": /* accept calls if DI1 closes */ nb_syslog("call %s: %s to %s got dispatched", id, struct_get(call, "calling"), struct_get(call, "called")); if (struct_get(call, "state") == "alerting") { if (austate == "available") { nb_syslog("hanging up call %d as audio is busy", id); nb_voice_call_hangup(call); } else { /* wait until IN1 has been closed */ nb_syslog("waiting 10s until IN1 is closed"); for (i = 0; i < 10; i++) { in1 = this.checkdio(); if (in1 == 1) { nb_syslog("IN1 closed"); if (nb_voice_call_accept(call) == 0) { nb_syslog("accepted call %d", id); if (1) { /* increase volume level */ nb_voice_call_volume(call, 7); } return; } else { nb_syslog("unable to accept call %d", id); break; } } sleep(1); } } /* otherwise hangup */ nb_syslog("hanging up call %d", id); nb_voice_call_hangup(call); } break; default: break; } } void run () { /* wait for calls */ while (1) { event = nb_voice_event(INTERVAL); if (is_struct(event)) { dump(event); this.handle_voice_event(event); } event = this.checkdio(); if (event != -1) { this.handle_dio_event(event); } } } } d = new dispatcher(); dump(d); d.run(); exit(0);