End-to-End Encryption API
Use the End-to-End Encryption API to encrypt media being sent through a media server from your application.
Important: In OpenTok.js 2.27.0+, end-to-end encryption will not work when connecting to clients using an earlier version of OpenTok.js. When you upgrade your app to use OpenTok.js 2.27.0+, make sure all clients are using OpenTok.js 2.27.0+ if the app uses end-to-end encryption.
Overview
End-to-end encryption (or E2EE) allows application developers to encrypt media in routed sessions from client to client. For relayed sessions, media is already encrypted client-to-client, through WebRTC protocols. This feature adds an encryption layer by encrypting the media payload at the client so that it will remain encrypted through the Media Router that routes media to other clients (in routed sessions). You enable end-to-end encryption when you create a session.
End-to-end encryption is supported in web apps on Chromium-based (Chrome, Opera, Samsung Internet and Edge) and WebKit-based browsers, for example Safari on macOS/iOS and Chrome on iOS. End-to-end encryption is not supported in web apps on Firefox.
WebKit-based browser support is only available from version OpenTok.js 2.30.0 onwards.
End-to-end encryption is supported in each of the native client SDKs (for Android, iOS, Windows, Linux, and macOS).
You set the encryption secret in a web application using OpenTok.js. You must set encryption secrets in the web client when you initialize a session, and you can change encryption secrets on the fly once the session has connected. The encryption secret is a non-empty string. All users must use the same secret to receive intelligible media. The encryption secret is key material for generating a cryptographic key that is used to encrypt and decrypt media. Specifically, the encryption secret generates an AES-256 encryption key using an AES-CTR algorithm with a 256-bit key.
Please note that the Media Router does not have access to unencrypted media when using end-to-end encryption.
So, features that require media decoding --- such as archiving, live streaming broadcasts, experience composer, audio connector, and SIP interconnect --- are unsupported in end-to-end encrypted sessions. .
End-to-End encryption per codec support across endpoints
| Codec/End-point | Chrome | Android Chrome | iOS Chrome | Firefox | Safari | Edge | iOS SDK | Android SDK | Windows SDK | macOS SDK | Linux SDK |
|---|---|---|---|---|---|---|---|---|---|---|---|
| VP8 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| H.264 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| VP9 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Adding end-to-end encryption for your account
End-to-end encryption is available as an add-on feature. You can enable it on your Video account page.
Enabling encryption using the REST API
You enable end-to-end encryption when you create a session using the REST API. Set the e2ee property to true.
See session creation.
Note: Before enabling end-to-end encryption for a session, you must enable it for your Video account.
The following Node.js example creates an end-to-end encryption enabled session:
const Vonage = require('@vonage/server-sdk');
const vonage = new Vonage({
applicationId: APP_ID,
privateKey: PRIVATE_KEY_PATH
});
try {
const session = await vonage.video.createSession({
mediaMode: "routed",
e2ee: true, // This will enable end-to-end encryption
});
} catch(error) {
console.error("Error creating session: ", error);
}
Implementations
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API). To have a React Native client join an end-to-end encrypted session, set the encryptionSecret prop of the OTSession component:
<OTSession
applicationId="api-key"
sessionId="session-id"
token="token"
encryptionSecret="initial-encryption-secret"
>
<OTPublisher />
<OTSubscriber />
</OTSession>
A valid secret is a string between 8 and 256 characters.
You can change the secret by setting the encryptionSecret prop to a property of the React state and changing its value:
<OTSession
applicationId="api-key"
sessionId="session-id"
token="token"
encryptionSecret={this.state.encryptionSecret}>
>
<OTPublisher />
<OTSubscriber />
</OTSession>
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.
The OTSubscriber error() event handler callback is invoked when the subscriber is unable to decode a stream's media due to a mismatched (or unset) encryption secret:
<OTSubscriber
eventHandlers={{
error: event => {
// Show UI notification.
},
}}
>
The OTSession error() event handler callback is invoked if the client tries to connect to an end-to-end encrypted session that was initialized with an invalid encryption secret (or without specifying an encryption secret). A valid secret is a string between 8 and 256 characters. For the best user experience, the application should catch an invalid user supplied secret before setting the OTSession encryptionSecret prop. In the following example, a session is initialized with an empty (and thus invalid) secret, which causes an error when attempting to connect:
<OTSession
applicationId="api-key"
sessionId="session-id"
token="token"
encryptionSecret=""
eventHanders={{
error: event => {
// An error event is dispatched if you set an invalid encryption secret
}
}}
>
<OTPublisher />
<OTSubscriber />
</OTSession>
Important Notes
- In OpenTok.js 2.27.0+, end-to-end encryption will not work when connecting to clients using an earlier version of OpenTok.js. When you upgrade your app to use OpenTok.js 2.27.0+, make sure all clients are using OpenTok.js 2.27.0+ if the app uses end-to-end encryption.
- End-to-end encryption support on WebKit-based browsers, for example Safari on macOS/iOS and Chrome on iOS, is only available from version OpenTok.js 2.30.0 onwards.
Note about Content Security Policies (CSP)
If the script-src directive is set, make sure 'wasm-unsafe-eval' is specified. Otherwise WebAssembly, required for end-to-end encryption, is blocked from loading and executing on the page.
Initializing a session with a secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API). To have a web client join an end-to-end encrypted session, specify an encryption secret when calling the OT.initSession() method:
const session = OT.initSession('api-key', 'session-id', {
encryptionSecret: 'initialEncryptionSecret',
});
A valid secret is a string between 8 and 256 characters. The secret can later be changed with the Session.setEncryptionSecret() method (see Changing the secret, below).
Checking whether the browser supports end-to-end encryption
Use the OT.hasEndToEndEncryptionSupport() method to check if the client's browser supports end-to-end encryption:
if (OT.hasEndToEndEncryptionSupport()) {
// Proceed with connecting to the session
}
else {
// Notify the user that they cannot join the session
}
End-to-end encryption is not currently supported in Firefox.
Changing the secret
You can change the secret using the Session.setEncryptionSecret() method after the session has connected:
await session.setEncryptionSecret('newEncryptionSecret');
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.
A Subscriber object dispatches an encryptionSecretMismatch event when the subscriber is unable to decode a stream's media. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video bug:
subscriber.on('encryptionSecretMismatch', () => {
// Activate a UI element communicating that there's been an encryption secret mismatch.
});
Also, it is important to communicate to users that encryption has been successfully enabled. A Subscriber object dispatches an encryptionSecretMatch event when the subscriber is able to decode the stream's media after a previous mismatch.
Also, it is important to communicate to users that encryption has been successfully enabled. A Subscriber object dispatches an encryptionSecretMatch event when the subscriber is able to decode the stream's media after a previous mismatch.
subscriber.on('encryptionSecretMatch', () => {
// Activate a UI element communicating that the media is being properly decrypted.
});
The Session.connect() callback is invoked with an error if the client tries to connect to an end-to-end encrypted session that was initialized with an invalid encryption secret. A valid secret is a string between 8 and 256 characters. For the best user experience, the application should catch an invalid user supplied secret before calling the OT.initSession() method. In the following example, a session is initialized with an empty (and thus invalid) secret, which causes an error when attempting to connect:
const session = OT.initSession(
'api-key',
'e2ee-session-id',
{
encryptionSecret: '',
}
)
session.connect('token', (error) => {
if (error && error.name === 'OT_INVALID_ENCRYPTION_SECRET') {
/*
The application should communicate that the secret was invalid.
*/
}
});
The Session.connect() callback is invoked with an error if a user attempts to connect to an end-to-end encrypted session in a browser that does not support end-to-end encryption.
const session = OT.initSession(
'api-key',
'e2ee-session-id',
{
encryptionSecret: 'validEncryptionSecret',
}
)
session.connect('token', (error) => {
if (error && error.name === 'OT_UNSUPPORTED_BROWSER') {
/*
The error will have the message 'Tried to connect an e2ee session but the browser does not support e2ee'
The application should communicate that the browser does not support encryption.
*/
}
});
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, the Session.publish() callback is invoked with an error. For the best user experience, the application should validate a user-supplied secret before calling the session.publish() method:
session.publish(publisher, (error) => {
if (error && error.name === 'OT_STREAM_CREATE_FAILED') {
/*
The error will have the message 'Tried to publish to an e2ee session but encryption secret was not set'
The application should communicate that the secret was not set.
*/
}
});
If a user tries to subscribe in an end-to-end encrypted session without having specified an encryption secret, the Session.subscribe() callback is invoked with an error. For the best user experience, the application should validate a user-supplied secret before calling the Session.subscribe() method:
subscriber = session.subscribe(stream, target, opts, (error) => {
if (error && error.name === 'OT_UNABLE_TO_SUBSCRIBE') {
/*
The error will have the message 'Tried to subscribe to an e2ee stream but encryption secret was not set'
The application should communicate that the secret was not set.
*/
}
});
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the Session.setEncryptionSecret() method:
session.setEncryptionSecret("encryption-secret");
session.connect(TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.setEncryptionSecret() function again.
Setting an invalid secret will result in an InvalidEncryptionSecret error.
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.
If a client tries to connect to an end-to-end encrypted session without setting an encryption secret, the SessionListener.onError() event handler is called with an error code set to ErrorCode.EncryptionSecretMissing:
// Implementation of SessionListener.onError():
@Override
public void onError(Session session, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionSecretMissing) {
// Notify the user that they cannot join the session
}
}
session.connect(token);
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the Session.publish() method results in the PublisherListener.onError() event handler being called with an error that has the code set to ErrorCode.EncryptionSecretMissing. For the best user experience, the application should validate a user-supplied secret before calling the Session.publish() method:
// Implementation of PublisherListener.onError():
@Override
public void onError(PublisherKit publisher, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionInternalError) {
// The application should communicate that the secret was not set.
}
}
session.publish(publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the SubscriberListener.onError() event handler is called with an error that has the code set to ErrorCode.EncryptionSecretMismatch. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video issue:
// Implementation of Subscriber.onError():
@Override
public void onError(SubscriberKit publisher, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionSecretMismatch) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
session.subscribe(subscriber);
If the application tries to subscribe without setting an encryption secret, the Subscriber.onError() event handler is called with an error that has the code set to ErrorCode.EncryptionSecretMissing.
If a subscriber encounters an internal error while decrypting a packet, the Subscriber.onError() event handler is called with an error that has the code set to ErrorCode.DecryptionInternalError.
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the [OTSession setEncryptionSecret:error:] method:
var error: OTError?
session.setEncryptionSecret("encryption-secret", error: &error)
if (error)
{
// Notify the user.
}
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.setEncryptionSecret() method again.
Setting an invalid secret will result in an InvalidEncryptionSecret error.
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.
If the client tries to connect to an end-to-end encrypted session and does not set the encryption secret before connecting, an error with the code set to EncryptionSecretMissing:
var error: OTError?
session.connect(withToken: token, error: &error)
if (error && (error.code ==EncryptionSecretMissing))
{
// Notify the user of the error connecting.
}
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the [OTSession publish:error:] method results in an error that has the code set to OTPublisherEncryptionSecretMissing. For the best user experience, the application should validate a user-supplied secret before publishing:
var error: OTError?
session.publish(publisher, error: &error)
if (error && (error.code == EncryptionSecretMissing))
{
// The application should communicate that the secret was not set.
}
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent with an error that has the code set to ErrorCode.EncryptionSecretMismatch. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video issue:
// Implementation of [OTSubscriberKitDelegate subscriber:didFailWithError:]:
func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {
if (error.code == EncryptionSecretMismatch) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
var error: OTError?
session.subscribe(subscriber!, error: &error)
// ...
If a subscriber encounters an internal error while decrypting a packet, the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent with an error that has the code set to OTSubscriberDecryptionInternalError.
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the [OTSession setEncryptionSecret:error:] method:
OTError *error = nil;
[_session setEncryptionSecret:@"encryption-secret" error:&error];
if (error)
{
// Notify the user.
}
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.setEncryptionSecret() method again.
Setting an invalid secret will result in an InvalidEncryptionSecret error.
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.
If the client tries to connect to an end-to-end encrypted session and does not set the encryption secret before connecting, an error with the code set to EncryptionSecretMissing:
OTError *error = nil;
[_session connectWithToken:kToken error:&error];
if (error && (error.code == EncryptionSecretMissing))
{
// Notify the user of the error connecting.
}
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the [OTSession publish:error:] method results in an error that has the code set to OTPublisherEncryptionSecretMissing. For the best user experience, the application should validate a user-supplied secret before publishing:
OTError *error = nil;
[_session publish:_publisher error:&error];
if (error && (error.code == OTPublisherEncryptionSecretMissing))
{
// The application should communicate that the secret was not set.
}
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent with an error that has the code set to ErrorCode.EncryptionSecretMismatch. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video issue:
// Implementation of [OTSubscriberKitDelegate subscriber:didFailWithError:]:
- (void)subscriber:(OTSubscriberKit*)subscriber
didFailWithError:(OTError*)error
{
if (error && (error.code == EncryptionSecretMismatch)) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
[_session subscribe:_subscriber error:&error];
// ...
If a subscriber encounters an internal error while decrypting a packet, the [OTSubscriberKitDelegate subscriber:didFailWithError:] message is sent with an error that has the code set to OTSubscriberDecryptionInternalError.
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the Session.SetEncryptionSecret() method:
Session.SetEncryptionSecret("encryption-secret");
Session.Connect(TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.SetEncryptionSecret() method again.
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.
If a client tries to connect to an end-to-end encrypted session without setting an encryption secret, the Session.Error event is sent with an error code set to ErrorCode.EncryptionSecretMissing:
private void Session_Error(object sender, ErrorEventArgs error)
{
if (Error.ErrorCode == ErrorCode.EncryptionSecretMissing) {
// Notify the user that they cannot join the session
}
}
Session.Error += Session_Error;
Session.Connect(TOKEN);
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the Session.Publish() function results in the Publisher.Error event being sent with an error that has the code set to ErrorCode.EncryptionInternalError. For the best user experience, the application should validate a user-supplied secret before calling the Session.Publish() method:
private void Publisher_Error(object sender, ErrorEventArgs error)
{
if (Error.ErrorCode == ErrorCode.EncryptionInternalError) {
// The application should communicate that the secret was not set.
}
}
Publisher.Error += Publisher_Error;
Session.Publish(Publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the Subscriber.Error event is sent with an error that has the code set to ErrorCode.EncryptionSecretMismatch. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video issue:
private void Subscriber_Error(object sender, ErrorEventArgs error)
{
if (Error.ErrorCode == ErrorCode.EncryptionSecretMismatch) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
Subscriber.Error += Subscriber_Error;
Session.Subscribe(Subscriber);
If a subscriber encounters an internal error while decrypting a packet, the Subscriber.Error event is sent with an error that has the code set to ErrorCode.DecryptionInternalError.
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the [REST API](/video/guides/end-to-end-encryption/overview#enabling-encryption-using-the-rest-api)).Before the client publishes or subscribes, call the otc_session_set_encryption_secret() function:
otc_session_set_encryption_secret(session, secret);
otc_session_connect(session, TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the otc_session_set_encryption_secret() function again.
Passing an invalid secret will result in an OTC_SESSION_INVALID_ENCRYPTION_SECRET error.
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.The new error code is OTC_SESSION_INVALID_ENCRYPTION_SECRET and will be returned as the result code of the set_encryption_secret method, not in the on_error callback.
If a client tries to set an invalid encryption secret for a session, the otc_session_callbacks.on_error() returns an error code set to OTC_SESSION_INVALID_ENCRYPTION_SECRET. In the following example, a session is initialized with an empty (and thus invalid) encryption secret:
int result = otc_session_set_encryption_secret(session, "");
if (result == OTC_SESSION_INVALID_ENCRYPTION_SECRET) {
// Report error...
}
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the otc_session_publish() function results in the otc_publisher_callbacks.on_error() function being called with an error that has the code set to OTC_SESSION_ENCRYPTION_SECRET_MISSING. For the best user experience, the application should validate a user-supplied secret before calling the otc_session_publish() function:
static void on_publisher_error(otc_publisher *publisher,
void *user_data,
const char* error_string,
enum otc_publisher_error_code error_code) {
if (otc_publisher_error_code == "OTC_SESSION_ENCRYPTION_SECRET_MISSING") {
// The application should communicate that the secret was not set.
}
}
struct otc_publisher_callbacks publisher_callbacks = {0};
publisher_callbacks.on_error = on_publisher_error;
session = otc_session_new(API_KEY, SESSION_ID, &session_callbacks);
otc_publisher *publisher = otc_publisher_new("Joe",
nullptr,
&publisher_callbacks);
otc_session_publish(session, publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the subscriber_callbacks.on_error() function is called with an error that has the code set to OTC_SUBSCRIBER_ENCRYPTION_SECRET_MISMATCH. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video issue:
static void on_subscriber_error(otc_subscriber *subscriber,
void *user_data,
const char* error_string,
enum otc_subscriber_error_code error_code) {
if (otc_subscriber_error_code == "OTC_SUBSCRIBER_ENCRYPTION_SECRET_MISMATCH") {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
struct otc_subscriber_callbacks subscriber_callbacks = {0};
subscriber_callbacks.on_error = on_subscriber_error;
otc_subscriber *subscriber = otc_subscriber_new(stream,
&subscriber_callbacks);
otc_session_subscribe(session, subscriber);
If a subscriber encounters an internal error while decrypting a packet, the subscriber_callbacks.on_error() function is called with an error that has the code set to OTC_SUBSCRIBER_DECRYPTION_INTERNAL_ERROR.
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the otc_session_set_encryption_secret() method:
otc_session_set_encryption_secret(session, secret);
otc_session_connect(session, TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the otc_session_set_encryption_secret() function again.
Setting an invalid secret will result in an OTC_SESSION_INVALID_ENCRYPTION_SECRET error.
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.
The new error code is OTC_SESSION_INVALID_ENCRYPTION_SECRET and will be returned as the result code of the set_encryption_secret method, not in the on_error callback.
If a client tries to set an invalid encryption secret for a session, the otc_session_callbacks.on_error() returns an error code set to OTC_SESSION_INVALID_ENCRYPTION_SECRET. In the following example, a session is initialized with an empty (and thus invalid) encryption secret:
int result = otc_session_set_encryption_secret(session, "");
if (result == OTC_SESSION_INVALID_ENCRYPTION_SECRET) {
// Report error...
}
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the otc_session_publish() function results in the otc_publisher_callbacks.on_error() function being called with an error that has the code set to OTC_SESSION_ENCRYPTION_SECRET_MISSING. For the best user experience, the application should validate a user-supplied secret before calling the otc_session_publish() function:
static void on_publisher_error(otc_publisher *publisher,
void *user_data,
const char* error_string,
enum otc_publisher_error_code error_code) {
if (otc_publisher_error_code == OTC_SESSION_ENCRYPTION_SECRET_MISSING) {
// The application should communicate that the secret was not set.
}
}
struct otc_publisher_callbacks publisher_callbacks = {0};
publisher_callbacks.on_error = on_publisher_error;
session = otc_session_new(API_KEY, SESSION_ID, &session_callbacks);
otc_publisher *publisher = otc_publisher_new("Joe",
nullptr,
&publisher_callbacks);
otc_session_publish(session, publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the subscriber_callbacks.on_error() function is called with an error that has the code set to OTC_SUBSCRIBER_ENCRYPTION_SECRET_MISMATCH. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video issue:
static void on_subscriber_error(otc_subscriber *subscriber,
void *user_data,
const char* error_string,
enum otc_subscriber_error_code error_code) {
if (otc_subscriber_error_code == OTC_SUBSCRIBER_ENCRYPTION_SECRET_MISMATCH) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
struct otc_subscriber_callbacks subscriber_callbacks = {0};
subscriber_callbacks.on_error = on_subscriber_error;
otc_subscriber *subscriber = otc_subscriber_new(stream,
&subscriber_callbacks);
otc_session_subscribe(session, subscriber);
If a subscriber encounters an internal error while decrypting a packet, the subscriber_callbacks.on_error() function is called with an error that has the code set to OTC_SUBSCRIBER_DECRYPTION_INTERNAL_ERROR.