From f094d85e79a188563aab24fbb2157a2529d90708 Mon Sep 17 00:00:00 2001 From: ajay-plivo Date: Tue, 13 Sep 2022 15:45:58 +0530 Subject: [PATCH 01/10] audioStreamAdded --- lib/resources/call.js | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/lib/resources/call.js b/lib/resources/call.js index 4bc181bb..2c2aae04 100644 --- a/lib/resources/call.js +++ b/lib/resources/call.js @@ -12,6 +12,7 @@ import { const clientKey = Symbol(); const action = 'Call/'; const idField = 'callUuid'; +const stream = '/Stream/'; export class CallTransferResponse { constructor(params) { @@ -592,6 +593,57 @@ export class CallInterface extends PlivoResourceInterface { }); } + /** + * Start a Stream over a Call + * @method + * @param {string} serviceUrl - Wss url over which data packets will be send. + * @param {string} callUuid - For this callUuid audio streaming will start. + * @param {object} params - optional params to start a stream + * @param {string} [params.bidirectional] Specifies if the audio being streamed over web-sockets is oneway (read only for the wss service) only or bidirectional (the wss service can read as well as write audio back). + * @param {string} [params.audioTrack] The audio track (inbound or outbound) of the underlying call which Plivo will fork and stream to the wss service. Inbound [default], outbound, both. Note: only inbound is allowed if bidirectional is true. + * @param {string} [params.streamTimeout] Maximum duration, in seconds, for which audio will be streamed once streaming starts. At the end of the specified duration, streaming will stop. This will have no impact on the rest of the call flow. Defaults to 86400 (24 hrs). + * @param {string} [params.statusCallbackUrl] URL that is notified by Plivo when stream is connected, stopped, failed to connect or disconnected. Note: not called when the call gets disconnected. + * @param {string} [params.statusCallbackMethod] POST[default], GET. + * @param {string} [params.contentType] Preferred audio codec and sampling rate. Allowed, audio/x-l16;rate=8000 [default], audio/x-l16;rate=16000 and audio/x-mulaw;rate=8000. + * @param {string} [params.extraHeaders] These are key value pairs which will be passed to the wss service along with your stream. Total length of the string being passed should be less than equal to 512 bytes. + * @promise {object} returns PlivoGenericResponse Object + * @fail {Error} returns Error + */ + + startStream(serviceUrl, callUuid, params = {}) { + let errors = validate([{ + field: 'serviceUrl', + value: serviceUrl, + validators: ['isRequired'] + }, + { + field: 'callUuid', + value: callUuid, + validators: ['isRequired'] + } + ]); + + if (errors) { + return errors; + } + params.serviceUrl = serviceUrl; + params.callUuid = callUuid; + params.isVoiceRequest = 'true'; + + let client = this[clientKey]; + return new Promise((resolve, reject) => { + client('POST', action + idField + stream, params) + .then(response => { + console.log("Response------>", response); + console.log("Response.Body----->", response.body); + resolve(new CreateCallResponse(response.body, idField)); + }) + .catch(error => { + reject(error); + }); + }); + } + /** * Hangup A Specific Call * @method From 0a89016e22b4fc0307871a091ec0983a564eee21 Mon Sep 17 00:00:00 2001 From: ajay-plivo Date: Tue, 13 Sep 2022 17:04:16 +0530 Subject: [PATCH 02/10] VT-4655 --- lib/resources/call.js | 15 +++++++++++++-- types/resources/call.d.ts | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/resources/call.js b/lib/resources/call.js index 2c2aae04..e3f0ef8e 100644 --- a/lib/resources/call.js +++ b/lib/resources/call.js @@ -13,6 +13,7 @@ const clientKey = Symbol(); const action = 'Call/'; const idField = 'callUuid'; const stream = '/Stream/'; +const streamField = 'streamId'; export class CallTransferResponse { constructor(params) { @@ -48,6 +49,16 @@ export class CreateCallResponse { } } +export class StartStreamResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.message = params.message; + this.streamId = params.streamId; + + } +} + export class GetQueuedCallResponse { constructor(params) { @@ -593,7 +604,7 @@ export class CallInterface extends PlivoResourceInterface { }); } - /** + /** * Start a Stream over a Call * @method * @param {string} serviceUrl - Wss url over which data packets will be send. @@ -636,7 +647,7 @@ export class CallInterface extends PlivoResourceInterface { .then(response => { console.log("Response------>", response); console.log("Response.Body----->", response.body); - resolve(new CreateCallResponse(response.body, idField)); + resolve(new StartStreamResponse(response.body, streamField)); }) .catch(error => { reject(error); diff --git a/types/resources/call.d.ts b/types/resources/call.d.ts index f8945c53..dab4739a 100644 --- a/types/resources/call.d.ts +++ b/types/resources/call.d.ts @@ -20,6 +20,12 @@ export class CreateCallResponse { message: string; requestUuid: Array | string; } +export class StartStreamResponse { + constructor(params: object); + apiId: string; + message: string; + streamId: Array | string; +} export class GetQueuedCallResponse { constructor(params: object); apiId: string; @@ -292,6 +298,25 @@ export class CallInterface extends PlivoResourceInterface { * @fail {Error} returns Error */ create(from: string, to: string, answerUrl: string, params ? : {}): Promise < CreateCallResponse > ; + + /** + * Start a Stream over a Call + * @method + * @param {string} serviceUrl - Wss url over which data packets will be send. + * @param {string} callUuid - For this callUuid audio streaming will start. + * @param {object} params - optional params to start a stream + * @param {string} [params.bidirectional] Specifies if the audio being streamed over web-sockets is oneway (read only for the wss service) only or bidirectional (the wss service can read as well as write audio back). + * @param {string} [params.audioTrack] The audio track (inbound or outbound) of the underlying call which Plivo will fork and stream to the wss service. Inbound [default], outbound, both. Note: only inbound is allowed if bidirectional is true. + * @param {string} [params.streamTimeout] Maximum duration, in seconds, for which audio will be streamed once streaming starts. At the end of the specified duration, streaming will stop. This will have no impact on the rest of the call flow. Defaults to 86400 (24 hrs). + * @param {string} [params.statusCallbackUrl] URL that is notified by Plivo when stream is connected, stopped, failed to connect or disconnected. Note: not called when the call gets disconnected. + * @param {string} [params.statusCallbackMethod] POST[default], GET. + * @param {string} [params.contentType] Preferred audio codec and sampling rate. Allowed, audio/x-l16;rate=8000 [default], audio/x-l16;rate=16000 and audio/x-mulaw;rate=8000. + * @param {string} [params.extraHeaders] These are key value pairs which will be passed to the wss service along with your stream. Total length of the string being passed should be less than equal to 512 bytes. + * @promise {object} returns PlivoGenericResponse Object + * @fail {Error} returns Error + */ + startStream(serviceUrl: string, callUuid: string, params ? : {}): Promise < StartStreamResponse > ; + /** * Hangup A Specific Call * @method From 4f388d347c4459b7ce240ab43999ef1dfc693add Mon Sep 17 00:00:00 2001 From: ajay-plivo Date: Tue, 13 Sep 2022 19:11:54 +0530 Subject: [PATCH 03/10] VT-4655 --- lib/resources/call.js | 83 ++++++++++++++++++++++++++++++++++++++- types/resources/call.d.ts | 44 +++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/lib/resources/call.js b/lib/resources/call.js index e3f0ef8e..8f9e2999 100644 --- a/lib/resources/call.js +++ b/lib/resources/call.js @@ -180,6 +180,15 @@ export class RecordCallResponse { } } +export class StartStreamResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.message = params.message; + this.streamId = params.streamId; + } +} + /** * Represents a Call * @constructor @@ -243,6 +252,40 @@ export class Call extends PlivoResource { }); }); } + + + /** + * start audio stream over a call + * @method + * @param {object} params - to start stream + * @promise {object} return PlivoGenericResponse Object + * @fail {Error} return Error + */ + startStream(params= {}) { + params.isVoiceRequest = 'true'; + return this.startStreaming(params); + } + + /** + * start audio stream over a call + * @method + * @param {object} params - to start stream + * @promise {object} return PlivoGenericResponse Object + * @fail {Error} return Error + */ + startStreaming(params) { + let client = this[clientKey]; + return new Promise((resolve, reject) => { + client('POST', action + this.id + '/Stream/', params) + .then(response => { + resolve(new StartStreamResponse(response.body, idField)); + }) + .catch(error => { + reject(error); + }); + }); + } + /** * record call * @method @@ -704,6 +747,44 @@ export class CallInterface extends PlivoResourceInterface { }).transfer(params, callUUID); } + /** + * Start a Stream over a Call + * @method + * @param {string} serviceUrl - Wss url over which data packets will be send. + * @param {string} callUuid - For this callUuid audio streaming will start. + * @param {object} params - optional params to start a stream + * @param {string} [params.bidirectional] Specifies if the audio being streamed over web-sockets is oneway (read only for the wss service) only or bidirectional (the wss service can read as well as write audio back). + * @param {string} [params.audioTrack] The audio track (inbound or outbound) of the underlying call which Plivo will fork and stream to the wss service. Inbound [default], outbound, both. Note: only inbound is allowed if bidirectional is true. + * @param {string} [params.streamTimeout] Maximum duration, in seconds, for which audio will be streamed once streaming starts. At the end of the specified duration, streaming will stop. This will have no impact on the rest of the call flow. Defaults to 86400 (24 hrs). + * @param {string} [params.statusCallbackUrl] URL that is notified by Plivo when stream is connected, stopped, failed to connect or disconnected. Note: not called when the call gets disconnected. + * @param {string} [params.statusCallbackMethod] POST[default], GET. + * @param {string} [params.contentType] Preferred audio codec and sampling rate. Allowed, audio/x-l16;rate=8000 [default], audio/x-l16;rate=16000 and audio/x-mulaw;rate=8000. + * @param {string} [params.extraHeaders] These are key value pairs which will be passed to the wss service along with your stream. Total length of the string being passed should be less than equal to 512 bytes. + * @promise {object} returns PlivoGenericResponse Object + * @fail {Error} returns Error + */ + startStream(serviceUrl, callUUID, optionalParams = {}) { + let errors = validate([{ + field: 'serviceUrl', + value: serviceUrl, + validators: ['isRequired'] + }, + { + field: 'callUUID', + value: callUUID, + validators: ['isRequired'] + } + ]); + + if (errors) { + return errors; + } + + return new Call(this[clientKey], { + id: callUUID + }).startStream(optionalParams); + } + /** * Record a Call * @method @@ -1098,4 +1179,4 @@ class QueuedCallInterface extends PlivoResourceInterface { }); }); } -} +} \ No newline at end of file diff --git a/types/resources/call.d.ts b/types/resources/call.d.ts index dab4739a..e3743bdc 100644 --- a/types/resources/call.d.ts +++ b/types/resources/call.d.ts @@ -117,6 +117,12 @@ export class RecordCallResponse { recordingId: string; url: string; } +export class StartStreamResponse { + constructor(params: object); + apiId: string; + message: string; + streamId: string; +} /** * Represents a Call * @constructor @@ -152,6 +158,25 @@ export class Call extends PlivoResource { blegUrl: string; blegMethod: string; }, callUUid: string): Promise < CallTransferResponse > ; + + /** + * start audio stream over call + * @method + * @param {object} params - to start audio stream over a call + * @promise {object} return PlivoGenericResponse Object + * @fail {Error} return Error + */ + startStream(params: object): Promise < any > ; + + /** + * start audio stream over call + * @method + * @param {object} params - to start audio stream over a call + * @promise {object} return PlivoGenericResponse Object + * @fail {Error} return Error + */ + startStreaming(params: object): Promise < StartStreamResponse > ; + /** * record call * @method @@ -345,6 +370,25 @@ export class CallInterface extends PlivoResourceInterface { blegUrl: string; blegMethod: string; }): Promise < any > ; + + /** + * Start a Stream over a Call + * @method + * @param {string} serviceUrl - Wss url over which data packets will be send. + * @param {string} callUuid - For this callUuid audio streaming will start. + * @param {object} params - optional params to start a stream + * @param {string} [params.bidirectional] Specifies if the audio being streamed over web-sockets is oneway (read only for the wss service) only or bidirectional (the wss service can read as well as write audio back). + * @param {string} [params.audioTrack] The audio track (inbound or outbound) of the underlying call which Plivo will fork and stream to the wss service. Inbound [default], outbound, both. Note: only inbound is allowed if bidirectional is true. + * @param {string} [params.streamTimeout] Maximum duration, in seconds, for which audio will be streamed once streaming starts. At the end of the specified duration, streaming will stop. This will have no impact on the rest of the call flow. Defaults to 86400 (24 hrs). + * @param {string} [params.statusCallbackUrl] URL that is notified by Plivo when stream is connected, stopped, failed to connect or disconnected. Note: not called when the call gets disconnected. + * @param {string} [params.statusCallbackMethod] POST[default], GET. + * @param {string} [params.contentType] Preferred audio codec and sampling rate. Allowed, audio/x-l16;rate=8000 [default], audio/x-l16;rate=16000 and audio/x-mulaw;rate=8000. + * @param {string} [params.extraHeaders] These are key value pairs which will be passed to the wss service along with your stream. Total length of the string being passed should be less than equal to 512 bytes. + * @promise {object} returns PlivoGenericResponse Object + * @fail {Error} returns Error + */ + startStream(serviceUrl: string, callUUID: string, optionalParams: object): Promise < any > ; + /** * Record a Call * @method From 513a5cf828f5c6c9dd0843a2efc584e5d4da764d Mon Sep 17 00:00:00 2001 From: ajay-plivo Date: Tue, 13 Sep 2022 19:16:44 +0530 Subject: [PATCH 04/10] VT-4655 --- lib/resources/call.js | 64 --------------------------------------- types/resources/call.d.ts | 24 --------------- 2 files changed, 88 deletions(-) diff --git a/lib/resources/call.js b/lib/resources/call.js index 8f9e2999..c3a4bc7d 100644 --- a/lib/resources/call.js +++ b/lib/resources/call.js @@ -12,8 +12,6 @@ import { const clientKey = Symbol(); const action = 'Call/'; const idField = 'callUuid'; -const stream = '/Stream/'; -const streamField = 'streamId'; export class CallTransferResponse { constructor(params) { @@ -49,17 +47,6 @@ export class CreateCallResponse { } } -export class StartStreamResponse { - constructor(params) { - params = params || {}; - this.apiId = params.apiId; - this.message = params.message; - this.streamId = params.streamId; - - } -} - - export class GetQueuedCallResponse { constructor(params) { params = params || {}; @@ -647,57 +634,6 @@ export class CallInterface extends PlivoResourceInterface { }); } - /** - * Start a Stream over a Call - * @method - * @param {string} serviceUrl - Wss url over which data packets will be send. - * @param {string} callUuid - For this callUuid audio streaming will start. - * @param {object} params - optional params to start a stream - * @param {string} [params.bidirectional] Specifies if the audio being streamed over web-sockets is oneway (read only for the wss service) only or bidirectional (the wss service can read as well as write audio back). - * @param {string} [params.audioTrack] The audio track (inbound or outbound) of the underlying call which Plivo will fork and stream to the wss service. Inbound [default], outbound, both. Note: only inbound is allowed if bidirectional is true. - * @param {string} [params.streamTimeout] Maximum duration, in seconds, for which audio will be streamed once streaming starts. At the end of the specified duration, streaming will stop. This will have no impact on the rest of the call flow. Defaults to 86400 (24 hrs). - * @param {string} [params.statusCallbackUrl] URL that is notified by Plivo when stream is connected, stopped, failed to connect or disconnected. Note: not called when the call gets disconnected. - * @param {string} [params.statusCallbackMethod] POST[default], GET. - * @param {string} [params.contentType] Preferred audio codec and sampling rate. Allowed, audio/x-l16;rate=8000 [default], audio/x-l16;rate=16000 and audio/x-mulaw;rate=8000. - * @param {string} [params.extraHeaders] These are key value pairs which will be passed to the wss service along with your stream. Total length of the string being passed should be less than equal to 512 bytes. - * @promise {object} returns PlivoGenericResponse Object - * @fail {Error} returns Error - */ - - startStream(serviceUrl, callUuid, params = {}) { - let errors = validate([{ - field: 'serviceUrl', - value: serviceUrl, - validators: ['isRequired'] - }, - { - field: 'callUuid', - value: callUuid, - validators: ['isRequired'] - } - ]); - - if (errors) { - return errors; - } - params.serviceUrl = serviceUrl; - params.callUuid = callUuid; - params.isVoiceRequest = 'true'; - - let client = this[clientKey]; - return new Promise((resolve, reject) => { - client('POST', action + idField + stream, params) - .then(response => { - console.log("Response------>", response); - console.log("Response.Body----->", response.body); - resolve(new StartStreamResponse(response.body, streamField)); - }) - .catch(error => { - reject(error); - }); - }); - } - /** * Hangup A Specific Call * @method diff --git a/types/resources/call.d.ts b/types/resources/call.d.ts index e3743bdc..0e2dc0ff 100644 --- a/types/resources/call.d.ts +++ b/types/resources/call.d.ts @@ -20,12 +20,6 @@ export class CreateCallResponse { message: string; requestUuid: Array | string; } -export class StartStreamResponse { - constructor(params: object); - apiId: string; - message: string; - streamId: Array | string; -} export class GetQueuedCallResponse { constructor(params: object); apiId: string; @@ -324,24 +318,6 @@ export class CallInterface extends PlivoResourceInterface { */ create(from: string, to: string, answerUrl: string, params ? : {}): Promise < CreateCallResponse > ; - /** - * Start a Stream over a Call - * @method - * @param {string} serviceUrl - Wss url over which data packets will be send. - * @param {string} callUuid - For this callUuid audio streaming will start. - * @param {object} params - optional params to start a stream - * @param {string} [params.bidirectional] Specifies if the audio being streamed over web-sockets is oneway (read only for the wss service) only or bidirectional (the wss service can read as well as write audio back). - * @param {string} [params.audioTrack] The audio track (inbound or outbound) of the underlying call which Plivo will fork and stream to the wss service. Inbound [default], outbound, both. Note: only inbound is allowed if bidirectional is true. - * @param {string} [params.streamTimeout] Maximum duration, in seconds, for which audio will be streamed once streaming starts. At the end of the specified duration, streaming will stop. This will have no impact on the rest of the call flow. Defaults to 86400 (24 hrs). - * @param {string} [params.statusCallbackUrl] URL that is notified by Plivo when stream is connected, stopped, failed to connect or disconnected. Note: not called when the call gets disconnected. - * @param {string} [params.statusCallbackMethod] POST[default], GET. - * @param {string} [params.contentType] Preferred audio codec and sampling rate. Allowed, audio/x-l16;rate=8000 [default], audio/x-l16;rate=16000 and audio/x-mulaw;rate=8000. - * @param {string} [params.extraHeaders] These are key value pairs which will be passed to the wss service along with your stream. Total length of the string being passed should be less than equal to 512 bytes. - * @promise {object} returns PlivoGenericResponse Object - * @fail {Error} returns Error - */ - startStream(serviceUrl: string, callUuid: string, params ? : {}): Promise < StartStreamResponse > ; - /** * Hangup A Specific Call * @method From b6ceba99b3e064a3445d7d3d30fad4570af809ac Mon Sep 17 00:00:00 2001 From: ajay-plivo Date: Tue, 13 Sep 2022 19:42:51 +0530 Subject: [PATCH 05/10] VT-4655 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7294f26b..275541dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## [v4.35.0](https://github.com/plivo/plivo-go/tree/v4.35.0) (2022-09-12) +**Feature - Audio Streaming** +- `Audio Stream over Call` added API to start, stop and get audioStream packets over a call. + ## [v4.34.0](https://github.com/plivo/plivo-go/tree/v4.34.0) (2022-08-07) **Feature - Token Creation** - `JWT Token Creation API` added API to create a new JWT token. diff --git a/package.json b/package.json index eae67d22..620a55c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plivo", - "version": "4.34.0", + "version": "4.35.0", "description": "A Node.js SDK to make voice calls and send SMS using Plivo and to generate Plivo XML", "homepage": "https://github.com/plivo/plivo-node", "files": [ From 6e8418101ff806c4fac0a79cf3aac4bcad756b21 Mon Sep 17 00:00:00 2001 From: Prashant Pandey Date: Mon, 3 Oct 2022 03:47:44 +0530 Subject: [PATCH 06/10] VT-4655: Audio Streaming implementation --- lib/resources/call.js | 117 ++++++++++++++++++++++++++++++++++++--- lib/rest/request-test.js | 14 ++++- lib/rest/utils.js | 33 +++++++++++ lib/utils/plivoxml.js | 29 +++++++++- test/calls.js | 13 ++++- test/xml.js | 16 ++++++ 6 files changed, 209 insertions(+), 13 deletions(-) diff --git a/lib/resources/call.js b/lib/resources/call.js index c3a4bc7d..5d300193 100644 --- a/lib/resources/call.js +++ b/lib/resources/call.js @@ -244,19 +244,19 @@ export class Call extends PlivoResource { /** * start audio stream over a call * @method - * @param {object} params - to start stream + * @param {object} params - to start stream * @promise {object} return PlivoGenericResponse Object * @fail {Error} return Error */ - startStream(params= {}) { - params.isVoiceRequest = 'true'; + stream(params= {}) { + params.isVoiceRequest = 'true'; return this.startStreaming(params); } /** * start audio stream over a call * @method - * @param {object} params - to start stream + * @param {object} params - to start stream * @promise {object} return PlivoGenericResponse Object * @fail {Error} return Error */ @@ -273,6 +273,26 @@ export class Call extends PlivoResource { }); } + stopStream(params= {}) { + params.isVoiceRequest = 'true'; + return super.executeAction(this.id + '/Stream/' + this.secondaryId, 'DELETE', params); + } + + stopAllStream(params= {}) { + params.isVoiceRequest = 'true'; + return super.executeAction(this.id + '/Stream/', 'DELETE', params); + } + + getStream(params= {}) { + params.isVoiceRequest = 'true'; + return super.executeAction(this.id + '/Stream/' + this.secondaryId, 'GET', params); + } + + getAllStream(params= {}) { + params.isVoiceRequest = 'true'; + return super.executeAction(this.id + '/Stream/', 'GET', params); + } + /** * record call * @method @@ -699,7 +719,7 @@ export class CallInterface extends PlivoResourceInterface { * @promise {object} returns PlivoGenericResponse Object * @fail {Error} returns Error */ - startStream(serviceUrl, callUUID, optionalParams = {}) { + stream(callUUID, serviceUrl, optionalParams = {}) { let errors = validate([{ field: 'serviceUrl', value: serviceUrl, @@ -711,14 +731,95 @@ export class CallInterface extends PlivoResourceInterface { validators: ['isRequired'] } ]); - + if (errors) { return errors; } + optionalParams.serviceUrl = serviceUrl return new Call(this[clientKey], { id: callUUID - }).startStream(optionalParams); + }).stream(optionalParams); + } + + stopStream(callUUID, streamId){ + let errors = validate([{ + field: 'callUUID', + value: callUUID, + validators: ['isRequired'] + }, + { + field: 'streamId', + value: streamId, + validators: ['isRequired'] + } + ]); + + if (errors) { + return errors; + } + + return new Call(this[clientKey], { + id: callUUID, + secondaryId: streamId + }).stopStream(); + } + + stopAllStream(callUUID){ + let errors = validate([{ + field: 'callUUID', + value: callUUID, + validators: ['isRequired'] + } + ]); + + if (errors) { + return errors; + } + + return new Call(this[clientKey], { + id: callUUID + }).stopAllStream(); + } + + getStream(callUUID, streamId){ + let errors = validate([{ + field: 'callUUID', + value: callUUID, + validators: ['isRequired'] + }, + { + field: 'streamId', + value: streamId, + validators: ['isRequired'] + } + ]); + + if (errors) { + return errors; + } + + return new Call(this[clientKey], { + id: callUUID, + secondaryId: streamId + }).getStream(); + } + + getAllStream(callUUID){ + let errors = validate([{ + field: 'callUUID', + value: callUUID, + validators: ['isRequired'] + } + ]); + + if (errors) { + return errors; + } + + return new Call(this[clientKey], { + id: callUUID + }).getAllStream(); } /** @@ -1115,4 +1216,4 @@ class QueuedCallInterface extends PlivoResourceInterface { }); }); } -} \ No newline at end of file +} diff --git a/lib/rest/request-test.js b/lib/rest/request-test.js index 9d038b3b..9a4c8f10 100644 --- a/lib/rest/request-test.js +++ b/lib/rest/request-test.js @@ -167,7 +167,7 @@ export function Request(config) { "total_rate": "0.03570", "stir_verification": "Not Applicable", "voice_network_group": "India All Networks", - "stir_attestation": "" + "stir_attestation": "" } }); } @@ -197,6 +197,16 @@ export function Request(config) { } }); } + else if (action == 'Call/aaa-deeiei3-dfddd/Stream/' && method == 'POST') { + resolve({ + response: {}, + body: { + message: 'stream started', + stream_id: 'db1d8121-1a75-4b75-bb69-35339bb26240', + api_id: 'c7b69074-58be-11e1-86da-adf28403fe48' + } + }); + } else if (action == 'Call/aaa-deeiei3-dfddd/Record/' && method == 'DELETE') { resolve({ response: {}, @@ -1568,7 +1578,7 @@ export function Request(config) { body: { apiId: '5b058374-bba8-11ec-ab4d-0242ac110002', campaignId: 'CFSOBZQ', - message: 'Request to create campaign was received and is being processed.' + message: 'Request to create campaign was received and is being processed.' } }); } diff --git a/lib/rest/utils.js b/lib/rest/utils.js index 389b651e..aabdf5a5 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -296,3 +296,36 @@ export function validRange(paramName, paramValue, mandatory = false, lowerBound throw new InvalidRequestError("Any one or both of lower and upper bound should be provided") } } + +export function validateStreamAttributes(body, attributes) { + + if (!body) { + return { success: false, msg: "No body set for Stream" }; + } + + if (attributes.extraHeaders) { + console.log("Has headers"); + console.log(typeof attributes.extraHeaders); + console.log(attributes.extraHeaders instanceof Object); + console.log(Object.keys(attributes.extraHeaders).length); + console.log(Object.keys(attributes.extraHeaders).length > 0); + if (attributes.extraHeaders instanceof Object && Object.keys(attributes.extraHeaders).length > 0) { + var headersDict = {}; + Object.entries(attributes.extraHeaders).forEach(([k,v]) => { + if (k.endsWith("X-PH")) { + headersDict[k] = v; + } else { + headersDict[k + "X-PH"] = v; + } + }) + var str = JSON.stringify(headersDict); + attributes.extraHeaders = str.replace('"', '/"'); + } else { + return { success: false, msg: "Invalid data for extraHeaders" }; + } + } + return { + success: true, + attributes: attributes + } +} diff --git a/lib/utils/plivoxml.js b/lib/utils/plivoxml.js index a31a7572..4de60842 100644 --- a/lib/utils/plivoxml.js +++ b/lib/utils/plivoxml.js @@ -14,7 +14,7 @@ export class PlivoXMLError extends Error { } export function Response() { this.element = 'Response'; this.nestables = ['Speak', 'Play', 'GetDigits', 'GetInput', 'Record', 'Dial', 'Message', - 'Redirect', 'Wait', 'Hangup', 'PreAnswer', 'Conference', 'DTMF', 'MultiPartyCall']; + 'Redirect', 'Wait', 'Hangup', 'PreAnswer', 'Conference', 'DTMF', 'MultiPartyCall', 'Stream']; this.valid_attributes = []; this.elem = xmlBuilder.begin().ele(this.element); } @@ -296,6 +296,19 @@ Response.prototype = { } }, + addStream: function (body, attributes) { + + let validation; + validation = plivoUtils.validateStreamAttributes(body, attributes); + var item = this; + if (validation.success == true) { + var result = item.add(new Stream(Response), body, validation.attributes); + return result; + } else { + throw new Exceptions.PlivoXMLValidationError(validation.msg); + } + }, + /** * Add a Break element * @method @@ -703,7 +716,7 @@ Response.prototype = { }, toXML: function () { - return this.elem.toString(); + return this.elem.toString().replace(/"/g, '"'); }, toJSON: jsonStringifier.stringify @@ -1023,3 +1036,15 @@ function MultiPartyCall(Response){ 'startRecordingAudio', 'startRecordingAudioMethod', 'stopRecordingAudio', 'stopRecordingAudioMethod']; } util.inherits(MultiPartyCall, Response); + +/** + * Stream element + * @constructor + */ +function Stream(Response) { + this.element = 'Stream'; + this.valid_attributes = ['bidirectional', 'audioTrack', 'streamTimeout', 'statusCallbackUrl', 'statusCallbackMethod', + 'contentType', 'extraHeaders']; + this.nestables = ['break', 'emphasis', 'lang', 'p', 'phoneme', 'prosody', 's', 'say-as', 'sub', 'w']; +} +util.inherits(Stream, Response); diff --git a/test/calls.js b/test/calls.js index ec654840..5ce80886 100644 --- a/test/calls.js +++ b/test/calls.js @@ -281,5 +281,16 @@ describe('calls', function () { assert.equal(resp.length, 2) }); }); - }) + }); + describe('Stream', function () { + it('should start stream!', function () { + client.calls.stream('aaa-deeiei3-dfddd', 'wss://mystream.ngrok.io/audiostream') + .then(function(call){ + return client.calls.stream(call.callUuid) + }) + .then(function(streamDetail) { + assert.equal(streamDetail.message, 'stream started') + }) + }); + }); }); diff --git a/test/xml.js b/test/xml.js index 7a630474..bdbb7136 100644 --- a/test/xml.js +++ b/test/xml.js @@ -38,4 +38,20 @@ describe('PlivoXML', function () { assert.equal('Nairobi',mpcResponse.toXML()); done(); }); + + it('tests Stream', function (done){ + const streamResponse = new Response(); + var stream_body = "text"; + var extraHeaders = { + 'key1': "val1", + 'key2': "val2" + }; + var params = { + 'audioTrack': "inbound", + 'extraHeaders': extraHeaders + }; + streamResponse.addStream(stream_body, params); + assert.equal('text',streamResponse.toXML()); + done(); + }); }); From 7eca83beab4a2cfbaf5cfb7f17d5ba946a34b325 Mon Sep 17 00:00:00 2001 From: "anindya.mahajan" Date: Tue, 25 Oct 2022 15:36:52 +0530 Subject: [PATCH 07/10] Removed logic for appending 'X-PH' to extraHeaders parameter in Stream XML --- lib/rest/utils.js | 28 ++++++++-------------------- test/xml.js | 2 +- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/lib/rest/utils.js b/lib/rest/utils.js index aabdf5a5..0f0a06d9 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -303,26 +303,14 @@ export function validateStreamAttributes(body, attributes) { return { success: false, msg: "No body set for Stream" }; } - if (attributes.extraHeaders) { - console.log("Has headers"); - console.log(typeof attributes.extraHeaders); - console.log(attributes.extraHeaders instanceof Object); - console.log(Object.keys(attributes.extraHeaders).length); - console.log(Object.keys(attributes.extraHeaders).length > 0); - if (attributes.extraHeaders instanceof Object && Object.keys(attributes.extraHeaders).length > 0) { - var headersDict = {}; - Object.entries(attributes.extraHeaders).forEach(([k,v]) => { - if (k.endsWith("X-PH")) { - headersDict[k] = v; - } else { - headersDict[k + "X-PH"] = v; - } - }) - var str = JSON.stringify(headersDict); - attributes.extraHeaders = str.replace('"', '/"'); - } else { - return { success: false, msg: "Invalid data for extraHeaders" }; - } + if (attributes.extraHeaders && attributes.extraHeaders !== null ) { + console.log("Has headers"); + console.log(typeof attributes.extraHeaders); + console.log(attributes.extraHeaders instanceof Object); + console.log(Object.keys(attributes.extraHeaders).length); + console.log(Object.keys(attributes.extraHeaders).length > 0); + var str = JSON.stringify(attributes.extraHeaders); + attributes.extraHeaders = str.replace('"', '/"'); } return { success: true, diff --git a/test/xml.js b/test/xml.js index bdbb7136..d82a66f2 100644 --- a/test/xml.js +++ b/test/xml.js @@ -51,7 +51,7 @@ describe('PlivoXML', function () { 'extraHeaders': extraHeaders }; streamResponse.addStream(stream_body, params); - assert.equal('text',streamResponse.toXML()); + assert.equal('text',streamResponse.toXML()); done(); }); }); From b6ce24261b34829d7746e5ecfc78ca1dc710112e Mon Sep 17 00:00:00 2001 From: "anindya.mahajan" Date: Mon, 14 Nov 2022 16:57:24 +0530 Subject: [PATCH 08/10] Changed extraHeaders parameter data type implicitly from object to string in XML --- lib/rest/utils.js | 156 ++++++++++++++++++++-------------------------- 1 file changed, 69 insertions(+), 87 deletions(-) diff --git a/lib/rest/utils.js b/lib/rest/utils.js index 0f0a06d9..0a815b20 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -3,9 +3,10 @@ import _snakeCase from 'lodash/snakeCase'; import _mapKeys from 'lodash/mapKeys'; import _mapValues from 'lodash/mapValues'; import _map from 'lodash/map'; -import { parseString } from 'xml2js'; +import {parseString} from 'xml2js'; -export class InvalidRequestError extends Error {} +export class InvalidRequestError extends Error { +} function recursivelyRenameObject(object, renameFunc) { if (!(object instanceof Object)) { @@ -72,7 +73,7 @@ export function camelCaseRequestWrapper(requestFunc) { export function validateSpeakAttributes(content, voice) { if (!voice || ['MAN', 'WOMAN'].indexOf(voice) != -1) { - return { success: true }; + return {success: true}; } var voiceParts = voice.split('.'); @@ -80,115 +81,112 @@ export function validateSpeakAttributes(content, voice) { return { success: false, msg: "Invalid voice " + voice + '.' }; - }; + } + ; return { success: true, } } -export function validSubAccount(accountId){ - if(accountId.constructor !== String){ +export function validSubAccount(accountId) { + if (accountId.constructor !== String) { throw new InvalidRequestError('Subaccount Id must be a string'); } - if(accountId.length !== 20){ + if (accountId.length !== 20) { throw new InvalidRequestError('Subaccount Id should be of length 20'); } - if(accountId.substring(0,2) !== 'SA'){ + if (accountId.substring(0, 2) !== 'SA') { throw new InvalidRequestError("Subaccount Id should start with 'SA'"); } return true; } -export function validMultipleDestinationNos(paramName, paramValue, options = {}){ - if(paramValue.split(options.delimiter).length > 1 && options.role.toLowerCase()!=='agent'){ +export function validMultipleDestinationNos(paramName, paramValue, options = {}) { + if (paramValue.split(options.delimiter).length > 1 && options.role.toLowerCase() !== 'agent') { throw new InvalidRequestError('Multiple ' + paramName + ' values given for role ' + options.role) - } - else if (paramValue.split(options.delimiter).length >= options.agentLimit){ + } else if (paramValue.split(options.delimiter).length >= options.agentLimit) { throw new InvalidRequestError('No of ' + paramName + ' values provided should be lesser than ' + options.agentLimit) - } - else { + } else { return true } } -export function validMultipleDestinationIntegers(paramName, paramValue){ +export function validMultipleDestinationIntegers(paramName, paramValue) { let val = paramValue.split("<"); - for (let i=0; i upperBound) { + if (lowerBound && upperBound) { + if (paramValue < lowerBound || paramValue > upperBound) { throw new InvalidRequestError(paramName + " ranges between " + lowerBound + " and " + upperBound) } - if(paramValue >= lowerBound && paramValue <= upperBound){ + if (paramValue >= lowerBound && paramValue <= upperBound) { return true; } - } - else if(lowerBound){ - if(paramValue < lowerBound){ + } else if (lowerBound) { + if (paramValue < lowerBound) { throw new InvalidRequestError(paramName + " should be greater than " + lowerBound) } - if(paramValue >= lowerBound){ + if (paramValue >= lowerBound) { return true; } - } - else if(upperBound){ - if(paramValue > upperBound){ + } else if (upperBound) { + if (paramValue > upperBound) { throw new InvalidRequestError(paramName + " should be lesser than " + upperBound) } - if(paramValue <= upperBound){ + if (paramValue <= upperBound) { return true; } - } - else{ + } else { throw new InvalidRequestError("Any one or both of lower and upper bound should be provided") } } @@ -300,18 +291,9 @@ export function validRange(paramName, paramValue, mandatory = false, lowerBound export function validateStreamAttributes(body, attributes) { if (!body) { - return { success: false, msg: "No body set for Stream" }; + return {success: false, msg: "No body set for Stream"}; } - if (attributes.extraHeaders && attributes.extraHeaders !== null ) { - console.log("Has headers"); - console.log(typeof attributes.extraHeaders); - console.log(attributes.extraHeaders instanceof Object); - console.log(Object.keys(attributes.extraHeaders).length); - console.log(Object.keys(attributes.extraHeaders).length > 0); - var str = JSON.stringify(attributes.extraHeaders); - attributes.extraHeaders = str.replace('"', '/"'); - } return { success: true, attributes: attributes From 0e4aa59c93e25a829b51b740481223b4451af109 Mon Sep 17 00:00:00 2001 From: anindya-plivo <109207212+anindya-plivo@users.noreply.github.com> Date: Tue, 15 Nov 2022 11:26:25 +0530 Subject: [PATCH 09/10] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 620a55c5..8be944fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plivo", - "version": "4.35.0", + "version": "4.36.0", "description": "A Node.js SDK to make voice calls and send SMS using Plivo and to generate Plivo XML", "homepage": "https://github.com/plivo/plivo-node", "files": [ From daa6369e590a9ede0e309d9823d7b367cd676be1 Mon Sep 17 00:00:00 2001 From: "anindya.mahajan" Date: Tue, 15 Nov 2022 15:11:42 +0530 Subject: [PATCH 10/10] Fixed UT for stream XML --- test/xml.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/xml.js b/test/xml.js index d82a66f2..aeb5600f 100644 --- a/test/xml.js +++ b/test/xml.js @@ -42,16 +42,13 @@ describe('PlivoXML', function () { it('tests Stream', function (done){ const streamResponse = new Response(); var stream_body = "text"; - var extraHeaders = { - 'key1': "val1", - 'key2': "val2" - }; + var extraHeaders = "a=1,b=2"; var params = { 'audioTrack': "inbound", 'extraHeaders': extraHeaders }; streamResponse.addStream(stream_body, params); - assert.equal('text',streamResponse.toXML()); + assert.equal('text',streamResponse.toXML()); done(); }); });