Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 071437a2 authored by Hassan Shojania's avatar Hassan Shojania
Browse files

Modular DRM for MediaPlayer

Bug:  34559906
Test: Manual through the test app
Change-Id: I752c3e2bbc2fac9c75f7ddc986014c4b8ce75d84
parent 217fc01b
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <system/audio.h>

#include <media/IMediaSource.h>
#include <media/drm/DrmAPI.h>   // for DrmPlugin::* enum

// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
// global, and not in android::
@@ -89,6 +90,22 @@ public:
    virtual status_t        setRetransmitEndpoint(const struct sockaddr_in* endpoint) = 0;
    virtual status_t        getRetransmitEndpoint(struct sockaddr_in* endpoint) = 0;
    virtual status_t        setNextPlayer(const sp<IMediaPlayer>& next) = 0;
    // ModDrm
    virtual status_t        prepareDrm(const uint8_t uuid[16], const int mode) = 0;
    virtual status_t        releaseDrm() = 0;
    virtual status_t        getKeyRequest(Vector<uint8_t> const& scope,
                                    String8 const &mimeType,
                                    DrmPlugin::KeyType keyType,
                                    KeyedVector<String8, String8>& optionalParameters,
                                    Vector<uint8_t>& request,
                                    String8& defaultUrl,
                                    DrmPlugin::KeyRequestType& keyRequestType) = 0;
    virtual status_t        provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
                                    Vector<uint8_t>& response,
                                    Vector<uint8_t>& keySetId) = 0;
    virtual status_t        restoreKeys(Vector<uint8_t> const& keySetId) = 0;
    virtual status_t        getDrmPropertyString(String8 const& name, String8& value) = 0;
    virtual status_t        setDrmPropertyString(String8 const& name, String8 const& value) = 0;

    // Invoke a generic method on the player by using opaque parcels
    // for the request and reply.
+28 −0
Original line number Diff line number Diff line
@@ -280,6 +280,34 @@ public:
        return INVALID_OPERATION;
    }

    // ModDrm
    virtual status_t prepareDrm(const uint8_t uuid[16], const int mode) {
        return INVALID_OPERATION;
    }
    virtual status_t releaseDrm() {
        return INVALID_OPERATION;
    }
    virtual status_t getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
                             DrmPlugin::KeyType keyType,
                             KeyedVector<String8, String8>& optionalParameters,
                             Vector<uint8_t>& request, String8& defaultUrl,
                             DrmPlugin::KeyRequestType& keyRequestType) {
        return INVALID_OPERATION;
    }
    virtual status_t provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
                             Vector<uint8_t>& response, Vector<uint8_t>& keySetId) {
        return INVALID_OPERATION;
    }
    virtual status_t restoreKeys(Vector<uint8_t> const& keySetId) {
        return INVALID_OPERATION;
    }
    virtual status_t getDrmPropertyString(String8 const& name, String8& value) {
        return INVALID_OPERATION;
    }
    virtual status_t setDrmPropertyString(String8 const& name, String8 const& value) {
        return INVALID_OPERATION;
    }

private:
    friend class MediaPlayerService;

+14 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ enum media_event_type {
    MEDIA_INFO              = 200,
    MEDIA_SUBTITLE_DATA     = 201,
    MEDIA_META_DATA         = 202,
    MEDIA_DRM_INFO          = 210,
};

// Generic error codes for the media player framework.  Errors are fatal, the
@@ -260,6 +261,19 @@ public:
            status_t        getParameter(int key, Parcel* reply);
            status_t        setRetransmitEndpoint(const char* addrString, uint16_t port);
            status_t        setNextMediaPlayer(const sp<MediaPlayer>& player);
            // ModDrm
            status_t        prepareDrm(const uint8_t uuid[16], const int mode);
            status_t        releaseDrm();
            status_t        getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
                                    DrmPlugin::KeyType keyType,
                                    KeyedVector<String8, String8>& optionalParameters,
                                    Vector<uint8_t>& request, String8& defaultUrl,
                                    DrmPlugin::KeyRequestType& keyRequestType);
            status_t        provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
                                    Vector<uint8_t>& response, Vector<uint8_t>& keySetId);
            status_t        restoreKeys(Vector<uint8_t> const& keySetId);
            status_t        getDrmPropertyString(String8 const& name, String8& value);
            status_t        setDrmPropertyString(String8 const& name, String8 const& value);

