Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding support for captions #332

Merged
merged 1 commit into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions lib/captions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
const fetch = require('node-fetch');
const errors = require('./errors');
const pkg = require('../package.json');
const generateJwt = require('./generateJwt');
const generateHeaders = (config) => {
return {
'User-Agent': 'OpenTok-Node-SDK/' + pkg.version,
'X-OPENTOK-AUTH': generateJwt(config),
Accept: 'application/json',
};
};
const api = (config, method, path, body, callback) => {
const rurl = config.apiEndpoint + '/v2/project/' + config.apiKey + path;

const headers = generateHeaders(config);

if (body && ['POST', 'PATCH', 'PUT'].includes(method)) {
headers['Content-Type'] = 'application/json';
}

Promise.resolve(fetch(
rurl,
{
method: method,
body: body ? JSON.stringify(body) : null,
headers: headers,
}
))
.then(async (response) => {
const otResponse = {
statusCode: response.status,
}

const body = await response.text();

callback(null, otResponse, body)
})
.catch(async (error) => {
callback(error);
});
};

exports.startCaptions = (
config,
sessionId,
token,
{
languageCode = 'en-US',
maxDuration = 1800,
partialCaptions = true
},
callback,
) => {
if (typeof callback !== 'function') {
throw new errors.ArgumentError('No callback given to startCaptions');
}

api(
config,
'POST',
'/captions',
{
sessionId: sessionId,
token: token,
languageCode: languageCode,
maxDuration: maxDuration,
partialCaptions: partialCaptions,
},
(err, response, body) => {
if (err) {
callback(err);
return;
}

let responseJson = {};
try {
responseJson = JSON.parse(body);
} catch {

}
switch (response?.statusCode) {
case 200:
const { captionsId } = responseJson
callback(null, captionsId);
break;
case 400:
callback(new errors.RequestError(body));
break;
case 409:
callback(new errors.CaptionsError());
break;
default:
callback(new errors.RequestError('Unexpected response from OpenTok: ' + JSON.stringify({ statusCode: response.statusCode, statusMessage: response.statusMessage })));
}
}
);
};

exports.stopCaptions = (
config,
captionsId,
callback,
) => {
if (typeof callback !== 'function') {
throw new errors.ArgumentError('No callback given to stopArchive');
}

api(
config,
'POST',
`/captions/${captionsId}/stop`,
{},
(err, response, body) => {
if (err) {
callback(err);
return;
}

switch (response?.statusCode) {
case 202:
callback(null, true);
break;
case 400:
callback(new errors.NotFoundError(`No matching captions found for ${captionsId}`));
break;
default:
callback(new errors.RequestError('Unexpected response from OpenTok: ' + JSON.stringify({ statusCode: response.statusCode, statusMessage: response.statusMessage })));
}
}
);
};
3 changes: 3 additions & 0 deletions lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ exports.ArchiveError = function (message) {

exports.ArchiveError.prototype = Object.create(Error.prototype);

exports.CaptionsError = function (message = 'Live captions have already started for this OpenTok Session') {
this.message = message;
};

exports.SipError = function (message) {
this.message = message;
Expand Down
96 changes: 96 additions & 0 deletions lib/opentok.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var errors = require('./errors');
var callbacks = require('./callbacks');
var generateJwt = require('./generateJwt');
var render = require('./render.js');
var captions = require('./captions.js');
var OpenTok;
var key;

Expand Down Expand Up @@ -486,6 +487,100 @@ OpenTok = function (apiKey, apiSecret, env) {
);
};


/**
* Starts live captions for an OpenTok Session
* <p>
* The maximum allowed duration is 4 hours, after which the audio captioning will stop without
* any effect on the ongoing OpenTok Session. An event will be posted to your callback URL if
* provided when starting the captions.
* <p>
* Each OpenTok Session supports only one audio captioning session.
*
* @param sessionId The session ID of the OpenTok session to archive.
*
* @param token A valid OpenTok token with role set to Moderator.
*
* @param options {Object} An optional options object with the following properties (each
* of which is optional):
* <p>
* <ul>
* <li>
* <code>languageCode</code> (String) &mdash; The BCP-47 code for a spoken language used on
* this call. The default value is "en-US". The following language codes are supported:
* "en-AU" (English, Australia), "en-GB" (Englsh, UK), "es-US" (English, US),
* "zh-CN” (Chinese, Simplified), "fr-FR" (French), "fr-CA" (French, Canadian),
* "de-DE" (German), "hi-IN" (Hindi, Indian), "it-IT" (Italian), "ja-JP" (Japanese),
* "ko-KR" (Korean), "pt-BR" (Portuguese, Brazilian), "th-TH" (Thai).
* </li>
* <li>
* <code>maxDuration</code> (Integer) &mdash; The maximum duration for the audio captioning,
* in seconds. The default value is 14,400 seconds (4 hours), the maximum duration allowed.
* The minimum value for maxDuration is 300 (300 seconds, or 5 minutes).
* </li>
* <li>
* <code>partialCaptions</code> (Boolean) &mdash; Whether to enable this to faster captioning
* at the cost of some degree of inaccuracies. The default value is true.
* </li>
* </ul>
*
* For more information on captions, see the
* <a href="https://tokbox.com/developer/rest/#starting-live-captions">OpenTok captions</a>
* programming guide.
*
* @param callback {Function} The function to call upon completing the operation. Two arguments
* are passed to the function:
*
* <ul>
* <li>
* <code>error</code> &mdash; An error object (if the call to the method fails).
* </li>
*
* <li>
* <code>captionID</code> &mdash; The id of the captions
* </li>
*
* </ul>
*
* @method #startCaptions
* @memberof OpenTok
*/

this.startCaptions = captions.startCaptions.bind(null, apiConfig);


/**
* Stops live captions for an OpenTok Session
*
* @param captionId The session ID of the OpenTok session to archive.
*
* </ul>
*
* For more information on captions, see the
* <a href="https://tokbox.com/developer/rest/#starting-live-captions">OpenTok captions</a>
* programming guide.
*
* @param callback {Function} The function to call upon completing the operation. Two arguments
* are passed to the function:
*
* <ul>
* <li>
* <code>error</code> &mdash; An error object (if the call to the method fails).
* </li>
*
* <li>
* <code>success</code> &mdash; True always
* </li>
*
* </ul>
*
* @method #startCaptions
* @memberof OpenTok
*/

this.stopCaptions = captions.stopCaptions.bind(null, apiConfig);


/**
* Retrieves a List of {@link Render} objects, representing any renders in the starting,
* started, stopped or failed state, for your API key.
Expand Down Expand Up @@ -2095,6 +2190,7 @@ OpenTok.prototype.generateToken = function (sessionId, opts) {
}

return encodeToken(tokenData, this.apiKey, this.apiSecret);

};

/*
Expand Down
Loading
Loading