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

Commit a7e0e8b4 authored by Nicolas Catania's avatar Nicolas Catania
Browse files

Implemented the metadata changed notification filters.

IMediaPlayer:
new setMetadataFilter method so set a filter (2 lists of allowed and blocked metadata type)
serialized in a Parcel.

MediaPlayer.java/android_media_MediaPlayer.cpp/mediaplayer.cpp
new setMetadataFilter that passes the filter down to the MediaPlayerService's binder interface.

MediaPlayerService.cpp
The Client inner class holds the allowed and blocked metadata types.
These are in 2 vectors that get populated in the setMetadataFilter.

A new shourldDropMetadata method returns true if a type of metadata should be dropped according
to the filters.

The notify method in run the metadata update notifications thru the filter and possibly drop them.
parent 814914cd
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -52,8 +52,13 @@ public:
    // @param request Parcel that must start with the media player
    // interface token.
    // @param[out] reply Parcel to hold the reply data. Cannot be null.
    // @return OK if the invocation was made. PERMISSION_DENIED otherwise.
    // @return OK if the invocation was made successfully.
    virtual status_t        invoke(const Parcel& request, Parcel *reply) = 0;

    // Set a new metadata filter.
    // @param filter A set of allow and drop rules serialized in a Parcel.
    // @return OK if the invocation was made successfully.
    virtual status_t        setMetadataFilter(const Parcel& filter) = 0;
};

// ----------------------------------------------------------------------------
+3 −0
Original line number Diff line number Diff line
@@ -97,6 +97,8 @@ enum media_info_type {
    MEDIA_INFO_BAD_INTERLEAVING = 800,
    // The media is not seekable (e.g live stream).
    MEDIA_INFO_NOT_SEEKABLE = 801,
    // New media metadata is available.
    MEDIA_INFO_METADATA_UPDATE = 802,
};


@@ -152,6 +154,7 @@ public:
    static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
    static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
            status_t        invoke(const Parcel& request, Parcel *reply);
            status_t        setMetadataFilter(const Parcel& filter);
private:
            void            clear_l();
            status_t        seekTo_l(int msec);
+15 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ enum {
    SET_LOOPING,
    SET_VOLUME,
    INVOKE,
    SET_METADATA_FILTER,
};

class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -178,6 +179,15 @@ public:
        status_t retcode = remote()->transact(INVOKE, request, reply);
        return retcode;
    }

    status_t setMetadataFilter(const Parcel& request)
    {
        Parcel reply;
        // Avoid doing any extra copy of the request. The interface
        // descriptor should have been set by MediaPlayer.java.
        remote()->transact(SET_METADATA_FILTER, request, &reply);
        return reply.readInt32();
    }
};

IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -273,6 +283,11 @@ status_t BnMediaPlayer::onTransact(
            invoke(data, reply);
            return NO_ERROR;
        } break;
        case SET_METADATA_FILTER: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);
            reply->writeInt32(setMetadataFilter(data));
            return NO_ERROR;
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
+10 −1
Original line number Diff line number Diff line
@@ -208,7 +208,16 @@ status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
    return INVALID_OPERATION;
}


status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
{
    LOGD("setMetadataFilter");
    Mutex::Autolock _l(mLock);
    if (mPlayer == NULL)
    {
        return NO_INIT;
    }
    return mPlayer->setMetadataFilter(filter);
}