private:
            void            clear_l();
+238 −0
Original line number Diff line number Diff line
@@ -70,8 +70,28 @@ enum {
    SET_RETRANSMIT_ENDPOINT,
    GET_RETRANSMIT_ENDPOINT,
    SET_NEXT_PLAYER,
    // ModDrm
    PREPARE_DRM,
    RELEASE_DRM,
    GET_KEY_REQUEST,
    PROVIDE_KEY_RESPONSE,
    RESTORE_KEYS,
    GET_DRM_PROPERTY_STRING,
    SET_DRM_PROPERTY_STRING,
};

// ModDrm helpers
static void readVector(const Parcel& reply, Vector<uint8_t>& vector) {
    uint32_t size = reply.readUint32();
    vector.insertAt((size_t)0, size);
    reply.read(vector.editArray(), size);
}

static void writeVector(Parcel& data, Vector<uint8_t> const& vector) {
    data.writeUint32(vector.size());
    data.write(vector.array(), vector.size());
}

class BpMediaPlayer: public BpInterface<IMediaPlayer>
{
public:
@@ -447,6 +467,137 @@ public:

        return err;
    }

    // ModDrm
    status_t prepareDrm(const uint8_t uuid[16], const int mode)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

        data.write(uuid, 16);
        data.writeInt32(mode);

        status_t status = remote()->transact(PREPARE_DRM, data, &reply);
        if (status != OK) {
            ALOGE("prepareDrm: binder call failed: %d", status);
            return status;
        }

        return reply.readInt32();
    }

    status_t releaseDrm()
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

        status_t status = remote()->transact(RELEASE_DRM, data, &reply);
        if (status != OK) {
            ALOGE("releaseDrm: binder call failed: %d", status);
            return status;
        }

        return reply.readInt32();
    }

    status_t getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
            DrmPlugin::KeyType keyType, KeyedVector<String8, String8>& optionalParameters,
            Vector<uint8_t>& request, String8& defaultUrl,
            DrmPlugin::KeyRequestType& keyRequestType)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

        writeVector(data, scope);
        data.writeString8(mimeType);
        data.writeInt32((int32_t)keyType);

        data.writeUint32(optionalParameters.size());
        for (size_t i = 0; i < optionalParameters.size(); ++i) {
            data.writeString8(optionalParameters.keyAt(i));
            data.writeString8(optionalParameters.valueAt(i));
        }

        status_t status = remote()->transact(GET_KEY_REQUEST, data, &reply);
        if (status != OK) {
            ALOGE("getKeyRequest: binder call failed: %d", status);
            return status;
        }

        readVector(reply, request);
        defaultUrl = reply.readString8();
        keyRequestType = (DrmPlugin::KeyRequestType)reply.readInt32();

        return reply.readInt32();
    }

    status_t provideKeyResponse(Vector<uint8_t>& releaseKeySetId, Vector<uint8_t>& response,
            Vector<uint8_t> &keySetId)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

        writeVector(data, releaseKeySetId);
        writeVector(data, response);

        status_t status = remote()->transact(PROVIDE_KEY_RESPONSE, data, &reply);
        if (status != OK) {
            ALOGE("provideKeyResponse: binder call failed: %d", status);
            return status;
        }

        readVector(reply, keySetId);

        return reply.readInt32();
    }

    status_t restoreKeys(Vector<uint8_t> const& keySetId)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

        writeVector(data, keySetId);

        status_t status = remote()->transact(RESTORE_KEYS, data, &reply);
        if (status != OK) {
            ALOGE("restoreKeys: binder call failed: %d", status);
            return status;
        }

        return reply.readInt32();
    }

    status_t getDrmPropertyString(String8 const& name, String8& value)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

        data.writeString8(name);
        status_t status = remote()->transact(GET_DRM_PROPERTY_STRING, data, &reply);
        if (status != OK) {
            ALOGE("getDrmPropertyString: binder call failed: %d", status);
            return status;
        }

        value = reply.readString8();
        return reply.readInt32();
    }

    status_t setDrmPropertyString(String8 const& name, String8 const& value)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

        data.writeString8(name);
        data.writeString8(value);
        status_t status = remote()->transact(SET_DRM_PROPERTY_STRING, data, &reply);
        if (status != OK) {
            ALOGE("setDrmPropertyString: binder call failed: %d", status);
            return status;
        }

        return reply.readInt32();
    }
};

IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -741,6 +892,93 @@ status_t BnMediaPlayer::onTransact(

            return NO_ERROR;
        } break;

        // ModDrm
        case PREPARE_DRM: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);
            uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));

            int mode = data.readInt32();

            uint32_t result = prepareDrm(uuid, mode);
            reply->writeInt32(result);
            return OK;
        }
        case RELEASE_DRM: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);

            uint32_t result = releaseDrm();
            reply->writeInt32(result);
            return OK;
        }
        case GET_KEY_REQUEST: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);

            Vector<uint8_t> scope;
            readVector(data, scope);
            String8 mimeType = data.readString8();
            DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)data.readInt32();

            KeyedVector<String8, String8> optionalParameters;
            uint32_t count = data.readUint32();
            for (size_t i = 0; i < count; ++i) {
                String8 key, value;
                key = data.readString8();
                value = data.readString8();
                optionalParameters.add(key, value);
            }

            Vector<uint8_t> request;
            String8 defaultUrl;
            DrmPlugin::KeyRequestType keyRequestType = DrmPlugin::kKeyRequestType_Unknown;

            status_t result = getKeyRequest(scope, mimeType, keyType, optionalParameters,
                                      request, defaultUrl, keyRequestType);

            writeVector(*reply, request);
            reply->writeString8(defaultUrl);
            reply->writeInt32(keyRequestType);
            reply->writeInt32(result);
            return OK;
        }
        case PROVIDE_KEY_RESPONSE: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);
            Vector<uint8_t> releaseKeySetId, response, keySetId;
            readVector(data, releaseKeySetId);
            readVector(data, response);
            uint32_t result = provideKeyResponse(releaseKeySetId, response, keySetId);
            writeVector(*reply, keySetId);
            reply->writeInt32(result);
            return OK;
        }
        case RESTORE_KEYS: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);

            Vector<uint8_t> keySetId;
            readVector(data, keySetId);
            uint32_t result = restoreKeys(keySetId);
            reply->writeInt32(result);
            return OK;
        }
        case GET_DRM_PROPERTY_STRING: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);
            String8 name, value;
            name = data.readString8();
            uint32_t result = getDrmPropertyString(name, value);
            reply->writeString8(value);
            reply->writeInt32(result);
            return OK;
        }
        case SET_DRM_PROPERTY_STRING: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);
            String8 name, value;
            name = data.readString8();
            value = data.readString8();
            uint32_t result = setDrmPropertyString(name, value);
            reply->writeInt32(result);
            return OK;
        }
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
+123 −1
Original line number Diff line number Diff line
@@ -874,7 +874,7 @@ void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
    case MEDIA_NOP: // interface test message
        break;
    case MEDIA_PREPARED:
        ALOGV("prepared");
        ALOGV("MediaPlayer::notify() prepared");
        mCurrentState = MEDIA_PLAYER_PREPARED;
        if (mPrepareSync) {
            ALOGV("signal application thread");
@@ -883,6 +883,9 @@ void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
            mSignal.signal();
        }
        break;
    case MEDIA_DRM_INFO:
        ALOGV("MediaPlayer::notify() MEDIA_DRM_INFO(%d, %d, %d, %p)", msg, ext1, ext2, obj);
        break;
    case MEDIA_PLAYBACK_COMPLETE:
        ALOGV("playback complete");
        if (mCurrentState == MEDIA_PLAYER_IDLE) {
@@ -983,4 +986,123 @@ status_t MediaPlayer::setNextMediaPlayer(const sp<MediaPlayer>& next) {
    return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer);
}

