数字版权保护(C/C++)
=============

#### 功能介绍

开发者可以调用DRM Kit的C/C++接口实现DRM证书管理、DRM许可证管理、DRM节目授权、DRM节目解密等数字版权保护功能。

DRM Kit提供MediaKeySystem实现DRM证书管理、DRM许可证管理功能，并管理MediaKeySession实例；MediaKeySession实现DRM节目授权，并可支持Media Kit或AVCodec Kit实现DRM节目解密以实现DRM节目播放。

#### 开发步骤

详细的API说明请参考[Drm](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-drm)。

1.  导入DRM Kit接口。
    
    #include "multimedia/drm\_framework/native\_drm\_common.h"
    #include "multimedia/drm\_framework/native\_drm\_err.h"
    #include "multimedia/drm\_framework/native\_mediakeysession.h"
    #include "multimedia/drm\_framework/native\_mediakeysystem.h"
    
2.  在CMake脚本中链接动态库。
    
    target\_link\_libraries(PUBLIC libnative\_drm.so)
    
3.  获取设备支持的DRM解决方案名称和唯一标识的列表。
    
    uint32\_t count = 3; // count是当前设备实际支持的DRM插件的个数，用户根据实际情况设置。
    DRM\_MediaKeySystemDescription descriptions\[3\];
    memset(descriptions, 0, sizeof(descriptions));
    Drm\_ErrCode ret = OH\_MediaKeySystem\_GetMediaKeySystems(descriptions, &count);
    if (ret != DRM\_ERR\_OK) {
        printf("OH\_MediaKeySystem\_GetMediaKeySystems failed.");
    }
    
4.  （可选）查询设备是否支持对应DRM解决方案名称、媒体类型、安全保护级别的DRM解决方案。
    
    bool isSupported = OH\_MediaKeySystem\_IsSupported3("com.wiseplay.drm", "video/mp4", CONTENT\_PROTECTION\_LEVEL\_SW\_CRYPTO);
    if (isSupported != true) {
        printf("The device does not support the content protection level.");
    }
    
5.  创建MediaKeySystem实例。
    
    MediaKeySystem \*mediaKeySystem = nullptr;
    ret = OH\_MediaKeySystem\_Create("com.wiseplay.drm", &mediaKeySystem);
    if (ret != DRM\_ERR\_OK || mediaKeySystem == nullptr) {
        printf("OH\_MediaKeySystem\_Create failed.");
    }
    
6.  （可选）设置MediaKeySystem事件监听回调。
    
    static Drm\_ErrCode SystemCallBackWithObj(MediaKeySystem \*mediaKeySystem, DRM\_EventType eventType,
        uint8\_t \*info, int32\_t infoLen, char \*extra)
    {
        printf("SystemCallBackWithObj enter");
        if (eventType == EVENT\_PROVISION\_REQUIRED) {
            // 设备DRM证书请求和处理。
        }
        return DRM\_ERR\_OK;
    }
    
    ret = OH\_MediaKeySystem\_SetCallback(mediaKeySystem, SystemCallBackWithObj);
    if (ret != DRM\_ERR\_OK) {
        printf("OH\_MediaKeySystem\_SetCallback failed.");
    }
    
7.  （可选）获取设备DRM证书状态。
    
    DRM\_CertificateStatus certStatus = CERT\_STATUS\_INVALID;
    // 检查设备DRM证书状态。
    ret = OH\_MediaKeySystem\_GetCertificateStatus(mediaKeySystem, &certStatus);
    if (ret == DRM\_ERR\_OK && certStatus != CERT\_STATUS\_PROVISIONED) {
        // 设备DRM证书请求和处理。
    }
    
