From 3835741d3d9fc8d0e7697b4d166265ed4e937c97 Mon Sep 17 00:00:00 2001 From: Sina Madani Date: Fri, 28 Feb 2025 11:50:45 +0000 Subject: [PATCH] docs: Tidy up Voice API Javadocs & refactoring / deprecations (#568) * Tidy up Voice API Javadocs * refactor:CallsFilter extends HalFilterRequest * Further refactoring & documentation * 100% Voice coverage again * Bump JUnit version * Package-private no-args constructors --- CHANGELOG.md | 9 +- pom.xml | 2 +- .../client/common/HalFilterRequest.java | 32 ++- .../AbstractConversationsFilterRequest.java | 18 +- .../conversations/ListEventsRequest.java | 16 +- .../ListUserConversationsRequest.java | 12 +- .../client/meetings/ListRoomsRequest.java | 8 +- .../client/voice/AddDtmfListenerRequest.java | 11 + .../voice/AdvancedMachineDetection.java | 3 + .../com/vonage/client/voice/AppEndpoint.java | 11 +- .../java/com/vonage/client/voice/Call.java | 48 ++++ .../vonage/client/voice/CallDirection.java | 21 ++ .../com/vonage/client/voice/CallEvent.java | 6 + .../com/vonage/client/voice/CallInfo.java | 105 ++++++-- .../com/vonage/client/voice/CallInfoPage.java | 37 +++ .../com/vonage/client/voice/CallOrder.java | 7 + .../com/vonage/client/voice/CallStatus.java | 8 +- .../com/vonage/client/voice/CallsFilter.java | 244 ++++++++++++------ .../vonage/client/voice/DisconnectedBy.java | 1 - .../com/vonage/client/voice/DtmfPayload.java | 14 + .../com/vonage/client/voice/DtmfResponse.java | 20 +- .../com/vonage/client/voice/DtmfResult.java | 5 + .../vonage/client/voice/EmbeddedCalls.java | 13 + .../com/vonage/client/voice/Endpoint.java | 4 + .../com/vonage/client/voice/EndpointType.java | 7 + .../vonage/client/voice/MachineDetection.java | 22 +- .../client/voice/MachineDetectionStatus.java | 7 + .../vonage/client/voice/ModifyCallAction.java | 9 +- .../client/voice/ModifyCallPayload.java | 14 + .../com/vonage/client/voice/PageLink.java | 6 + .../com/vonage/client/voice/PageLinks.java | 2 + .../vonage/client/voice/PhoneEndpoint.java | 3 + .../com/vonage/client/voice/SipEndpoint.java | 8 +- .../com/vonage/client/voice/SipHeader.java | 4 + .../vonage/client/voice/SpeechResults.java | 5 + .../client/voice/SpeechTimeoutReason.java | 22 ++ .../vonage/client/voice/SpeechTranscript.java | 6 + .../vonage/client/voice/StreamPayload.java | 31 ++- .../vonage/client/voice/StreamResponse.java | 21 +- .../com/vonage/client/voice/TalkResponse.java | 21 +- .../client/voice/TextToSpeechLanguage.java | 10 + .../client/voice/TransferCallPayload.java | 18 +- .../client/voice/TransferDestination.java | 40 ++- .../com/vonage/client/voice/VbcEndpoint.java | 8 + .../com/vonage/client/voice/VoiceClient.java | 4 +- .../client/voice/VoiceResponseException.java | 5 + .../client/voice/WebSocketEndpoint.java | 41 ++- .../vonage/client/voice/ncco/AppEndpoint.java | 3 + .../client/voice/ncco/ConnectAction.java | 129 ++++++++- .../client/voice/ncco/ConversationAction.java | 187 ++++++++++++-- .../vonage/client/voice/ncco/Endpoint.java | 6 + .../vonage/client/voice/ncco/EventType.java | 6 +- .../vonage/client/voice/ncco/InputAction.java | 33 ++- .../vonage/client/voice/ncco/InputMode.java | 7 + .../com/vonage/client/voice/ncco/Ncco.java | 26 +- .../client/voice/ncco/NotifyAction.java | 113 ++++++-- .../client/voice/ncco/PhoneEndpoint.java | 82 +++++- .../client/voice/ncco/RecordAction.java | 212 ++++++++++++--- .../client/voice/ncco/RecordingFormat.java | 10 + .../vonage/client/voice/ncco/SipEndpoint.java | 3 + .../client/voice/ncco/SpeechSettings.java | 87 +++++-- .../client/voice/ncco/SplitRecording.java | 3 + .../client/voice/ncco/StreamAction.java | 186 +++++++++++-- .../vonage/client/voice/ncco/TalkAction.java | 196 +++++++++++--- .../voice/ncco/TranscriptionSettings.java | 3 + .../client/voice/ncco/WebSocketEndpoint.java | 83 +++++- .../com/vonage/client/voice/CallInfoTest.java | 10 +- .../com/vonage/client/voice/CallTest.java | 2 +- .../vonage/client/voice/CallsFilterTest.java | 73 ++++-- .../vonage/client/voice/VoiceClientTest.java | 4 +- .../client/voice/ncco/NotifyActionTest.java | 13 +- .../client/voice/ncco/RecordActionTest.java | 8 +- .../client/voice/ncco/StreamActionTest.java | 14 +- .../voice/ncco/WebSocketEndpointTest.java | 7 +- 74 files changed, 2081 insertions(+), 394 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fff14aa8..8dc96ef94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,15 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -# [8.17.0] - 2025-02-2? +# [8.17.0] - 2025-02-28 - Added user/domain name support to `com.vonage.client.voice.ncco.SipEndpoint` +- Improved Voice API documentation +- Deprecated primitive wrapper methods in NCCO action builders +- Deprecated singleton URL / Endpoint array/collection methods in Voice API +- Refactored `com.vonage.client.voice.CallsFilter` to extend `HalFilterRequest` + - Deprecated `java.util.Date`-based methods + - `getOrder()` returns a `com.vonage.client.common.SortOrder` instead of `CallOrder` +- Made constructors for response objects in Voice API package-private # [8.16.2] - 2025-02-05 - Added `disconnected_by` enum to `com.vonage.client.voice.EventWebhook` diff --git a/pom.xml b/pom.xml index 45d8b3639..222424040 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ org.junit.jupiter junit-jupiter-engine - 5.11.4 + 5.12.0 test diff --git a/src/main/java/com/vonage/client/common/HalFilterRequest.java b/src/main/java/com/vonage/client/common/HalFilterRequest.java index 9bace762b..01897037f 100644 --- a/src/main/java/com/vonage/client/common/HalFilterRequest.java +++ b/src/main/java/com/vonage/client/common/HalFilterRequest.java @@ -17,6 +17,7 @@ import com.vonage.client.QueryParamsRequest; import java.time.Instant; +import java.time.format.DateTimeFormatter; import java.util.LinkedHashMap; import java.util.Map; @@ -66,21 +67,26 @@ protected HalFilterRequest(Integer page, Integer pageSize, SortOrder order) { @Override public Map makeParams() { Map params = new LinkedHashMap<>(); - if (cursor != null) { - params.put("cursor", cursor); - } - if (page != null) { - params.put("page", page.toString()); - } - if (pageSize != null) { - params.put("page_size", pageSize.toString()); - } - if (order != null) { - params.put("order", order.toString()); - } + conditionalAdd(params, "cursor", cursor); + conditionalAdd(params, "page", page); + conditionalAdd(params, "page_size", pageSize); + conditionalAdd(params, "order", order); return params; } + protected static void conditionalAdd(Map params, String name, Object value) { + if (value != null) { + String valueStr; + if (value instanceof Instant) { + valueStr = DateTimeFormatter.ISO_INSTANT.format((Instant) value); + } + else { + valueStr = value.toString(); + } + params.put(name, valueStr); + } + } + /** * Page number to navigate to in the response. * @@ -171,7 +177,7 @@ protected B page(int page) { /** * Number of results per page. * - * @param pageSize he page size as an int. + * @param pageSize The page size as an int. * * @return This builder. */ diff --git a/src/main/java/com/vonage/client/conversations/AbstractConversationsFilterRequest.java b/src/main/java/com/vonage/client/conversations/AbstractConversationsFilterRequest.java index aae498ea7..a813589a0 100644 --- a/src/main/java/com/vonage/client/conversations/AbstractConversationsFilterRequest.java +++ b/src/main/java/com/vonage/client/conversations/AbstractConversationsFilterRequest.java @@ -29,6 +29,10 @@ protected AbstractConversationsFilterRequest(Builder< super(builder); } + protected String formatTimestamp(Instant time) { + return time != null ? time.toString().replace('T', ' ').replace("Z", "") : null; + } + @Override protected Integer validatePageSize(Integer pageSize) { if (pageSize != null && (pageSize < 1 || pageSize > 100)) { @@ -37,12 +41,6 @@ protected Integer validatePageSize(Integer pageSize) { return pageSize; } - protected String formatTimestamp(Instant time) { - return time.toString() - .replace('T', ' ') - .replace("Z", ""); - } - @Override public String getCursor() { return super.getCursor(); @@ -51,12 +49,8 @@ public String getCursor() { @Override public Map makeParams() { Map params = super.makeParams(); - if (startDate != null) { - params.put("date_start", formatTimestamp(startDate)); - } - if (endDate != null) { - params.put("date_end", formatTimestamp(endDate)); - } + conditionalAdd(params, "date_start", formatTimestamp(startDate)); + conditionalAdd(params, "date_end", formatTimestamp(endDate)); return params; } diff --git a/src/main/java/com/vonage/client/conversations/ListEventsRequest.java b/src/main/java/com/vonage/client/conversations/ListEventsRequest.java index 8c9c9d343..a4e75d7e4 100644 --- a/src/main/java/com/vonage/client/conversations/ListEventsRequest.java +++ b/src/main/java/com/vonage/client/conversations/ListEventsRequest.java @@ -36,18 +36,10 @@ public class ListEventsRequest extends AbstractConversationsFilterRequest { @Override public Map makeParams() { Map params = super.makeParams(); - if (excludeDeletedEvents != null) { - params.put("exclude_deleted_events", excludeDeletedEvents.toString()); - } - if (startId != null) { - params.put("start_id", String.valueOf(startId)); - } - if (endId != null) { - params.put("end_id", String.valueOf(endId)); - } - if (eventType != null) { - params.put("event_type", eventType.toString()); - } + conditionalAdd(params, "exclude_deleted_events", excludeDeletedEvents); + conditionalAdd(params, "start_id", startId); + conditionalAdd(params, "end_id", endId); + conditionalAdd(params, "event_type", eventType); return params; } diff --git a/src/main/java/com/vonage/client/conversations/ListUserConversationsRequest.java b/src/main/java/com/vonage/client/conversations/ListUserConversationsRequest.java index c74e8fcc6..a9c9ff5aa 100644 --- a/src/main/java/com/vonage/client/conversations/ListUserConversationsRequest.java +++ b/src/main/java/com/vonage/client/conversations/ListUserConversationsRequest.java @@ -36,15 +36,9 @@ public final class ListUserConversationsRequest extends AbstractListUserRequest @Override public Map makeParams() { Map params = super.makeParams(); - if (state != null) { - params.put("state", state.toString()); - } - if (orderBy != null) { - params.put("order_by", orderBy.toString()); - } - if (includeCustomData != null) { - params.put("include_custom_data", includeCustomData.toString()); - } + conditionalAdd(params, "state", state); + conditionalAdd(params, "order_by", orderBy); + conditionalAdd(params, "include_custom_data", includeCustomData); return params; } diff --git a/src/main/java/com/vonage/client/meetings/ListRoomsRequest.java b/src/main/java/com/vonage/client/meetings/ListRoomsRequest.java index d6dbf72b7..5bf62bf7a 100644 --- a/src/main/java/com/vonage/client/meetings/ListRoomsRequest.java +++ b/src/main/java/com/vonage/client/meetings/ListRoomsRequest.java @@ -34,12 +34,8 @@ class ListRoomsRequest extends HalFilterRequest { @Override public Map makeParams() { Map params = super.makeParams(); - if (startId != null) { - params.put("start_id", String.valueOf(startId)); - } - if (endId != null) { - params.put("end_id", String.valueOf(endId)); - } + conditionalAdd(params, "start_id", startId); + conditionalAdd(params, "end_id", endId); return params; } } diff --git a/src/main/java/com/vonage/client/voice/AddDtmfListenerRequest.java b/src/main/java/com/vonage/client/voice/AddDtmfListenerRequest.java index c451643db..bc31e61d3 100644 --- a/src/main/java/com/vonage/client/voice/AddDtmfListenerRequest.java +++ b/src/main/java/com/vonage/client/voice/AddDtmfListenerRequest.java @@ -22,10 +22,21 @@ import java.util.Collection; import java.util.Collections; +/** + * Request wrapper for {@linkplain VoiceClient#addDtmfListener(String, String)}. + * + * @since 8.12.0 + */ class AddDtmfListenerRequest extends JsonableBaseObject { @JsonIgnore final String uuid; @JsonProperty("event_url") final Collection eventUrl; + /** + * Creates a new DTMF listener request. + * + * @param uuid ID of the call to add the DTMF listener to. + * @param eventUrl URL to send the DTMF events to. + */ public AddDtmfListenerRequest(String uuid, URI eventUrl) { this.uuid = uuid; this.eventUrl = Collections.singletonList(eventUrl); diff --git a/src/main/java/com/vonage/client/voice/AdvancedMachineDetection.java b/src/main/java/com/vonage/client/voice/AdvancedMachineDetection.java index fad85b8ec..73daf506c 100644 --- a/src/main/java/com/vonage/client/voice/AdvancedMachineDetection.java +++ b/src/main/java/com/vonage/client/voice/AdvancedMachineDetection.java @@ -70,6 +70,9 @@ public String toString() { private Mode mode; private Integer beepTimeout; + /** + * Constructor used reflectively by Jackson for instantiation. + */ AdvancedMachineDetection() {} AdvancedMachineDetection(Builder builder) { diff --git a/src/main/java/com/vonage/client/voice/AppEndpoint.java b/src/main/java/com/vonage/client/voice/AppEndpoint.java index b480c79f4..9ff6c33b2 100644 --- a/src/main/java/com/vonage/client/voice/AppEndpoint.java +++ b/src/main/java/com/vonage/client/voice/AppEndpoint.java @@ -26,9 +26,16 @@ public class AppEndpoint extends JsonableBaseObject implements Endpoint { private String user; - protected AppEndpoint() { - } + /** + * Constructor used reflectively by Jackson for instantiation. + */ + protected AppEndpoint() {} + /** + * Create an AppEndpoint with the given user. + * + * @param user The username. + */ public AppEndpoint(String user) { this.user = user; } diff --git a/src/main/java/com/vonage/client/voice/Call.java b/src/main/java/com/vonage/client/voice/Call.java index 24a6af6c4..2843e1b29 100644 --- a/src/main/java/com/vonage/client/voice/Call.java +++ b/src/main/java/com/vonage/client/voice/Call.java @@ -79,26 +79,74 @@ else if ((fromRandomNumber = builder.fromRandomNumber) != null && fromRandomNumb Call() {} + /** + * Create a new Call with {@linkplain PhoneEndpoint} as the recipient and caller. + * + * @param to The recipient phone number. + * @param from The caller phone number. + * @param answerUrl The URL to fetch the NCCO from. + */ public Call(String to, String from, String answerUrl) { this(new PhoneEndpoint(to), new PhoneEndpoint(from), answerUrl); } + /** + * Create a new Call with the specified recipient and caller endpoints. + * + * @param to The recipient endpoint. + * @param from The caller endpoint. + * @param answerUrl The URL to fetch the NCCO from. + */ public Call(Endpoint to, Endpoint from, String answerUrl) { this(new Endpoint[]{to}, from, answerUrl); } + /** + * Create a new Call with {@linkplain PhoneEndpoint} as the recipient and caller. + * + * @param to The recipient phone number. + * @param from The caller phone number. + * @param ncco The NCCO actions to take. + */ public Call(String to, String from, Collection ncco) { this(new PhoneEndpoint(to), new PhoneEndpoint(from), ncco); } + /** + * Create a new Call with the specified recipient and caller endpoints. + * + * @param to The recipient endpoint. + * @param from The caller endpoint. + * @param ncco The NCCO actions to take. + */ public Call(Endpoint to, Endpoint from, Collection ncco) { this(new Endpoint[]{to}, from, ncco); } + /** + * Create a new Call. + * + * @param to The recipient endpoint in an array. + * @param from The caller endpoint. + * @param answerUrl The URL to fetch the NCCO from. + * + * @deprecated This will be removed in the next major release. + */ + @Deprecated public Call(Endpoint[] to, Endpoint from, String answerUrl) { this(builder().to(to).from(from).answerUrl(answerUrl)); } + /** + * Create a new Call. + * + * @param to The recipient endpoint in an array. + * @param from The caller endpoint. + * @param ncco The NCCO actions to take. + * + * @deprecated This will be removed in the next major release. + */ + @Deprecated public Call(Endpoint[] to, Endpoint from, Collection ncco) { this(builder().to(to).from(from).ncco(ncco)); } diff --git a/src/main/java/com/vonage/client/voice/CallDirection.java b/src/main/java/com/vonage/client/voice/CallDirection.java index 0679616d7..bff18443f 100644 --- a/src/main/java/com/vonage/client/voice/CallDirection.java +++ b/src/main/java/com/vonage/client/voice/CallDirection.java @@ -18,9 +18,23 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +/** + * Represents the direction of a call. + */ public enum CallDirection { + /** + * Outgoing call. + */ OUTBOUND, + + /** + * Incoming call. + */ INBOUND, + + /** + * Unknown call direction. + */ UNKNOWN; @JsonValue @@ -29,6 +43,13 @@ public String toString() { return name().toLowerCase(); } + /** + * Convert a string to a CallDirection enum. + * + * @param name The call direction as a string. + * + * @return The call direction as an enum, or {@link #UNKNOWN} if an invalid value was provided. + */ @JsonCreator public static CallDirection fromString(String name) { try { diff --git a/src/main/java/com/vonage/client/voice/CallEvent.java b/src/main/java/com/vonage/client/voice/CallEvent.java index 0e4f4e9a4..8d405e9ac 100644 --- a/src/main/java/com/vonage/client/voice/CallEvent.java +++ b/src/main/java/com/vonage/client/voice/CallEvent.java @@ -27,6 +27,11 @@ public class CallEvent extends JsonableBaseObject { private CallStatus status; private CallDirection direction; + /** + * Constructor used reflectively by Jackson for instantiation. + */ + CallEvent() {} + /** * The unique identifier for this call leg. The UUID is created when your call request is accepted by Vonage. * You use the UUID in all requests for individual live calls. @@ -74,6 +79,7 @@ public CallDirection getDirection() { * @param json The JSON string to parse. * * @return An instance of this class with the fields populated, if present. + * * @deprecated Use {@link Jsonable#fromJson(String, Class)}. */ @Deprecated diff --git a/src/main/java/com/vonage/client/voice/CallInfo.java b/src/main/java/com/vonage/client/voice/CallInfo.java index 7baba1f8f..4dcec16fa 100644 --- a/src/main/java/com/vonage/client/voice/CallInfo.java +++ b/src/main/java/com/vonage/client/voice/CallInfo.java @@ -21,82 +21,142 @@ import java.util.Date; /** - * CallInfo holds the information related to a call. It is obtained using {@link VoiceClient#listCalls()}. + * Holds the information related to a call. It is obtained using {@link VoiceClient#listCalls()}. */ public class CallInfo extends JsonableBaseObject { - Endpoint from, to; - String conversationUuid, uuid, network, price, rate; - CallDirection direction; - Integer duration; - Date startTime, endTime; - CallStatus status; + private Endpoint from, to; + private String conversationUuid, uuid, network, price, rate; + private CallDirection direction; + private Integer duration; + private Date startTime, endTime; + private CallStatus status; + /** + * Constructor used reflectively by Jackson for instantiation. + */ CallInfo() {} - CallInfo(String to, String from) { - this(new PhoneEndpoint(to), new PhoneEndpoint(from)); - } - - CallInfo(Endpoint to, Endpoint from) { - this.to = to; - this.from = from; - } - + /** + * Call destination. + * + * @return The call recipient endpoint. + */ @JsonProperty("to") public Endpoint getTo() { return to; } + /** + * Call source. + * + * @return The caller endpoint. + */ @JsonProperty("from") public Endpoint getFrom() { return from; } + /** + * ID of the call. + * + * @return The call ID as a string. + */ @JsonProperty("uuid") public String getUuid() { return uuid; } + /** + * ID of the conversation. + * + * @return The conversation ID as a string. + */ @JsonProperty("conversation_uuid") public String getConversationUuid() { return conversationUuid; } + /** + * Time elapsed for the call to take place in seconds. + * This is only present if {@linkplain #getStatus()} is {@linkplain CallStatus#COMPLETED}. + * + * @return The call duration in seconds as an integer, or {@code null} if unknown. + */ @JsonProperty("duration") public Integer getDuration() { return duration; } + /** + * Start time of the call. + * This is only present if {@linkplain #getStatus()} is {@linkplain CallStatus#COMPLETED}. + * + * @return The start time of the call as a {@link Date} object, or {@code null} if unknown. + */ + @JsonProperty("start_time") + public Date getStartTime() { + return this.startTime; + } + + /** + * End time of the call. + * This is only present if {@linkplain #getStatus()} is {@linkplain CallStatus#COMPLETED}. + * + * @return The end time of the call as a {@link Date} object, or {@code null} if unknown. + */ @JsonProperty("end_time") public Date getEndTime() { return endTime; } + /** + * Total price charged for this call. + * This is only present if {@linkplain #getStatus()} is {@linkplain CallStatus#COMPLETED}. + * + * @return The call total cost as a string, or {@code null} if unknown. + */ @JsonProperty("price") public String getPrice() { return price; } + /** + * Price per minute for this call. + * This is only present if {@linkplain #getStatus()} is {@linkplain CallStatus#COMPLETED}. + * + * @return The per-minute call rate as a string, or {@code null} if unknown. + */ @JsonProperty("rate") public String getRate() { return rate; } - @JsonProperty("start_time") - public Date getStartTime() { - return this.startTime; - } - + /** + * Status of the call. + * + * @return The call status as an enum. + */ @JsonProperty("status") public CallStatus getStatus() { return status; } + /** + * Direction of the call: either inbound or outbound. + * + * @return The call direction as an enum. + */ @JsonProperty("direction") public CallDirection getDirection() { return direction; } + /** + * The Mobile Country Code Mobile Network Code (MCCMNC) for the carrier network used to make this call. + * This is only present if {@linkplain #getStatus()} is {@linkplain CallStatus#COMPLETED}. + * + * @return The MCCMNC as a string, or {@code null} if unknown. + */ @JsonProperty("network") public String getNetwork() { return network; @@ -118,7 +178,10 @@ public String toString() { * @param json The JSON string to parse. * * @return An instance of this class with the fields populated, if present. + * + * @deprecated Use {@link Jsonable#fromJson(String, Class)}. This will be removed in a future release. */ + @Deprecated public static CallInfo fromJson(String json) { return Jsonable.fromJson(json); } diff --git a/src/main/java/com/vonage/client/voice/CallInfoPage.java b/src/main/java/com/vonage/client/voice/CallInfoPage.java index ef537a1b1..906871e93 100644 --- a/src/main/java/com/vonage/client/voice/CallInfoPage.java +++ b/src/main/java/com/vonage/client/voice/CallInfoPage.java @@ -21,31 +21,65 @@ import com.vonage.client.JsonableBaseObject; import java.util.Iterator; +/** + * Response from {@link VoiceClient#listCalls(CallsFilter)}. + * This will be refactored to be based on {@link com.vonage.client.common.HalPageResponse} in the next major release. + */ public class CallInfoPage extends JsonableBaseObject implements Iterable { private int count, pageSize, recordIndex; private PageLinks links; private EmbeddedCalls embedded; + /** + * Constructor used reflectively by Jackson for instantiation. + */ + CallInfoPage() {} + + /** + * Total number of results. + * + * @return The total count as an integer. + */ @JsonProperty("count") public int getCount() { return count; } + /** + * Number of results per page. + * + * @return The page size as an integer. + */ @JsonProperty("page_size") public int getPageSize() { return pageSize; } + /** + * Index of the first record in the result set. + * + * @return The record index as an integer. + */ @JsonProperty("record_index") public int getRecordIndex() { return recordIndex; } + /** + * Links to the first, last, next, and previous pages. + * + * @return The {@code _links} section of the response. + */ @JsonProperty("_links") public PageLinks getLinks() { return links; } + /** + * Main response body containing call information objects. + * + * @return The {@code _embedded} section of the response. + */ @JsonProperty("_embedded") public EmbeddedCalls getEmbedded() { return embedded; @@ -62,7 +96,10 @@ public Iterator iterator() { * @param json The JSON string to parse. * * @return An instance of this class with the fields populated, if present. + * + * @deprecated This will be removed in a future release. */ + @Deprecated public static CallInfoPage fromJson(String json) { return Jsonable.fromJson(json); } diff --git a/src/main/java/com/vonage/client/voice/CallOrder.java b/src/main/java/com/vonage/client/voice/CallOrder.java index 31c7e34ad..32e0f131a 100644 --- a/src/main/java/com/vonage/client/voice/CallOrder.java +++ b/src/main/java/com/vonage/client/voice/CallOrder.java @@ -16,6 +16,8 @@ package com.vonage.client.voice; /** + * Represents the order in which calls are returned in {@link VoiceClient#listCalls(CallsFilter)}. + * * @deprecated Replaced by {@link com.vonage.client.common.SortOrder}. */ @Deprecated @@ -28,6 +30,11 @@ public enum CallOrder { this.callOrder = callOrder; } + /** + * Converts this enum into its string value. + * + * @return The call order as a string. + */ public String getCallOrder() { return callOrder; } diff --git a/src/main/java/com/vonage/client/voice/CallStatus.java b/src/main/java/com/vonage/client/voice/CallStatus.java index e60db0900..bb23fcc5a 100644 --- a/src/main/java/com/vonage/client/voice/CallStatus.java +++ b/src/main/java/com/vonage/client/voice/CallStatus.java @@ -22,7 +22,6 @@ * Describes the status of the call, and also the event in {@link EventWebhook#getStatus()}. */ public enum CallStatus { - /** * Indicates that the call has been created. */ @@ -113,6 +112,13 @@ public String toString() { return name().toLowerCase(); } + /** + * Convert a string into a {@link CallStatus} enum. + * + * @param name The call status name as a string. + * + * @return The call status as an enum, or {@code UNKNOWN} if an invalid value is provided. + */ @JsonCreator public static CallStatus fromString(String name) { try { diff --git a/src/main/java/com/vonage/client/voice/CallsFilter.java b/src/main/java/com/vonage/client/voice/CallsFilter.java index 20a385189..57a0e5574 100644 --- a/src/main/java/com/vonage/client/voice/CallsFilter.java +++ b/src/main/java/com/vonage/client/voice/CallsFilter.java @@ -15,108 +15,135 @@ */ package com.vonage.client.voice; -import com.vonage.client.QueryParamsRequest; -import java.time.format.DateTimeFormatter; +import com.vonage.client.common.HalFilterRequest; +import com.vonage.client.common.SortOrder; +import java.time.Instant; import java.util.Date; -import java.util.LinkedHashMap; import java.util.Map; /** * Filter options for {@link VoiceClient#listCalls(CallsFilter)}. */ -public class CallsFilter implements QueryParamsRequest { +public class CallsFilter extends HalFilterRequest { private final CallStatus status; - private final Date dateStart, dateEnd; - private final Integer pageSize, recordIndex; - private final CallOrder order; + private final Integer recordIndex; private final String conversationUuid; private CallsFilter(Builder builder) { + super(builder); this.status = builder.status; - this.dateStart = builder.dateStart; - this.dateEnd = builder.dateEnd; - this.pageSize = builder.pageSize; this.recordIndex = builder.recordIndex; - this.order = builder.order; this.conversationUuid = builder.conversationUuid; } - public CallStatus getStatus() { - return status; + @Override + public Integer getPageSize() { + return super.getPageSize(); + } + + @Override + public Instant getStartDate() { + return super.getStartDate(); + } + + @Override + public Instant getEndDate() { + return super.getEndDate(); } + @Override + public SortOrder getOrder() { + return super.getOrder(); + } + + /** + * Minimum in the date range of the calls to lookup. + * + * @return The start date, or {@code null} if unspecified. + * + * @deprecated Use {@link #getStartDate()} instead. This will be removed in a future release. + */ + @Deprecated public Date getDateStart() { - return dateStart; + return Date.from(getStartDate()); } + /** + * Maximum in the date range of calls to lookup. + * + * @return The end date, or {@code null} if unspecified. + * + * @deprecated Use {@link #getEndDate()} instead. This will be removed in a future release. + */ + @Deprecated public Date getDateEnd() { - return dateEnd; + return Date.from(getEndDate()); } - public Integer getPageSize() { - return pageSize; + /** + * Status of the calls to lookup. + * + * @return The call status as an enum, or {@code null} if unspecified. + */ + public CallStatus getStatus() { + return status; } + /** + * Start index for the results. + * + * @return The starting index as an integer, or {@code null} if unspecified. + */ public Integer getRecordIndex() { return recordIndex; } - public CallOrder getOrder() { - return order; - } - + /** + * ID of the conversation to filter by. + * + * @return The conversation ID, or {@code null} if unspecified. + */ public String getConversationUuid() { return conversationUuid; } @Override public Map makeParams() { - Map params = new LinkedHashMap<>(); - conditionalAdd(params, "status", this.status); - conditionalAdd(params, "date_start", this.dateStart); - conditionalAdd(params, "date_end", this.dateEnd); - conditionalAdd(params, "page_size", this.pageSize); - conditionalAdd(params, "record_index", this.recordIndex); - conditionalAdd(params, "order", (this.order != null) ? this.order.getCallOrder() : null); - conditionalAdd(params, "conversation_uuid", this.conversationUuid); + Map params = super.makeParams(); + conditionalAdd(params, "status", status); + conditionalAdd(params, "date_start", startDate); + conditionalAdd(params, "date_end", endDate); + conditionalAdd(params, "record_index", recordIndex); + conditionalAdd(params, "conversation_uuid", conversationUuid); return params; } - private void conditionalAdd(Map params, String name, String value) { - if (value != null) { - params.put(name, value); - } - } - - private void conditionalAdd(Map params, String name, Date value) { - if (value != null) { - params.put(name, DateTimeFormatter.ISO_INSTANT.format(value.toInstant())); - } - } - - private void conditionalAdd(Map params, String name, Object value) { - if (value != null) { - params.put(name, value.toString()); - } - } - + /** + * Entrypoint for constructing an instance of this class. All fields are optional. + * + * @return A new Builder instance. + */ public static Builder builder() { return new Builder(); } - public static class Builder { + /** + * Builder for specifying the call filter query parameters. + */ + public static final class Builder extends HalFilterRequest.Builder { private CallStatus status; - private Date dateStart, dateEnd; - private Integer pageSize, recordIndex; - private CallOrder order; + private Integer recordIndex; private String conversationUuid; - Builder() {} + Builder() { + } /** - * @param status The status of the calls to lookup. + * Status of the calls to lookup. + * + * @param status The call status as an enum. * - * @return This Builder to keep building. + * @return This builder. */ public Builder status(CallStatus status) { this.status = status; @@ -124,63 +151,118 @@ public Builder status(CallStatus status) { } /** - * @param dateStart The minimum in the date range of the calls to lookup. + * Start index for the results. * - * @return This Builder to keep building. + * @param recordIndex The starting index as an integer. + * + * @return This builder. */ - public Builder dateStart(Date dateStart) { - this.dateStart = dateStart; + public Builder recordIndex(int recordIndex) { + this.recordIndex = recordIndex; return this; } /** - * @param dateEnd The maximum in the date range of calls to lookup. + * Specific conversation to return calls for. * - * @return This Builder to keep building. + * @param conversationUuid The conversation ID to filter by. + * + * @return This builder. */ - public Builder dateEnd(Date dateEnd) { - this.dateEnd = dateEnd; + public Builder conversationUuid(String conversationUuid) { + this.conversationUuid = conversationUuid; return this; } + @Override + public Builder pageSize(int pageSize) { + return super.pageSize(pageSize); + } + + @Override + public Builder order(SortOrder order) { + return super.order(order); + } + + @Override + public Builder startDate(Instant startDate) { + return super.startDate(startDate); + } + + @Override + public Builder endDate(Instant endDate) { + return super.endDate(endDate); + } + /** - * @param pageSize The number of calls in the response. + * Minimum in the date range of the calls to lookup. + * + * @param dateStart The start date. * - * @return This Builder to keep building. + * @return This builder. + * + * @deprecated Use {@link #startDate(Instant)} instead. This will be removed in a future release. */ - public Builder pageSize(Integer pageSize) { - this.pageSize = pageSize; - return this; + @Deprecated + public Builder dateStart(Date dateStart) { + return dateStart != null ? super.startDate(dateStart.toInstant()) : this; } /** - * @param recordIndex The starting index. + * Maximum in the date range of calls to lookup. + * + * @param dateEnd The end date. * - * @return This Builder to keep building. + * @return This builder. + * + * @deprecated Use {@link #endDate(Instant)} instead. This will be removed in a future release. */ - public Builder recordIndex(Integer recordIndex) { - this.recordIndex = recordIndex; - return this; + @Deprecated + public Builder dateEnd(Date dateEnd) { + return dateEnd != null ? super.endDate(dateEnd.toInstant()) : this; + } + + /** + * Number of results to include in the response. + * + * @param pageSize The number of calls in the response. + * + * @return This builder. + * + * @deprecated Use {@link #pageSize(int)} instead. This will be removed in a future release. + */ + @Deprecated + public Builder pageSize(Integer pageSize) { + return pageSize != null ? super.pageSize(pageSize) : this; } /** - * @param order The order of the calls. + * Start index for the results. + * + * @param recordIndex The starting index as an integer. + * + * @return This builder. * - * @return This Builder to keep building. + * @deprecated Use {@link #recordIndex(int)} instead. This will be removed in a future release. */ - public Builder order(CallOrder order) { - this.order = order; + @Deprecated + public Builder recordIndex(Integer recordIndex) { + this.recordIndex = recordIndex; return this; } /** - * @param conversationUuid The specific conversation to return calls for. + * Order of the returned calls. + * + * @param order The sort order as an enum. + * + * @return This builder. * - * @return This Builder to keep building. + * @deprecated Use {@link #order(SortOrder)} instead. This will be removed in a future release. */ - public Builder conversationUuid(String conversationUuid) { - this.conversationUuid = conversationUuid; - return this; + @Deprecated + public Builder order(CallOrder order) { + return order != null ? order(SortOrder.fromString(order.getCallOrder())) : this; } /** diff --git a/src/main/java/com/vonage/client/voice/DisconnectedBy.java b/src/main/java/com/vonage/client/voice/DisconnectedBy.java index 9283741fc..1878d9c65 100644 --- a/src/main/java/com/vonage/client/voice/DisconnectedBy.java +++ b/src/main/java/com/vonage/client/voice/DisconnectedBy.java @@ -24,7 +24,6 @@ * @since 8.16.2 */ public enum DisconnectedBy { - /** * The call was terminated by the Voice API platform, * for example the NCCO finished its last action and call was disconnected. diff --git a/src/main/java/com/vonage/client/voice/DtmfPayload.java b/src/main/java/com/vonage/client/voice/DtmfPayload.java index d28b650d5..337715a3c 100644 --- a/src/main/java/com/vonage/client/voice/DtmfPayload.java +++ b/src/main/java/com/vonage/client/voice/DtmfPayload.java @@ -19,10 +19,19 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.vonage.client.JsonableBaseObject; +/** + * Request wrapper used in {@linkplain VoiceClient#sendDtmf(String, String)}. + */ class DtmfPayload extends JsonableBaseObject { @JsonIgnore final String uuid; private final String digits; + /** + * Create a new DtmfPayload object. + * + * @param digits DTMF digits to send to the call as a string. + * @param uuid TUUID of the call to play DTMF into. + */ public DtmfPayload(String digits, String uuid) { if ((this.digits = digits) == null || digits.trim().isEmpty()) { throw new IllegalArgumentException("Must include at least one digit to send."); @@ -30,6 +39,11 @@ public DtmfPayload(String digits, String uuid) { this.uuid = uuid; } + /** + * DTMF digits to send to the call. + * + * @return The DTMF digits as a string. + */ @JsonProperty("digits") public String getDigits() { return digits; diff --git a/src/main/java/com/vonage/client/voice/DtmfResponse.java b/src/main/java/com/vonage/client/voice/DtmfResponse.java index 30cb98fe7..4a9a0393d 100644 --- a/src/main/java/com/vonage/client/voice/DtmfResponse.java +++ b/src/main/java/com/vonage/client/voice/DtmfResponse.java @@ -20,18 +20,32 @@ import com.vonage.client.JsonableBaseObject; /** - * Response if DTMF tones were successfully sent to an active {@link Call}. - *

- * Returned by {@link VoiceClient#sendDtmf(String, String)} + * Response if DTMF tones were successfully sent to an active {@link Call}, as + * returned by {@link VoiceClient#sendDtmf(String, String)}. */ public class DtmfResponse extends JsonableBaseObject { private String uuid, message; + /** + * Constructor used reflectively by Jackson for instantiation. + */ + DtmfResponse() {} + + /** + * Unique identifier for the call leg DTMF was sent to. + * + * @return The call ID as a string. + */ @JsonProperty("uuid") public String getUuid() { return uuid; } + /** + * Description of the action taken. + * + * @return The action description. + */ @JsonProperty("message") public String getMessage() { return message; diff --git a/src/main/java/com/vonage/client/voice/DtmfResult.java b/src/main/java/com/vonage/client/voice/DtmfResult.java index 313860c7b..d6efe4a19 100644 --- a/src/main/java/com/vonage/client/voice/DtmfResult.java +++ b/src/main/java/com/vonage/client/voice/DtmfResult.java @@ -25,6 +25,11 @@ public class DtmfResult extends JsonableBaseObject { private String digits; private boolean timedOut; + /** + * Constructor used reflectively by Jackson for instantiation. + */ + DtmfResult() {} + /** * The button sequence pressed by the user. * diff --git a/src/main/java/com/vonage/client/voice/EmbeddedCalls.java b/src/main/java/com/vonage/client/voice/EmbeddedCalls.java index bcf48b8f7..76631f63f 100644 --- a/src/main/java/com/vonage/client/voice/EmbeddedCalls.java +++ b/src/main/java/com/vonage/client/voice/EmbeddedCalls.java @@ -18,9 +18,22 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.vonage.client.JsonableBaseObject; +/** + * Results wrapper for the {@linkplain VoiceClient#listCalls(CallsFilter)} method. + */ public class EmbeddedCalls extends JsonableBaseObject { @JsonProperty("calls") private CallInfo[] callInfos; + /** + * Constructor used reflectively by Jackson for instantiation. + */ + EmbeddedCalls() {} + + /** + * Gets the call details. + * + * @return The CallInfos as an array. + */ public CallInfo[] getCallInfos() { return callInfos; } diff --git a/src/main/java/com/vonage/client/voice/Endpoint.java b/src/main/java/com/vonage/client/voice/Endpoint.java index a74ab0984..4c3e2e1ec 100644 --- a/src/main/java/com/vonage/client/voice/Endpoint.java +++ b/src/main/java/com/vonage/client/voice/Endpoint.java @@ -20,6 +20,10 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +/** + * Represents a receiver endpoint in a {@link Call}. + * For NCCO endpoints, see {@link com.vonage.client.voice.ncco.Endpoint}. + */ @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, diff --git a/src/main/java/com/vonage/client/voice/EndpointType.java b/src/main/java/com/vonage/client/voice/EndpointType.java index 62a4de94c..8d54eb3ff 100644 --- a/src/main/java/com/vonage/client/voice/EndpointType.java +++ b/src/main/java/com/vonage/client/voice/EndpointType.java @@ -36,6 +36,13 @@ public String toString() { return name().toLowerCase(); } + /** + * Convert a string to an EndpointType enum. + * + * @param name The endpoint type as a string. + * + * @return The endpoint type as an enum, or {@code null} if the string is null. + */ @JsonCreator public static EndpointType fromString(String name) { if (name == null) return null; diff --git a/src/main/java/com/vonage/client/voice/MachineDetection.java b/src/main/java/com/vonage/client/voice/MachineDetection.java index fdc9ffd78..a6c05cf04 100644 --- a/src/main/java/com/vonage/client/voice/MachineDetection.java +++ b/src/main/java/com/vonage/client/voice/MachineDetection.java @@ -22,7 +22,20 @@ * Represents machine detection behaviour. */ public enum MachineDetection { - CONTINUE, HANGUP, UNKNOWN; + /** + * Vonage sends an HTTP request to the event URL with the Call event machine. + */ + CONTINUE, + + /** + * End the call on encounter. + */ + HANGUP, + + /** + * Unmapped / invalid value. + */ + UNKNOWN; @JsonValue @Override @@ -30,6 +43,13 @@ public String toString() { return name().toLowerCase(); } + /** + * Convert a string to a MachineDetection enum. + * + * @param name The string to convert to a MachineDetection enum. + * + * @return The machine detection mode as an enum, or {@linkplain #UNKNOWN} if an invalid value is provided. + */ @JsonCreator public static MachineDetection fromString(String name) { try { diff --git a/src/main/java/com/vonage/client/voice/MachineDetectionStatus.java b/src/main/java/com/vonage/client/voice/MachineDetectionStatus.java index b8a592942..1af444cdf 100644 --- a/src/main/java/com/vonage/client/voice/MachineDetectionStatus.java +++ b/src/main/java/com/vonage/client/voice/MachineDetectionStatus.java @@ -46,6 +46,13 @@ public String toString() { return name().toLowerCase(); } + /** + * Convert a string to a MachineDetectionStatus enum. + * + * @param name The machine detection status as a string. + * + * @return The machine detection status as an enum, or {@link #UNKNOWN} if an invalid value was provided. + */ @JsonCreator public static MachineDetectionStatus fromString(String name) { try { diff --git a/src/main/java/com/vonage/client/voice/ModifyCallAction.java b/src/main/java/com/vonage/client/voice/ModifyCallAction.java index e85477b53..542e42d05 100644 --- a/src/main/java/com/vonage/client/voice/ModifyCallAction.java +++ b/src/main/java/com/vonage/client/voice/ModifyCallAction.java @@ -21,7 +21,7 @@ /** * Enum representing call modification actions. */ -public enum ModifyCallAction { +enum ModifyCallAction { HANGUP, MUTE, UNMUTE, EARMUFF, UNEARMUFF, TRANSFER, UNKNOWN; @JsonValue @@ -30,6 +30,13 @@ public String toString() { return name().toLowerCase(); } + /** + * Convert a string to a ModifyCallAction enum. + * + * @param name The call modification action as a string. + * + * @return The call modification action as an enum, or {@link #UNKNOWN} if an invalid value was passed in. + */ @JsonCreator public static ModifyCallAction fromString(String name) { try { diff --git a/src/main/java/com/vonage/client/voice/ModifyCallPayload.java b/src/main/java/com/vonage/client/voice/ModifyCallPayload.java index 8eb93c05d..bc364c45a 100644 --- a/src/main/java/com/vonage/client/voice/ModifyCallPayload.java +++ b/src/main/java/com/vonage/client/voice/ModifyCallPayload.java @@ -20,15 +20,29 @@ import com.vonage.client.JsonableBaseObject; import java.util.Objects; +/** + * Wrapper for call modification requests. + */ class ModifyCallPayload extends JsonableBaseObject { @JsonIgnore final String uuid; private final ModifyCallAction action; + /** + * Create a new ModifyCallPayload. + * + * @param action The action to perform as an enum. + * @param uuid The call ID to modify. + */ ModifyCallPayload(ModifyCallAction action, String uuid) { this.action = Objects.requireNonNull(action, "Action is required."); this.uuid = Objects.requireNonNull(uuid, "callId is required."); } + /** + * Call modification action. + * + * @return The action as an enum. + */ @JsonProperty("action") public ModifyCallAction getAction() { return action; diff --git a/src/main/java/com/vonage/client/voice/PageLink.java b/src/main/java/com/vonage/client/voice/PageLink.java index 813238743..184c30663 100644 --- a/src/main/java/com/vonage/client/voice/PageLink.java +++ b/src/main/java/com/vonage/client/voice/PageLink.java @@ -18,6 +18,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.vonage.client.JsonableBaseObject; +/** + * Represents the link to a page in the response from the API. + * + * @deprecated {@link PageLinks} will be replaced with {@link com.vonage.client.common.HalLinks} in the future. + */ +@Deprecated public class PageLink extends JsonableBaseObject { private String href; diff --git a/src/main/java/com/vonage/client/voice/PageLinks.java b/src/main/java/com/vonage/client/voice/PageLinks.java index 457a40a13..07a07cb08 100644 --- a/src/main/java/com/vonage/client/voice/PageLinks.java +++ b/src/main/java/com/vonage/client/voice/PageLinks.java @@ -19,6 +19,8 @@ import com.vonage.client.JsonableBaseObject; /** + * Represents the {@code _links} section in a paginated response. + * * @deprecated Will be replaced by {@link com.vonage.client.common.HalLinks} in a future release. */ @Deprecated diff --git a/src/main/java/com/vonage/client/voice/PhoneEndpoint.java b/src/main/java/com/vonage/client/voice/PhoneEndpoint.java index 21988c881..be35bc9b4 100644 --- a/src/main/java/com/vonage/client/voice/PhoneEndpoint.java +++ b/src/main/java/com/vonage/client/voice/PhoneEndpoint.java @@ -21,6 +21,9 @@ public class PhoneEndpoint extends JsonableBaseObject implements Endpoint { private String number, dtmfAnswer; + /** + * Constructor used reflectively by Jackson for instantiation. + */ PhoneEndpoint() {} /** diff --git a/src/main/java/com/vonage/client/voice/SipEndpoint.java b/src/main/java/com/vonage/client/voice/SipEndpoint.java index 44b87e977..d6532edc6 100644 --- a/src/main/java/com/vonage/client/voice/SipEndpoint.java +++ b/src/main/java/com/vonage/client/voice/SipEndpoint.java @@ -17,10 +17,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.vonage.client.JsonableBaseObject; -import com.vonage.client.users.channels.Sip; import static com.vonage.client.voice.SipHeader.USER_TO_USER; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.Map; /** @@ -31,8 +29,10 @@ public class SipEndpoint extends JsonableBaseObject implements Endpoint { private Map headers; private Map standardHeaders; - protected SipEndpoint() { - } + /** + * Constructor used reflectively by Jackson for instantiation. + */ + protected SipEndpoint() {} /** * Creates a new SIP endpoint request. diff --git a/src/main/java/com/vonage/client/voice/SipHeader.java b/src/main/java/com/vonage/client/voice/SipHeader.java index af28def47..0ac5e2bfd 100644 --- a/src/main/java/com/vonage/client/voice/SipHeader.java +++ b/src/main/java/com/vonage/client/voice/SipHeader.java @@ -24,6 +24,10 @@ * @since 8.9.0 */ public enum SipHeader { + /** + * Used to submit user-to-user information if supported by the vendor, as per + * RFC 7433. + */ USER_TO_USER; @JsonValue diff --git a/src/main/java/com/vonage/client/voice/SpeechResults.java b/src/main/java/com/vonage/client/voice/SpeechResults.java index d743824f7..9590f39b1 100644 --- a/src/main/java/com/vonage/client/voice/SpeechResults.java +++ b/src/main/java/com/vonage/client/voice/SpeechResults.java @@ -31,6 +31,11 @@ public class SpeechResults extends JsonableBaseObject { private String error; private URI recordingUrl; + /** + * Constructor used reflectively by Jackson for instantiation. + */ + SpeechResults() {} + /** * Speech recording URL. Included if the {@code saveAudio} flag is set to {@code true} in * the input action. Requires JWT authorization for downloading see - * {@code streamUrl}: An array containing a single URL to an mp3 or wav (16-bit) audio file. - * {@code loop}: The number of times the audio file at {@code streamUrl} is repeated before the stream ends. Set to 0 to loop infinitely + * Represents the JSON payload that will be sent in {@link VoiceClient#startStream}. */ class StreamPayload extends JsonableBaseObject { @JsonIgnore final String uuid; @@ -31,23 +29,46 @@ class StreamPayload extends JsonableBaseObject { private final Integer loop; private final Double level; + /** + * Creates a new StreamPayload. + * + * @param streamUrl URL to an MP3 or wav (16-bit) audio file. + * @param loop Number of times the audio is repeated before the stream ends (0 means infinite). + * @param level The volume the audio is played at (-1.0 to 1.0). + * @param uuid UUID of the call to stream audio into. + */ public StreamPayload(String streamUrl, Integer loop, Double level, String uuid) { - this.streamUrl = new String[]{streamUrl}; + this.streamUrl = new String[]{Objects.requireNonNull(streamUrl, "Stream URL is required.")}; this.loop = loop; this.level = level; this.uuid = uuid; } + /** + * An array containing a single URL to an MP3 or wav (16-bit) audio file. + * + * @return The stream URL wrapped in an array. + */ @JsonProperty("stream_url") public String[] getStreamUrl() { return streamUrl; } + /** + * Number of times the audio file at {@code streamUrl} is repeated before the stream ends. + * + * @return The number of times the audio file is repeated, or {@code null} if unspecified. + */ @JsonProperty("loop") public Integer getLoop() { return loop; } + /** + * Volume which the audio is played at. + * + * @return The stream volume between -1.0 and 1.0, or {@code null} if unspecified. + */ @JsonProperty("level") public Double getLevel() { return level; diff --git a/src/main/java/com/vonage/client/voice/StreamResponse.java b/src/main/java/com/vonage/client/voice/StreamResponse.java index 9f614da7b..cddb3cc6f 100644 --- a/src/main/java/com/vonage/client/voice/StreamResponse.java +++ b/src/main/java/com/vonage/client/voice/StreamResponse.java @@ -21,17 +21,31 @@ /** * Response from successfully streaming an audio file or stopping a stream to an active {@link Call}. - *

- * This would be returned by {@link VoiceClient#startStream(String, String)} or {@link VoiceClient#stopStream(String)} + * This is returned by {@link VoiceClient#startStream(String, String)} or {@link VoiceClient#stopStream(String)} */ public class StreamResponse extends JsonableBaseObject { private String uuid, message; + /** + * Constructor used reflectively by Jackson for instantiation. + */ + StreamResponse() {} + + /** + * UUID of the call to which the message was sent. + * + * @return The call ID as a string. + */ @JsonProperty("uuid") public String getUuid() { return uuid; } + /** + * A message describing the result of the operation. + * + * @return The response message. + */ @JsonProperty("message") public String getMessage() { return message; @@ -43,7 +57,10 @@ public String getMessage() { * @param json The JSON string to parse. * * @return An instance of this class with the fields populated, if present. + * + * @deprecated This will be removed in a future release. */ + @Deprecated public static StreamResponse fromJson(String json) { return Jsonable.fromJson(json); } diff --git a/src/main/java/com/vonage/client/voice/TalkResponse.java b/src/main/java/com/vonage/client/voice/TalkResponse.java index adff25df2..d954f368c 100644 --- a/src/main/java/com/vonage/client/voice/TalkResponse.java +++ b/src/main/java/com/vonage/client/voice/TalkResponse.java @@ -21,17 +21,31 @@ /** * Response from successfully sending a synthesized speech message or stopping a message to an active {@link Call}. - *

- * This would be returned by {@link VoiceClient#startTalk(String, TalkPayload)} or {@link VoiceClient#stopTalk(String)} + * This is returned by {@link VoiceClient#startTalk(String, TalkPayload)} or {@link VoiceClient#stopTalk(String)}. */ public class TalkResponse extends JsonableBaseObject { private String uuid, message; + /** + * Constructor used reflectively by Jackson for instantiation. + */ + TalkResponse() {} + + /** + * UUID of the call to which the message was sent. + * + * @return The call ID as a string. + */ @JsonProperty("uuid") public String getUuid() { return uuid; } + /** + * A message describing the result of the operation. + * + * @return The response message. + */ @JsonProperty("message") public String getMessage() { return message; @@ -43,7 +57,10 @@ public String getMessage() { * @param json The JSON string to parse. * * @return An instance of this class with the fields populated, if present. + * + * @deprecated This will be removed in a future release. */ + @Deprecated public static TalkResponse fromJson(String json) { return Jsonable.fromJson(json); } diff --git a/src/main/java/com/vonage/client/voice/TextToSpeechLanguage.java b/src/main/java/com/vonage/client/voice/TextToSpeechLanguage.java index c429857ee..12f88be4f 100644 --- a/src/main/java/com/vonage/client/voice/TextToSpeechLanguage.java +++ b/src/main/java/com/vonage/client/voice/TextToSpeechLanguage.java @@ -95,10 +95,20 @@ public enum TextToSpeechLanguage { private final String language; + /** + * Constructor for the TextToSpeechLanguage enum. + * + * @param language The language code. + */ TextToSpeechLanguage(String language) { this.language = language; } + /** + * Gets the language code for this enum. + * + * @return The language code as a string. + */ @JsonValue public String getLanguage() { return this.language; diff --git a/src/main/java/com/vonage/client/voice/TransferCallPayload.java b/src/main/java/com/vonage/client/voice/TransferCallPayload.java index d654c80a7..f64cb59a7 100644 --- a/src/main/java/com/vonage/client/voice/TransferCallPayload.java +++ b/src/main/java/com/vonage/client/voice/TransferCallPayload.java @@ -21,21 +21,37 @@ /** * Extension of ModifyCallPayload which adds an NCCO destination to the serialized form. - * */ class TransferCallPayload extends ModifyCallPayload { private final TransferDestination destination; + /** + * Create a TransferCallPayload with an NCCO URL destination. + * + * @param nccoUrl URL of the NCCO to transfer the call to. + * @param uuid ID of the call to transfer. + */ public TransferCallPayload(String nccoUrl, String uuid) { super(ModifyCallAction.TRANSFER, uuid); destination = new TransferDestination(nccoUrl); } + /** + * Create a TransferCallPayload with an NCCO destination. + * + * @param ncco NCCO to transfer the call to. + * @param uuid ID of the call to transfer. + */ public TransferCallPayload(Ncco ncco, String uuid) { super(ModifyCallAction.TRANSFER, uuid); destination = new TransferDestination(Objects.requireNonNull(ncco, "NCCO is required.")); } + /** + * Call transfer destination. + * + * @return The destination of the transfer. + */ @JsonProperty("destination") public TransferDestination getDestination() { return destination; diff --git a/src/main/java/com/vonage/client/voice/TransferDestination.java b/src/main/java/com/vonage/client/voice/TransferDestination.java index 7f74f698e..9c320d104 100644 --- a/src/main/java/com/vonage/client/voice/TransferDestination.java +++ b/src/main/java/com/vonage/client/voice/TransferDestination.java @@ -20,40 +20,78 @@ import com.vonage.client.JsonableBaseObject; import com.vonage.client.voice.ncco.Ncco; +/** + * Represents the destination of a transfer action in {@link TransferCallPayload#getDestination()}. + */ class TransferDestination extends JsonableBaseObject { private final Type type; private final String[] urls; private final Ncco ncco; + /** + * Create a new TransferDestination. + * + * @param url URL to transfer the call to. + */ TransferDestination(String url) { this(Type.NCCO, url, null); } + /** + * Create a new TransferDestination. + * + * @param ncco NCCO to transfer the call to. + */ TransferDestination(Ncco ncco) { this(Type.NCCO, null, ncco); } + /** + * Create a new TransferDestination. + * + * @param type Transfer destination type. + * @param url URL to transfer the call to. + * @param ncco NCCO to transfer the call to. + */ public TransferDestination(Type type, String url, Ncco ncco) { this.type = type; this.urls = url != null ? new String[]{url} : null; this.ncco = ncco; } + /** + * Transfer destination type. + * + * @return The type as an enum. + */ @JsonProperty("type") public Type getType() { return type; } + /** + * URL to transfer the call to. + * + * @return The URL wrapped in a singleton string array, or {@code null} if using NCCO instead. + */ @JsonProperty("url") - public String[] getUrls() { + public String[] getUrl() { return urls; } + /** + * NCCO to transfer the call to. + * + * @return The NCCO, or {@code null} if using URL instead. + */ @JsonProperty("ncco") public Ncco getNcco() { return ncco; } + /** + * Represents the destination type. + */ public enum Type { NCCO; diff --git a/src/main/java/com/vonage/client/voice/VbcEndpoint.java b/src/main/java/com/vonage/client/voice/VbcEndpoint.java index ae13e6491..ab0de8acd 100644 --- a/src/main/java/com/vonage/client/voice/VbcEndpoint.java +++ b/src/main/java/com/vonage/client/voice/VbcEndpoint.java @@ -26,9 +26,17 @@ public class VbcEndpoint extends JsonableBaseObject implements Endpoint { private String extension; + /** + * Constructor used reflectively by Jackson for instantiation. + */ protected VbcEndpoint() { } + /** + * Creates a new VBC endpoint. + * + * @param extension The extension number as a string. + */ public VbcEndpoint(String extension) { this.extension = extension; } diff --git a/src/main/java/com/vonage/client/voice/VoiceClient.java b/src/main/java/com/vonage/client/voice/VoiceClient.java index 647fd1618..b16593ec4 100644 --- a/src/main/java/com/vonage/client/voice/VoiceClient.java +++ b/src/main/java/com/vonage/client/voice/VoiceClient.java @@ -430,8 +430,8 @@ public TalkResponse startTalk(String uuid, String text, int loop) throws VonageR * @param text The message to be spoken to the call participants. * @param language The language to use for the text-to-speech. * @param style The language style to use for the text-to-speech. - * @param loop The number of times to repeat the message. The default value is {@code 1}, or you can use {@code - * 0} to indicate that the message should be repeated indefinitely. + * @param loop The number of times to repeat the message. The default value is {@code 1}, or you can use + * {@code 0} to indicate that the message should be repeated indefinitely. * * @return The data returned from the Voice API. * diff --git a/src/main/java/com/vonage/client/voice/VoiceResponseException.java b/src/main/java/com/vonage/client/voice/VoiceResponseException.java index 5169b9fe1..66e59ea9e 100644 --- a/src/main/java/com/vonage/client/voice/VoiceResponseException.java +++ b/src/main/java/com/vonage/client/voice/VoiceResponseException.java @@ -25,6 +25,11 @@ */ public final class VoiceResponseException extends VonageApiResponseException { + /** + * Sets the HTTP status code of the response. Intended to be called reflectively. + * + * @param statusCode The status code as an integer (typically in the 4xx range). + */ void setStatusCode(int statusCode) { this.statusCode = statusCode; } diff --git a/src/main/java/com/vonage/client/voice/WebSocketEndpoint.java b/src/main/java/com/vonage/client/voice/WebSocketEndpoint.java index 6ad3fe287..1b782163f 100644 --- a/src/main/java/com/vonage/client/voice/WebSocketEndpoint.java +++ b/src/main/java/com/vonage/client/voice/WebSocketEndpoint.java @@ -17,18 +17,49 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.vonage.client.JsonableBaseObject; +import com.vonage.client.users.channels.Websocket; +import java.net.URI; import java.util.Map; +import java.util.Objects; public class WebSocketEndpoint extends JsonableBaseObject implements Endpoint { + // TODO: Use stronger typing private String uri, contentType; @JsonProperty("headers") private Map headers; + /** + * Constructor used reflectively by Jackson for instantiation. + */ protected WebSocketEndpoint() { } + /** + * Create a new WebSocket Endpoint + * + * @param uri URI to the websocket, starting with {@code ws://} or {@code wss://}. + * @param contentType The audio MIME type. + * @param headers Additional headers to be sent with the request. + */ public WebSocketEndpoint(String uri, String contentType, Map headers) { - this.uri = uri; - this.contentType = contentType; + this( + URI.create(uri), + contentType != null ? Websocket.ContentType.fromString(contentType) : null, + headers + ); + } + + /** + * Create a new WebSocket Endpoint + * + * @param uri URI to the websocket, starting with {@code ws://} or {@code wss://}. + * @param contentType The audio MIME type. + * @param headers Additional headers to be sent with the request. + * + * @since 8.17.0 + */ + public WebSocketEndpoint(URI uri, Websocket.ContentType contentType, Map headers) { + this.uri = Objects.requireNonNull(uri, "URI is required.").toString(); + this.contentType = contentType != null ? contentType.toString() : null; this.headers = headers; } @@ -53,6 +84,7 @@ public String getUri() { } /** + * Content type of the audio stream; either {@code audio/l16;rate=16000} or {@code audio/l16;rate=8000}. * * @return The content type. */ @@ -61,6 +93,11 @@ public String getContentType() { return contentType; } + /** + * Additional headers to be sent with the request. + * + * @return A map of headers to be sent in the payload. + */ @JsonProperty("headers") public Map getHeadersMap() { return headers; diff --git a/src/main/java/com/vonage/client/voice/ncco/AppEndpoint.java b/src/main/java/com/vonage/client/voice/ncco/AppEndpoint.java index 2d8379a43..985c156a9 100644 --- a/src/main/java/com/vonage/client/voice/ncco/AppEndpoint.java +++ b/src/main/java/com/vonage/client/voice/ncco/AppEndpoint.java @@ -59,6 +59,9 @@ public static Builder builder(String user) { return new Builder(user); } + /** + * Builder for constructing an instance of this class. + */ public static class Builder { private String user; diff --git a/src/main/java/com/vonage/client/voice/ncco/ConnectAction.java b/src/main/java/com/vonage/client/voice/ncco/ConnectAction.java index 62e6d1dc5..02256e2e7 100644 --- a/src/main/java/com/vonage/client/voice/ncco/ConnectAction.java +++ b/src/main/java/com/vonage/client/voice/ncco/ConnectAction.java @@ -27,8 +27,6 @@ * An NCCO connect action that allows for the establishment of a connection to various {@link Endpoint}. */ public class ConnectAction extends JsonableBaseObject implements Action { - private static final String ACTION = "connect"; - private Collection endpoint; private String from; private EventType eventType; @@ -40,6 +38,9 @@ public class ConnectAction extends JsonableBaseObject implements Action { private Boolean randomFromNumber; private URI ringbackTone; + /** + * Constructor used reflectively by Jackson for instantiation. + */ ConnectAction() {} private ConnectAction(Builder builder) { @@ -64,62 +65,116 @@ private ConnectAction(Builder builder) { ringbackTone = builder.ringbackTone; } - @JsonProperty("action") @Override public String getAction() { - return ACTION; + return "connect"; } + /** + * Endpoint to connect the call to. + * + * @return The endpoint wrapped in a collection. + */ @JsonProperty("endpoint") public Collection getEndpoint() { return endpoint; } + /** + * Caller ID number in E.164 format. + * + * @return The caller ID number as a string, or {@code null} if unspecified. + */ @JsonProperty("from") public String getFrom() { return from; } + /** + * Event type for the action. + * + * @return The event type as an enum, or {@code null} if unspecified. + */ @JsonProperty("eventType") public EventType getEventType() { return eventType; } + /** + * Number in seconds before Vonage stops ringing if the call is unanswered. + * + * @return The ringing timeout in seconds, or {@code null} if unspecified. + */ @JsonProperty("timeout") public Integer getTimeOut() { return timeOut; } + /** + * Maximum length of the call in seconds. + * + * @return The maximum call length in seconds as an integer, or {@code null} if unspecified. + */ @JsonProperty("limit") public Integer getLimit() { return limit; } + /** + * Behavior when Vonage detects an answerphone. + * + * @return The machine detection mode as an enum, or {@code null} if unspecified. + */ @JsonProperty("machineDetection") public MachineDetection getMachineDetection() { return machineDetection; } + /** + * Behavior of Vonage's advanced machine detection. + * + * @return The advanced machine detection settings, or {@code null} if unspecified. + */ @JsonProperty("advancedMachineDetection") public AdvancedMachineDetection getAdvancedMachineDetection() { return advancedMachineDetection; } + /** + * Webhook endpoint that Vonage calls asynchronously on each of the possible call states. + * + * @return The event URL wrapped in a collection, or {@code null} if unspecified. + */ @JsonProperty("eventUrl") public Collection getEventUrl() { return eventUrl; } + /** + * HTTP method Vonage uses to make the request to eventUrl. + * + * @return The HTTP method as an enum, or {@code null} if unspecified. + */ @JsonProperty("eventMethod") public EventMethod getEventMethod() { return eventMethod; } + /** + * Use a random phone number as {@code from}. + * + * @return Whether the caller ID number will be randomly selected, or {@code null} if unspecified. + */ @JsonProperty("randomFromNumber") public Boolean getRandomFromNumber() { return randomFromNumber; } + /** + * Ringback tone to be played back on repeat to the caller. + * + * @return The ringback tone URL, or {@code null} if unspecified. + */ @JsonProperty("ringbackTone") public URI getRingbackTone() { return ringbackTone; @@ -131,7 +186,9 @@ public URI getRingbackTone() { * @param endpoint Connect the call to a specific #{@link Endpoint}. * * @return A new Builder. + * @deprecated Use {@link #builder(Endpoint...)}. This will be removed in the next major release. */ + @Deprecated public static Builder builder(Collection endpoint) { return new Builder(endpoint); } @@ -147,6 +204,9 @@ public static Builder builder(Endpoint... endpoint) { return builder(Arrays.asList(endpoint)); } + /** + * Builder to create a ConnectAction. The endpoint to connect to is mandatory. + */ public static class Builder { private Collection endpoint; private String from; @@ -169,7 +229,7 @@ private Builder(Collection endpoint) { * @param endpoint The endpoints to connect to. * * @return This builder. - * @deprecated This will be removed in the next major release. + * @deprecated Use {@link #endpoint(Endpoint...)}. This will be removed in the next major release. */ @Deprecated public Builder endpoint(Collection endpoint) { @@ -209,7 +269,8 @@ public Builder from(String from) { * specific states. * *

- * See the Connect with fallback NCCO example. + * See the + * Connect with fallback NCCO example. * * @param eventType The event type as an enum. * @@ -227,33 +288,57 @@ public Builder eventType(EventType eventType) { * @param timeOut The call timeout in seconds. * * @return This builder. + * + * @deprecated Use {@link #timeOut(int)}. This will be removed in the next major release. */ + @Deprecated public Builder timeOut(Integer timeOut) { this.timeOut = timeOut; return this; } + /** + * If the call is unanswered, set the number in seconds before Vonage stops ringing endpoint. + * The default value is 60, minimum is 3 and maximum is 7200 (2 hours). + * + * @param timeOut The call timeout in seconds. + * + * @return This builder. + */ + public Builder timeOut(int timeOut) { + return timeOut(Integer.valueOf(timeOut)); + } + /** * Maximum length of the call in seconds. The default and maximum value is 7200 seconds (2 hours). * * @param limit The maximum call length as an int. * * @return This builder. + * + * @deprecated Use {@link #limit(int)}. This will be removed in the next major release. */ + @Deprecated public Builder limit(Integer limit) { this.limit = limit; return this; } + /** + * Maximum length of the call in seconds. The default and maximum value is 7200 seconds (2 hours). + * + * @param limit The maximum call length as an int. + * + * @return This builder. + */ + public Builder limit(int limit) { + return limit(Integer.valueOf(limit)); + } + /** * Configure the behavior when Vonage detects that a destination is an answerphone. * - * @param machineDetection - * Set to either: - *

    - *
  • {@link MachineDetection#CONTINUE} Vonage sends an HTTP request to event_url with the Call event machine - *
  • {@link MachineDetection#HANGUP} to end the Call - *
+ * @param machineDetection The machine detection mode as an enum. * * @return This builder. */ @@ -286,7 +371,10 @@ public Builder advancedMachineDetection(AdvancedMachineDetection advancedMachine * @param eventUrl The event URLs. * * @return This builder. + * + * @deprecated Use {@link #eventUrl(String)}. This will be removed in the next major release. */ + @Deprecated public Builder eventUrl(Collection eventUrl) { this.eventUrl = eventUrl; return this; @@ -301,11 +389,28 @@ public Builder eventUrl(Collection eventUrl) { * @param eventUrl The event URL(s). * * @return This builder. + * + * @deprecated Use {@link #eventUrl(String)}. This will be removed in the next major release. */ + @Deprecated public Builder eventUrl(String... eventUrl) { return eventUrl(Arrays.asList(eventUrl)); } + /** + * Set the webhook endpoint that Vonage calls asynchronously on each of the possible + * Call States. + * If eventType is set to synchronous the eventUrl can return an NCCO that overrides the current + * NCCO when a timeout occurs. + * + * @param eventUrl The event URL as a string. + * + * @return This builder. + */ + public Builder eventUrl(String eventUrl) { + return eventUrl(new String[]{eventUrl}); + } + /** * The HTTP method Vonage uses to make the request to eventUrl. * The default value is {@linkplain EventMethod#POST}. diff --git a/src/main/java/com/vonage/client/voice/ncco/ConversationAction.java b/src/main/java/com/vonage/client/voice/ncco/ConversationAction.java index f423bdc42..59439d3fe 100644 --- a/src/main/java/com/vonage/client/voice/ncco/ConversationAction.java +++ b/src/main/java/com/vonage/client/voice/ncco/ConversationAction.java @@ -24,14 +24,15 @@ * An NCCO conversation action which enables the ability to host conference calls. */ public class ConversationAction extends JsonableBaseObject implements Action { - private static final String ACTION = "conversation"; - private String name; private Boolean startOnEnter, endOnExit, record, mute; private EventMethod eventMethod; private Collection musicOnHoldUrl, eventUrl, canSpeak, canHear; private TranscriptionSettings transcription; + /** + * Constructor used reflectively by Jackson for instantiation. + */ ConversationAction() {} private ConversationAction(Builder builder) { @@ -52,59 +53,119 @@ record = builder.record; @Override public String getAction() { - return ACTION; + return "conversation"; } + /** + * Name of the Conversation room. + * + * @return The conversation name as a string. + */ @JsonProperty("name") public String getName() { return name; } + /** + * A URL to the MP3 file to stream to participants until the conversation starts. By default, the conversation + * starts when the first person calls the virtual number associated with your Voice app. + * + * @return The music on hold URL wrapped in a collection. + */ @JsonProperty("musicOnHoldUrl") public Collection getMusicOnHoldUrl() { return musicOnHoldUrl; } + /** + * The default value of true ensures that the conversation starts when this caller joins conversation name. + * + * @return Whether to start the conversation when joining, or {@code null} if unspecified. + */ @JsonProperty("startOnEnter") public Boolean getStartOnEnter() { return startOnEnter; } + /** + * Specifies whether a moderated conversation ends when the moderator hangs up. This is set to false by default, + * which means that the conversation only ends when the last remaining participant hangs up, regardless of whether + * the moderator is still on the call. or hangs up. + * + * @return Whether to end the conversation on hangup, or {@code null} if unspecified. + */ @JsonProperty("endOnExit") public Boolean getEndOnExit() { return endOnExit; } + /** + * Determines if the audio from the participant will be played to the conversation and recorded. + * When using {@code canSpeak}, the mute parameter is not supported. + * + * @return Whether the participant will be muted, or {@code null} if unspecified. + */ @JsonProperty("mute") public Boolean getMute() { return mute; } + /** + * Determines if this conversation is recorded. For standard conversations, recordings start when one or more + * attendees connect to the conversation. For moderated conversations, recordings start when the moderator joins. + * + * @return Whether recording is enabled, or {@code null} if unspecified. + */ @JsonProperty("record") public Boolean getRecord() { return record; } + /** + * URL to the webhook endpoint Vonage calls asynchronously on each of the Call States. + * + * @return The event URL wrapped in a collection, or {@code null} if unspecified. + */ @JsonProperty("eventUrl") public Collection getEventUrl() { return eventUrl; } + /** + * HTTP method used to make the request to eventUrl. The default value is POST. + * + * @return The event method as an enum, or {@code null} if unspecified. + */ @JsonProperty("eventMethod") public EventMethod getEventMethod() { return eventMethod; } + /** + * Call leg IDs that can hear this participant speak. + * + * @return The leg UUIDs that can hear this participant speak, or {@code null} if unspecified. + */ @JsonProperty("canSpeak") public Collection getCanSpeak() { return canSpeak; } + /** + * Call leg IDs that this participant can hear. + * + * @return The leg UUIDs that this participant can hear, or {@code null} if unspecified. + */ @JsonProperty("canHear") public Collection getCanHear() { return canHear; } + /** + * Transcription settings. If present (even if all settings are default), transcription is activated. + * + * @return The transcription settings, or {@code null} if unspecified. + */ @JsonProperty("transcription") public TranscriptionSettings getTranscription() { return transcription; @@ -148,13 +209,16 @@ public Builder name(String name) { } /** - * @param musicOnHoldUrl A URL to the mp3 file to stream to participants until the conversation starts. - * By default, the conversation starts when the first person calls the virtual number - * associated with your Voice app. To stream this mp3 before the moderator joins the - * conversation, set startOnEnter to false for all users other than the moderator. + * A URL to the MP3 file to stream to participants until the conversation starts. By default, the + * conversation starts when the first person calls the virtual number associated with your Voice app. To + * stream this MP3 before the moderator joins the conversation, set {@linkplain #startOnEnter(boolean)} + * to {@code false} for all users other than the moderator. + * + * @param musicOnHoldUrl Absolute URL to the hold music in MP3 format, wrapped in a string collection. * * @return This builder. - * @deprecated This will be removed in the next major release. + * + * @deprecated Use {@linkplain #musicOnHoldUrl(String)}. This will be removed in the next major release. */ @Deprecated public Builder musicOnHoldUrl(Collection musicOnHoldUrl) { @@ -163,19 +227,36 @@ public Builder musicOnHoldUrl(Collection musicOnHoldUrl) { } /** - * A URL to the mp3 file to stream to participants until the conversation starts. - * By default, the conversation starts when the first person calls the virtual number - * associated with your Voice app. To stream this mp3 before the moderator joins the - * conversation, set startOnEnter to false for all users other than the moderator. + * A URL to the MP3 file to stream to participants until the conversation starts. By default, the + * conversation starts when the first person calls the virtual number associated with your Voice app. To + * stream this MP3 before the moderator joins the conversation, set {@linkplain #startOnEnter(boolean)} + * to {@code false} for all users other than the moderator. * * @param musicOnHoldUrl Absolute URL to the hold music in MP3 format, as a string. * * @return This builder. + * + * @deprecated Use {@link #musicOnHoldUrl(Collection)}. This will be removed in the next major release. */ + @Deprecated public Builder musicOnHoldUrl(String... musicOnHoldUrl) { return musicOnHoldUrl(Arrays.asList(musicOnHoldUrl)); } + /** + * A URL to the MP3 file to stream to participants until the conversation starts. By default, the + * conversation starts when the first person calls the virtual number associated with your Voice app. To + * stream this MP3 before the moderator joins the conversation, set {@linkplain #startOnEnter(boolean)} + * to {@code false} for all users other than the moderator. + * + * @param musicOnHoldUrl Absolute URL to the hold music in MP3 format, as a string. + * + * @return This builder. + */ + public Builder musicOnHoldUrl(String musicOnHoldUrl) { + return musicOnHoldUrl(new String[]{musicOnHoldUrl}); + } + /** * The default value of {@code true} ensures that the conversation starts when this caller joins * the conversation. Set to false for attendees in a moderated conversation. @@ -183,12 +264,27 @@ public Builder musicOnHoldUrl(String... musicOnHoldUrl) { * @param startOnEnter Whether to start the conversation when joining. * * @return This builder. + * + * @deprecated Use {@link #startOnEnter(boolean)}. This will be removed in the next major release. */ + @Deprecated public Builder startOnEnter(Boolean startOnEnter) { this.startOnEnter = startOnEnter; return this; } + /** + * The default value of {@code true} ensures that the conversation starts when this caller joins + * the conversation. Set to false for attendees in a moderated conversation. + * + * @param startOnEnter Whether to start the conversation when joining. + * + * @return This builder. + */ + public Builder startOnEnter(boolean startOnEnter) { + return startOnEnter(Boolean.valueOf(startOnEnter)); + } + /** * For moderated conversations, set to {@code true} in the moderator NCCO so the conversation is ended * when the moderator hangs up. The default value of false means the conversation is not terminated @@ -197,38 +293,70 @@ public Builder startOnEnter(Boolean startOnEnter) { * @param endOnExit Whether to end the conversation when the moderator hangs up. * * @return This builder. + * + * @deprecated Use {@link #endOnExit(boolean)}. This will be removed in the next major release. */ + @Deprecated public Builder endOnExit(Boolean endOnExit) { this.endOnExit = endOnExit; return this; } + /** + * For moderated conversations, set to {@code true} in the moderator NCCO so the conversation is ended + * when the moderator hangs up. The default value of false means the conversation is not terminated + * when a caller hangs up; the conversation ends when the last caller hangs up. + * + * @param endOnExit Whether to end the conversation when the moderator hangs up. + * + * @return This builder. + */ + public Builder endOnExit(boolean endOnExit) { + return endOnExit(Boolean.valueOf(endOnExit)); + } + /** * Set to {@code true} to record this conversation. For standard conversations, recordings start * when one or more attendees connects to the conversation. For moderated conversations, recordings * start when the moderator joins. That is, when an NCCO is executed for the named conversation where * startOnEnter is set to true. When the recording is terminated, the URL you download the recording - * from is sent to the event URL. - *

- * By default, audio is recorded in MP3 format. See the - * recording guide - * for more details. + * from is sent to the event URL. By default, audio is recorded in MP3 format. * * @param record Whether to enable recording. * * @return This builder. + * + * @deprecated Use {@link #record(boolean)}. This will be removed in the next major release. */ + @Deprecated public Builder record(Boolean record) { this.record = record; return this; } /** - * @param eventUrl Set the URL to the webhook endpoint Vonage calls asynchronously on each of the - * Call States. + * Set to {@code true} to record this conversation. For standard conversations, recordings start + * when one or more attendees connects to the conversation. For moderated conversations, recordings + * start when the moderator joins. That is, when an NCCO is executed for the named conversation where + * startOnEnter is set to true. When the recording is terminated, the URL you download the recording + * from is sent to the event URL. By default, audio is recorded in MP3 format. + * + * @param record Whether to enable recording. * * @return This builder. - * @deprecated This will be removed in the next major release. + */ + public Builder record(boolean record) { + return record(Boolean.valueOf(record)); + } + + /** + * Set the URL to the webhook endpoint Vonage calls asynchronously on each of the Call States. + * + * @param eventUrl The event URL wrapped in a string collection. + * + * @return This builder. + * + * @deprecated Use {@linkplain #eventUrl(String)}. This will be removed in the next major release. */ @Deprecated public Builder eventUrl(Collection eventUrl) { @@ -237,17 +365,30 @@ public Builder eventUrl(Collection eventUrl) { } /** - * Set the URL to the webhook endpoint Vonage calls asynchronously on each of the - * Call States. + * Set the URL to the webhook endpoint Vonage calls asynchronously on each of the Call States. * - * @param eventUrl The event URL as a string. + * @param eventUrl The event URL as a string array. * * @return This builder. + * + * @deprecated Use {@linkplain #eventUrl(String)}. This will be removed in the next major release. */ + @Deprecated public Builder eventUrl(String... eventUrl) { return eventUrl(Arrays.asList(eventUrl)); } + /** + * Set the URL to the webhook endpoint Vonage calls asynchronously on each of the Call States. + * + * @param eventUrl The event URL as a string. + * + * @return This builder. + */ + public Builder eventUrl(String eventUrl) { + return eventUrl(new String[]{eventUrl}); + } + /** * Set the HTTP method used to make the request to eventUrl. The default value is POST. * diff --git a/src/main/java/com/vonage/client/voice/ncco/Endpoint.java b/src/main/java/com/vonage/client/voice/ncco/Endpoint.java index ee5e574f4..2b59b3054 100644 --- a/src/main/java/com/vonage/client/voice/ncco/Endpoint.java +++ b/src/main/java/com/vonage/client/voice/ncco/Endpoint.java @@ -19,9 +19,15 @@ /** * An endpoint for a {@link ConnectAction} to connect to. + * Not to be confused with Call endpoints - see {@link com.vonage.client.voice.Endpoint}. */ public interface Endpoint { + /** + * Gets the endpoint type name. + * + * @return The endpoint type as a string. + */ @JsonProperty("type") String getType(); } diff --git a/src/main/java/com/vonage/client/voice/ncco/EventType.java b/src/main/java/com/vonage/client/voice/ncco/EventType.java index 6f676894a..55e7ddf44 100644 --- a/src/main/java/com/vonage/client/voice/ncco/EventType.java +++ b/src/main/java/com/vonage/client/voice/ncco/EventType.java @@ -18,9 +18,13 @@ import com.fasterxml.jackson.annotation.JsonValue; /** - * The type of event to use. + * The type of event to use for {@link ConnectAction}. */ public enum EventType { + + /** + * Enables eventUrl to return an NCCO that overrides the current NCCO when a call moves to specific states. + */ SYNCHRONOUS; @JsonValue diff --git a/src/main/java/com/vonage/client/voice/ncco/InputAction.java b/src/main/java/com/vonage/client/voice/ncco/InputAction.java index 69fb2914b..9abead86b 100644 --- a/src/main/java/com/vonage/client/voice/ncco/InputAction.java +++ b/src/main/java/com/vonage/client/voice/ncco/InputAction.java @@ -23,8 +23,6 @@ * An NCCO input action which allows for the collection of digits and automatic speech recognition from a person. */ public class InputAction extends JsonableBaseObject implements Action { - private static final String ACTION = "input"; - @JsonProperty(required = true) private Collection type; private DtmfSettings dtmf; @@ -33,6 +31,9 @@ public class InputAction extends JsonableBaseObject implements Action { private EventMethod eventMethod; private InputMode mode; + /** + * Constructor used reflectively by Jackson for instantiation. + */ InputAction() {} private InputAction(Builder builder) { @@ -50,29 +51,55 @@ private InputAction(Builder builder) { @Override public String getAction() { - return ACTION; + return "input"; } + /** + * Input types that are acceptable for this action. + * + * @return The input types as a collection of strings. Valid values are ["dtmf"] for DTMF input only, + * ["speech"] for ASR only, or ["dtmf", "speech"] for both. + */ @JsonProperty("type") public Collection getType() { return type; } + /** + * DTMF settings for this action. + * + * @return The DTMF settings object, or {@code null} if unspecified. + */ @JsonProperty("dtmf") public DtmfSettings getDtmf() { return dtmf; } + /** + * Event URL for this action. + * + * @return The event URL wrapped in a singleton string collection, or {@code null} if unspecified. + */ @JsonProperty("eventUrl") public Collection getEventUrl() { return eventUrl; } + /** + * Event method that will be used with the eventUrl, either {@code GET} or {@code POST}. + * + * @return The event HTTP method as an enum, or {@code null} if unspecified. + */ @JsonProperty("eventMethod") public EventMethod getEventMethod() { return eventMethod; } + /** + * Speech settings for this action. + * + * @return The speech settings object, or {@code null} if unspecified. + */ @JsonProperty("speech") public SpeechSettings getSpeech() { return speech; diff --git a/src/main/java/com/vonage/client/voice/ncco/InputMode.java b/src/main/java/com/vonage/client/voice/ncco/InputMode.java index 20f45933c..127c53dca 100644 --- a/src/main/java/com/vonage/client/voice/ncco/InputMode.java +++ b/src/main/java/com/vonage/client/voice/ncco/InputMode.java @@ -41,6 +41,13 @@ public String toString() { return name().toLowerCase(); } + /** + * Convert a string into an {@link InputMode} enum. + * + * @param name The input mode name as a string. + * + * @return The {@link InputMode} enum, or {@code null} if invalid / unknown. + */ @JsonCreator public static InputMode fromString(String name) { if (name == null) return null; diff --git a/src/main/java/com/vonage/client/voice/ncco/Ncco.java b/src/main/java/com/vonage/client/voice/ncco/Ncco.java index 9e87b7b74..c14f700ba 100644 --- a/src/main/java/com/vonage/client/voice/ncco/Ncco.java +++ b/src/main/java/com/vonage/client/voice/ncco/Ncco.java @@ -33,14 +33,31 @@ public class Ncco implements Jsonable { private Collection actions; private ObjectWriter writer; + /** + * Creates an empty NCCO object. + */ public Ncco() { this(new ObjectMapper().writer(), Collections.emptyList()); } + /** + * Creates an NCCO object with the given actions. + * + * @param actions The actions to take in execution order. + */ public Ncco(Collection actions) { this(Jsonable.createDefaultObjectMapper().writer(), actions); } + /** + * Creates an NCCO object with the given actions. + * + * @param action The actions to take in execution order. + */ + public Ncco(Action... action) { + this(Arrays.asList(action)); + } + @Deprecated public Ncco(ObjectWriter writer) { this(writer, Collections.emptyList()); @@ -57,10 +74,11 @@ public Ncco(ObjectWriter writer, Action... action) { this(writer, Arrays.asList(action)); } - public Ncco(Action... action) { - this(Arrays.asList(action)); - } - + /** + * Gets the NCCO actions as an ordered collection. + * + * @return The call actions to take in execution order. + */ public Collection getActions() { return this.actions; } diff --git a/src/main/java/com/vonage/client/voice/ncco/NotifyAction.java b/src/main/java/com/vonage/client/voice/ncco/NotifyAction.java index b504bcc4b..f818a8f59 100644 --- a/src/main/java/com/vonage/client/voice/ncco/NotifyAction.java +++ b/src/main/java/com/vonage/client/voice/ncco/NotifyAction.java @@ -25,12 +25,13 @@ * An NCCO notify action which allows for custom events to be sent to a configured webhook. */ public class NotifyAction extends JsonableBaseObject implements Action { - private static final String ACTION = "notify"; - private Map payload; private Collection eventUrl; private EventMethod eventMethod; + /** + * Constructor used reflectively by Jackson for instantiation. + */ NotifyAction() {} private NotifyAction(Builder builder) { @@ -41,48 +42,107 @@ private NotifyAction(Builder builder) { @Override public String getAction() { - return ACTION; + return "notify"; } + /** + * Map of custom keys and values that will be converted to JSON and sent to your event URL. + * + * @return The payload as a Map. + */ @JsonProperty("payload") public Map getPayload() { return payload; } + /** + * Webhook URL to send events to. + * + * @return The event URL wrapped as a singleton string collection. + */ @JsonProperty("eventUrl") public Collection getEventUrl() { return eventUrl; } + /** + * HTTP method to use when sending the payload to your event URL. + * + * @return The event HTTP method as an enum, or {@code null} if unspecified. + */ @JsonProperty("eventMethod") public EventMethod getEventMethod() { return eventMethod; } + /** + * Entrypoint for constructing an instance of this class. + * + * @param payload The payload to send to the event URL as a Map. + * @param eventUrl The event URL to send the payload wrapped in a singleton string collection. + * + * @return A new Builder. + * + * @deprecated Use {@link #builder(Map, String)} instead. + */ + @Deprecated public static Builder builder(Map payload, Collection eventUrl) { - return new Builder(payload, eventUrl); + return builder().payload(payload).eventUrl(eventUrl); } + /** + * Entrypoint for constructing an instance of this class. + * + * @param payload The payload to send to the event URL as a Map. + * @param eventUrl The event URL to send the payload to as a string array. + * + * @return A new Builder. + * + * @deprecated Use {@link #builder(Map, String)} instead. + */ + @Deprecated public static Builder builder(Map payload, String... eventUrl) { return builder(payload, Arrays.asList(eventUrl)); } + /** + * Entrypoint for constructing an instance of this class. + * + * @param payload The payload to send to the event URL as a Map. + * @param eventUrl The event URL to send the payload to. + * + * @return A new Builder. + */ + public static Builder builder(Map payload, String eventUrl) { + return builder().payload(payload).eventUrl(eventUrl); + } + + /** + * Entrypoint for constructing an instance of this class. + * You must specify the payload and eventUrl fields using the builder's methods. + * + * @return A new Builder. + * @since 8.17.0 + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder to create a NotifyAction. The payload and eventUrl fields are mandatory. + */ public static class Builder { private Map payload; private Collection eventUrl; private EventMethod eventMethod; - /** - * @param payload A Map of String keys and ? values that will be converted to JSON and sent to your event URL. - * @param eventUrl The URL to send events to. - */ - private Builder(Map payload, Collection eventUrl) { - this.payload = payload; - this.eventUrl = eventUrl; + private Builder() { } /** - * @param payload A Map of String keys and ? values that will be converted to JSON and sent to your event URL. + * Map of custom keys and values that will be converted to JSON and sent to your event URL. + * + * @param payload The action payload as a Map. * * @return This builder. */ @@ -92,26 +152,49 @@ public Builder payload(Map payload) { } /** - * @param eventUrl The URL to send events to. + * Webhook URL to send events to. + * + * @param eventUrl The event webhook URL wrapped in a collection. * * @return This builder. + * + * @deprecated Use {@link #eventUrl(String)} instead. */ + @Deprecated public Builder eventUrl(Collection eventUrl) { this.eventUrl = eventUrl; return this; } /** - * @param eventUrl The URL to send events to. + * Webhook URL to send events to. + * + * @param eventUrl The event webhook URL as a string array. * * @return This builder. + * + * @deprecated Use {@link #eventUrl(String)} instead. */ + @Deprecated public Builder eventUrl(String... eventUrl) { return eventUrl(Arrays.asList(eventUrl)); } /** - * @param eventMethod The HTTP method to use when sending the payload to your event url. + * Webhook URL to send events to. + * + * @param eventUrl The event webhook URL as a string. + * + * @return This builder. + */ + public Builder eventUrl(String eventUrl) { + return eventUrl(new String[]{eventUrl}); + } + + /** + * HTTP method to use when sending the payload to your event URL; either {@code GET} or {@code POST}. + * + * @param eventMethod The event HTTP method as an enum. * * @return This builder. */ diff --git a/src/main/java/com/vonage/client/voice/ncco/PhoneEndpoint.java b/src/main/java/com/vonage/client/voice/ncco/PhoneEndpoint.java index 9f4d2d3da..6d0fdacc2 100644 --- a/src/main/java/com/vonage/client/voice/ncco/PhoneEndpoint.java +++ b/src/main/java/com/vonage/client/voice/ncco/PhoneEndpoint.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.vonage.client.JsonableBaseObject; import com.vonage.client.voice.EndpointType; +import java.util.Objects; /** * Represents a phone endpoint used in a {@link ConnectAction}. See @@ -29,9 +30,9 @@ public class PhoneEndpoint extends JsonableBaseObject implements Endpoint { private final OnAnswer onAnswer; private PhoneEndpoint(Builder builder) { - this.number = builder.number; - this.dtmfAnswer = builder.dtmfAnswer; - this.onAnswer = (builder.onAnswerUrl != null) ? new OnAnswer(builder.onAnswerUrl, builder.onAnswerRingback) : null; + number = builder.number; + dtmfAnswer = builder.dtmfAnswer; + onAnswer = (builder.onAnswerUrl != null) ? new OnAnswer(builder.onAnswerUrl, builder.onAnswerRingback) : null; } @Override @@ -60,15 +61,34 @@ public String getDtmfAnswer() { return dtmfAnswer; } + /** + * An object containing a required URL key. The URL serves an NCCO to execute in the number being connected to, + * before that call is joined to your existing conversation. Optionally, the ringbackTone key can be specified + * with a URL value that points to a ringbackTone to be played back on repeat to the caller, so they do not hear + * just silence. The ringbackTone will automatically stop playing when the call is fully connected. Please note, + * the key ringback is still supported. + * + * @return The OnAnswer object, or {@code null} if unspecified. + */ @JsonProperty("onAnswer") public OnAnswer getOnAnswer() { return onAnswer; } + /** + * Entry point for constructing an instance of this class. + * + * @param number The phone number to connect to in E.164 format. + * + * @return A new Builder. + */ public static Builder builder(String number) { return new Builder(number); } + /** + * Builder for specifying properties of a phone endpoint. + */ public static class Builder { private String number, dtmfAnswer, onAnswerUrl, onAnswerRingback; @@ -76,52 +96,102 @@ public static class Builder { this.number = number; } + /** + * Phone number to connect to in E.164 format. + * + * @param number The phone number as a string. + * + * @return This builder. + */ public Builder number(String number) { this.number = number; return this; } + /** + * Set the digits that are sent to the user as soon as the Call is answered. + * The * and # digits are respected. You create pauses using p. Each pause is 500ms. + * + * @param dtmfAnswer The DTMF digits as a string. + * + * @return This builder. + */ public Builder dtmfAnswer(String dtmfAnswer) { this.dtmfAnswer = dtmfAnswer; return this; } + /** + * Set the URL to an NCCO to execute in the number being connected to, before that call is joined to your + * existing conversation. + * + * @param url The URL to an NCCO as a string. + * + * @return This builder. + */ public Builder onAnswer(String url) { this.onAnswerUrl = url; return this; } + /** + * Set the URL to an NCCO to execute in the number being connected to, before that call is joined to your + * existing conversation. Optionally, the ringbackTone key can be specified with a URL value that points to a + * ringbackTone to be played back on repeat to the caller, so they do not hear just silence. The ringbackTone + * will automatically stop playing when the call is fully connected. Please note, the key ringback is still + * supported. + * + * @param url (REQUIRED) The URL to an NCCO as a string. + * @param ringback (OPTIONAL) The URL to a ringback tone as a string. + * + * @return This builder. + */ public Builder onAnswer(String url, String ringback) { this.onAnswerUrl = url; this.onAnswerRingback = ringback; return this; } + /** + * Builds the PhoneEndpoint with this builder's properties. + * + * @return A new PhoneEndpoint instance. + */ public PhoneEndpoint build() { return new PhoneEndpoint(this); } } /** - * An object containing a required url key. The URL serves an NCCO to execute in the number being connected to, + * An object containing a required URL key. The URL serves an NCCO to execute in the number being connected to, * before that call is joined to your existing conversation. Optionally, the ringbackTone key can be specified * with a URL value that points to a ringbackTone to be played back on repeat to the caller, so they do not hear * just silence. The ringbackTone will automatically stop playing when the call is fully connected. Please note, * the key ringback is still supported. */ - public static class OnAnswer { + public static class OnAnswer { private final String url, ringback; private OnAnswer(String url, String ringback) { - this.url = url; + this.url = Objects.requireNonNull(url); this.ringback = ringback; } + /** + * URL of the NCCO to execute. + * + * @return The URL as a string. + */ @JsonProperty("url") public String getUrl() { return url; } + /** + * URL of the ringback tone to play to the caller. + * + * @return The ringback tone URL as a string, or {@code null} if unspecified. + */ @JsonProperty("ringback") public String getRingback() { return ringback; diff --git a/src/main/java/com/vonage/client/voice/ncco/RecordAction.java b/src/main/java/com/vonage/client/voice/ncco/RecordAction.java index 60181ad00..b068bc944 100644 --- a/src/main/java/com/vonage/client/voice/ncco/RecordAction.java +++ b/src/main/java/com/vonage/client/voice/ncco/RecordAction.java @@ -29,8 +29,6 @@ * set a synchronous condition, the Voice API immediately executes the next NCCO without recording. */ public final class RecordAction extends JsonableBaseObject implements Action { - private static final String ACTION = "record"; - private RecordingFormat format; private Integer endOnSilence, timeOut, channels; private Character endOnKey; @@ -40,6 +38,9 @@ public final class RecordAction extends JsonableBaseObject implements Action { private SplitRecording split; private TranscriptionSettings transcription; + /** + * Constructor used reflectively by Jackson for instantiation. + */ RecordAction() {} private RecordAction(Builder builder) { @@ -52,61 +53,116 @@ private RecordAction(Builder builder) { eventMethod = builder.eventMethod; // Split conversation must be enabled for multiple channels. Checked during construction to avoid // method-chaining state confusion. - split = (builder.channels != null && builder.channels > 1) ? SplitRecording.CONVERSATION : builder.split; + split = (builder.channels != null && builder.channels > 1) ? SplitRecording.CONVERSATION : null; channels = builder.channels; transcription = builder.transcription; } @Override public String getAction() { - return ACTION; + return "record"; } + /** + * Format of the recording. + * + * @return The recording format as an enum, or {@code null} if unspecified. + */ @JsonProperty("format") public RecordingFormat getFormat() { return format; } + /** + * Stop recording after this many seconds of silence. + * Once the recording is stopped the recording data is sent to the eventUrl. + * + * @return The number of seconds of silence that will end the recording, or {@code null} if unspecified. + */ @JsonProperty("endOnSilence") public Integer getEndOnSilence() { return endOnSilence; } + /** + * Stop recording when a digit is pressed on the handset. + * + * @return The key that will end the recording as a character, or {@code null} if unspecified. + */ @JsonProperty("endOnKey") public Character getEndOnKey() { return endOnKey; } + /** + * Maximum length of a recording in seconds. + * Once the recording is stopped the recording data is sent to the eventUrl. + * + * @return The maximum recording length in seconds, or {@code null} if unspecified. + */ @JsonProperty("timeOut") public Integer getTimeOut() { return timeOut; } + /** + * Play a beep when the recording starts. + * + * @return Whether a beep will be played on recording start, or {@code null} if unspecified. + */ @JsonProperty("beepStart") public Boolean getBeepStart() { return beepStart; } + /** + * URL to the webhook endpoint that is called asynchronously when a recording is finished. + * If the message recording is hosted by Vonage, this webhook contains the URL you need to download the + * recording and other metadata, which can be parsed using {@linkplain com.vonage.client.voice.EventWebhook}. + * + * @return The URL to deliver the webhook to wrapped in a string collection, or {@code null} if unspecified. + */ @JsonProperty("eventUrl") public Collection getEventUrl() { return eventUrl; } + /** + * HTTP method used to make the request to eventUrl. + * + * @return The webhook event method as an enum, or {@code null} if unspecified. + */ @JsonProperty("eventMethod") public EventMethod getEventMethod() { return eventMethod; } + /** + * Record the sent and received audio in separate channels of a stereo recording. + * + * @return The split recording enum, or {@code null} if the recording is single channel audio. + */ @JsonProperty("split") public SplitRecording getSplit() { return split; } + /** + * Number of channels to record. + * + * @return The number of channels to record, or {@code null} if unspecified. + */ @JsonProperty("channels") public Integer getChannels() { return channels; } + /** + * Transcription settings for the recording. + * + * @return The transcription settings object, or {@code null} if transcription is not enabled. + * @since 8.2.0 + */ @JsonProperty("transcription") public TranscriptionSettings getTranscription() { return transcription; @@ -131,16 +187,15 @@ public static class Builder { private Boolean beepStart; private Collection eventUrl; private EventMethod eventMethod; - private SplitRecording split; private TranscriptionSettings transcription; Builder() {} /** - * @param format Record the Call in a specific {@link RecordingFormat}. - *

- * The default value is {@link RecordingFormat#MP3}, or {@link RecordingFormat#WAV} when recording - * more than 2 channels. + * Record the Call in a specific format. The default value is {@link RecordingFormat#MP3}, or + * {@link RecordingFormat#WAV} when recording more than 2 channels. + * + * @param format The recording file format as an enum. * * @return This builder. */ @@ -150,8 +205,10 @@ public Builder format(RecordingFormat format) { } /** - * @param endOnSilence Stop recording after n seconds of silence. Once the recording is stopped the recording - * data is sent to event_url. The range of possible values is between 3 and 10 inclusively. + * Stop recording after n seconds of silence. Once the recording is stopped the recording data is sent to + * eventUrl. The range of possible values is between 3 and 10 inclusively. + * + * @param endOnSilence The number of seconds of silence that will end the recording. * * @return This builder. */ @@ -161,63 +218,135 @@ public Builder endOnSilence(Integer endOnSilence) { } /** - * @param endOnKey Stop recording when a digit is pressed on the handset. Possible values are: *, # or any - * single digit e.g. 9 + * Stop recording when a digit is pressed on the handset. Possible values are: *, # and digits 0-9. + * + * @param endOnKey The key that will end the recording as a character. * * @return This builder. + * + * @deprecated Please use {@link #endOnKey(char)} instead. */ + @Deprecated public Builder endOnKey(Character endOnKey) { this.endOnKey = endOnKey; return this; } /** - * @param timeOut The maximum length of a recording in seconds. One the recording is stopped the recording data - * is sent to event_url. The range of possible values is between 3 seconds and 7200 seconds (2 - * hours) + * Stop recording when a digit is pressed on the handset. Possible values are: *, # and digits 0-9. + * + * @param endOnKey The key that will end the recording as a character. * * @return This builder. */ + public Builder endOnKey(char endOnKey) { + return endOnKey(Character.valueOf(endOnKey)); + } + + /** + * Maximum length of a recording in seconds. Once the recording is stopped the recording data is sent to + * the eventUrl. The range of possible values is between 3 and 7200 seconds (i.e. 2 hours). + * + * @param timeOut The maximum recording length in seconds. + * + * @return This builder. + * + * @deprecated Please use {@link #timeOut(int)} instead. + */ + @Deprecated public Builder timeOut(Integer timeOut) { this.timeOut = timeOut; return this; } /** - * @param beepStart Set to true to play a beep when a recording starts + * Maximum length of a recording in seconds. Once the recording is stopped the recording data is sent to + * the eventUrl. The range of possible values is between 3 and 7200 seconds (i.e. 2 hours). + * + * @param timeOut The maximum recording length in seconds. * * @return This builder. */ + public Builder timeOut(int timeOut) { + return timeOut(Integer.valueOf(timeOut)); + } + + /** + * Whether to play a beep when the recording starts. + * + * @param beepStart Set {@code true} to play a beep when a recording starts, {@code false} otherwise. + * + * @return This builder. + * + * @deprecated Please use {@link #beepStart(boolean)} instead. + */ + @Deprecated public Builder beepStart(Boolean beepStart) { this.beepStart = beepStart; return this; } /** - * @param eventUrl The URL to the webhook endpoint that is called asynchronously when a recording is finished. - * If the message recording is hosted by Vonage, this webhook contains the URL you need to - * download the recording and other meta data. + * Whether to play a beep when the recording starts. + * + * @param beepStart Set {@code true} to play a beep when a recording starts, {@code false} otherwise. + * + * @return This builder. + */ + public Builder beepStart(boolean beepStart) { + return beepStart(Boolean.valueOf(beepStart)); + } + + /** + * URL to the webhook endpoint that is called asynchronously when a recording is finished. If the message + * recording is hosted by Vonage, this webhook contains the URL you need to download the recording and + * other metadata. + * + * @param eventUrl The URL to deliver the webhook to as a singleton string collection. * * @return This builder. + * + * @deprecated This method will be removed in the next major release. Use {@linkplain #eventUrl(String)}. */ + @Deprecated public Builder eventUrl(Collection eventUrl) { this.eventUrl = eventUrl; return this; } /** - * @param eventUrl The URL to the webhook endpoint that is called asynchronously when a recording is finished. - * If the message recording is hosted by Vonage, this webhook contains the URL you need to - * download the recording and other meta data. + * URL to the webhook endpoint that is called asynchronously when a recording is finished. If the message + * recording is hosted by Vonage, this webhook contains the URL you need to download the recording and + * other metadata. + * + * @param eventUrl The URL to deliver the webhook to as a string array. * * @return This builder. + * + * @deprecated This method will be removed in the next major release. Use {@linkplain #eventUrl(String)}. */ + @Deprecated public Builder eventUrl(String... eventUrl) { return eventUrl(Arrays.asList(eventUrl)); } /** - * @param eventMethod The HTTP method used to make the request to eventUrl. The default value is POST. + * URL to the webhook endpoint that is called asynchronously when a recording is finished. If the message + * recording is hosted by Vonage, this webhook contains the URL you need to download the recording and + * other metadata, which can be parsed using {@linkplain com.vonage.client.voice.EventWebhook}. + * + * @param eventUrl The URL to deliver the webhook to as a string. + * + * @return This builder. + */ + public Builder eventUrl(String eventUrl) { + return eventUrl(new String[]{eventUrl}); + } + + /** + * HTTP method used to make the request to eventUrl. The default value is {@code POST}. + * + * @param eventMethod The webhook event method as an enum. * * @return This builder. */ @@ -227,29 +356,50 @@ public Builder eventMethod(EventMethod eventMethod) { } /** - * @param split Record the sent and received audio in separate channels of a stereo recording-set to {@link - * SplitRecording#CONVERSATION} to enable this. + * Record the sent and received audio in separate channels of a stereo recording - set to + * {@link SplitRecording#CONVERSATION} to enable this. + * + * @param split The split recording enum. * * @return This builder. + * + * @deprecated This will be set automatically if the number of channels is greater than 1. */ + @Deprecated public Builder split(SplitRecording split) { - this.split = split; return this; } /** - * @param channels The number of channels to record (maximum 32). If the number of participants exceeds channels - * any additional participants will be added to the last channel in file. {@link #split} will be - * set to {@link SplitRecording#CONVERSATION} during the build process if channels is greater - * than 1. + * Number of channels to record (maximum 32). If the number of participants exceeds channels any additional + * participants will be added to the last channel in file. {@link #split} will be set to + * {@link SplitRecording#CONVERSATION} during the build process if channels is greater than 1. + * + * @param channels The number of channels to record. * * @return This builder. + * + * @deprecated Please use {@link #channels(int)} instead. */ + @Deprecated public Builder channels(Integer channels) { this.channels = channels; return this; } + /** + * Number of channels to record (maximum 32). If the number of participants exceeds channels any additional + * participants will be added to the last channel in file. {@link #split} will be set to + * {@link SplitRecording#CONVERSATION} during the build process if channels is greater than 1. + * + * @param channels The number of channels to record. + * + * @return This builder. + */ + public Builder channels(int channels) { + return channels(Integer.valueOf(channels)); + } + /** * Set this parameter to a non-null value to transcribe the recording. * diff --git a/src/main/java/com/vonage/client/voice/ncco/RecordingFormat.java b/src/main/java/com/vonage/client/voice/ncco/RecordingFormat.java index 82716374e..4abc09e17 100644 --- a/src/main/java/com/vonage/client/voice/ncco/RecordingFormat.java +++ b/src/main/java/com/vonage/client/voice/ncco/RecordingFormat.java @@ -18,6 +18,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +/** + * Represents the audio recording file format in {@linkplain RecordAction}. + */ public enum RecordingFormat { MP3, WAV, OGG, UNKNOWN; @@ -27,6 +30,13 @@ public String toString() { return name().toLowerCase(); } + /** + * Convert a string value into a {@link RecordingFormat} enum. + * + * @param name The string value to convert. + * + * @return The recording format as an enum, or {@code UNKNOWN} if an invalid value is provided. + */ @JsonCreator public static RecordingFormat fromString(String name) { try { diff --git a/src/main/java/com/vonage/client/voice/ncco/SipEndpoint.java b/src/main/java/com/vonage/client/voice/ncco/SipEndpoint.java index 47666e780..568ae1b40 100644 --- a/src/main/java/com/vonage/client/voice/ncco/SipEndpoint.java +++ b/src/main/java/com/vonage/client/voice/ncco/SipEndpoint.java @@ -141,6 +141,9 @@ public static Builder builder() { return new Builder(); } + /** + * Builder for a SIP endpoint. + */ public static class Builder { private URI uri; private String domain, user; diff --git a/src/main/java/com/vonage/client/voice/ncco/SpeechSettings.java b/src/main/java/com/vonage/client/voice/ncco/SpeechSettings.java index c8ef4b4e1..a152995e1 100644 --- a/src/main/java/com/vonage/client/voice/ncco/SpeechSettings.java +++ b/src/main/java/com/vonage/client/voice/ncco/SpeechSettings.java @@ -32,10 +32,9 @@ public class SpeechSettings extends JsonableBaseObject { private Boolean saveAudio; /** - * @deprecated This will be made private in a future release. Use {@link #builder()}. + * Constructor used reflectively by Jackson for instantiation. */ - @Deprecated - public SpeechSettings() {} + SpeechSettings() {} private SpeechSettings(Builder builder) { if (builder.uuid != null) { @@ -58,49 +57,91 @@ private SpeechSettings(Builder builder) { saveAudio = builder.saveAudio; } + /** + * Unique ID of the Call leg for the user to capture the speech of. The first joined leg of the call by default. + * + * @return The call ID wrapped in a string collection, or {@code null} if unspecified. + */ @JsonProperty("uuid") public Collection getUuid() { return uuid; } + /** + * Expected language of the user's speech. + * + * @return The language as an enum, or {@code null} if unspecified. + */ @JsonProperty("language") public Language getLanguage() { return language; } + /** + * List of hints to improve recognition quality of certain words are expected from the user. + * + * @return The collection of hint strings, or {@code null} if unspecified. + */ @JsonProperty("context") public Collection getContext() { return context; } + /** + * Controls how long the system will wait after user stops speaking to decide the input is completed. + * + * @return The input completion wait time in seconds as a double, or {@code null} if unspecified. + */ @JsonProperty("endOnSilence") public Double getEndOnSilence() { return endOnSilence; } + /** + * Controls how long the system will wait for the user to start speaking. + * + * @return The initial speech timeout in seconds as an integer, or {@code null} if unspecified. + */ @JsonProperty("startTimeout") public Integer getStartTimeout() { return startTimeout; } + /** + * Controls maximum speech duration from the moment user starts speaking. + * + * @return The maximum speech duration in seconds as an integer, or {@code null} if unspecified. + */ @JsonProperty("maxDuration") public Integer getMaxDuration() { return maxDuration; } + /** + * Audio sensitivity used to differentiate noise from speech. + * + * @return The audio sensitivity as an integer, or {@code null} if unspecified. + */ @JsonProperty("sensitivity") public Integer getSensitivity() { return sensitivity; } + /** + * Controls whether the speech input recording is sent to your webhook endpoint at eventUrl. + * + * @return Whether to send the speech input to the event webhook, or {@code null} if unspecified. + */ @JsonProperty("saveAudio") public Boolean getSaveAudio() { return saveAudio; } - /** - * @param language expected language of the user's speech. If empty, default value is en-US. + * Sets the expected language of the user's speech. + * + * @param language The language of the user's speech as an enum. + * * @deprecated Use {@link Builder#language(Language)}. This will be removed in a future release. */ @Deprecated @@ -109,8 +150,10 @@ public void setLanguage(Language language) { } /** + * Sets the unique ID of the call leg for the user to capture the speech of. + * + * @param uuid The unique ID of the call leg for the user to capture the speech of, wrapped in a collection. * - * @param uuid The unique ID of the Call leg for the user to capture the speech of, wrapped in a collection. * @deprecated Use {@link Builder#uuid(String)}. This will be removed in a future release. */ @Deprecated @@ -121,7 +164,8 @@ public void setUuid(Collection uuid) { /** * List of hints to improve recognition quality if certain words are expected from the user. * - * @param context list of hints + * @param context The collection of hints. + * * @deprecated Use {@link Builder#context(Collection)}. This will be removed in a future release. */ @Deprecated @@ -131,9 +175,10 @@ public void setContext(Collection context) { /** * Controls how long the system will wait after user stops speaking to decide the input is completed. - * Timeout range 1-10 seconds. If empty,Default value is 2 + * Timeout range 1-10 seconds. If empty, default value is 2. + * + * @param endOnSilence Wait time for voice input to complete. * - * @param endOnSilence wait time for voice input to complete * @deprecated Use {@link Builder#endOnSilence(double)}. This will be removed in a future release. */ @Deprecated @@ -142,10 +187,10 @@ public void setEndOnSilence(Integer endOnSilence) { } /** - * Controls how long the system will wait for the user to start speaking. - * Timeout range 1-10 seconds. + * Controls how long the system will wait for the user to start speaking. Timeout range 1-10 seconds. + * + * @param startTimeout Timeout for voice input initiation. * - * @param startTimeout timeout for voice input initiation * @deprecated Use {@link Builder#startTimeout(int)}. This will be removed in a future release. */ @Deprecated @@ -154,9 +199,10 @@ public void setStartTimeout(Integer startTimeout) { } /** - * Controls maximum speech duration from the moment user starts speaking. Default value is 60 + * Controls maximum speech duration from the moment user starts speaking. Default value is 60. + * + * @param maxDuration Speech duration starting from user's initiation of speech. * - * @param maxDuration speech duration starting from user's initiation of speech * @deprecated Use {@link Builder#maxDuration(int)}. This will be removed in a future release. */ @Deprecated @@ -202,10 +248,11 @@ public Builder uuid(String uuid) { } /** - * Hints to improve recognition quality if certain words are expected from the user. + * Hints to improve recognition quality of certain words are expected from the user. * * @param context The collection of hint strings. * @return This builder. + * * @see #context(String...) */ public Builder context(Collection context) { @@ -214,7 +261,7 @@ public Builder context(Collection context) { } /** - * Hints to improve recognition quality if certain words are expected from the user. + * Hints to improve recognition quality of certain words are expected from the user. * * @param context The hint strings. * @return This builder. @@ -305,6 +352,9 @@ public SpeechSettings build() { } } + /** + * Represents the languages supported by the ASR (Automatic Speech Recognition) feature. + */ public enum Language { AFRIKAANS("af-ZA"), ALBANIAN("sq-AL"), @@ -392,6 +442,11 @@ public enum Language { this.language = language; } + /** + * Retrieve the language code associated with this enum. + * + * @return The language code as a string. + */ @JsonValue public String getLanguage() { return language; diff --git a/src/main/java/com/vonage/client/voice/ncco/SplitRecording.java b/src/main/java/com/vonage/client/voice/ncco/SplitRecording.java index 99917c70b..5144fd2e8 100644 --- a/src/main/java/com/vonage/client/voice/ncco/SplitRecording.java +++ b/src/main/java/com/vonage/client/voice/ncco/SplitRecording.java @@ -17,6 +17,9 @@ import com.fasterxml.jackson.annotation.JsonValue; +/** + * Enum for declaring multichannel recordings in {@link RecordAction}. + */ public enum SplitRecording { CONVERSATION; diff --git a/src/main/java/com/vonage/client/voice/ncco/StreamAction.java b/src/main/java/com/vonage/client/voice/ncco/StreamAction.java index b712c7d8a..085aca18a 100644 --- a/src/main/java/com/vonage/client/voice/ncco/StreamAction.java +++ b/src/main/java/com/vonage/client/voice/ncco/StreamAction.java @@ -24,13 +24,14 @@ * An NCCO stream action which allows for media to be streamed to a call. */ public class StreamAction extends JsonableBaseObject implements Action { - private static final String ACTION = "stream"; - private Collection streamUrl; private Float level; private Boolean bargeIn; private Integer loop; + /** + * Constructor used reflectively by Jackson for instantiation. + */ StreamAction() {} private StreamAction(Builder builder) { @@ -42,117 +43,246 @@ private StreamAction(Builder builder) { @Override public String getAction() { - return ACTION; + return "stream"; } + /** + * Publicly accessible URL to an MP3 or 16-bit WAV audio file to stream into the Call or Conversation. + * + * @return The stream URL wrapped in a collection. + */ @JsonProperty("streamUrl") public Collection getStreamUrl() { return streamUrl; } + /** + * Set the audio level of the stream in the range between -1 and 1 inclusively with a precision of 0.1. + * The default value is 0. + * + * @return The volume level that the audio is played at, or {@code null} if unspecified. + */ @JsonProperty("level") public Float getLevel() { return level; } + /** + * Determines whether this action is terminated when the user presses a button on the keypad. Use this + * feature to enable users to choose an option without having to listen to the whole message in your + * Interactive Voice Response (IVR). If you set bargeIn to true on one more Stream actions then the next + * action in the NCCO stack must be an input action. The default value is {@code false}. + * + * @return Whether user input can terminate this action, or {@code null} if unspecified. + */ @JsonProperty("bargeIn") public Boolean getBargeIn() { return bargeIn; } + /** + * Number of times audio is repeated before the Call is closed. The default value is 1. + * Set to 0 to loop infinitely. + * + * @return The number of times the audio stream is repeated, or {@code null} if unspecified. + */ @JsonProperty("loop") public Integer getLoop() { return loop; } /** - * @param streamUrl An array containing a single URL to an mp3 or wav (16-bit) audio file to stream to the - * Call or Conversation. - * @return A {@link Builder}. + * Entrypoint for constructing an instance of this class. + * + * @param streamUrl A collection containing a single URL to an MP3 or 16-bit WAV audio file to stream to the call. + * + * @return A new Builder. + * + * @deprecated Use {@link #builder(String)}. This method will be removed in the next major release. */ + @Deprecated public static Builder builder(Collection streamUrl) { - return new Builder(streamUrl); + return builder().streamUrl(streamUrl); } /** - * @param streamUrl An array containing a single URL to an mp3 or wav (16-bit) audio file to stream to the - * Call or Conversation. - * @return A {@link Builder}. + * Entrypoint for constructing an instance of this class. + * + * @param streamUrl An array containing a single URL to an MP3 or 16-bit WAV audio file to stream to the call. + * + * @return A new Builder. + * + * @deprecated Use {@link #builder(String)}. This method will be removed in the next major release. */ + @Deprecated public static Builder builder(String... streamUrl) { - return builder(Arrays.asList(streamUrl)); + return builder().streamUrl(streamUrl); + } + + /** + * Entrypoint for constructing an instance of this class. + * + * @param streamUrl URL to an MP3 or 16-bit WAV audio file to stream into the Call or Conversation. + * + * @return A new Builder. + */ + public static Builder builder(String streamUrl) { + return builder().streamUrl(streamUrl); } + /** + * Entrypoint for constructing an instance of this class. + * You must provide the stream URL by calling the {@linkplain Builder#streamUrl(String)} method. + * + * @return A new Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder to create a StreamAction. The stream URL is mandatory. + */ public static class Builder { private Collection streamUrl; private Float level; private Boolean bargeIn; private Integer loop; - Builder(Collection streamUrl) { - this.streamUrl = streamUrl; + Builder() {} + + /** + * URL to an MP3 or 16-bit WAV audio file to stream into the Call or Conversation. + * + * @param streamUrl The publicly accessible URL to the audio file to stream. + * + * @return This builder. + */ + public Builder streamUrl(String streamUrl) { + return streamUrl(new String[]{streamUrl}); } /** - * @param streamUrl An array containing a single URL to an mp3 or wav (16-bit) audio file to stream to the - * Call or Conversation. + * URL to an MP3 or 16-bit WAV audio file to stream into the Call or Conversation. + * + * @param streamUrl The publicly accessible URL to the audio file to stream wrapped in a collection. * * @return This builder. + * + * @deprecated Use {@link #streamUrl(String)}. This method will be removed in the next major release. */ + @Deprecated public Builder streamUrl(Collection streamUrl) { this.streamUrl = streamUrl; return this; } /** - * @param streamUrl An array containing a single URL to an mp3 or wav (16-bit) audio file to stream to the - * Call or Conversation. + * URL to an MP3 or 16-bit WAV audio file to stream into the Call or Conversation. + * + * @param streamUrl The publicly accessible URL to the audio file to stream wrapped in an array. * * @return This builder. + * + * @deprecated Use {@link #streamUrl(String)}. This method will be removed in the next major release. */ + @Deprecated public Builder streamUrl(String... streamUrl) { return streamUrl(Arrays.asList(streamUrl)); } /** - * @param level Set the audio level of the stream in the range between -1 and 1 inclusively with a precision - * of 0.1. The default value is 0. + * Set the audio level of the stream in the range between -1 and 1 inclusively with a precision of 0.1. + * The default value is 0. + * + * @param level The volume level that the audio is played at as a Float, between -1.0 and 1.0 (inclusive). * * @return This builder. + * + * @deprecated Use {@link #level(double)}. This method will be removed in the next major release. */ + @Deprecated public Builder level(Float level) { this.level = level; return this; } /** - * @param bargeIn Set to true so this action is terminated when the user presses a button on the keypad. - * Use this feature to enable users to choose an option without having to listen to the whole - * message in your Interactive Voice Response (IVR ). If you set bargeIn to true on one more - * Stream actions then the next action in the NCCO stack must be an input action. - *

- * The default value is false. + * Set the audio level of the stream in the range between -1 and 1 inclusively with a precision of 0.1. + * The default value is 0. + * + * @param level The volume level that the audio is played at, between -1.0 and 1.0 (inclusive). * * @return This builder. */ + public Builder level(double level) { + return level(Float.valueOf((float) level)); + } + + /** + * Set to {@code true} so this action is terminated when the user presses a button on the keypad. Use this + * feature to enable users to choose an option without having to listen to the whole message in your + * Interactive Voice Response (IVR). If you set bargeIn to true on one more Stream actions then the next + * action in the NCCO stack must be an input action. The default value is {@code false}. + * + * @param bargeIn Whether to allow user input to terminate this action. + * + * @return This builder. + * + * @deprecated Use {@link #bargeIn(boolean)}. This method will be removed in the next major release. + */ + @Deprecated public Builder bargeIn(Boolean bargeIn) { this.bargeIn = bargeIn; return this; } /** - * @param loop The number of times audio is repeated before the Call is closed. - * The default value is 1. Set to 0 to loop infinitely. + * Set to {@code true} so this action is terminated when the user presses a button on the keypad. Use this + * feature to enable users to choose an option without having to listen to the whole message in your + * Interactive Voice Response (IVR). If you set bargeIn to true on one more Stream actions then the next + * action in the NCCO stack must be an input action. The default value is {@code false}. + * + * @param bargeIn Whether to allow user input to terminate this action. + * + * @return This builder. + */ + public Builder bargeIn(boolean bargeIn) { + return bargeIn(Boolean.valueOf(bargeIn)); + } + + /** + * Number of times audio is repeated before the Call is closed. The default value is 1. + * Set to 0 to loop infinitely. + * + * @param loop The number of times the audio stream is repeated (0 meaning infinite). * * @return This builder. + * + * @deprecated Use {@link #loop(int)}. This method will be removed in the next major release. */ + @Deprecated public Builder loop(Integer loop) { this.loop = loop; return this; } /** - * @return A new {@link StreamAction} object from the stored builder options. + * Number of times audio is repeated before the Call is closed. The default value is 1. + * Set to 0 to loop infinitely. + * + * @param loop The number of times the audio stream is repeated (0 meaning infinite). + * + * @return This builder. + */ + public Builder loop(int loop) { + return loop(Integer.valueOf(loop)); + } + + /** + * Builds the StreamAction. + * + * @return A new SteamAction object from the stored builder options. */ public StreamAction build() { return new StreamAction(this); diff --git a/src/main/java/com/vonage/client/voice/ncco/TalkAction.java b/src/main/java/com/vonage/client/voice/ncco/TalkAction.java index f72317830..77425d0d5 100644 --- a/src/main/java/com/vonage/client/voice/ncco/TalkAction.java +++ b/src/main/java/com/vonage/client/voice/ncco/TalkAction.java @@ -23,8 +23,6 @@ * An NCCO talk action which allows for synthesized speech to be sent to a call. */ public class TalkAction extends JsonableBaseObject implements Action { - private static final String ACTION = "talk"; - private String text; private Boolean bargeIn; private Integer loop, style; @@ -32,6 +30,9 @@ public class TalkAction extends JsonableBaseObject implements Action { private TextToSpeechLanguage language; private Boolean premium; + /** + * Constructor used reflectively by Jackson for instantiation. + */ TalkAction() {} private TalkAction(Builder builder) { @@ -46,56 +47,110 @@ private TalkAction(Builder builder) { @Override public String getAction() { - return ACTION; + return "talk"; } + /** + * A string of up to 1,500 characters (excluding SSML tags) containing the message to be synthesized into the + * Call or Conversation. A single comma in text adds a short pause to the synthesized speech. + * + * @return The text or Speech Synthesis Markup Language to be spoken into the call. + */ @JsonProperty("text") public String getText() { return text; } + /** + * Determines whether the action is terminated when the user presses a button on the keypad. + * The default value is {@code false}. + * + * @return {@code true} if early termination by user is allowed, or {@code null} if unspecified. + */ @JsonProperty("bargeIn") public Boolean getBargeIn() { return bargeIn; } + /** + * Number of times text is repeated before the Call is closed. The default value is 1. + * + * @return The number of iterations of the text to be spoken, or {@code null} if unspecified. + */ @JsonProperty("loop") public Integer getLoop() { return loop; } + /** + * Volume level that the speech is played at. This can be any value between -1 to 1, with 0 being the default. + * + * @return The volume level as a Float between -1.0 and 1.0, or {@code null} if unspecified. + */ @JsonProperty("level") public Float getLevel() { return level; } + /** + * Language to use when converting the text to speech. + * + * @return The text-to-speech language as an enum, or {@code null} if unspecified. + */ @JsonProperty("language") public TextToSpeechLanguage getLanguage() { return language; } + /** + * Vocal style (vocal range, tessitura and timbre). Default is {@code 0}. Possible values are listed in the + * + * Text-To-Speech guide. + * + * @return The vocal style number to use, or {@code null} if unspecified. + */ @JsonProperty("style") public Integer getStyle() { return style; } + /** + * Whether to use Premium text-to-speech. Premium voices incur an additional charge - see + * the Voice Pricing page + * for details on the exact rate. + * + * @return {@code true} if the premium version will be used where available, or {@code null} if unspecified. + */ @JsonProperty("premium") public Boolean getPremium() { return premium; } /** - * @param text A string of up to 1,500 characters (excluding SSML tags) containing the message to be - * synthesized in the Call or Conversation. A single comma in text adds a short pause to the - * synthesized speech. To add a longer pause a break tag needs to be used in SSML. - *

- * To use SSML tags, you must enclose the text in a speak element. + * Entrypoint for constructing an instance of this class. + * + * @param text The text to be spoken into the call. + * * @return A new {@linkplain Builder} with the text field initialised. */ public static Builder builder(String text) { - return new Builder(text); + return builder().text(text); } + /** + * Entrypoint for constructing an instance of this class. + * You must provide the text to be spoken using the {@linkplain Builder#text(String)} method. + * + * @return A new Builder. + * @since 8.17.0 + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for specifying the properties of a TalkAction. The text is mandatory, all other parameters are optional. + */ public static class Builder { private String text; private Boolean bargeIn, premium; @@ -103,17 +158,15 @@ public static class Builder { private Float level; private TextToSpeechLanguage language; - - Builder(String text) { - this.text = text; - } + Builder() {} /** - * @param text A string of up to 1,500 characters (excluding SSML tags) containing the message to be - * synthesized in the Call or Conversation. A single comma in text adds a short pause to the - * synthesized speech. To add a longer pause a break tag needs to be used in SSML. - *

- * To use SSML tags, you must enclose the text in a speak element. + * A string of up to 1,500 characters (excluding SSML tags) containing the message to be synthesized into the + * Call or Conversation. A single comma in text adds a short pause to the synthesized speech. To add a longer + * pause, a {@code } tag needs to be used in SSML. To use SSML tags, you must enclose the text in a + * {@code } element. + * + * @param text The text to be spoken in the call. * * @return This builder. */ @@ -123,21 +176,42 @@ public Builder text(String text) { } /** - * @param bargeIn Set to true so this action is terminated when the user presses a button on the keypad. - * Use this feature to enable users to choose an option without having to listen to the whole - * message in your Interactive Voice Response (IVR). If you set bargeIn to true the next - * action in the NCCO stack must be an input action. The default value is false. + * Set to true so this action is terminated when the user presses a button on the keypad. Use this feature to + * enable users to choose an option without having to listen to the whole message in your Interactive Voice + * Response (IVR). If you set this to {@code true} the next action in the NCCO stack must be an input action. + * The default value is {@code false}. + * + * @param bargeIn Whether to allow early termination of the action upon user input. * * @return This builder. + * + * @deprecated Use {@link #bargeIn(boolean)} instead. This method will be removed in the next major release. */ + @Deprecated public Builder bargeIn(Boolean bargeIn) { this.bargeIn = bargeIn; return this; } /** - * @param loop The number of times text is repeated before the Call is closed. - * The default value is 1. Set to 0 to loop infinitely. + * Set to true so this action is terminated when the user presses a button on the keypad. Use this feature to + * enable users to choose an option without having to listen to the whole message in your Interactive Voice + * Response (IVR). If you set this to {@code true} the next action in the NCCO stack must be an input action. + * The default value is {@code false}. + * + * @param bargeIn Whether to allow early termination of the action upon user input. + * + * @return This builder. + */ + public Builder bargeIn(boolean bargeIn) { + return bargeIn(Boolean.valueOf(bargeIn)); + } + + /** + * Number of times text is repeated before the Call is closed. + * The default value is 1. Set to 0 to loop infinitely. + * + * @param loop The loop count as an integer. * * @return This builder. */ @@ -147,18 +221,35 @@ public Builder loop(Integer loop) { } /** - * @param level The volume level that the speech is played. This can be any value between -1 to 1 with 0 - * being the default. + * Volume level that the speech is played at. This can be any value between -1 to 1 with 0 being the default. + * + * @param level The volume level as a Float between -1.0 and 1.0. * * @return This builder. + * + * @deprecated Use {@link #level(double)} instead. This method will be removed in the next major release. */ + @Deprecated public Builder level(Float level) { this.level = level; return this; } /** - * @param language The Language to use when converting the text to speech. + * Volume level that the speech is played at. This can be any value between -1 to 1 with 0 being the default. + * + * @param level The volume level, between -1.0 and 1.0 (inclusive). + * + * @return This builder. + */ + public Builder level(double level) { + return level(Float.valueOf((float) level)); + } + + /** + * Language to use when converting the text to speech. + * + * @param language The text-to-speech language as an enum. * * @return This builder. */ @@ -168,28 +259,71 @@ public Builder language(TextToSpeechLanguage language) { } /** - * @param style The vocal style to use. + * Vocal style (vocal range, tessitura and timbre). Default is {@code 0}. Possible values are listed in the + * + * Text-To-Speech guide. + * + * @param style The vocal style number to use. * * @return This builder. + * + * @deprecated Use {@link #style(int)} instead. This method will be removed in the next major release. */ + @Deprecated public Builder style(Integer style) { this.style = style; return this; } /** - * @param premium Whether to use Premium text-to-speech. Set to {@code true} to use the premium version - * of the specified style if available, otherwise the standard version will be used. + * Vocal style (vocal range, tessitura and timbre). Default is {@code 0}. Possible values are listed in the + * + * Text-To-Speech guide. + * + * @param style The vocal style number to use. * * @return This builder. */ + public Builder style(int style) { + return style(Integer.valueOf(style)); + } + + /** + * Whether to use Premium text-to-speech. Set to {@code true} to use the premium version of the specified + * style if available, otherwise the standard version will be used. Premium voices incur an additional + * charge - see the Voice Pricing page + * for details on the exact rate. + * + * @param premium {@code true} to use the premium version where possible, {@code false} for standard. + * + * @return This builder. + * + * @deprecated Use {@link #premium(boolean)} instead. This method will be removed in the next major release. + */ + @Deprecated public Builder premium(Boolean premium) { this.premium = premium; return this; } /** - * @return A new {@link TalkAction} object from the stored builder options. + * Whether to use Premium text-to-speech. Set to {@code true} to use the premium version of the specified + * style if available, otherwise the standard version will be used. Premium voices incur an additional + * charge - see the Voice Pricing page + * for details on the exact rate. + * + * @param premium {@code true} to use the premium version where possible, {@code false} for standard. + * + * @return This builder. + */ + public Builder premium(boolean premium) { + return premium(Boolean.valueOf(premium)); + } + + /** + * Builds the TalkAction. + * + * @return A new TalkAction object from the stored builder options. */ public TalkAction build() { return new TalkAction(this); diff --git a/src/main/java/com/vonage/client/voice/ncco/TranscriptionSettings.java b/src/main/java/com/vonage/client/voice/ncco/TranscriptionSettings.java index d586cd989..fd38b68a8 100644 --- a/src/main/java/com/vonage/client/voice/ncco/TranscriptionSettings.java +++ b/src/main/java/com/vonage/client/voice/ncco/TranscriptionSettings.java @@ -32,6 +32,9 @@ public final class TranscriptionSettings extends JsonableBaseObject { private EventMethod eventMethod; private Boolean sentimentAnalysis; + /** + * Constructor used reflectively by Jackson for instantiation. + */ TranscriptionSettings() {} private TranscriptionSettings(Builder builder) { diff --git a/src/main/java/com/vonage/client/voice/ncco/WebSocketEndpoint.java b/src/main/java/com/vonage/client/voice/ncco/WebSocketEndpoint.java index 1a8b5eb8e..2c01438b0 100644 --- a/src/main/java/com/vonage/client/voice/ncco/WebSocketEndpoint.java +++ b/src/main/java/com/vonage/client/voice/ncco/WebSocketEndpoint.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.vonage.client.JsonableBaseObject; +import com.vonage.client.users.channels.Websocket; import com.vonage.client.voice.EndpointType; import java.net.URI; import java.util.Map; @@ -37,30 +38,56 @@ private WebSocketEndpoint(Builder builder) { headers = builder.headers; } - @JsonProperty("uri") - public URI getUri() { - return uri; - } - @Override public String getType() { return EndpointType.WEBSOCKET.toString(); } + /** + * URI to the websocket you are streaming to. + * + * @return The websocket URI. + */ + @JsonProperty("uri") + public URI getUri() { + return uri; + } + + /** + * The internet media type for the audio you are streaming. + * + * @return The content type as a string. + */ @JsonProperty("content-type") public String getContentType() { return contentType; } + /** + * Additional headers to be sent with the WebSocket request. + * + * @return The headers data as a map, or {@code null} if unspecified. + */ @JsonProperty("headers") public Map getHeaders() { return headers; } + /** + * Entry point for constructing an instance of this class. + * + * @param uri The websocket URI. + * @param contentType The content type as a string. + * + * @return A new Builder. + */ public static Builder builder(String uri, String contentType) { return new Builder(uri, contentType); } + /** + * Builder for specifying properties of a WebSocket endpoint. + */ public static class Builder { private URI uri; private String contentType; @@ -71,25 +98,71 @@ public static class Builder { this.contentType = contentType; } + /** + * URI to the websocket you are streaming to. + * + * @param uri The websocket URI. + * + * @return This builder. + */ public Builder uri(URI uri) { this.uri = uri; return this; } + /** + * URI to the websocket you are streaming to. + * + * @param uri The websocket URI as a string. + * + * @return This builder. + */ public Builder uri(String uri) { return uri(URI.create(uri)); } + /** + * The internet media type for the audio you are streaming. Possible values are: + * {@code audio/l16;rate=16000} or {@code audio/l16;rate=8000}. + * + * @param contentType The content type as a string. + * + * @return This builder. + */ public Builder contentType(String contentType) { this.contentType = contentType; return this; } + /** + * The internet media type for the audio you are streaming. + * + * @param contentType The content type as an enum. + * + * @return This builder. + * @since 8.17.0 + */ + public Builder contentType(Websocket.ContentType contentType) { + return contentType(contentType.toString()); + } + + /** + * Additional headers to be sent with the WebSocket request. + * + * @param headers The headers data as a map. + * + * @return This builder. + */ public Builder headers(Map headers) { this.headers = headers; return this; } + /** + * Builds the WebSocketEndpoint with this builder's properties. + * + * @return A new WebSocketEndpoint instance. + */ public WebSocketEndpoint build() { return new WebSocketEndpoint(this); } diff --git a/src/test/java/com/vonage/client/voice/CallInfoTest.java b/src/test/java/com/vonage/client/voice/CallInfoTest.java index cb5f3ac00..de5b8fab8 100644 --- a/src/test/java/com/vonage/client/voice/CallInfoTest.java +++ b/src/test/java/com/vonage/client/voice/CallInfoTest.java @@ -15,6 +15,7 @@ */ package com.vonage.client.voice; +import com.vonage.client.Jsonable; import com.vonage.client.TestUtils; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.*; @@ -193,9 +194,12 @@ public void testStatus(String value, CallStatus expectedValue) throws Exception @Test public void testToString() throws Exception { - CallInfo record = new CallInfo("447700900104", "447700900105"); - record.uuid = "93137ee3-580e-45f7-a61a-e0b5716000ef"; - record.status = CallStatus.COMPLETED; + CallInfo record = Jsonable.fromJson("{" + + "\"uuid\":\"93137ee3-580e-45f7-a61a-e0b5716000ef\"," + + "\"status\":\"completed\"," + + "\"from\":{\"type\":\"phone\",\"number\":\"447700900105\"}," + + "\"to\":{\"type\":\"phone\",\"number\":\"447700900104\"}" + + "}"); assertEquals("", record.toString()); } } diff --git a/src/test/java/com/vonage/client/voice/CallTest.java b/src/test/java/com/vonage/client/voice/CallTest.java index 7ee012d4e..42da04903 100644 --- a/src/test/java/com/vonage/client/voice/CallTest.java +++ b/src/test/java/com/vonage/client/voice/CallTest.java @@ -301,7 +301,7 @@ public void testConstructAllParams() { new AppEndpoint("nexmo"), new SipEndpoint(sipUri, sipCustomHeaders), new VbcEndpoint("7890"), - new WebSocketEndpoint("wss://example.org", "audio/l16", Collections.emptyMap()), + new WebSocketEndpoint("wss://example.org", null, null), new SipEndpoint(sipUri, sipUser2User), new SipEndpoint(sipUri, sipCustomHeaders, sipUser2User) ) diff --git a/src/test/java/com/vonage/client/voice/CallsFilterTest.java b/src/test/java/com/vonage/client/voice/CallsFilterTest.java index f70645151..f2a1fa29b 100644 --- a/src/test/java/com/vonage/client/voice/CallsFilterTest.java +++ b/src/test/java/com/vonage/client/voice/CallsFilterTest.java @@ -15,15 +15,16 @@ */ package com.vonage.client.voice; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotSame; +import com.vonage.client.common.SortOrder; import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; +import java.time.Instant; import java.util.*; public class CallsFilterTest { @Test - public void testAllParams() { + public void testAllDeprecatedParams() { Calendar startCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); startCalendar.set(2016, Calendar.JANUARY, 1, 7, 8, 20); startCalendar.set(Calendar.MILLISECOND, 0); @@ -32,33 +33,36 @@ public void testAllParams() { endCalendar.set(2016, Calendar.JANUARY, 1, 7, 8, 55); endCalendar.set(Calendar.MILLISECOND, 0); Date endDate = endCalendar.getTime(); + Integer pageSize = 10, recordIndex = 12; + String conversationUuid = "this-is-not-a-uuid"; + CallStatus status = CallStatus.COMPLETED; + CallOrder order = CallOrder.ASCENDING; CallsFilter filter = CallsFilter.builder() - .status(CallStatus.COMPLETED).dateStart(startDate).dateEnd(endDate) - .recordIndex(12).order(CallOrder.ASCENDING).pageSize(10) - .conversationUuid("this-is-not-a-uuid").build(); + .order((CallOrder) null).order(order) + .dateStart(null).dateStart(startDate) + .dateEnd(null).dateEnd(endDate) + .recordIndex(null).recordIndex(recordIndex) + .pageSize(null).pageSize(pageSize) + .conversationUuid(conversationUuid) + .status(status).build(); - assertEquals(CallStatus.COMPLETED, filter.getStatus()); assertEquals(startDate, filter.getDateStart()); assertEquals(endDate, filter.getDateEnd()); - assertEquals(12, (int) filter.getRecordIndex()); - assertEquals(CallOrder.ASCENDING, filter.getOrder()); - assertEquals(10, (int) filter.getPageSize()); - assertEquals("this-is-not-a-uuid", filter.getConversationUuid()); - Map paramLookup = filter.makeParams(); - assertEquals("completed", paramLookup.get("status")); + assertEquals(7, paramLookup.size()); + assertEquals(status.name().toLowerCase(), paramLookup.get("status")); assertEquals("2016-01-01T07:08:55Z", paramLookup.get("date_end")); assertEquals("2016-01-01T07:08:20Z", paramLookup.get("date_start")); - assertEquals("12", paramLookup.get("record_index")); - assertEquals("asc", paramLookup.get("order")); - assertEquals("10", paramLookup.get("page_size")); - assertEquals("this-is-not-a-uuid", paramLookup.get("conversation_uuid")); + assertEquals(recordIndex.toString(), paramLookup.get("record_index")); + assertEquals(order.getCallOrder(), paramLookup.get("order")); + assertEquals(pageSize.toString(), paramLookup.get("page_size")); + assertEquals(conversationUuid, paramLookup.get("conversation_uuid")); } @Test - public void testNoParams() throws Exception { + public void testNoParams() { assertEquals(0, CallsFilter.builder().build().makeParams().size()); } @@ -66,4 +70,37 @@ public void testNoParams() throws Exception { public void testStaticBuilderProducesNewBuilder() { assertNotSame(CallsFilter.builder(), CallsFilter.builder()); } + + @Test + public void testAllParams() { + Instant startDate = Instant.parse("2020-01-30T07:08:24Z"), endDate = Instant.now(); + String conversationId = "CON-aaaaaaaa-bbbb-4ccc-8ddd-0123456789ab"; + int recordIndex = 6, pageSize = 31; + CallStatus status = CallStatus.RINGING; + SortOrder order = SortOrder.DESCENDING; + + CallsFilter filter = CallsFilter.builder() + .startDate(startDate).endDate(endDate) + .conversationUuid(conversationId).recordIndex(recordIndex) + .pageSize(pageSize).status(status).order(order).build(); + + assertEquals(startDate, filter.getStartDate()); + assertEquals(endDate, filter.getEndDate()); + assertEquals(conversationId, filter.getConversationUuid()); + assertEquals(recordIndex, filter.getRecordIndex()); + assertEquals(pageSize, filter.getPageSize()); + assertEquals(status, filter.getStatus()); + assertEquals(order, filter.getOrder()); + + var params = filter.makeParams(); + assertNotNull(params); + assertEquals(7, params.size()); + assertEquals(startDate, Instant.parse(params.get("date_start"))); + assertEquals(endDate, Instant.parse(params.get("date_end"))); + assertEquals(conversationId, params.get("conversation_uuid")); + assertEquals(Integer.toString(recordIndex), params.get("record_index")); + assertEquals(Integer.toString(pageSize), params.get("page_size")); + assertEquals(status.name().toLowerCase(), params.get("status")); + assertEquals("desc", params.get("order")); + } } \ No newline at end of file diff --git a/src/test/java/com/vonage/client/voice/VoiceClientTest.java b/src/test/java/com/vonage/client/voice/VoiceClientTest.java index 87fb6a4af..33f7fc09f 100644 --- a/src/test/java/com/vonage/client/voice/VoiceClientTest.java +++ b/src/test/java/com/vonage/client/voice/VoiceClientTest.java @@ -17,7 +17,6 @@ import com.vonage.client.AbstractClientTest; import com.vonage.client.RestEndpoint; -import com.vonage.client.TestUtils; import static com.vonage.client.TestUtils.testJsonableBaseObject; import com.vonage.client.common.HttpMethod; import com.vonage.client.voice.ncco.Ncco; @@ -671,8 +670,7 @@ protected String expectedEndpointUri(ModifyCallPayload request) { protected ModifyCallPayload sampleRequest() { ModifyCallAction[] actions = ModifyCallAction.values(); action = actions[(int) (Math.random() * actions.length)]; - ModifyCallPayload request = new ModifyCallPayload(action, SAMPLE_CALL_ID); - return request; + return new ModifyCallPayload(action, SAMPLE_CALL_ID); } @Override diff --git a/src/test/java/com/vonage/client/voice/ncco/NotifyActionTest.java b/src/test/java/com/vonage/client/voice/ncco/NotifyActionTest.java index 339bdd547..f39821421 100644 --- a/src/test/java/com/vonage/client/voice/ncco/NotifyActionTest.java +++ b/src/test/java/com/vonage/client/voice/ncco/NotifyActionTest.java @@ -15,17 +15,26 @@ */ package com.vonage.client.voice.ncco; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; import org.junit.jupiter.api.*; +import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.*; public class NotifyActionTest { @Test public void testBuilderMultipleInstances() { - NotifyAction.Builder builder = NotifyAction.builder(new HashMap<>(), "http://example.com/webhooks/event"); + var map = Collections. emptyMap(); + var url = "http://example.com/webhooks/event"; + + NotifyAction.Builder builder = NotifyAction.builder(); assertNotSame(builder.build(), builder.build()); + assertNotSame( + NotifyAction.builder(map, new String[]{url}), + NotifyAction.builder(map, Collections.singleton(url)) + ); } @Test diff --git a/src/test/java/com/vonage/client/voice/ncco/RecordActionTest.java b/src/test/java/com/vonage/client/voice/ncco/RecordActionTest.java index 232d83fd7..029772511 100644 --- a/src/test/java/com/vonage/client/voice/ncco/RecordActionTest.java +++ b/src/test/java/com/vonage/client/voice/ncco/RecordActionTest.java @@ -32,9 +32,9 @@ public void testBuilderMultipleInstances() { public void testAllFields() { RecordAction record = RecordAction.builder() .transcription(TranscriptionSettings.builder().sentimentAnalysis(false).build()) - .format(RecordingFormat.MP3).split(SplitRecording.CONVERSATION) - .eventMethod(EventMethod.POST).eventUrl("https://example.com").channels(10) - .endOnSilence(3).endOnKey('#').timeOut(5).beepStart(true).build(); + .format(RecordingFormat.MP3).eventMethod(EventMethod.POST) + .eventUrl("https://example.com").channels(10).endOnSilence(3) + .endOnKey('#').timeOut(5).beepStart(true).build(); TestUtils.testJsonableBaseObject(record); String expectedJson = "[{\"format\":\"mp3\",\"endOnSilence\":3,\"timeOut\":5," + @@ -70,7 +70,7 @@ public void testFormatField() { @Test public void testSplit() { RecordAction record = RecordAction.builder().split(SplitRecording.CONVERSATION).build(); - assertEquals("[{\"split\":\"conversation\",\"action\":\"record\"}]", new Ncco(record).toJson()); + assertEquals("[{\"action\":\"record\"}]", new Ncco(record).toJson()); } @Test diff --git a/src/test/java/com/vonage/client/voice/ncco/StreamActionTest.java b/src/test/java/com/vonage/client/voice/ncco/StreamActionTest.java index ffe5d8ffd..6beab699e 100644 --- a/src/test/java/com/vonage/client/voice/ncco/StreamActionTest.java +++ b/src/test/java/com/vonage/client/voice/ncco/StreamActionTest.java @@ -17,12 +17,24 @@ import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; +import java.util.Collections; public class StreamActionTest { + @Test public void testBuilderMultipleInstances() { - StreamAction.Builder builder = StreamAction.builder("http://example.com"); + var url = "http://example.com/stream/audio/mp3"; + var builder = StreamAction.builder().streamUrl(url); assertNotSame(builder.build(), builder.build()); + + assertNotSame( + StreamAction.builder(url), + StreamAction.builder(url, url) + ); + assertNotSame( + StreamAction.builder(Collections.singletonList(url)), + StreamAction.builder(new String[]{url}) + ); } @Test diff --git a/src/test/java/com/vonage/client/voice/ncco/WebSocketEndpointTest.java b/src/test/java/com/vonage/client/voice/ncco/WebSocketEndpointTest.java index cefd1a113..ac827fc5d 100644 --- a/src/test/java/com/vonage/client/voice/ncco/WebSocketEndpointTest.java +++ b/src/test/java/com/vonage/client/voice/ncco/WebSocketEndpointTest.java @@ -15,6 +15,7 @@ */ package com.vonage.client.voice.ncco; +import com.vonage.client.users.channels.Websocket; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.*; import java.util.Collections; @@ -25,13 +26,13 @@ public class WebSocketEndpointTest { public void testAllFields() { WebSocketEndpoint endpoint = WebSocketEndpoint.builder("wss://example.com", "some-content") .uri("wss://example.net") - .contentType("some-content-type") + .contentType(Websocket.ContentType.AUDIO_L16_8K) .headers(Collections.singletonMap("keyOne", Collections.singletonList(1))) .build(); ConnectAction connect = ConnectAction.builder(endpoint).build(); - String expectedJson = "[{\"endpoint\":[{\"uri\":\"wss://example.net\",\"content-type\":\"some-content-type\"," + - "\"headers\":{\"keyOne\":[1]},\"type\":\"websocket\"}],\"action\":\"connect\"}]"; + String expectedJson = "[{\"endpoint\":[{\"uri\":\"wss://example.net\",\"content-type\":\"" + + "audio/l16;rate=8000\",\"headers\":{\"keyOne\":[1]},\"type\":\"websocket\"}],\"action\":\"connect\"}]"; assertEquals(expectedJson, new Ncco(connect).toJson()); } }