Advanced: Customizing Encryption

Advanced: Customizing Encryption

This page describes how to encrypt voice and video packets by implementing the customized data encryption algorithm of your application.

The following figure shows the data encryption/decryption process:

../_images/developer-encryption_en.png

Step 1: Register a Packet Observer

The Agora Native SDK allows your application to register a packet observer to receive events whenever a voice or video packet is transmitting.

Register a packet observer on your application using the following API:

virtual int registerPacketObserver(IPacketObserver* observer);

The observer must inherit from agora::rtc::IPacketObserver and be implemented in C++. The following example is the definition of the IPacketObserver class:

class IPacketObserver
{
public:

        struct Packet
        {
                const unsigned char* buffer;
                unsigned int size;
        };
        /**
        * called by sdk before the voice packet is sent to other participants
        * @param [in,out] packet:
        *      buffer *buffer points the data to be sent
        *      size of buffer data to be sent
        * @return returns true to send out the packet, returns false to discard the packet
        */
        virtual bool onSendAudioPacket(Packet& packet) = 0;
        /**
        * called by sdk before the video packet is sent to other participants
        * @param [in,out] packet:
        *      buffer *buffer points the data to be sent
        *      size of buffer data to be sent
        * @return returns true to send out the packet, returns false to discard the packet
        */


virtual bool onSendVideoPacket(Packet& packet) = 0;
        /**
        * called by sdk when the voice packet is received from other participants
        * @param [in,out] packet
        *      buffer *buffer points the data to be sent
        *      size of buffer data to be sent
        * @return returns true to process the packet, returns false to discard the packet
        */
        virtual bool onReceiveAudioPacket(Packet& packet) = 0;
        /**
        * called by sdk when the video packet is received from other participants
        * @param [in,out] packet
        *      buffer *buffer points the data to be sent
        *      size of buffer data to be sent
        * @return returns true to process the packet, returns false to discard the packet
        */
        virtual bool onReceiveVideoPacket(Packet& packet) = 0;

Step 2: Implement a Customized Data Encryption Algorithm

Inherit from agora::rtc::IPacketObserver to implement the customized data encryption algorithm on your application. The following example uses XOR for data processing. For the Agora Native SDK, sending and receiving packets are handled by different threads, which is why encryption and decryption can use different buffers:

class AgoraPacketObserver : public agora::rtc::IPacketObserver
 {
             public:
                 AgoraPacketObserver()
                 {
                     m_txAudioBuffer.resize(2048);
                     m_rxAudioBuffer.resize(2048);
                     m_txVideoBuffer.resize(2048);
                     m_rxVideoBuffer.resize(2048);
                 }
                 virtual bool onSendAudioPacket(Packet& packet)
                 {
                     int i;
                     //encrypt the packet
                     const unsigned char* p = packet.buffer;
                     const unsigned char* pe = packet.buffer+packet.size;


                              for (i = 0; p < pe && i < m_txAudioBuffer.size(); ++p, ++i)
                     {
                         m_txAudioBuffer[i] = *p ^ 0x55;
                     }
                     //assign a new buffer and the length back to SDK
                     packet.buffer = &m_txAudioBuffer[0];
                     packet.size = i;
                     return true;
                 }

                 virtual bool onSendVideoPacket(Packet& packet)
                 {
                     int i;
                     //encrypt the packet
                     const unsigned char* p = packet.buffer;
                     const unsigned char* pe = packet.buffer+packet.size;
                     for (i = 0; p < pe && i < m_txVideoBuffer.size(); ++p, ++i)
                     {
                         m_txVideoBuffer[i] = *p ^ 0x55;
                     }
                     //assign a new buffer and the length back to SDK
                     packet.buffer = &m_txVideoBuffer[0];
                     packet.size = i;
                     return true;
                 }

                 virtual bool onReceiveAudioPacket(Packet& packet)
                 {
                     int i = 0;
                     //decrypt the packet
                     const unsigned char* p = packet.buffer;
                     const unsigned char* pe = packet.buffer+packet.size;
                     for (i = 0; p < pe && i < m_rxAudioBuffer.size(); ++p, ++i)
                     {
                         m_rxAudioBuffer[i] = *p ^ 0x55;
                     }
                     //assign a new buffer and the length back to SDK
                     packet.buffer = &m_rxAudioBuffer[0];
                     packet.size = i;
                     return true;
                 }

                 virtual bool onReceiveVideoPacket(Packet& packet)
                 {
                     int i = 0;
                     //decrypt the packet
                     const unsigned char* p = packet.buffer;
                     const unsigned char* pe = packet.buffer+packet.size;


                             for (i = 0; p < pe && i < m_rxVideoBuffer.size(); ++p, ++i)
                     {
                         m_rxVideoBuffer[i] = *p ^ 0x55;
                     }
                     //assign a new buffer and the length back to SDK
                     packet.buffer = &m_rxVideoBuffer[0];
                     packet.size = i;
                     return true;
                 }

             private:
                 std::vector<unsigned char> m_txAudioBuffer; //buffer for sending audio data
                 std::vector<unsigned char> m_txVideoBuffer; //buffer for sending video data

                 std::vector<unsigned char> m_rxAudioBuffer; //buffer for receiving audio data
                 std::vector<unsigned char> m_rxVideoBuffer; //buffer for receiving video data
     };

Step 3: Register the Instance

  1. Implement a Java wrapper. For example,

      JNIEXPORT jint JNICALL Java_io_agora_video_demo_RtcEngineEncryption_enableEncryption(JNIEnv *env, jclass clazz, jlong engineHandle)
    {
       typedef jint (*PFN_registerAgoraPacketObserver)(void* engine, agora::rtc::IPacketObserver* observer);
    
       void* handle = dlopen("libagora-rtc-sdk-jni.so", RTLD_LAZY);
       if (!handle)
       {
          __android_log_print(ANDROID_LOG_ERROR, "agora encrypt demo",
    
    "cannot find libagora-rtc-sdk-jni.so");
          return -1;
       }
       PFN_registerAgoraPacketObserver pfn = (PFN_registerAgoraPacketObserver)dlsym(handle, "registerAgoraPacketObserver");
       if (!pfn)
       {
          __android_log_print(ANDROID_LOG_ERROR, "aogra encrypt demo", "cannot find registerAgoraPacketObserver");
          return -2;
       }
       return pfn((void*)engineHandle, &s_packetObserver);
    }
    
    Java wrapper:
    public class RtcEngineEncryption {
        static {
            System.loadLibrary("agora-encrypt-demo-jni");
        }
        public static native int enableEncryption(long rtcEngineHandle);
    }
    
  2. Call registerAgoraPacketObserver to register the instance of the agora::rtc::IPacketObserver class implemented by your application.

Is this page helpful?