本文介绍如何选择加密方案。

通信和直播模式均支持加密功能,但是如果您在直播场景下使用 CDN 推流、录制或储存,声网不建议您使用数据加密功能。

场景 1: 不需要加密

如果您不需要加密,可以删除下载的 SDK 软件包 里的独立动态库 libagora-crypto.so

场景 2: 使用内置的加密算法

使用 Agora SDK 内置的加密算法会用到通信模式下的 API。下图描述了启用了内置加密方案的声网音视频通信方案:

../_images/agora-encryption.png

在下载的 SDK 软件包/libs/arm64-v8a/libs/armeabi-v7a 文件夹下均包含一个独立的动态库 libagora-crypto.so 供 App 动态加载。

步骤 1:

libagora-crypto.so文件放在与你项目内 libagora-rtc-sdk-jni.so 文件所在的相同路径下。

步骤 2: 启用加密功能。

调用 setEncryptionSecret,启用内置加密,并设置数据加密密码。

步骤 3: 设置加密模式。

调用 setEncryptionMode,设置内置的加密方法。

如果您有缩小 SDK 包的考虑,且如果您的 App 已经有了 libcrypto.so ,由于 SDK 包里也包含了一个 libagora-crypto.so ,可以共用一个 .so 文件。 声网提供的 .so库指定版本为 1.0.2g,与 App 使用的库的版本不同。

场景 3: 使用自定义的加密方案

下图描述了集成了自定义加密解密算法的声网音视频通信方案:

../_images/developer-encryption.png

步骤 1: 注册数据包观测器

应用程序可以注册数据包观测器 (Packet Observer), 用于在语音或视频数据包传输时接收事件。在你的应用程序上,调用以下 API 注册数据包观测器:

virtual int registerPacketObserver(IPacketObserver* observer);

观测器必须继承 agora::IPacketObserver类,且用 C++ 语言实现。以下为 IPacketObserver 类的定义:

class IPacketObserver
{
public:

struct Packet
{
        /** Buffer address of the sent or received data.
         */
const unsigned char* buffer;
        /** Buffer size of the sent or received data.
         */
unsigned int size;
};
/** An audio packet is sent to other users.

     @param packet See Packet.
     @return
     - true: The packet is sent successfully.
     - false: The packet is discarded.
     */
virtual bool onSendAudioPacket(Packet& packet) = 0;
/** A video packet is sent to other users.

     @param packet See Packet.
     @return
     - true: The packet is sent successfully.
     - false: The packet is discarded.
     */
virtual bool onSendVideoPacket(Packet& packet) = 0;
/** An audio packet is sent by other users.

     @param packet See Packet.
     @return
     - true: The packet is received successfully.
     - false: The packet is discarded.
*/
virtual bool onReceiveAudioPacket(Packet& packet) = 0;
/** A video packet is sent by other users.

     @param packet See Packet.
     @return
     - true: The packet is received successfully.
     - false: The packet is discarded.
*/
virtual bool onReceiveVideoPacket(Packet& packet) = 0;
};

步骤 2: 使用定制的数据加密算法

继承 agora::IPacketObserver,在你的应用程序上使用你自定义的数据加密算法。

class AgoraPacketObserver : public agora::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 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 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 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 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
 };

步骤 3: 注册实例

  1. 实现一个 java 包装程序。例如:

      JNIEXPORT jint JNICALL Java_io_agora_video_demo_RtcEngineEncryption_enableEncryption(JNIEnv *env, jclass clazz, jlong engineHandle)
    {
       typedef jint (*PFN_registerAgoraPacketObserver)(void* engine, agora::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. 调用 registerAgoraPacketObserver 为应用程序使用的 agora::IPacketObserver 类注册一个实例。