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
132status_t MediaMetadataRetriever::setDataSource(
133    const sp<IDataSource>& dataSource)
134{
135    ALOGV("setDataSource(IDataSource)");
136    Mutex::Autolock _l(mLock);
137    if (mRetriever == 0) {
138        ALOGE("retriever is not initialized");
139        return INVALID_OPERATION;
140    }
141    return mRetriever->setDataSource(dataSource);
142}
143
144sp<IMemory> MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option)
145{
146    ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d)", timeUs, option);
147    Mutex::Autolock _l(mLock);
148    if (mRetriever == 0) {
149        ALOGE("retriever is not initialized");
150        return NULL;
151    }
152    return mRetriever->getFrameAtTime(timeUs, option);
153}
154
155const char* MediaMetadataRetriever::extractMetadata(int keyCode)
156{
157    ALOGV("extractMetadata(%d)", keyCode);
158    Mutex::Autolock _l(mLock);
159    if (mRetriever == 0) {
160        ALOGE("retriever is not initialized");
161        return NULL;
162    }
163    return mRetriever->extractMetadata(keyCode);
164}
165
166sp<IMemory> MediaMetadataRetriever::extractAlbumArt()
167{
168    ALOGV("extractAlbumArt");
169    Mutex::Autolock _l(mLock);
170    if (mRetriever == 0) {
171        ALOGE("retriever is not initialized");
172        return NULL;
173    }
174    return mRetriever->extractAlbumArt();
175}
176
177void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
178    Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
179    MediaMetadataRetriever::sService.clear();
180    ALOGW("MediaMetadataRetriever server died!");
181}
182
183MediaMetadataRetriever::DeathNotifier::~DeathNotifier()
184{
185    Mutex::Autolock lock(sServiceLock);
186    if (sService != 0) {
187        IInterface::asBinder(sService)->unlinkToDeath(this);
188    }
189}
190
191} // namespace android
192