/** * End this page, by clearing up all timers, outbound calls, the inbound call, and the RTP forker. * * <p>synchronized so multiple calls are serialized. Only the first should be needed. */ public synchronized void end() { // Remove all timers associated with me Timers.removeTimer(this); // Hangup on all outbound calls. for (Leg outbound : outbounds) { try { outbound.destroyLeg(); } catch (Exception e) { LOG.error("PageGroup::end outbound", e); } } outbounds.removeAllElements(); // Stop the RTP processing. rtpFork.stop(); rtpFork.removeAllDestinations(); // Hangup on the inbound call if (inbound != null) { try { inbound.destroyLeg(); } catch (Exception e) { LOG.error("PageGroup::end inbound", e); } inbound = null; } busy = false; }
/** The event handler for this group's timers, RtpFork, and calls. */ public boolean onEvent(LegEvent event) { LOG.debug("PageGroup::onEvent got event " + event.getDescription()); if (event.getDescription().equals("timer: status=fired name=maximum_duration")) { // Maximum duration timer fired, end the page. end(); } else if (event.getDescription().equals("timer: status=fired name=beep_start")) { if (beep != null) { // Start the beep (if any) // Add the inbound caller to the RTP mix so he can hear the beep rtpFork.addDestination(inboundRtp); rtpFork.startLocalAudio(beep); } } else if (event.getDescription().equals("localAudio end")) { // Now that the beep is done, remove the inbound caller to the RTP mix // So he does not hear himself rtpFork.removeDestination(inboundRtp); } else if (event.getDescription().startsWith("dialog bye")) { // Someone hung up. Leg leg = event.getLeg(); if (leg == inbound) { // Inbound call ended. End the page. end(); } else { // Outbound call ended. Stop sending rtp to it rtpFork.removeDestination(leg.getRemoteRtpAddress()); } } else if (event.getDescription().equals("sdp")) { // SDP changed, keep rtpFork informed. rtpFork.removeDestination(event.getLeg().getPreviousRtpAddress()); rtpFork.addDestination(event.getLeg().getRemoteRtpAddress()); } return true; }
/** * Trigger a page of all the destinations. * * @param inbound The inbound Leg (audio from here goes to all destinations) * @param inboundRtp The destination to send RTP packets so the inbound caller can hear. * @param alertInfoKey The magic key needed for Polycom Auto-Answer * @return */ public boolean page(Leg inbound, InetSocketAddress inboundRtp, String alertInfoKey) { if (busy == false) { LOG.debug("PageGroup::page starting"); busy = true; this.inbound = inbound; this.inboundRtp = inboundRtp; // Spin up the RTP forker rtpFork.start(); try { // Get the originator for the Page. InboundLeg origLeg = (InboundLeg) inbound; String pageOriginatorAddress; pageOriginatorAddress = origLeg.getAddress(); // Answer the inbound call. inbound.acceptCall(rtpPort); // Start the timers if (maximumDuration > 0) { // Start the maximumDuration timer if it is greater than 0 Timers.addTimer( "maximum_duration", maximumDuration, this); // End this page after this many mS } Timers.addTimer("beep_start", 1000, this); // Start the beep after this much time // Place a call to each destination for (String destination : destinations) { // Compare the originator with the destination. Only place an outbound call // if they aren't the same. We don't make a call to the same destination that // is initiating the page. if (destination.compareToIgnoreCase(pageOriginatorAddress) != 0) { Leg outbound = placeCall(inbound.getDisplayName(), origLeg.getCallId(), destination, alertInfoKey); if (outbound != null) { // Keep track of them! outbounds.add(outbound); } } else { LOG.info( String.format("Skipping %s as it is the page originator.", pageOriginatorAddress)); } } return true; } catch (Throwable t) { LOG.warn("PageGroup::page", t); end(); } } LOG.debug("PageGroup::page failed"); return false; }