diff --git a/src/activities/Elsa.Activities.Telnyx/Activities/PlayAudio.cs b/src/activities/Elsa.Activities.Telnyx/Activities/PlayAudio.cs new file mode 100644 index 000000000..be57d89cc --- /dev/null +++ b/src/activities/Elsa.Activities.Telnyx/Activities/PlayAudio.cs @@ -0,0 +1,104 @@ +using System; +using System.Threading.Tasks; +using Elsa.Activities.Telnyx.Client.Models; +using Elsa.Activities.Telnyx.Client.Services; +using Elsa.Activities.Telnyx.Extensions; +using Elsa.ActivityResults; +using Elsa.Attributes; +using Elsa.Design; +using Elsa.Exceptions; +using Elsa.Services; +using Elsa.Services.Models; +using Refit; + +namespace Elsa.Activities.Telnyx.Activities +{ + [Action( + Category = Constants.Category, + Description = "Play an audio file on the call.", + Outcomes = new[] { OutcomeNames.Done, TelnyxOutcomeNames.CallIsNoLongerActive }, + DisplayName = "Play Audio" + )] + public class PlayAudio : Activity + { + private readonly ITelnyxClient _telnyxClient; + public PlayAudio(ITelnyxClient telnyxClient) => _telnyxClient = telnyxClient; + + [ActivityProperty( + Label = "Call Control ID", + Hint = "Unique identifier and token for controlling the call", + Category = PropertyCategories.Advanced + )] + public string CallControlId { get; set; } = default!; + + [ActivityProperty( + Label = "Audio URL", + Hint = "The URL of a file to be played back at the beginning of each prompt. The URL can point to either a WAV or MP3 file." + )] + public Uri AudioUrl { get; set; } = default!; + + [ActivityProperty( + Hint = "Use this field to add state to every subsequent webhook. It must be a valid Base-64 encoded string.", + Category = PropertyCategories.Advanced + )] + public string? ClientState { get; set; } + + [ActivityProperty( + Label = "Command ID", + Hint = "Use this field to avoid duplicate commands. Telnyx will ignore commands with the same Command ID.", + Category = PropertyCategories.Advanced + )] + public string? CommandId { get; set; } + + [ActivityProperty( + Hint = "The number of times the audio file should be played. If supplied, the value must be an integer between 1 and 100, or the special string 'infinity' for an endless loop.", + DefaultValue = "1", + Category = PropertyCategories.Advanced + )] + public string? Loop { get; set; } = "1"; + + [ActivityProperty( + Hint = "When enabled, audio will be mixed on top of any other audio that is actively being played back. Note that `overlay: true` will only work if there is another audio file already being played on the call.", + DefaultValue = false, + Category = PropertyCategories.Advanced + )] + public bool Overlay { get; set; } + + [ActivityProperty( + Hint = "Specifies the leg or legs on which audio will be played. If supplied, the value must be either 'self', 'opposite' or 'both'.", + UIHint = ActivityPropertyUIHints.Dropdown, + Options = new[]{ "", "self", "opposite", "both" }, + Category = PropertyCategories.Advanced + )] + public string? TargetLegs { get; set; } + + protected override async ValueTask OnExecuteAsync(ActivityExecutionContext context) + { + var request = new PlayAudioRequest( + AudioUrl, + EmptyToNull(ClientState), + EmptyToNull(CommandId), + string.IsNullOrWhiteSpace(Loop) ? null : Loop == "infinity" ? Loop : int.Parse(Loop), + Overlay, + EmptyToNull(TargetLegs) + ); + + var callControlId = context.GetCallControlAppId(CallControlId); + + try + { + await _telnyxClient.Calls.PlayAudioAsync(callControlId, request, context.CancellationToken); + return Done(); + } + catch (ApiException e) + { + if (await e.CallIsNoLongerActiveAsync()) + return Outcome(TelnyxOutcomeNames.CallIsNoLongerActive); + + throw new WorkflowException(e.Content ?? e.Message, e); + } + } + + private static string? EmptyToNull(string? value) => value is "" ? null : value; + } +} \ No newline at end of file diff --git a/src/activities/Elsa.Activities.Telnyx/Client/Models/Requests.cs b/src/activities/Elsa.Activities.Telnyx/Client/Models/Requests.cs index 466bb0a50..545d88e9c 100644 --- a/src/activities/Elsa.Activities.Telnyx/Client/Models/Requests.cs +++ b/src/activities/Elsa.Activities.Telnyx/Client/Models/Requests.cs @@ -4,8 +4,9 @@ using System.Collections.Generic; namespace Elsa.Activities.Telnyx.Client.Models { public record AnswerCallRequest(string? BillingGroupId, string? ClientState, string? CommandId, string? WebhookUrl, string? WebhookUrlMethod); + public record HangupCallRequest(string? ClientState, string? CommandId); - + public record GatherUsingAudioRequest( Uri AudioUrl, string? ClientState, @@ -17,8 +18,9 @@ namespace Elsa.Activities.Telnyx.Client.Models int? MinimumDigits, string? TerminatingDigit, int? TimeoutMillis, - string? ValidDigits); - + string? ValidDigits + ); + public record TransferCallRequest( string To, string? From, @@ -37,7 +39,7 @@ namespace Elsa.Activities.Telnyx.Client.Models string? WebhookUrl, string? WebhookUrlMethod ); - + public record DialRequest( string ConnectionId, string To, @@ -55,11 +57,19 @@ namespace Elsa.Activities.Telnyx.Client.Models string? WebhookUrl, string? WebhookUrlMethod ); - + public record BridgeCallsRequest( string CallControlId, string? ClientState, string? CommandId, string? ParkAfterUnbridge ); + + public record PlayAudioRequest( + Uri AudioUrl, + string? ClientState, + string? CommandId, + object? Loop, + bool Overlay, + string? TargetLegs); } \ No newline at end of file diff --git a/src/activities/Elsa.Activities.Telnyx/Client/Services/ICallsApi.cs b/src/activities/Elsa.Activities.Telnyx/Client/Services/ICallsApi.cs index 2b37023d3..e0bad30af 100644 --- a/src/activities/Elsa.Activities.Telnyx/Client/Services/ICallsApi.cs +++ b/src/activities/Elsa.Activities.Telnyx/Client/Services/ICallsApi.cs @@ -24,5 +24,8 @@ namespace Elsa.Activities.Telnyx.Client.Services [Post("/v2/calls/{callControlId}/actions/bridge")] Task BridgeCallsAsync(string callControlId, [Body]BridgeCallsRequest request, CancellationToken cancellationToken = default); + + [Post("/v2/calls/{callControlId}/actions/playback_start")] + Task PlayAudioAsync(string callControlId, [Body]PlayAudioRequest request, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/src/activities/Elsa.Activities.Telnyx/Extensions/ActivityExecutionContextExtensions.cs b/src/activities/Elsa.Activities.Telnyx/Extensions/ActivityExecutionContextExtensions.cs index a4fc4365a..0102afe55 100644 --- a/src/activities/Elsa.Activities.Telnyx/Extensions/ActivityExecutionContextExtensions.cs +++ b/src/activities/Elsa.Activities.Telnyx/Extensions/ActivityExecutionContextExtensions.cs @@ -9,16 +9,11 @@ namespace Elsa.Activities.Telnyx.Extensions /// /// Returns the default call control app ID if the specified value is null or empty. /// - public static string GetCallControlId(this ActivityExecutionContext context, string? callControlId) + public static string GetCallControlAppId(this ActivityExecutionContext context, string? callControlId) { if (!string.IsNullOrWhiteSpace(callControlId)) return callControlId; - // callControlId = context.GetVariable("CallControlId"); - // - // if (!string.IsNullOrWhiteSpace(callControlId)) - // return callControlId; - var options = context.GetService(); callControlId = options.CallControlAppId;