From 47cf892febbcd632f98558efaa6638aca584fb29 Mon Sep 17 00:00:00 2001 From: Sina Madani Date: Fri, 6 Sep 2024 17:12:23 +0100 Subject: [PATCH] Voice KDocs & small tweaks --- CHANGELOG.md | 32 +- src/main/kotlin/com/vonage/client/kt/Video.kt | 2 +- src/main/kotlin/com/vonage/client/kt/Voice.kt | 323 +++++++++++++++++- .../com/vonage/client/kt/AbstractTest.kt | 4 +- .../kotlin/com/vonage/client/kt/UsersTest.kt | 6 +- .../kotlin/com/vonage/client/kt/VoiceTest.kt | 28 +- 6 files changed, 351 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b533b6a..7513d10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,23 +4,31 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.0.0] - 2024-09-?? +## [1.0.0] - 2024-09-12 GA release! +### [1.0.0-beta2] - 2024-09-06 + ### Added -- Documentation (KDocs) for all classes and methods. +- Documentation (KDocs) for all classes and methods ### Changed -- Moved Video API's `connectToWebSocket`, `startRender` and `sipDial` methods to `ExistingSession`. +- Moved Video API's `connectToWebSocket`, `startRender` and `sipDial` methods to `ExistingSession` +- `CallsFilter.Builder.dateStart` and `dateEnd` extension functions now accept `Instant` instead of `String` +- `Voice.inputAction` requires body +- `Voice.connectToWebSocket` and `Call.Builder.toWebSocket` `contentType` parameter changed to (mandatory) enum + +### Removed +- `Voice.ExistingCall.transfer(URI)` method ## [1.0.0-beta1] - 2024-09-02 -Feature-complete beta release. +Feature-complete beta release ### Added - Video API ### Changed -- Renamed `VerifyLegacy.ExistingRequest#search` to `info` for consistency with other APIs. +- Renamed `VerifyLegacy.ExistingRequest#search` to `info` for consistency with other APIs ### Changed - Standardised `Existing*` classes to extend `ExistingResource` for consistency. @@ -42,8 +50,8 @@ Feature-complete beta release. - Account API ### Changed -- Explicit return types for all methods. -- Introduced `ExistingRequest` class to Verify (v2) to reduce duplicating `requestId` parameter. +- Explicit return types for all methods +- Introduced `ExistingRequest` class to Verify (v2) to reduce duplicating `requestId` parameter ## [0.6.0] - 2024-07-30 @@ -52,8 +60,8 @@ Feature-complete beta release. - Number Verification API ### Changed -- `InputAction.Builder#dtmf` extension method uses `DtmfSettings` builder instead of setters. -- `Messages#send` now uses optional Boolean parameter for sandbox instead of separate method. +- `InputAction.Builder#dtmf` extension method uses `DtmfSettings` builder instead of setters +- `Messages#send` now uses optional Boolean parameter for sandbox instead of separate method ## [0.5.0] - 2024-07-25 @@ -68,7 +76,7 @@ Feature-complete beta release. ## [0.3.1] - 2024-07-12 ### Changed -- Upgraded Java SDK version to 8.9.2. +- Upgraded Java SDK version to 8.9.2 ## [0.3.0] - 2024-07-08 @@ -87,10 +95,10 @@ Feature-complete beta release. - Voice API ### Fixed -- `authFromEnv` now checks for absent environment variables before attempting to set them. +- `authFromEnv` now checks for absent environment variables before attempting to set them ## [0.1.0] - 2024-06-25 -Initial version. +Initial version ### Added - Messages API diff --git a/src/main/kotlin/com/vonage/client/kt/Video.kt b/src/main/kotlin/com/vonage/client/kt/Video.kt index a39da72..d6b5c88 100644 --- a/src/main/kotlin/com/vonage/client/kt/Video.kt +++ b/src/main/kotlin/com/vonage/client/kt/Video.kt @@ -40,7 +40,7 @@ class Video(private val client: VideoClient) { /** * Call this method to work with an existing session. * - * @param sessionId The UUID of the session to work with. + * @param sessionId ID of the session to work with. * * @return An [ExistingSession] object with methods to interact with the session. */ diff --git a/src/main/kotlin/com/vonage/client/kt/Voice.kt b/src/main/kotlin/com/vonage/client/kt/Voice.kt index b08ecbf..61a9651 100644 --- a/src/main/kotlin/com/vonage/client/kt/Voice.kt +++ b/src/main/kotlin/com/vonage/client/kt/Voice.kt @@ -15,9 +15,9 @@ */ package com.vonage.client.kt +import com.vonage.client.users.channels.Websocket import com.vonage.client.voice.* import com.vonage.client.voice.ncco.* -import java.net.URI import java.time.Instant import java.util.* @@ -28,95 +28,315 @@ import java.util.* */ class Voice internal constructor(private val client: VoiceClient) { + /** + * Call this method to work with an existing call. + * + * @param callId UUID of the call to work with. + */ fun call(callId: String): ExistingCall = ExistingCall(callId) + /** + * Class for working with an existing call. + * + * @property id The call ID. + */ inner class ExistingCall internal constructor(id: String): ExistingResource(id) { + /** + * Get information about the call. + * + * @return Details of the call. + */ fun info(): CallInfo = client.getCallDetails(id) + /** + * End the call. + */ fun hangup(): Unit = client.terminateCall(id) + /** + * Mute the call. The other party will not be able to hear this call. + */ fun mute(): Unit = client.muteCall(id) + /** + * Unmute the call. The other party will be able to hear this call again. + */ fun unmute(): Unit = client.unmuteCall(id) + /** + * Earmuff the call. This call will not be able to hear audio. + */ fun earmuff(): Unit = client.earmuffCall(id) + /** + * Unearmuff the call. This call will be able to hear audio again. + */ fun unearmuff(): Unit = client.unearmuffCall(id) + /** + * Transfer the call using an NCCO. + * + * @param actions The actions to perform after the transfer. + */ fun transfer(vararg actions: Action): Unit = client.transferCall(id, Ncco(actions.asList())) + /** + * Transfer the call using an answer URL. + * + * @param nccoUrl URL of the endpoint that will return the NCCO to execute after the transfer. + */ fun transfer(nccoUrl: String): Unit = client.transferCall(id, nccoUrl) - fun transfer(nccoUrl: URI): Unit = transfer(nccoUrl.toString()) - + /** + * Play DTMF tones into the call. + * + * @param digits The digits to send. Valid characters are `0-9`, `#`, `*` and `p`, + * which indicates a short pause between tones. + * + * @return The DTMF status and call leg ID. + */ fun sendDtmf(digits: String): DtmfResponse = client.sendDtmf(id, digits) + /** + * Play an audio file to the call. + * + * @param url The publicly accessible URL of the audio file to play. + * @param loop The number of times to loop the audio file. + * @param level The volume level at which to play the audio file, between -1 (quietest) and 1 (loudest). + * + * @return The stream status and call leg ID. + */ fun streamAudio(streamUrl: String, loop: Int = 1, level: Double = 0.0): StreamResponse = client.startStream(id, streamUrl, loop, level) + /** + * Stop playing audio into the call. + * + * @return The stream status and call leg ID. + */ fun stopStream(): StreamResponse = client.stopStream(id) + /** + * Speak text into the call. + * + * @param text The text to speak. + * @param properties (OPTIONAL) Additional properties for the talk action. + * + * @return The talk status and call leg ID. + */ fun startTalk(text: String, properties: (TalkPayload.Builder.() -> Unit) = {}): TalkResponse = client.startTalk(id, TalkPayload.builder(text).apply(properties).build()) + /** + * Stop the Text-to-Speech (TTS). + * + * @return The talk status and call leg ID. + */ fun stopTalk(): TalkResponse = client.stopTalk(id) } + /** + * Retrieve details of your calls. + * + * @param filter (OPTIONAL) A lambda function for specifying the parameters to narrow down the results. + */ fun listCalls(filter: (CallsFilter.Builder.() -> Unit)? = null): CallInfoPage = if (filter == null) client.listCalls() else client.listCalls(CallsFilter.builder().apply(filter).build()) - fun createCall(call: Call.Builder.() -> Unit): CallEvent = - client.createCall(Call.builder().apply(call).build()) + /** + * Initiate an outbound call. + * + * @param properties A lambda function for specifying the call's parameters. + * + * @return Details of the created call. + */ + fun createCall(properties: Call.Builder.() -> Unit): CallEvent = + client.createCall(Call.builder().apply(properties).build()) } -fun CallsFilter.Builder.dateStart(dateStart: String): CallsFilter.Builder = - dateStart(Date.from(Instant.parse(dateStart))) +/** + * Sets the start date for the [Voice.listCalls] filter. + * + * @param dateStart ISO-8601 timestamp start retrieving calls from. + * + * @return The updated [CallsFilter.Builder]. + */ +fun CallsFilter.Builder.dateStart(dateStart: Instant): CallsFilter.Builder = dateStart(Date.from(dateStart)) -fun CallsFilter.Builder.dateEnd(dateEnd: String): CallsFilter.Builder = - dateEnd(Date.from(Instant.parse(dateEnd))) +/** + * Sets the end date for the [Voice.listCalls] filter. + * + * @param dateStart ISO-8601 timestamp to stop retrieving calls from. + * + * @return The updated [CallsFilter.Builder]. + */ +fun CallsFilter.Builder.dateEnd(dateEnd: Instant): CallsFilter.Builder = dateEnd(Date.from(dateEnd)) +/** + * Configure the behavior of Advanced Machine Detection. This overrides [Call.Builder#machineDetection] setting + * and is a premium feature, so you cannot set both. + * + * @param amd A lambda function for configuring the Advanced Machine Detection settings. + * + * @return The updated [Call.Builder]. + */ fun Call.Builder.advancedMachineDetection(amd: AdvancedMachineDetection.Builder.() -> Unit = {}): Call.Builder = advancedMachineDetection(AdvancedMachineDetection.builder().apply(amd).build()) +/** + * Configure the behavior of Automatic Speech Recognition to enable speech input. This setting is mutually + * exclusive with [Call.Builder#dtmf], so you must provide one or the other for receiving input from the callee. + * + * @param settings (OPTIONAL) A lambda function for configuring the speech recognition settings. + * + * @return The updated [InputAction.Builder]. + */ fun InputAction.Builder.speech(settings: SpeechSettings.Builder.() -> Unit = {}): InputAction.Builder = speech(SpeechSettings.builder().apply(settings).build()) +/** + * Configure the behavior of Dual-Tone Multi-Frequency (DTMF) input. This setting is mutually exclusive with + * [Call.Builder#speech], so you must provide one or the other for receiving input from the callee. + * + * @param settings (OPTIONAL) A lambda function for configuring the DTMF settings. + * + * @return The updated [InputAction.Builder]. + */ fun InputAction.Builder.dtmf(settings: DtmfSettings.Builder.() -> Unit = {}): InputAction.Builder = dtmf(DtmfSettings.builder().apply(settings).build()) +/** + * Configure the behaviour of call recording transcription. If present (even if all settings are default), + * transcription is activated. The [ConversationAction.Builder.record] parameter must also be set to `true`. + * + * @param settings (OPTIONAL) A lambda function for configuring the transcription settings. + * + * @return The updated [ConversationAction.Builder]. + */ fun ConversationAction.Builder.transcription(settings: TranscriptionSettings.Builder.() -> Unit = {}): ConversationAction.Builder = transcription(TranscriptionSettings.builder().apply(settings).build()) +/** + * Configure the behaviour of call recording transcription. Calling this method activates transcription. + * + * @param settings (OPTIONAL) A lambda function for configuring the transcription settings. + * + * @return The updated [RecordAction.Builder]. + */ fun RecordAction.Builder.transcription(settings: TranscriptionSettings.Builder.() -> Unit = {}): RecordAction.Builder = transcription(TranscriptionSettings.builder().apply(settings).build()) +/** + * Configure the behavior of Advanced Machine Detection. This overrides [ConnectAction.Builder#machineDetection] + * setting and is a premium feature, so you cannot set both. + * + * @param amd A lambda function for configuring the Advanced Machine Detection settings. + * + * @return The updated [ConnectAction.Builder]. + */ fun ConnectAction.Builder.advancedMachineDetection(amd: AdvancedMachineDetection.Builder.() -> Unit = {}): ConnectAction.Builder = advancedMachineDetection(AdvancedMachineDetection.builder().apply(amd).build()) +/** + * Builds an NCCO action to record the call. + * + * @param properties (OPTIONAL) A lambda function for configuring parameters of the record action. + * + * @return A new [RecordAction] with the specified properties. + */ fun recordAction(properties: RecordAction.Builder.() -> Unit = {}): RecordAction = RecordAction.builder().apply(properties).build() +/** + * Builds an NCCO action to play Text-to-Speech into the call. + * + * @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. + * + * @param properties (OPTIONAL) A lambda function for configuring additional parameters of the TTS action. + * + * @return A new [TalkAction] with the specified properties. + */ fun talkAction(text: String, properties: TalkAction.Builder.() -> Unit = {}): TalkAction = TalkAction.builder(text).apply(properties).build() +/** + * Builds an NCCO action to play an audio stream into the call. + * + * @param streamUrl The URL of the audio stream to play. + * + * @param properties (OPTIONAL) A lambda function for configuring additional parameters of the stream action. + * + * @return A new [StreamAction] with the specified properties. + */ fun streamAction(streamUrl: String, properties: StreamAction.Builder.() -> Unit = {}): StreamAction = StreamAction.builder(streamUrl).apply(properties).build() +/** + * Builds an NCCO action to send custom events to a configured webhook. + * + * @param eventUrl The URL to send events to. If you return an NCCO when you receive a notification, + * it will replace the current NCCO. + * + * @param payload A map of key-value pairs to send as the event payload. + * + * @param eventMethod (OPTIONAL) The HTTP method to use when sending the event. + * + * @return A new [NotifyAction] with the specified properties. + */ fun notifyAction(eventUrl: String, payload: Map, eventMethod: EventMethod? = null): NotifyAction = NotifyAction.builder(payload, eventUrl).eventMethod(eventMethod).build() -fun inputAction(properties: InputAction.Builder.() -> Unit = {}): InputAction = +/** + * Builds an NCCO action for gathering input from the call via DTMF or speech recognition. + * + * @param properties A lambda function for configuring the input action parameters. + * + * @return A new [InputAction] with the specified properties. + */ +fun inputAction(properties: InputAction.Builder.() -> Unit): InputAction = InputAction.builder().apply(properties).build() +/** + * Builds an NCCO action to enable hosting conference calls, while preserving the communication context. + * + * @param name The name of the conversation. + * + * @param properties (OPTIONAL) A lambda function for configuring the Conversation action parameters. + * + * @return A new [ConversationAction] with the specified properties. + */ fun conversationAction(name: String, properties: ConversationAction.Builder.() -> Unit = {}): ConversationAction = ConversationAction.builder(name).apply(properties).build() +/** + * Builds an NCCO action to connect the call to another destination. This is the underlying method that other + * `connectTo*` methods in [Voice] use to build their actions. It is recommended to use those instead. + * + * @param endpoint The endpoint to connect the call to. + * + * @param properties (OPTIONAL) A lambda function for configuring the connect action parameters. + * + * @return A new [ConnectAction] with the specified properties. + */ fun connectAction(endpoint: com.vonage.client.voice.ncco.Endpoint, properties: ConnectAction.Builder.() -> Unit = {}): ConnectAction = ConnectAction.builder(endpoint).apply(properties).build() +/** + * Builds an NCCO action to connect the call to a PSTN number. + * + * @param number The MSISDN to connect the call to, in E.164 format. + * @param dtmfAnswer (OPTIONAL) The DTMF digits to send when the call is answered. + * @param onAnswerUrl (OPTIONAL) The URL to fetch a new NCCO from when the call is answered. + * @param onAnswerRingback (OPTIONAL) The URL to fetch a ringback tone from when the call is answered. + * @param properties (OPTIONAL) A lambda function for additional configuration of the connect action parameters. + * + * @return A new [ConnectAction] with the [com.vonage.client.voice.ncco.PhoneEndpoint] and specified properties. + */ fun connectToPstn(number: String, dtmfAnswer: String? = null, onAnswerUrl: String? = null, onAnswerRingback: String? = null, properties: ConnectAction.Builder.() -> Unit = {}) : ConnectAction = @@ -124,18 +344,55 @@ fun connectToPstn(number: String, dtmfAnswer: String? = null, .dtmfAnswer(dtmfAnswer).onAnswer(onAnswerUrl, onAnswerRingback).build(), properties ) +/** + * Builds an NCCO action to connect the call to a Vonage Business Communications (VBC) extension. + * + * @param extension The VBC extension number to connect the call to. + * + * @param properties (OPTIONAL) A lambda function for additional configuration of the connect action parameters. + * + * @return A new [ConnectAction] with the [com.vonage.client.voice.ncco.VbcEndpoint] and specified properties. + */ fun connectToVbc(extension: String, properties: ConnectAction.Builder.() -> Unit = {}) : ConnectAction = connectAction(com.vonage.client.voice.ncco.VbcEndpoint.builder(extension).build(), properties) +/** + * Builds an NCCO action to connect the call to an RTC capable application. + * + * @param user The username to connect the call to. + * @param properties (OPTIONAL) A lambda function for additional configuration of the connect action parameters. + * + * @return A new [ConnectAction] with the [com.vonage.client.voice.ncco.AppEndpoint] and specified properties. + */ fun connectToApp(user: String, properties: ConnectAction.Builder.() -> Unit = {}) : ConnectAction = connectAction(com.vonage.client.voice.ncco.AppEndpoint.builder(user).build(), properties) -fun connectToWebsocket(uri: String, contentType: String, headers: Map? = null, +/** + * Builds an NCCO action to connect the call to a WebSocket endpoint. + * + * @param uri The URI of the WebSocket to connect to. + * @param contentType The internet media type for the audio you are streaming. + * @param headers (OPTIONAL) A map of custom metadata to send with the WebSocket connection. + * @param properties (OPTIONAL) A lambda function for additional configuration of the connect action parameters. + * + * @return A new [ConnectAction] with the [com.vonage.client.voice.ncco.WebSocketEndpoint] and specified properties. + */ +fun connectToWebsocket(uri: String, contentType: Websocket.ContentType, headers: Map? = null, properties: ConnectAction.Builder.() -> Unit = {}) : ConnectAction = - connectAction(com.vonage.client.voice.ncco.WebSocketEndpoint.builder(uri, contentType) + connectAction(com.vonage.client.voice.ncco.WebSocketEndpoint.builder(uri, contentType.toString()) .headers(headers).build(), properties ) +/** + * Builds an NCCO action to connect the call to a SIP endpoint. + * + * @param uri The URI of the SIP endpoint to connect to. + * @param customHeaders (OPTIONAL) A map of custom metadata to send with the SIP connection. + * @param userToUserHeader (OPTIONAL) A string to send as the User-to-User header, as per RFC 7433. + * @param properties (OPTIONAL) A lambda function for additional configuration of the connect action parameters. + * + * @return A new [ConnectAction] with the [com.vonage.client.voice.ncco.SipEndpoint] and specified properties. + */ fun connectToSip(uri: String, customHeaders: Map? = null, userToUserHeader: String? = null, properties: ConnectAction.Builder.() -> Unit = {}) : ConnectAction { val builder = com.vonage.client.voice.ncco.SipEndpoint.builder(uri) @@ -148,19 +405,57 @@ fun connectToSip(uri: String, customHeaders: Map? = null, userToUse return connectAction(builder.build(), properties) } +/** + * Sets the call destination to a Public Switched Telephone Network (PSTN) or mobile number. + * + * @param number The MSISDN to call, in E.164 format. + * @param dtmfAnswer (OPTIONAL) The DTMF digits to send when the call is answered. + * + * @return The updated [Call.Builder]. + */ fun Call.Builder.toPstn(number: String, dtmfAnswer: String? = null): Call.Builder = to(com.vonage.client.voice.PhoneEndpoint(number, dtmfAnswer)) +/** + * Sets the call destination to a SIP URI. + * + * @param uri URI of the SIP endpoint to call. + * @param customHeaders (OPTIONAL) A map of custom metadata to send with the SIP connection. + * @param userToUserHeader (OPTIONAL) A string to send as the User-to-User header, as per RFC 7433. + * + * @return The updated [Call.Builder]. + */ fun Call.Builder.toSip(uri: String, customHeaders: Map? = null, userToUserHeader: String? = null): Call.Builder = to(com.vonage.client.voice.SipEndpoint(uri, customHeaders, userToUserHeader)) -fun Call.Builder.toWebSocket(uri: String, contentType: String? = null, +/** + * Sets the call destination to a WebSocket endpoint. + * + * @param uri The URI of the WebSocket to connect to. + * @param contentType The internet media type for the audio you are streaming. + * @param headers (OPTIONAL) A map of custom metadata to send with the WebSocket connection. + */ +fun Call.Builder.toWebSocket(uri: String, contentType: Websocket.ContentType, headers: Map? = null): Call.Builder = - to(com.vonage.client.voice.WebSocketEndpoint(uri, contentType, headers)) + to(com.vonage.client.voice.WebSocketEndpoint(uri, contentType.toString(), headers)) +/** + * Sets the call destination to a Vonage Business Communications (VBC) extension. + * + * @param extension The VBC extension number to call. + * + * @return The updated [Call.Builder]. + */ fun Call.Builder.toVbc(extension: String): Call.Builder = to(com.vonage.client.voice.VbcEndpoint(extension)) +/** + * Sets the call destination to an RTC capable application user. + * + * @param user The username of the application user to call. + * + * @return The updated [Call.Builder]. + */ fun Call.Builder.toApp(user: String): Call.Builder = to(com.vonage.client.voice.AppEndpoint(user)) diff --git a/src/test/kotlin/com/vonage/client/kt/AbstractTest.kt b/src/test/kotlin/com/vonage/client/kt/AbstractTest.kt index b9238cc..763380b 100644 --- a/src/test/kotlin/com/vonage/client/kt/AbstractTest.kt +++ b/src/test/kotlin/com/vonage/client/kt/AbstractTest.kt @@ -27,6 +27,7 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.assertThrows import com.fasterxml.jackson.databind.ObjectMapper +import com.vonage.client.users.channels.Websocket import java.net.URI import java.net.URLEncoder import java.nio.charset.StandardCharsets @@ -66,7 +67,8 @@ abstract class AbstractTest { protected val dtmf = "p*123#" protected val sipUri = "sip:rebekka@sip.example.com" protected val websocketUri = "wss://example.com/socket" - protected val wsContentType = "audio/l16;rate=8000" + protected val wsContentTypeStr = "audio/l16;rate=8000" + protected val wsContentType = Websocket.ContentType.AUDIO_L16_8K protected val clientRef = "my-personal-reference" protected val textHexEncoded = "48656c6c6f2c20576f726c6421" protected val entityId = "1101407360000017170" diff --git a/src/test/kotlin/com/vonage/client/kt/UsersTest.kt b/src/test/kotlin/com/vonage/client/kt/UsersTest.kt index a9659ca..0bc6960 100644 --- a/src/test/kotlin/com/vonage/client/kt/UsersTest.kt +++ b/src/test/kotlin/com/vonage/client/kt/UsersTest.kt @@ -60,7 +60,7 @@ class UsersTest : AbstractTest() { )), "websocket" to listOf(mapOf( "uri" to websocketUri, - "content-type" to wsContentType, + "content-type" to wsContentTypeStr, "headers" to customData )), "mms" to listOf(mapOf( @@ -120,7 +120,7 @@ class UsersTest : AbstractTest() { assertNotNull(websocket) assertEquals(1, websocket.size) assertEquals(URI.create(websocketUri), websocket[0].uri) - assertEquals(Websocket.ContentType.fromString(wsContentType), websocket[0].contentType) + assertEquals(Websocket.ContentType.fromString(wsContentTypeStr), websocket[0].contentType) assertEquals(customData, websocket[0].headers) val sip = channels.sip @@ -273,7 +273,7 @@ class UsersTest : AbstractTest() { customData(customData) channels( Pstn(toNumber), Sip(sipUri, sipUser, sipPassword), - Websocket(websocketUri, Websocket.ContentType.fromString(wsContentType), customData), + Websocket(websocketUri, Websocket.ContentType.fromString(wsContentTypeStr), customData), Vbc(vbcExt.toInt()), Mms(toNumber), Whatsapp(altNumber), Viber(altNumber), Messenger(messengerId) ) diff --git a/src/test/kotlin/com/vonage/client/kt/VoiceTest.kt b/src/test/kotlin/com/vonage/client/kt/VoiceTest.kt index d833bb9..37db160 100644 --- a/src/test/kotlin/com/vonage/client/kt/VoiceTest.kt +++ b/src/test/kotlin/com/vonage/client/kt/VoiceTest.kt @@ -18,7 +18,6 @@ package com.vonage.client.kt import com.vonage.client.common.HttpMethod import com.vonage.client.voice.* import com.vonage.client.voice.ncco.* -import java.net.URI import java.util.* import kotlin.test.* @@ -300,7 +299,6 @@ class VoiceTest : AbstractTest() { @Test fun `transfer call with answer url`() { testModifyCall(nccoUrl = onAnswerUrl, invocation = { - existingCall.transfer(URI.create(onAnswerUrl)) existingCall.transfer(onAnswerUrl) }) } @@ -384,8 +382,8 @@ class VoiceTest : AbstractTest() { fun `list calls all filter parameters`() { mockGet(callsBaseUrl, expectedQueryParams = mapOf( "status" to "unanswered", - "date_start" to startTime, - "date_end" to endTime, + "date_start" to startTimeStr, + "date_end" to endTimeStr, "page_size" to pageSize, "record_index" to recordIndex, "order" to "desc", @@ -394,7 +392,7 @@ class VoiceTest : AbstractTest() { val callsPage = client.listCalls { status(CallStatus.UNANSWERED) - dateStart(startTimeStr); dateEnd(endTimeStr) + dateStart(startTime); dateEnd(endTime) pageSize(pageSize); recordIndex(recordIndex) order(CallOrder.DESCENDING); conversationUuid(conversationId) } @@ -475,9 +473,9 @@ class VoiceTest : AbstractTest() { } testCreateCallToSingleEndpoint(baseMap + mapOf( - "content-type" to wsContentType, "headers" to customHeaders + "content-type" to wsContentTypeStr, "headers" to customHeaders )) { - toWebSocket(websocketUri, wsContentType, customHeaders) + toWebSocket(websocketUri, wsContentTypeStr, customHeaders) } } @@ -512,7 +510,7 @@ class VoiceTest : AbstractTest() { mapOf( "type" to "websocket", "uri" to websocketUri, - "content-type" to wsContentType, + "content-type" to wsContentTypeStr, "headers" to customHeaders ), mapOf( @@ -548,7 +546,7 @@ class VoiceTest : AbstractTest() { com.vonage.client.voice.AppEndpoint(userName), com.vonage.client.voice.PhoneEndpoint(toNumber, dtmf), com.vonage.client.voice.VbcEndpoint(vbcExt), - com.vonage.client.voice.WebSocketEndpoint(websocketUri, wsContentType, customHeaders), + com.vonage.client.voice.WebSocketEndpoint(websocketUri, wsContentTypeStr, customHeaders), com.vonage.client.voice.SipEndpoint(sipUri, customHeaders, userToUserHeader) ) } @@ -571,7 +569,11 @@ class VoiceTest : AbstractTest() { @Test fun `create call with input action required parameters only`() { - testSingleNcco(ncco = inputAction()) + val types = listOf("dtmf", "speech") + testSingleNcco( + additionalParams = mapOf("type" to types), + ncco = inputAction { type(types) } + ) } @Test @@ -645,12 +647,12 @@ class VoiceTest : AbstractTest() { @Test fun `create call with connect to WebSocket ncco`() { testSingleNccoConnect( - mapOf("uri" to websocketUri, "content-type" to wsContentType), - connectToWebsocket(websocketUri, wsContentType) + mapOf("uri" to websocketUri, "content-type" to wsContentTypeStr), + connectToWebsocket(websocketUri) ) testSingleNccoConnect( - mapOf("uri" to websocketUri, "content-type" to wsContentType, "headers" to customHeaders), + mapOf("uri" to websocketUri, "content-type" to wsContentTypeStr, "headers" to customHeaders), connectToWebsocket(websocketUri, wsContentType, customHeaders) ) }