status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
{
+185 −0
Original line number Diff line number Diff line
@@ -69,6 +69,150 @@ pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif

namespace {
using android::status_t;
using android::OK;
using android::BAD_VALUE;
using android::NOT_ENOUGH_DATA;
using android::Parcel;
using android::Vector;

// Max number of entries in the filter.
const int kMaxFilterSize = 64;  // I pulled that out of thin air.

// Keep in sync with ANY in Metadata.java
const int32_t kAny = 0;

// To order the metadata types in the vector-filter.
int lessThan(const int32_t *lhs, const int32_t *rhs)
{
    return *lhs < *rhs ? 0 : 1;
}

// Unmarshall a filter from a Parcel.
// Filter format in a parcel:
//
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       number of entries (n)                   |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       metadata type 1                         |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       metadata type 2                         |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//  ....
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       metadata type n                         |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// @param p Parcel that should start with a filter.
// @param[out] filter On exit contains the list of metadata type to be
//                    filtered.
// @param[out] status On exit contains the status code to be returned.
// @return true if the parcel starts with a valid filter.
bool unmarshallFilter(const Parcel& p,
                      Vector<int32_t> *filter,
                      status_t *status)
{
    int32_t s;
    if (p.readInt32(&s) != OK)
    {
        LOGE("Failed to read filter's length");
        *status = NOT_ENOUGH_DATA;
        return false;
    }

    if( s > kMaxFilterSize || s < 0)
    {
        LOGE("Invalid filter len %d", s);
        *status = BAD_VALUE;
        return false;
    }

    size_t size = s;

    filter->clear();
    filter->setCapacity(size);

    s *= sizeof(int32_t);

    if (p.dataAvail() < static_cast<size_t>(s))
    {
        LOGE("Filter too short expected %d but got %d", s, p.dataAvail());
        *status = NOT_ENOUGH_DATA;
        return false;
    }

    const int32_t *data = static_cast<const int32_t*>(p.readInplace(s));

    if (NULL == data )
    {
        LOGE("Filter had no data");
        *status = BAD_VALUE;
        return false;
    }

    // TODO: The stl impl of vector would be more efficient here
    // because it degenerates into a memcpy on pod types. Try to
    // replace later or use stl::set.
    for (size_t i = 0; i < size; ++i)
    {
        filter->push(*data);
        ++data;
    }
    *status = OK;
    return true;
}

bool unmarshallBothFilters(const Parcel& p,
                           Vector<int32_t> *allow,
                           Vector<int32_t> *block,
                           status_t *status)
{
    if (!(unmarshallFilter(p, allow, status) && unmarshallFilter(p, block, status)))
    {
        return false;
    }
    allow->sort(lessThan);
    block->sort(lessThan);
    return true;
}

// @param filter Should be sorted in ascending order.
// @param val To be searched.
// @return true if a match was found.
bool findMetadata(const Vector<int32_t> filter, const int32_t val)
{
    // Deal with empty and ANY right away
    if (filter.isEmpty()) return false;
    if (filter[0] == kAny) return true;

    ssize_t min = 0;
    ssize_t max = filter.size() - 1;
    ssize_t mid;
    do
    {
        mid = (min + max) / 2;
        if (val > filter[mid])
        {
            min = mid + 1;
        }
        else
        {
            max = mid - 1;
        }
        if (filter[mid] == val)
        {
            return true;
        }
    }
    while(min <= max);
    return false;
}

}  // anonymous namespace


namespace android {

// TODO: Temp hack until we can register players
@@ -686,6 +830,22 @@ status_t MediaPlayerService::Client::invoke(const Parcel& request,
    return p->invoke(request, reply);
}

// This call doesn't need to access the native player.
status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
{
    status_t status;
    Vector<int32_t> allow, drop;

    if (unmarshallBothFilters(filter, &allow, &drop, &status))
    {
        Mutex::Autolock l(mLock);

        mMetadataAllow = allow;
        mMetadataDrop = drop;
    }
    return status;
}

status_t MediaPlayerService::Client::prepareAsync()
{
    LOGV("[%d] prepareAsync", mConnId);
@@ -808,10 +968,35 @@ status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolu
void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
{
    Client* client = static_cast<Client*>(cookie);

    if (MEDIA_INFO == msg &&
        MEDIA_INFO_METADATA_UPDATE == ext1 &&
        client->shouldDropMetadata(ext2 /* metadata type */)) {
        return;
    }
    LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
    client->mClient->notify(msg, ext1, ext2);
}

bool MediaPlayerService::Client::shouldDropMetadata(int code) const
{
    Mutex::Autolock l(mLock);

    if (findMetadata(mMetadataDrop, code))
    {
        return true;
    }

    if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code))
    {
        return false;
    }
    else
    {
        return true;
    }
}

#if CALLBACK_ANTAGONIZER
const int Antagonizer::interval = 10000; // 10 msecs

Loading