// ModDrm
status_t MediaPlayer::prepareDrm(const uint8_t uuid[16], const int mode)
{
    Mutex::Autolock _l(mLock);
    if (mPlayer == NULL) {
        return NO_INIT;
    }

    // Only allowing it in player's prepared state
    if (!(mCurrentState & MEDIA_PLAYER_PREPARED)) {
        ALOGE("prepareDrm must only be called in the prepared state.");
        return INVALID_OPERATION;
    }

    status_t ret = mPlayer->prepareDrm(uuid, mode);
    ALOGV("prepareDrm: ret=%d", ret);

    return ret;
}

status_t MediaPlayer::releaseDrm()
{
    Mutex::Autolock _l(mLock);
    if (mPlayer == NULL) {
        return NO_INIT;
    }

    // Not allowing releaseDrm in an active state
    if (mCurrentState & (MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED)) {
        ALOGE("releaseDrm can not be called in the started/paused state.");
        return INVALID_OPERATION;
    }

    status_t ret = mPlayer->releaseDrm();
    ALOGV("releaseDrm: ret=%d", ret);

    return ret;
}

status_t MediaPlayer::getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
                              DrmPlugin::KeyType keyType,
                              KeyedVector<String8, String8>& optionalParameters,
                              Vector<uint8_t>& request, String8& defaultUrl,
                              DrmPlugin::KeyRequestType& keyRequestType)
{
    Mutex::Autolock _l(mLock);
    if (mPlayer == NULL) {
        return NO_INIT;
    }

    // Not enforcing a particular state beyond the checks enforced by the Java layer
    // Key exchange can happen after the start.
    status_t ret = mPlayer->getKeyRequest(scope, mimeType, keyType, optionalParameters,
                                     request, defaultUrl, keyRequestType);
    ALOGV("getKeyRequest ret=%d  %d %s %d ", ret,
          (int)request.size(), defaultUrl.string(), (int)keyRequestType);

    return ret;
}

status_t MediaPlayer::provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
                              Vector<uint8_t>& response, Vector<uint8_t>& keySetId)
{
    Mutex::Autolock _l(mLock);
    if (mPlayer == NULL) {
        return NO_INIT;
    }

    // Not enforcing a particular state beyond the checks enforced by the Java layer
    // Key exchange can happen after the start.
    status_t ret = mPlayer->provideKeyResponse(releaseKeySetId, response, keySetId);
    ALOGV("provideKeyResponse: ret=%d", ret);

    return ret;
}

status_t MediaPlayer::restoreKeys(Vector<uint8_t> const& keySetId)
{
    Mutex::Autolock _l(mLock);
    if (mPlayer == NULL) {
        return NO_INIT;
    }

    // Not enforcing a particular state beyond the checks enforced by the Java layer
    // Key exchange can happen after the start.
    status_t ret = mPlayer->restoreKeys(keySetId);
    ALOGV("restoreKeys: ret=%d", ret);

    return ret;
}

status_t MediaPlayer::getDrmPropertyString(String8 const& name, String8& value)
{
    Mutex::Autolock _l(mLock);
    if (mPlayer == NULL) {
        return NO_INIT;
    }

    // Not enforcing a particular state beyond the checks enforced by the Java layer
    status_t ret = mPlayer->getDrmPropertyString(name, value);
    ALOGV("getDrmPropertyString: ret=%d", ret);

    return ret;
}

status_t MediaPlayer::setDrmPropertyString(String8 const& name, String8 const& value)
{
    Mutex::Autolock _l(mLock);
    if (mPlayer == NULL) {
        return NO_INIT;
    }

    // Not enforcing a particular state beyond the checks enforced by the Java layer
    status_t ret = mPlayer->setDrmPropertyString(name, value);
    ALOGV("setDrmPropertyString: ret=%d", ret);

    return ret;
}

} // namespace android
Loading