Skip to content
On this page

Audio Encoding & Encryption

Plasmo Voice uses the 'Opus' codec to encode audio packets and 'AES/CBC/PKCS5Padding' encryption to encrypt the audio packets.

Encoding & Encryption

TIP

For most use-cases it's easier to use an AudioSender.

If you want to send your own PCM audio frames, you need to encode each frame with Opus and then encrypt it with AES.

Each frame should be a 20ms 48kHz 16-bit frame.

java
PlasmoVoiceServer voiceServer = /**/;
short[] audioFrame = new short[960];

AudioEncoder encoder = voiceServer.createOpusEncoder(false); // false means mono
Encryption encryption = voiceServer.getDefaultEncryption();

try {
    byte[] encodedFrame = encoder.encode(audioFrame);
    byte[] encryptedFrame = encryption.encrypt(encodedFrame);
    
    // .. send encryptedFrame to the source
} catch (CodecException e) {
    throw new RuntimeException("Failed to encode audio frame", e);
} catch (EncryptionException e) {
    throw new RuntimeException("Failed to encrypt audio frame", e);
}

encoder.close()
kotlin
val voiceServer: PlasmoVoiceServer = /**/;
val audioFrame = ShortArray(960) { 0 }

val encoder = voiceServer.createOpusEncoder(false); // false means mono
val encryption = voiceServer.defaultEncryption

try {
    val encodedFrame = encoder.encode(audioFrame);
    val encryptedFrame = encryption.encrypt(encodedFrame);

    // ... send encryptedFrame to the source
} catch (e: CodecException) {
    throw RuntimeException("Failed to encode audio frame", e);
} catch (e: EncryptionException) {
    throw RuntimeException("Failed to encrypt audio frame", e);
}

encoder.close()

WARNING

To prevent memory leaks, you need to close the AudioEncoder if it is no longer used.

Decoding & Decryption

To obtain a raw PCM audio frame received from the client, decrypt it with AES and decode it with Opus:

java
PlasmoVoiceServer voiceServer = /**/;
byte[] encryptedFrame = /**/;

AudioDecoder decoder = voiceServer.createOpusDecoder(false);
Encryption encryption = voiceServer.getDefaultEncryption();

try {
    byte[] decryptedFrame = encryption.decrypt(encryptedFrame);
    short[] audioFrame = decoder.decode(decryptedFrame);
    
    // do whatever you want
} catch (CodecException e) {
    throw new RuntimeException("Failed to decrypt audio frame", e);
} catch (EncryptionException e) {
    throw new RuntimeException("Failed to decode audio frame", e);
}

decoder.close();
kotlin
val voiceServer: PlasmoVoiceServer = /**/;
val encryptedFrame: ByteArray = /**/;

val decoder = voiceServer.createOpusDecoder(false)
val encryption = voiceServer.defaultEncryption

try {
    val decryptedFrame = encryption.decrypt(encryptedFrame)
    val audioFrame = decoder.decode(decryptedFrame)

    // ...
} catch (e: CodecException) {
    throw RuntimeException("Failed to decrypt audio frame", e)
} catch (e: EncryptionException) {
    throw RuntimeException("Failed to decode audio frame", e)
}

decoder.close()

WARNING

To prevent memory leaks, you need to close the AudioDecoder if it is no longer used.