8.  （可选）生成设备DRM证书请求与处理设备DRM证书响应。
    
    #define MAX\_DRM\_PROVISION\_BUF\_SIZE 24576 // 24576: (2 \* 12 \* 1024)
    unsigned char request\[MAX\_DRM\_PROVISION\_BUF\_SIZE\] = { 0x00 };  // 设备DRM证书request最大长度为MAX\_DRM\_PROVISION\_BUF\_SIZE，按实际大小申请。
    int32\_t requestLen = MAX\_DRM\_PROVISION\_BUF\_SIZE;
    // DRM服务URL的最大长度为2048。
    char defaultUrl\[2048\] = { 0x00 };
    int32\_t defaultUrlLen = 2048;
    ret = OH\_MediaKeySystem\_GenerateKeySystemRequest(mediaKeySystem, request, &requestLen, defaultUrl,
        defaultUrlLen);
    if (ret != DRM\_ERR\_OK) {
        printf("OH\_MediaKeySystem\_GenerateKeySystemRequest failed.");
    }
    /\*
      应用通过网络请求，将设备DRM证书请求信息传到DRM服务获取设备DRM证书请求响应keySystemResponse，
      再将设备DRM证书请求响应设置到设备上，请根据实际的数据和长度传入。
     \*/
    unsigned char keySystemResponse\[MAX\_DRM\_PROVISION\_BUF\_SIZE\] = {0x00};
    ret = OH\_MediaKeySystem\_ProcessKeySystemResponse(mediaKeySystem, keySystemResponse, sizeof(keySystemResponse));
    if (ret != DRM\_ERR\_OK) {
        printf("OH\_MediaKeySystem\_ProcessKeySystemResponse failed.");
    }
    
9.  （可选）获取设备支持的最大内容保护级别。
    
    DRM\_ContentProtectionLevel maxContentProtectionLevel = CONTENT\_PROTECTION\_LEVEL\_UNKNOWN;
    ret = OH\_MediaKeySystem\_GetMaxContentProtectionLevel(mediaKeySystem, &maxContentProtectionLevel);
    if (ret != DRM\_ERR\_OK) {
        printf("OH\_MediaKeySystem\_GetMaxContentProtectionLevel failed.");
    }
    
10.  创建MediaKeySession实例。
     
     MediaKeySession \*mediaKeySession = nullptr;
     DRM\_ContentProtectionLevel contentProtectionLevel = CONTENT\_PROTECTION\_LEVEL\_SW\_CRYPTO; // 依据设备支持的内容保护级别设置。
     ret = OH\_MediaKeySystem\_CreateMediaKeySession(mediaKeySystem, &contentProtectionLevel, &mediaKeySession);
     if (ret != DRM\_ERR\_OK || mediaKeySession == nullptr) {
         printf("OH\_MediaKeySystem\_CreateMediaKeySession failed.");
     }
     
11.  （可选）设置MediaKeySession事件监听回调。
     
     static Drm\_ErrCode SessionEventCallBackWithObj(MediaKeySession \*mediaKeySession, DRM\_EventType eventType, uint8\_t \*info, int32\_t infoLen, char \*extra)
     {
         if (eventType == EVENT\_KEY\_REQUIRED) {
             // 媒体密钥请求与处理。
         }
         return DRM\_ERR\_OK;
     }
     
     static Drm\_ErrCode SessionKeyChangeCallBackWithObj(MediaKeySession \*mediaKeySession, DRM\_KeysInfo \*keysInfo, bool hasNewGoodKeys)
     {
         return DRM\_ERR\_OK;
     }
     
     OH\_MediaKeySession\_Callback sessionCallback = { SessionEventCallBackWithObj, SessionKeyChangeCallBackWithObj };
     ret = OH\_MediaKeySession\_SetCallback(mediaKeySession, &sessionCallback);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySession\_SetCallback failed.");
     }
     
12.  （可选）查询是否需要安全解码。
     
     bool requireSecureDecoder;
     ret = OH\_MediaKeySession\_RequireSecureDecoderModule(mediaKeySession, "video/avc", &requireSecureDecoder);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySession\_RequireSecureDecoderModule failed.");
     }
     
