static void call_event_handler(struct call *call, enum call_event ev, const char *str, void *arg) { struct ua *ua = arg; const char *peeruri; struct call *call2 = NULL; int err; MAGIC_CHECK(ua); peeruri = call_peeruri(call); /* stop any ringtones */ ua->play = mem_deref(ua->play); switch (ev) { case CALL_EVENT_INCOMING: if (contact_block_access(peeruri)) { info("ua: blocked access: \"%s\"\n", peeruri); ua_event(ua, UA_EVENT_CALL_CLOSED, call, str); mem_deref(call); break; } switch (ua->acc->answermode) { case ANSWERMODE_EARLY: (void)call_progress(call); break; case ANSWERMODE_AUTO: (void)call_answer(call, 200); break; case ANSWERMODE_MANUAL: default: if (list_count(&ua->calls) > 1) { (void)play_file(&ua->play, "callwaiting.wav", 3); } else { /* Alert user */ (void)play_file(&ua->play, "ring.wav", -1); } ua_event(ua, UA_EVENT_CALL_INCOMING, call, peeruri); break; } break; case CALL_EVENT_RINGING: (void)play_file(&ua->play, "ringback.wav", -1); ua_event(ua, UA_EVENT_CALL_RINGING, call, peeruri); break; case CALL_EVENT_PROGRESS: ua_printf(ua, "Call in-progress: %s\n", peeruri); ua_event(ua, UA_EVENT_CALL_PROGRESS, call, peeruri); break; case CALL_EVENT_ESTABLISHED: ua_printf(ua, "Call established: %s\n", peeruri); ua_event(ua, UA_EVENT_CALL_ESTABLISHED, call, peeruri); break; case CALL_EVENT_CLOSED: if (call_scode(call)) { const char *tone; tone = translate_errorcode(call_scode(call)); if (tone) (void)play_file(&ua->play, tone, 1); } ua_event(ua, UA_EVENT_CALL_CLOSED, call, str); mem_deref(call); break; case CALL_EVENT_TRANSFER: /* * Create a new call to transfer target. * * NOTE: we will automatically connect a new call to the * transfer target */ ua_printf(ua, "transferring call to %s\n", str); err = ua_call_alloc(&call2, ua, VIDMODE_ON, NULL, call, call_localuri(call)); if (!err) { struct pl pl; pl_set_str(&pl, str); err = call_connect(call2, &pl); if (err) { warning("ua: transfer: connect error: %m\n", err); } } if (err) { (void)call_notify_sipfrag(call, 500, "Call Error"); mem_deref(call2); } break; case CALL_EVENT_TRANSFER_FAILED: ua_event(ua, UA_EVENT_CALL_TRANSFER_FAILED, call, str); break; } }
int audio_alloc(struct audio **ap, const struct config *cfg, struct call *call, struct sdp_session *sdp_sess, int label, const struct mnat *mnat, struct mnat_sess *mnat_sess, const struct menc *menc, struct menc_sess *menc_sess, uint32_t ptime, const struct list *aucodecl, audio_event_h *eventh, audio_err_h *errh, void *arg) { struct audio *a; struct autx *tx; struct aurx *rx; struct le *le; int err; if (!ap || !cfg) return EINVAL; a = mem_zalloc(sizeof(*a), audio_destructor); if (!a) return ENOMEM; MAGIC_INIT(a); a->cfg = cfg->audio; tx = &a->tx; rx = &a->rx; err = stream_alloc(&a->strm, &cfg->avt, call, sdp_sess, "audio", label, mnat, mnat_sess, menc, menc_sess, call_localuri(call), stream_recv_handler, NULL, a); if (err) goto out; if (cfg->avt.rtp_bw.max) { stream_set_bw(a->strm, AUDIO_BANDWIDTH); } err = sdp_media_set_lattr(stream_sdpmedia(a->strm), true, "ptime", "%u", ptime); if (err) goto out; /* Audio codecs */ for (le = list_head(aucodecl); le; le = le->next) { err = add_audio_codec(a, stream_sdpmedia(a->strm), le->data); if (err) goto out; } tx->mb = mbuf_alloc(STREAM_PRESZ + 4096); tx->sampv = mem_zalloc(AUDIO_SAMPSZ * 2, NULL); rx->sampv = mem_zalloc(AUDIO_SAMPSZ * 2, NULL); if (!tx->mb || !tx->sampv || !rx->sampv) { err = ENOMEM; goto out; } err = telev_alloc(&a->telev, TELEV_PTIME); if (err) goto out; err = add_telev_codec(a); if (err) goto out; auresamp_init(&tx->resamp); str_ncpy(tx->device, a->cfg.src_dev, sizeof(tx->device)); tx->ptime = ptime; tx->ts = rand_u16(); tx->marker = true; auresamp_init(&rx->resamp); str_ncpy(rx->device, a->cfg.play_dev, sizeof(rx->device)); rx->pt = -1; rx->ptime = ptime; a->eventh = eventh; a->errh = errh; a->arg = arg; if (a->cfg.txmode == AUDIO_MODE_TMR) tmr_init(&tx->u.tmr); out: if (err) mem_deref(a); else *ap = a; return err; }