/// <summary> /// Renders the high-level switch action instance into zero or more <see cref="SwitchExecuteAction" /> /// instances and then adds these to the <see cref="ActionRenderingContext" />.<see cref="ActionRenderingContext.Actions" /> /// collection. /// </summary> /// <param name="context">The action rendering context.</param> /// <exception cref="NotSupportedException">Thrown for parameters that are not supported for the current execution context.</exception> /// <remarks> /// <note> /// It is perfectly reasonable for an action to render no actions to the /// context or to render multiple actions based on its properties. /// </note> /// </remarks> public override void Render(ActionRenderingContext context) { if (callID1 != Guid.Empty && callID2 != Guid.Empty) { context.Actions.Add(new SwitchExecuteAction("uuid_bridge", "{0:D} {1:D}", callID1, callID2)); return; } // Special case FreeSWITCH style dialstrings. if (dialstring != null) { if (context.IsDialplan) { context.Actions.Add(new SwitchExecuteAction("bridge", dialstring)); } else { context.Actions.Add(new SwitchExecuteAction(CallID, "bridge", dialstring)); } return; } if (endpoints.Count == 0) { throw new InvalidOperationException("Attempt to render a BridgeAction with no endpoints."); } // Add an action queue any DTMF digits. if (queuedDtmfDigits != null && queuedDtmfDigits.Length > 0) { var duration = ToneDuration; if (duration < Switch.MinDtmfDuration) { duration = Switch.MinDtmfDuration; } else if (duration > Switch.MaxDtmfDuration) { duration = Switch.MaxDtmfDuration; } if (context.IsDialplan) { context.Actions.Add(new SwitchExecuteAction("queue_dtmf", "{0}@{1}", queuedDtmfDigits, (int)duration.TotalMilliseconds)); } else { context.Actions.Add(new SwitchExecuteAction(CallID, "queue_dtmf", "{0}@{1}", queuedDtmfDigits, (int)duration.TotalMilliseconds)); } } // Add any propety variables to the variables collection. if (AnswerTimeout.HasValue) { Variables["call_timeout"] = SwitchHelper.GetScheduleSeconds(AnswerTimeout.Value).ToString(); } if (BypassMedia.HasValue) { Variables["bypass_media"] = BypassMedia.Value ? "true" : "false"; } if (Ringback.HasValue && Ringback.Value) { Variables["ringback"] = "${us-ring}"; } if (CallerIDName != null) { Variables["effective_caller_id_name"] = CallerIDName; } if (CallerIDNumber != null) { Variables["effective_caller_id_number"] = CallerIDNumber; } // I'm not going to use the FreeSWITCH global channel variable syntax {..} at the beginning of // the dialstring since this is really just a human friendly shortcut. Instead, I'm going // to explicitly add any global variables that aren't overridden to each endpoint. if (Variables.Count > 0) { foreach (var endpoint in Endpoints) { foreach (var variable in Variables) { if (!endpoint.Variables.ContainsKey(variable.Key)) { endpoint.Variables[variable.Key] = variable.Value; } } } } // Render the dialstring if there's only one endpoint. if (endpoints.Count == 1) { if (context.IsDialplan) { context.Actions.Add(new SwitchExecuteAction("bridge", endpoints[0].ToString())); } else { context.Actions.Add(new SwitchExecuteAction(CallID, "bridge", endpoints[0].ToString())); } return; } // We have multiple endpoints so we need to render based on the bridge mode. var sb = new StringBuilder(); switch (Mode) { case BridgeMode.LinearHunt: foreach (var endpoint in endpoints) { sb.AppendFormat("{0},", endpoint); } break; case BridgeMode.RandomHunt: endpoints.Shuffle(); foreach (var endpoint in endpoints) { sb.AppendFormat("{0},", endpoint); } break; case BridgeMode.RingAll: foreach (var endpoint in endpoints) { sb.AppendFormat("{0}|", endpoint); } break; } if (sb.Length > 0) { sb.Length--; } if (context.IsDialplan) { context.Actions.Add(new SwitchExecuteAction("bridge", sb.ToString())); } else { context.Actions.Add(new SwitchExecuteAction(CallID, "bridge", sb.ToString())); } }