13.  生成媒体密钥请求与处理媒体密钥响应，以请求许可证完成DRM节目授权。
     
     #define MAX\_DRM\_MEDIA\_KEY\_RESPONSE\_BUF\_SIZE 24576 // 24576: (2 \* 12 \* 1024)
     DRM\_MediaKeyRequest mediaKeyRequest;
     DRM\_MediaKeyRequestInfo info;
     // initData对应码流中的pssh数据，请按实际数据填入。
     unsigned char initData\[512\] = {0x00};
     memset(&info, 0, sizeof(DRM\_MediaKeyRequestInfo));
     info.initDataLen = sizeof(initData);
     info.type = MEDIA\_KEY\_TYPE\_ONLINE; // MEDIA\_KEY\_TYPE\_ONLINE: 在线媒体密钥请求类型; MEDIA\_KEY\_TYPE\_OFFLINE: 离线媒体密钥请求类型。
     memcpy(info.mimeType, (char \*)"video/mp4", sizeof("video/mp4"));
     memcpy(info.initData, initData, sizeof(initData));
     memcpy(info.optionName\[0\], (char \*)"optionalDataName", sizeof("optionalDataName"));
     memcpy(info.optionData\[0\], (char \*)"optionalDataValue", sizeof("optionalDataValue"));
     info.optionsCount = 1;
     ret = OH\_MediaKeySession\_GenerateMediaKeyRequest(mediaKeySession, &info, &mediaKeyRequest);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySession\_GenerateMediaKeyRequest failed.");
     }
     /\*
       应用通过网络请求DRM服务，获取媒体密钥响应mediaKeyResponse，将响应传到OH\_MediaKeySession\_ProcessMediaKeyResponse，
       若是离线媒体密钥响应处理，则返回离线媒体密钥标识mediaKeyId，请根据实际的数据和长度传入。
      \*/
     unsigned char mediaKeyId\[128\] = {0x00};
     int32\_t mediaKeyIdLen = 128;
     // 媒体密钥响应长度最大为MAX\_DRM\_MEDIA\_KEY\_RESPONSE\_BUF\_SIZE，请按实际数据输入。
     unsigned char mediaKeyResponse\[MAX\_DRM\_MEDIA\_KEY\_RESPONSE\_BUF\_SIZE\] = {0x00};
     int32\_t mediaKeyResponseLen = MAX\_DRM\_MEDIA\_KEY\_RESPONSE\_BUF\_SIZE;
     ret = OH\_MediaKeySession\_ProcessMediaKeyResponse(mediaKeySession, mediaKeyResponse,
         mediaKeyResponseLen, mediaKeyId, &mediaKeyIdLen);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySession\_ProcessMediaKeyResponse failed.");
     }
     
14.  （可选）恢复离线媒体密钥。
     
     // 将指定媒体密钥标识的媒体密钥加载到当前会话。
     ret = OH\_MediaKeySession\_RestoreOfflineMediaKeys(mediaKeySession, mediaKeyId, mediaKeyIdLen);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySession\_RestoreOfflineMediaKeys failed.");
     }
     
15.  （可选）检查媒体密钥状态。
     
     DRM\_MediaKeyStatus mediaKeyStatus;
     ret = OH\_MediaKeySession\_CheckMediaKeyStatus(mediaKeySession, &mediaKeyStatus);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySession\_CheckMediaKeyStatus failed.");
     }
     
16.  （可选）获取离线媒体密钥标识列表、获取离线媒体密钥状态与清除离线媒体密钥。
     
     DRM\_OfflineMediakeyIdArray offlineMediaKeyIds;
     ret = OH\_MediaKeySystem\_GetOfflineMediaKeyIds(mediaKeySystem, &offlineMediaKeyIds);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySystem\_GetOfflineMediaKeyIds failed.");
     }
     DRM\_OfflineMediaKeyStatus OfflineMediaKeyStatus = OFFLINE\_MEDIA\_KEY\_STATUS\_UNKNOWN;
     ret = OH\_MediaKeySystem\_GetOfflineMediaKeyStatus(mediaKeySystem, offlineMediaKeyIds.ids\[0\], offlineMediaKeyIds.idsLen\[0\], &OfflineMediaKeyStatus);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySystem\_GetOfflineMediaKeyStatus failed.");
     }
     ret = OH\_MediaKeySystem\_ClearOfflineMediaKeys(mediaKeySystem, offlineMediaKeyIds.ids\[0\], offlineMediaKeyIds.idsLen\[0\]);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySystem\_ClearOfflineMediaKeys failed.");
     }
     
17.  销毁MediaKeySession实例。
     
     ret = OH\_MediaKeySession\_Destroy(mediaKeySession);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySession\_Destroy failed.");
     }
     
18.  销毁MediaKeySystem实例。
     
     ret = OH\_MediaKeySystem\_Destroy(mediaKeySystem);
     if (ret != DRM\_ERR\_OK) {
         printf("OH\_MediaKeySystem\_Destroy failed.");
     }