1/*
2**
3** Copyright 2008, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaMetadataRetriever"
20
21#include <inttypes.h>
22
23#include <binder/IServiceManager.h>
24#include <binder/IPCThreadState.h>
25#include <media/mediametadataretriever.h>
26#include <media/IMediaHTTPService.h>
27#include <media/IMediaPlayerService.h>
28#include <utils/Log.h>
29#include <dlfcn.h>
30
31namespace android {
32
33// client singleton for binder interface to service
34Mutex MediaMetadataRetriever::sServiceLock;
35sp<IMediaPlayerService> MediaMetadataRetriever::sService;
36sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
37
38const sp<IMediaPlayerService>& MediaMetadataRetriever::getService()
39{
40    Mutex::Autolock lock(sServiceLock);
41    if (sService == 0) {
42        sp<IServiceManager> sm = defaultServiceManager();
43        sp<IBinder> binder;
44        do {
45            binder = sm->getService(String16("media.player"));
46            if (binder != 0) {
47                break;
48            }
49            ALOGW("MediaPlayerService not published, waiting...");
50            usleep(500000); // 0.5 s
51        } while (true);
52        if (sDeathNotifier == NULL) {
53            sDeathNotifier = new DeathNotifier();
54        }
55        binder->linkToDeath(sDeathNotifier);
56        sService = interface_cast<IMediaPlayerService>(binder);
57    }
58    ALOGE_IF(sService == 0, "no MediaPlayerService!?");
59    return sService;
60}
61
62MediaMetadataRetriever::MediaMetadataRetriever()
63{
64    ALOGV("constructor");
65    const sp<IMediaPlayerService>& service(getService());
66    if (service == 0) {
67        ALOGE("failed to obtain MediaMetadataRetrieverService");
68        return;
69    }
70    sp<IMediaMetadataRetriever> retriever(service->createMetadataRetriever());
71    if (retriever == 0) {
72        ALOGE("failed to create IMediaMetadataRetriever object from server");
73    }
74    mRetriever = retriever;
75}
76
77MediaMetadataRetriever::~MediaMetadataRetriever()
78{
79    ALOGV("destructor");
80    disconnect();
81    IPCThreadState::self()->flushCommands();
82}
83
84void MediaMetadataRetriever::disconnect()
85{
86    ALOGV("disconnect");
87    sp<IMediaMetadataRetriever> retriever;
88    {
89        Mutex::Autolock _l(mLock);
90        retriever = mRetriever;
91        mRetriever.clear();
92    }
93    if (retriever != 0) {
94        retriever->disconnect();
95    }
96}
97
98status_t MediaMetadataRetriever::setDataSource(
99        const sp<IMediaHTTPService> &httpService,
100        const char *srcUrl,
101        const KeyedVector<String8, String8> *headers)
102{
103    ALOGV("setDataSource");
104    Mutex::Autolock _l(mLock);
105    if (mRetriever == 0) {
106        ALOGE("retriever is not initialized");
107        return INVALID_OPERATION;
108    }
109    if (srcUrl == NULL) {
110        ALOGE("data source is a null pointer");
111        return UNKNOWN_ERROR;
112    }
113    ALOGV("data source (%s)", srcUrl);
114    return mRetriever->setDataSource(httpService, srcUrl, headers);
115}
116
117status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
118{
119    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
120    Mutex::Autolock _l(mLock);
121    if (mRetriever == 0) {
122        ALOGE("retriever is not initialized");
123        return INVALID_OPERATION;
124    }
125    if (fd < 0 || offset < 0 || length < 0) {
126        ALOGE("Invalid negative argument");
127        return UNKNOWN_ERROR;
128    }
129    return mRetriever->setDataSource(fd, offset, length);
130}
131
132sp<IMemory> MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option)
133{
134    ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d)", timeUs, option);
135    Mutex::Autolock _l(mLock);
136    if (mRetriever == 0) {
137        ALOGE("retriever is not initialized");
138        return NULL;
139    }
140    return mRetriever->getFrameAtTime(timeUs, option);
141}
142
143const char* MediaMetadataRetriever::extractMetadata(int keyCode)
144{
145    ALOGV("extractMetadata(%d)", keyCode);
146    Mutex::Autolock _l(mLock);
147    if (mRetriever == 0) {
148        ALOGE("retriever is not initialized");
149        return NULL;
150    }
151    return mRetriever->extractMetadata(keyCode);
152}
153
154sp<IMemory> MediaMetadataRetriever::extractAlbumArt()
155{
156    ALOGV("extractAlbumArt");
157    Mutex::Autolock _l(mLock);
158    if (mRetriever == 0) {
159        ALOGE("retriever is not initialized");
160        return NULL;
161    }
162    return mRetriever->extractAlbumArt();
163}
164
165void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
166    Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
167    MediaMetadataRetriever::sService.clear();
168    ALOGW("MediaMetadataRetriever server died!");
169}
170
171MediaMetadataRetriever::DeathNotifier::~DeathNotifier()
172{
173    Mutex::Autolock lock(sServiceLock);
174    if (sService != 0) {
175        sService->asBinder()->unlinkToDeath(this);
176    }
177}
178
179}; // namespace android
180