blob: 1c6018ca879889a912542c8f269a81c34536efa3 [file] [log] [blame]
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001/*
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// Proxy for media player implementations
19
20//#define LOG_NDEBUG 0
21#define LOG_TAG "MediaPlayerService"
22#include <utils/Log.h>
23
24#include <sys/types.h>
25#include <sys/stat.h>
Gloria Wang7cf180c2011-02-19 18:37:57 -080026#include <sys/time.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080027#include <dirent.h>
28#include <unistd.h>
29
30#include <string.h>
Mathias Agopian6f74b0c2009-06-03 17:32:49 -070031
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080032#include <cutils/atomic.h>
Nicolas Catania14d27472009-07-13 14:37:49 -070033#include <cutils/properties.h> // for property_get
Mathias Agopian6f74b0c2009-06-03 17:32:49 -070034
35#include <utils/misc.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080036
Mathias Agopian75624082009-05-19 19:08:10 -070037#include <binder/IPCThreadState.h>
38#include <binder/IServiceManager.h>
39#include <binder/MemoryHeapBase.h>
40#include <binder/MemoryBase.h>
Mathias Agopianb1e7cd12013-02-14 17:11:27 -080041#include <gui/Surface.h>
Nicolas Catania1d187f12009-05-12 23:25:55 -070042#include <utils/Errors.h> // for status_t
43#include <utils/String8.h>
Marco Nelissen10dbb8e2009-09-20 10:42:13 -070044#include <utils/SystemClock.h>
Nicolas Catania1d187f12009-05-12 23:25:55 -070045#include <utils/Vector.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080046
Andreas Huber1b86fe02014-01-29 11:13:26 -080047#include <media/IMediaHTTPService.h>
Jeff Brown2013a542012-09-04 21:38:42 -070048#include <media/IRemoteDisplay.h>
49#include <media/IRemoteDisplayClient.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080050#include <media/MediaPlayerInterface.h>
51#include <media/mediarecorder.h>
52#include <media/MediaMetadataRetrieverInterface.h>
nikoa64c8c72009-07-20 15:07:26 -070053#include <media/Metadata.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080054#include <media/AudioTrack.h>
James Dong8635b7b2011-03-14 17:01:38 -070055#include <media/MemoryLeakTrackUtil.h>
Eric Laurent9cb839a2011-09-27 09:48:56 -070056#include <media/stagefright/MediaErrors.h>
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +010057#include <media/stagefright/AudioPlayer.h>
58#include <media/stagefright/foundation/ADebug.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080059
Dima Zavin64760242011-05-11 14:15:23 -070060#include <system/audio.h>
Dima Zavinfce7a472011-04-19 22:30:36 -070061
Gloria Wang7cf180c2011-02-19 18:37:57 -080062#include <private/android_filesystem_config.h>
63
James Dong559bf282012-03-28 10:29:14 -070064#include "ActivityManager.h"
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080065#include "MediaRecorderClient.h"
66#include "MediaPlayerService.h"
67#include "MetadataRetrieverClient.h"
John Grossman44a7e422012-06-21 17:29:24 -070068#include "MediaPlayerFactory.h"
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080069
70#include "MidiFile.h"
Nicolas Catania14d27472009-07-13 14:37:49 -070071#include "TestPlayerStub.h"
Andreas Huber20111aa2009-07-14 16:56:47 -070072#include "StagefrightPlayer.h"
Andreas Huberf9334412010-12-15 15:17:42 -080073#include "nuplayer/NuPlayerDriver.h"
Andreas Huber20111aa2009-07-14 16:56:47 -070074
Andreas Huber20111aa2009-07-14 16:56:47 -070075#include <OMX.h>
Nicolas Catania14d27472009-07-13 14:37:49 -070076
Andreas Hubered3e3e02012-03-26 11:13:27 -070077#include "Crypto.h"
Jeff Tinkercc82dc62013-02-08 10:18:35 -080078#include "Drm.h"
Andreas Huber59451f82012-09-18 10:36:32 -070079#include "HDCP.h"
Andreas Huberb7319a72013-05-29 14:20:52 -070080#include "HTTPBase.h"
Andreas Huber35213f12012-08-29 11:41:50 -070081#include "RemoteDisplay.h"
Andreas Hubered3e3e02012-03-26 11:13:27 -070082
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070083namespace {
nikoa64c8c72009-07-20 15:07:26 -070084using android::media::Metadata;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070085using android::status_t;
86using android::OK;
87using android::BAD_VALUE;
88using android::NOT_ENOUGH_DATA;
89using android::Parcel;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070090
91// Max number of entries in the filter.
92const int kMaxFilterSize = 64; // I pulled that out of thin air.
93
nikoa64c8c72009-07-20 15:07:26 -070094// FIXME: Move all the metadata related function in the Metadata.cpp
nikod608a812009-07-16 16:39:53 -070095
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070096
97// Unmarshall a filter from a Parcel.
98// Filter format in a parcel:
99//
100// 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
101// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102// | number of entries (n) |
103// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104// | metadata type 1 |
105// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106// | metadata type 2 |
107// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108// ....
109// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
110// | metadata type n |
111// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112//
113// @param p Parcel that should start with a filter.
114// @param[out] filter On exit contains the list of metadata type to be
115// filtered.
116// @param[out] status On exit contains the status code to be returned.
117// @return true if the parcel starts with a valid filter.
118bool unmarshallFilter(const Parcel& p,
nikoa64c8c72009-07-20 15:07:26 -0700119 Metadata::Filter *filter,
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700120 status_t *status)
121{
Nicolas Catania48290382009-07-10 13:53:06 -0700122 int32_t val;
123 if (p.readInt32(&val) != OK)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700124 {
Steve Block29357bc2012-01-06 19:20:56 +0000125 ALOGE("Failed to read filter's length");
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700126 *status = NOT_ENOUGH_DATA;
127 return false;
128 }
129
Nicolas Catania48290382009-07-10 13:53:06 -0700130 if( val > kMaxFilterSize || val < 0)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700131 {
Steve Block29357bc2012-01-06 19:20:56 +0000132 ALOGE("Invalid filter len %d", val);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700133 *status = BAD_VALUE;
134 return false;
135 }
136
Nicolas Catania48290382009-07-10 13:53:06 -0700137 const size_t num = val;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700138
139 filter->clear();
Nicolas Catania48290382009-07-10 13:53:06 -0700140 filter->setCapacity(num);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700141
nikoa64c8c72009-07-20 15:07:26 -0700142 size_t size = num * sizeof(Metadata::Type);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700143
Nicolas Catania48290382009-07-10 13:53:06 -0700144
145 if (p.dataAvail() < size)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700146 {
Steve Block29357bc2012-01-06 19:20:56 +0000147 ALOGE("Filter too short expected %d but got %d", size, p.dataAvail());
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700148 *status = NOT_ENOUGH_DATA;
149 return false;
150 }
151
nikoa64c8c72009-07-20 15:07:26 -0700152 const Metadata::Type *data =
153 static_cast<const Metadata::Type*>(p.readInplace(size));
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700154
Nicolas Catania48290382009-07-10 13:53:06 -0700155 if (NULL == data)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700156 {
Steve Block29357bc2012-01-06 19:20:56 +0000157 ALOGE("Filter had no data");
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700158 *status = BAD_VALUE;
159 return false;
160 }
161
162 // TODO: The stl impl of vector would be more efficient here
163 // because it degenerates into a memcpy on pod types. Try to
164 // replace later or use stl::set.
Nicolas Catania48290382009-07-10 13:53:06 -0700165 for (size_t i = 0; i < num; ++i)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700166 {
Nicolas Catania48290382009-07-10 13:53:06 -0700167 filter->add(*data);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700168 ++data;
169 }
170 *status = OK;
171 return true;
172}
173
Nicolas Catania48290382009-07-10 13:53:06 -0700174// @param filter Of metadata type.
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700175// @param val To be searched.
176// @return true if a match was found.
nikoa64c8c72009-07-20 15:07:26 -0700177bool findMetadata(const Metadata::Filter& filter, const int32_t val)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700178{
179 // Deal with empty and ANY right away
180 if (filter.isEmpty()) return false;
nikoa64c8c72009-07-20 15:07:26 -0700181 if (filter[0] == Metadata::kAny) return true;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700182
Nicolas Catania48290382009-07-10 13:53:06 -0700183 return filter.indexOf(val) >= 0;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700184}
185
186} // anonymous namespace
187
188
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800189namespace android {
190
Dave Burked681bbb2011-08-30 14:39:17 +0100191static bool checkPermission(const char* permissionString) {
192#ifndef HAVE_ANDROID_OS
193 return true;
194#endif
195 if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
196 bool ok = checkCallingPermission(String16(permissionString));
Steve Block29357bc2012-01-06 19:20:56 +0000197 if (!ok) ALOGE("Request requires %s", permissionString);
Dave Burked681bbb2011-08-30 14:39:17 +0100198 return ok;
199}
200
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800201// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800202/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
203/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
204
205void MediaPlayerService::instantiate() {
206 defaultServiceManager()->addService(
207 String16("media.player"), new MediaPlayerService());
208}
209
210MediaPlayerService::MediaPlayerService()
211{
Steve Block3856b092011-10-20 11:56:00 +0100212 ALOGV("MediaPlayerService created");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800213 mNextConnId = 1;
Gloria Wang9ee159b2011-02-24 14:51:45 -0800214
215 mBatteryAudio.refCount = 0;
216 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
217 mBatteryAudio.deviceOn[i] = 0;
218 mBatteryAudio.lastTime[i] = 0;
219 mBatteryAudio.totalTime[i] = 0;
220 }
221 // speaker is on by default
222 mBatteryAudio.deviceOn[SPEAKER] = 1;
John Grossman44a7e422012-06-21 17:29:24 -0700223
224 MediaPlayerFactory::registerBuiltinFactories();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800225}
226
227MediaPlayerService::~MediaPlayerService()
228{
Steve Block3856b092011-10-20 11:56:00 +0100229 ALOGV("MediaPlayerService destroyed");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800230}
231
Glenn Kastenf37971f2012-02-03 11:06:53 -0800232sp<IMediaRecorder> MediaPlayerService::createMediaRecorder()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800233{
Glenn Kastenf37971f2012-02-03 11:06:53 -0800234 pid_t pid = IPCThreadState::self()->getCallingPid();
Gloria Wangdac6a312009-10-29 15:46:37 -0700235 sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid);
236 wp<MediaRecorderClient> w = recorder;
237 Mutex::Autolock lock(mLock);
238 mMediaRecorderClients.add(w);
Steve Block3856b092011-10-20 11:56:00 +0100239 ALOGV("Create new media recorder client from pid %d", pid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800240 return recorder;
241}
242
Gloria Wangdac6a312009-10-29 15:46:37 -0700243void MediaPlayerService::removeMediaRecorderClient(wp<MediaRecorderClient> client)
244{
245 Mutex::Autolock lock(mLock);
246 mMediaRecorderClients.remove(client);
Steve Block3856b092011-10-20 11:56:00 +0100247 ALOGV("Delete media recorder client");
Gloria Wangdac6a312009-10-29 15:46:37 -0700248}
249
Glenn Kastenf37971f2012-02-03 11:06:53 -0800250sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800251{
Glenn Kastenf37971f2012-02-03 11:06:53 -0800252 pid_t pid = IPCThreadState::self()->getCallingPid();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800253 sp<MetadataRetrieverClient> retriever = new MetadataRetrieverClient(pid);
Steve Block3856b092011-10-20 11:56:00 +0100254 ALOGV("Create new media retriever from pid %d", pid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800255 return retriever;
256}
257
Glenn Kastenf37971f2012-02-03 11:06:53 -0800258sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
Dave Burked681bbb2011-08-30 14:39:17 +0100259 int audioSessionId)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800260{
Glenn Kastenf37971f2012-02-03 11:06:53 -0800261 pid_t pid = IPCThreadState::self()->getCallingPid();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800262 int32_t connId = android_atomic_inc(&mNextConnId);
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700263
264 sp<Client> c = new Client(
265 this, pid, connId, client, audioSessionId,
266 IPCThreadState::self()->getCallingUid());
267
Steve Block3856b092011-10-20 11:56:00 +0100268 ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
Dave Burked681bbb2011-08-30 14:39:17 +0100269 IPCThreadState::self()->getCallingUid());
270
271 wp<Client> w = c;
272 {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800273 Mutex::Autolock lock(mLock);
274 mClients.add(w);
275 }
Andreas Hubere2b10282010-11-23 11:41:34 -0800276 return c;
277}
278
Andreas Huber318ad9c2009-10-15 13:46:54 -0700279sp<IOMX> MediaPlayerService::getOMX() {
280 Mutex::Autolock autoLock(mLock);
281
282 if (mOMX.get() == NULL) {
283 mOMX = new OMX;
284 }
285
286 return mOMX;
Andreas Huber20111aa2009-07-14 16:56:47 -0700287}
288
Andreas Hubered3e3e02012-03-26 11:13:27 -0700289sp<ICrypto> MediaPlayerService::makeCrypto() {
Andreas Huber1bd139a2012-04-03 14:19:20 -0700290 return new Crypto;
Andreas Hubered3e3e02012-03-26 11:13:27 -0700291}
292
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800293sp<IDrm> MediaPlayerService::makeDrm() {
294 return new Drm;
295}
296
Andreas Huber279dcd82013-01-30 10:41:25 -0800297sp<IHDCP> MediaPlayerService::makeHDCP(bool createEncryptionModule) {
298 return new HDCP(createEncryptionModule);
Andreas Huber59451f82012-09-18 10:36:32 -0700299}
300
Jeff Brown2013a542012-09-04 21:38:42 -0700301sp<IRemoteDisplay> MediaPlayerService::listenForRemoteDisplay(
302 const sp<IRemoteDisplayClient>& client, const String8& iface) {
Jeff Brownaba33d52012-09-07 17:38:58 -0700303 if (!checkPermission("android.permission.CONTROL_WIFI_DISPLAY")) {
304 return NULL;
305 }
306
Jeff Brownced24b32012-09-05 17:48:03 -0700307 return new RemoteDisplay(client, iface.string());
Jeff Brown2013a542012-09-04 21:38:42 -0700308}
309
Andreas Huberb7319a72013-05-29 14:20:52 -0700310status_t MediaPlayerService::updateProxyConfig(
311 const char *host, int32_t port, const char *exclusionList) {
312 return HTTPBase::UpdateProxyConfig(host, port, exclusionList);
313}
314
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800315status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
316{
317 const size_t SIZE = 256;
318 char buffer[SIZE];
319 String8 result;
320
321 result.append(" AudioCache\n");
322 if (mHeap != 0) {
Eric Laurent3d00aa62013-09-24 09:53:27 -0700323 snprintf(buffer, 255, " heap base(%p), size(%d), flags(%d)\n",
324 mHeap->getBase(), mHeap->getSize(), mHeap->getFlags());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800325 result.append(buffer);
326 }
Scott Fan7d409692013-04-28 10:13:54 +0800327 snprintf(buffer, 255, " msec per frame(%f), channel count(%d), format(%d), frame count(%zd)\n",
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800328 mMsecsPerFrame, mChannelCount, mFormat, mFrameCount);
329 result.append(buffer);
330 snprintf(buffer, 255, " sample rate(%d), size(%d), error(%d), command complete(%s)\n",
331 mSampleRate, mSize, mError, mCommandComplete?"true":"false");
332 result.append(buffer);
333 ::write(fd, result.string(), result.size());
334 return NO_ERROR;
335}
336
337status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& args) const
338{
339 const size_t SIZE = 256;
340 char buffer[SIZE];
341 String8 result;
342
343 result.append(" AudioOutput\n");
344 snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
345 mStreamType, mLeftVolume, mRightVolume);
346 result.append(buffer);
347 snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
Eric Laurentdb354e52012-03-05 17:27:11 -0800348 mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800349 result.append(buffer);
Eric Laurent2beeb502010-07-16 07:43:46 -0700350 snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
351 mAuxEffectId, mSendLevel);
352 result.append(buffer);
353
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800354 ::write(fd, result.string(), result.size());
355 if (mTrack != 0) {
356 mTrack->dump(fd, args);
357 }
358 return NO_ERROR;
359}
360
361status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args) const
362{
363 const size_t SIZE = 256;
364 char buffer[SIZE];
365 String8 result;
366 result.append(" Client\n");
367 snprintf(buffer, 255, " pid(%d), connId(%d), status(%d), looping(%s)\n",
368 mPid, mConnId, mStatus, mLoop?"true": "false");
369 result.append(buffer);
370 write(fd, result.string(), result.size());
Andreas Hubera0b1d4b2011-06-07 15:52:25 -0700371 if (mPlayer != NULL) {
372 mPlayer->dump(fd, args);
373 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800374 if (mAudioOutput != 0) {
375 mAudioOutput->dump(fd, args);
376 }
377 write(fd, "\n", 1);
378 return NO_ERROR;
379}
380
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800381status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
382{
383 const size_t SIZE = 256;
384 char buffer[SIZE];
385 String8 result;
386 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
387 snprintf(buffer, SIZE, "Permission Denial: "
388 "can't dump MediaPlayerService from pid=%d, uid=%d\n",
389 IPCThreadState::self()->getCallingPid(),
390 IPCThreadState::self()->getCallingUid());
391 result.append(buffer);
392 } else {
393 Mutex::Autolock lock(mLock);
394 for (int i = 0, n = mClients.size(); i < n; ++i) {
395 sp<Client> c = mClients[i].promote();
396 if (c != 0) c->dump(fd, args);
397 }
James Dongb9141222010-07-08 11:16:11 -0700398 if (mMediaRecorderClients.size() == 0) {
399 result.append(" No media recorder client\n\n");
400 } else {
401 for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
402 sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
James Donge579e282011-10-18 22:29:20 -0700403 if (c != 0) {
404 snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
405 result.append(buffer);
406 write(fd, result.string(), result.size());
407 result = "\n";
408 c->dump(fd, args);
409 }
James Dongb9141222010-07-08 11:16:11 -0700410 }
Gloria Wangdac6a312009-10-29 15:46:37 -0700411 }
412
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800413 result.append(" Files opened and/or mapped:\n");
Glenn Kasten0512ab52011-05-04 17:58:57 -0700414 snprintf(buffer, SIZE, "/proc/%d/maps", gettid());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800415 FILE *f = fopen(buffer, "r");
416 if (f) {
417 while (!feof(f)) {
418 fgets(buffer, SIZE, f);
Marco Nelissen73ac1ee2012-05-07 15:36:32 -0700419 if (strstr(buffer, " /storage/") ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800420 strstr(buffer, " /system/sounds/") ||
Dave Sparks02fa8342010-09-27 16:55:18 -0700421 strstr(buffer, " /data/") ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800422 strstr(buffer, " /system/media/")) {
423 result.append(" ");
424 result.append(buffer);
425 }
426 }
427 fclose(f);
428 } else {
429 result.append("couldn't open ");
430 result.append(buffer);
431 result.append("\n");
432 }
433
Glenn Kasten0512ab52011-05-04 17:58:57 -0700434 snprintf(buffer, SIZE, "/proc/%d/fd", gettid());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800435 DIR *d = opendir(buffer);
436 if (d) {
437 struct dirent *ent;
438 while((ent = readdir(d)) != NULL) {
439 if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
Glenn Kasten0512ab52011-05-04 17:58:57 -0700440 snprintf(buffer, SIZE, "/proc/%d/fd/%s", gettid(), ent->d_name);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800441 struct stat s;
442 if (lstat(buffer, &s) == 0) {
443 if ((s.st_mode & S_IFMT) == S_IFLNK) {
444 char linkto[256];
445 int len = readlink(buffer, linkto, sizeof(linkto));
446 if(len > 0) {
447 if(len > 255) {
448 linkto[252] = '.';
449 linkto[253] = '.';
450 linkto[254] = '.';
451 linkto[255] = 0;
452 } else {
453 linkto[len] = 0;
454 }
Marco Nelissen73ac1ee2012-05-07 15:36:32 -0700455 if (strstr(linkto, "/storage/") == linkto ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800456 strstr(linkto, "/system/sounds/") == linkto ||
Dave Sparks02fa8342010-09-27 16:55:18 -0700457 strstr(linkto, "/data/") == linkto ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800458 strstr(linkto, "/system/media/") == linkto) {
459 result.append(" ");
460 result.append(buffer);
461 result.append(" -> ");
462 result.append(linkto);
463 result.append("\n");
464 }
465 }
466 } else {
467 result.append(" unexpected type for ");
468 result.append(buffer);
469 result.append("\n");
470 }
471 }
472 }
473 }
474 closedir(d);
475 } else {
476 result.append("couldn't open ");
477 result.append(buffer);
478 result.append("\n");
479 }
480
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800481 bool dumpMem = false;
482 for (size_t i = 0; i < args.size(); i++) {
483 if (args[i] == String16("-m")) {
484 dumpMem = true;
485 }
486 }
487 if (dumpMem) {
James Dong8635b7b2011-03-14 17:01:38 -0700488 dumpMemoryAddresses(fd);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800489 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800490 }
491 write(fd, result.string(), result.size());
492 return NO_ERROR;
493}
494
495void MediaPlayerService::removeClient(wp<Client> client)
496{
497 Mutex::Autolock lock(mLock);
498 mClients.remove(client);
499}
500
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700501MediaPlayerService::Client::Client(
502 const sp<MediaPlayerService>& service, pid_t pid,
503 int32_t connId, const sp<IMediaPlayerClient>& client,
504 int audioSessionId, uid_t uid)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800505{
Steve Block3856b092011-10-20 11:56:00 +0100506 ALOGV("Client(%d) constructor", connId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800507 mPid = pid;
508 mConnId = connId;
509 mService = service;
510 mClient = client;
511 mLoop = false;
512 mStatus = NO_INIT;
Eric Laurenta514bdb2010-06-21 09:27:30 -0700513 mAudioSessionId = audioSessionId;
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700514 mUID = uid;
John Grossmanc795b642012-02-22 15:38:35 -0800515 mRetransmitEndpointValid = false;
Eric Laurenta514bdb2010-06-21 09:27:30 -0700516
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800517#if CALLBACK_ANTAGONIZER
Steve Blockb8a80522011-12-20 16:23:08 +0000518 ALOGD("create Antagonizer");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800519 mAntagonizer = new Antagonizer(notify, this);
520#endif
521}
522
523MediaPlayerService::Client::~Client()
524{
Steve Block3856b092011-10-20 11:56:00 +0100525 ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800526 mAudioOutput.clear();
527 wp<Client> client(this);
528 disconnect();
529 mService->removeClient(client);
530}
531
532void MediaPlayerService::Client::disconnect()
533{
Steve Block3856b092011-10-20 11:56:00 +0100534 ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800535 // grab local reference and clear main reference to prevent future
536 // access to object
537 sp<MediaPlayerBase> p;
538 {
539 Mutex::Autolock l(mLock);
540 p = mPlayer;
beanzdcfefde2012-11-05 09:51:43 +0800541 mClient.clear();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800542 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700543
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800544 mPlayer.clear();
545
546 // clear the notification to prevent callbacks to dead client
547 // and reset the player. We assume the player will serialize
548 // access to itself if necessary.
549 if (p != 0) {
550 p->setNotifyCallback(0, 0);
551#if CALLBACK_ANTAGONIZER
Steve Blockb8a80522011-12-20 16:23:08 +0000552 ALOGD("kill Antagonizer");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800553 mAntagonizer->kill();
554#endif
555 p->reset();
556 }
557
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700558 disconnectNativeWindow();
559
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800560 IPCThreadState::self()->flushCommands();
561}
562
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800563sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
564{
565 // determine if we have the right player type
566 sp<MediaPlayerBase> p = mPlayer;
567 if ((p != NULL) && (p->playerType() != playerType)) {
Steve Block3856b092011-10-20 11:56:00 +0100568 ALOGV("delete player");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800569 p.clear();
570 }
571 if (p == NULL) {
John Grossman44a7e422012-06-21 17:29:24 -0700572 p = MediaPlayerFactory::createPlayer(playerType, this, notify);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800573 }
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700574
Jason Simmonsdb29e522011-08-12 13:46:55 -0700575 if (p != NULL) {
576 p->setUID(mUID);
577 }
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700578
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800579 return p;
580}
581
John Grossmanc795b642012-02-22 15:38:35 -0800582sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
583 player_type playerType)
584{
585 ALOGV("player type = %d", playerType);
586
587 // create the right type of player
588 sp<MediaPlayerBase> p = createPlayer(playerType);
589 if (p == NULL) {
590 return p;
591 }
592
593 if (!p->hardwareOutput()) {
Marco Nelissen462fd2f2013-01-14 14:12:05 -0800594 mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid());
John Grossmanc795b642012-02-22 15:38:35 -0800595 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
596 }
597
598 return p;
599}
600
601void MediaPlayerService::Client::setDataSource_post(
602 const sp<MediaPlayerBase>& p,
603 status_t status)
604{
605 ALOGV(" setDataSource");
606 mStatus = status;
607 if (mStatus != OK) {
608 ALOGE(" error: %d", mStatus);
609 return;
610 }
611
612 // Set the re-transmission endpoint if one was chosen.
613 if (mRetransmitEndpointValid) {
614 mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
615 if (mStatus != NO_ERROR) {
616 ALOGE("setRetransmitEndpoint error: %d", mStatus);
617 }
618 }
619
620 if (mStatus == OK) {
621 mPlayer = p;
622 }
623}
624
Andreas Huber2db84552010-01-28 11:19:57 -0800625status_t MediaPlayerService::Client::setDataSource(
Andreas Huber1b86fe02014-01-29 11:13:26 -0800626 const sp<IMediaHTTPService> &httpService,
627 const char *url,
628 const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800629{
Steve Block3856b092011-10-20 11:56:00 +0100630 ALOGV("setDataSource(%s)", url);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800631 if (url == NULL)
632 return UNKNOWN_ERROR;
633
Dave Burked681bbb2011-08-30 14:39:17 +0100634 if ((strncmp(url, "http://", 7) == 0) ||
635 (strncmp(url, "https://", 8) == 0) ||
636 (strncmp(url, "rtsp://", 7) == 0)) {
637 if (!checkPermission("android.permission.INTERNET")) {
638 return PERMISSION_DENIED;
639 }
640 }
641
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800642 if (strncmp(url, "content://", 10) == 0) {
643 // get a filedescriptor for the content Uri and
644 // pass it to the setDataSource(fd) method
645
646 String16 url16(url);
647 int fd = android::openContentProviderFile(url16);
648 if (fd < 0)
649 {
Steve Block29357bc2012-01-06 19:20:56 +0000650 ALOGE("Couldn't open fd for %s", url);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800651 return UNKNOWN_ERROR;
652 }
653 setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
654 close(fd);
655 return mStatus;
656 } else {
John Grossman44a7e422012-06-21 17:29:24 -0700657 player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
John Grossmanc795b642012-02-22 15:38:35 -0800658 sp<MediaPlayerBase> p = setDataSource_pre(playerType);
659 if (p == NULL) {
660 return NO_INIT;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800661 }
662
Andreas Huber1b86fe02014-01-29 11:13:26 -0800663 setDataSource_post(p, p->setDataSource(httpService, url, headers));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800664 return mStatus;
665 }
666}
667
668status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
669{
Steve Block3856b092011-10-20 11:56:00 +0100670 ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800671 struct stat sb;
672 int ret = fstat(fd, &sb);
673 if (ret != 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000674 ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800675 return UNKNOWN_ERROR;
676 }
677
Steve Block3856b092011-10-20 11:56:00 +0100678 ALOGV("st_dev = %llu", sb.st_dev);
679 ALOGV("st_mode = %u", sb.st_mode);
680 ALOGV("st_uid = %lu", sb.st_uid);
681 ALOGV("st_gid = %lu", sb.st_gid);
682 ALOGV("st_size = %llu", sb.st_size);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800683
684 if (offset >= sb.st_size) {
Steve Block29357bc2012-01-06 19:20:56 +0000685 ALOGE("offset error");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800686 ::close(fd);
687 return UNKNOWN_ERROR;
688 }
689 if (offset + length > sb.st_size) {
690 length = sb.st_size - offset;
Steve Block3856b092011-10-20 11:56:00 +0100691 ALOGV("calculated length = %lld", length);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800692 }
693
John Grossman44a7e422012-06-21 17:29:24 -0700694 player_type playerType = MediaPlayerFactory::getPlayerType(this,
695 fd,
696 offset,
697 length);
John Grossmanc795b642012-02-22 15:38:35 -0800698 sp<MediaPlayerBase> p = setDataSource_pre(playerType);
699 if (p == NULL) {
700 return NO_INIT;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800701 }
702
703 // now set data source
John Grossmanc795b642012-02-22 15:38:35 -0800704 setDataSource_post(p, p->setDataSource(fd, offset, length));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800705 return mStatus;
706}
707
Andreas Hubere2b10282010-11-23 11:41:34 -0800708status_t MediaPlayerService::Client::setDataSource(
709 const sp<IStreamSource> &source) {
710 // create the right type of player
John Grossman44a7e422012-06-21 17:29:24 -0700711 player_type playerType = MediaPlayerFactory::getPlayerType(this, source);
John Grossmanc795b642012-02-22 15:38:35 -0800712 sp<MediaPlayerBase> p = setDataSource_pre(playerType);
Andreas Hubere2b10282010-11-23 11:41:34 -0800713 if (p == NULL) {
714 return NO_INIT;
715 }
716
Andreas Hubere2b10282010-11-23 11:41:34 -0800717 // now set data source
John Grossmanc795b642012-02-22 15:38:35 -0800718 setDataSource_post(p, p->setDataSource(source));
Andreas Hubere2b10282010-11-23 11:41:34 -0800719 return mStatus;
720}
721
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700722void MediaPlayerService::Client::disconnectNativeWindow() {
723 if (mConnectedWindow != NULL) {
724 status_t err = native_window_api_disconnect(mConnectedWindow.get(),
725 NATIVE_WINDOW_API_MEDIA);
726
727 if (err != OK) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000728 ALOGW("native_window_api_disconnect returned an error: %s (%d)",
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700729 strerror(-err), err);
730 }
731 }
732 mConnectedWindow.clear();
733}
734
Glenn Kasten11731182011-02-08 17:26:17 -0800735status_t MediaPlayerService::Client::setVideoSurfaceTexture(
Andy McFadden484566c2012-12-18 09:46:54 -0800736 const sp<IGraphicBufferProducer>& bufferProducer)
Glenn Kasten11731182011-02-08 17:26:17 -0800737{
Andy McFadden484566c2012-12-18 09:46:54 -0800738 ALOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, bufferProducer.get());
Glenn Kasten11731182011-02-08 17:26:17 -0800739 sp<MediaPlayerBase> p = getPlayer();
740 if (p == 0) return UNKNOWN_ERROR;
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700741
Andy McFadden484566c2012-12-18 09:46:54 -0800742 sp<IBinder> binder(bufferProducer == NULL ? NULL :
743 bufferProducer->asBinder());
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700744 if (mConnectedWindowBinder == binder) {
745 return OK;
746 }
747
748 sp<ANativeWindow> anw;
Andy McFadden484566c2012-12-18 09:46:54 -0800749 if (bufferProducer != NULL) {
Marco Nelissenee08f7e2013-09-16 13:30:01 -0700750 anw = new Surface(bufferProducer, true /* controlledByApp */);
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700751 status_t err = native_window_api_connect(anw.get(),
752 NATIVE_WINDOW_API_MEDIA);
753
754 if (err != OK) {
Steve Block29357bc2012-01-06 19:20:56 +0000755 ALOGE("setVideoSurfaceTexture failed: %d", err);
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700756 // Note that we must do the reset before disconnecting from the ANW.
757 // Otherwise queue/dequeue calls could be made on the disconnected
758 // ANW, which may result in errors.
759 reset();
760
761 disconnectNativeWindow();
762
763 return err;
764 }
765 }
766
Andy McFadden484566c2012-12-18 09:46:54 -0800767 // Note that we must set the player's new GraphicBufferProducer before
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700768 // disconnecting the old one. Otherwise queue/dequeue calls could be made
769 // on the disconnected ANW, which may result in errors.
Andy McFadden484566c2012-12-18 09:46:54 -0800770 status_t err = p->setVideoSurfaceTexture(bufferProducer);
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700771
772 disconnectNativeWindow();
773
774 mConnectedWindow = anw;
775
776 if (err == OK) {
777 mConnectedWindowBinder = binder;
778 } else {
779 disconnectNativeWindow();
780 }
781
782 return err;
Glenn Kasten11731182011-02-08 17:26:17 -0800783}
784
Nicolas Catania1d187f12009-05-12 23:25:55 -0700785status_t MediaPlayerService::Client::invoke(const Parcel& request,
786 Parcel *reply)
787{
788 sp<MediaPlayerBase> p = getPlayer();
789 if (p == NULL) return UNKNOWN_ERROR;
790 return p->invoke(request, reply);
791}
792
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700793// This call doesn't need to access the native player.
794status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
795{
796 status_t status;
nikoa64c8c72009-07-20 15:07:26 -0700797 media::Metadata::Filter allow, drop;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700798
Nicolas Catania48290382009-07-10 13:53:06 -0700799 if (unmarshallFilter(filter, &allow, &status) &&
800 unmarshallFilter(filter, &drop, &status)) {
801 Mutex::Autolock lock(mLock);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700802
803 mMetadataAllow = allow;
804 mMetadataDrop = drop;
805 }
806 return status;
807}
808
Nicolas Catania48290382009-07-10 13:53:06 -0700809status_t MediaPlayerService::Client::getMetadata(
810 bool update_only, bool apply_filter, Parcel *reply)
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700811{
nikoa64c8c72009-07-20 15:07:26 -0700812 sp<MediaPlayerBase> player = getPlayer();
813 if (player == 0) return UNKNOWN_ERROR;
Nicolas Catania48290382009-07-10 13:53:06 -0700814
nikod608a812009-07-16 16:39:53 -0700815 status_t status;
816 // Placeholder for the return code, updated by the caller.
817 reply->writeInt32(-1);
818
nikoa64c8c72009-07-20 15:07:26 -0700819 media::Metadata::Filter ids;
Nicolas Catania48290382009-07-10 13:53:06 -0700820
821 // We don't block notifications while we fetch the data. We clear
822 // mMetadataUpdated first so we don't lose notifications happening
823 // during the rest of this call.
824 {
825 Mutex::Autolock lock(mLock);
826 if (update_only) {
nikod608a812009-07-16 16:39:53 -0700827 ids = mMetadataUpdated;
Nicolas Catania48290382009-07-10 13:53:06 -0700828 }
829 mMetadataUpdated.clear();
830 }
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700831
nikoa64c8c72009-07-20 15:07:26 -0700832 media::Metadata metadata(reply);
Nicolas Catania48290382009-07-10 13:53:06 -0700833
nikoa64c8c72009-07-20 15:07:26 -0700834 metadata.appendHeader();
835 status = player->getMetadata(ids, reply);
nikod608a812009-07-16 16:39:53 -0700836
837 if (status != OK) {
nikoa64c8c72009-07-20 15:07:26 -0700838 metadata.resetParcel();
Steve Block29357bc2012-01-06 19:20:56 +0000839 ALOGE("getMetadata failed %d", status);
nikod608a812009-07-16 16:39:53 -0700840 return status;
841 }
842
843 // FIXME: Implement filtering on the result. Not critical since
844 // filtering takes place on the update notifications already. This
845 // would be when all the metadata are fetch and a filter is set.
846
nikod608a812009-07-16 16:39:53 -0700847 // Everything is fine, update the metadata length.
nikoa64c8c72009-07-20 15:07:26 -0700848 metadata.updateLength();
nikod608a812009-07-16 16:39:53 -0700849 return OK;
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700850}
851
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800852status_t MediaPlayerService::Client::prepareAsync()
853{
Steve Block3856b092011-10-20 11:56:00 +0100854 ALOGV("[%d] prepareAsync", mConnId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800855 sp<MediaPlayerBase> p = getPlayer();
856 if (p == 0) return UNKNOWN_ERROR;
857 status_t ret = p->prepareAsync();
858#if CALLBACK_ANTAGONIZER
Steve Blockb8a80522011-12-20 16:23:08 +0000859 ALOGD("start Antagonizer");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800860 if (ret == NO_ERROR) mAntagonizer->start();
861#endif
862 return ret;
863}
864
865status_t MediaPlayerService::Client::start()
866{
Steve Block3856b092011-10-20 11:56:00 +0100867 ALOGV("[%d] start", mConnId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800868 sp<MediaPlayerBase> p = getPlayer();
869 if (p == 0) return UNKNOWN_ERROR;
870 p->setLooping(mLoop);
871 return p->start();
872}
873
874status_t MediaPlayerService::Client::stop()
875{
Steve Block3856b092011-10-20 11:56:00 +0100876 ALOGV("[%d] stop", mConnId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800877 sp<MediaPlayerBase> p = getPlayer();
878 if (p == 0) return UNKNOWN_ERROR;
879 return p->stop();
880}
881
882status_t MediaPlayerService::Client::pause()
883{
Steve Block3856b092011-10-20 11:56:00 +0100884 ALOGV("[%d] pause", mConnId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800885 sp<MediaPlayerBase> p = getPlayer();
886 if (p == 0) return UNKNOWN_ERROR;
887 return p->pause();
888}
889
890status_t MediaPlayerService::Client::isPlaying(bool* state)
891{
892 *state = false;
893 sp<MediaPlayerBase> p = getPlayer();
894 if (p == 0) return UNKNOWN_ERROR;
895 *state = p->isPlaying();
Steve Block3856b092011-10-20 11:56:00 +0100896 ALOGV("[%d] isPlaying: %d", mConnId, *state);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800897 return NO_ERROR;
898}
899
900status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
901{
Steve Block3856b092011-10-20 11:56:00 +0100902 ALOGV("getCurrentPosition");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800903 sp<MediaPlayerBase> p = getPlayer();
904 if (p == 0) return UNKNOWN_ERROR;
905 status_t ret = p->getCurrentPosition(msec);
906 if (ret == NO_ERROR) {
Steve Block3856b092011-10-20 11:56:00 +0100907 ALOGV("[%d] getCurrentPosition = %d", mConnId, *msec);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800908 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000909 ALOGE("getCurrentPosition returned %d", ret);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800910 }
911 return ret;
912}
913
914status_t MediaPlayerService::Client::getDuration(int *msec)
915{
Steve Block3856b092011-10-20 11:56:00 +0100916 ALOGV("getDuration");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800917 sp<MediaPlayerBase> p = getPlayer();
918 if (p == 0) return UNKNOWN_ERROR;
919 status_t ret = p->getDuration(msec);
920 if (ret == NO_ERROR) {
Steve Block3856b092011-10-20 11:56:00 +0100921 ALOGV("[%d] getDuration = %d", mConnId, *msec);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800922 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000923 ALOGE("getDuration returned %d", ret);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800924 }
925 return ret;
926}
927
Marco Nelissen6b74d672012-02-28 16:07:44 -0800928status_t MediaPlayerService::Client::setNextPlayer(const sp<IMediaPlayer>& player) {
929 ALOGV("setNextPlayer");
930 Mutex::Autolock l(mLock);
931 sp<Client> c = static_cast<Client*>(player.get());
932 mNextClient = c;
John Grossman5f7e55e2012-08-24 14:47:25 -0700933
934 if (c != NULL) {
935 if (mAudioOutput != NULL) {
936 mAudioOutput->setNextOutput(c->mAudioOutput);
937 } else if ((mPlayer != NULL) && !mPlayer->hardwareOutput()) {
938 ALOGE("no current audio output");
939 }
940
941 if ((mPlayer != NULL) && (mNextClient->getPlayer() != NULL)) {
942 mPlayer->setNextPlayer(mNextClient->getPlayer());
943 }
Marco Nelissen6b74d672012-02-28 16:07:44 -0800944 }
John Grossman5f7e55e2012-08-24 14:47:25 -0700945
Marco Nelissen6b74d672012-02-28 16:07:44 -0800946 return OK;
947}
948
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800949status_t MediaPlayerService::Client::seekTo(int msec)
950{
Steve Block3856b092011-10-20 11:56:00 +0100951 ALOGV("[%d] seekTo(%d)", mConnId, msec);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800952 sp<MediaPlayerBase> p = getPlayer();
953 if (p == 0) return UNKNOWN_ERROR;
954 return p->seekTo(msec);
955}
956
957status_t MediaPlayerService::Client::reset()
958{
Steve Block3856b092011-10-20 11:56:00 +0100959 ALOGV("[%d] reset", mConnId);
John Grossmanc795b642012-02-22 15:38:35 -0800960 mRetransmitEndpointValid = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800961 sp<MediaPlayerBase> p = getPlayer();
962 if (p == 0) return UNKNOWN_ERROR;
963 return p->reset();
964}
965
Glenn Kastenfff6d712012-01-12 16:38:12 -0800966status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800967{
Steve Block3856b092011-10-20 11:56:00 +0100968 ALOGV("[%d] setAudioStreamType(%d)", mConnId, type);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800969 // TODO: for hardware output, call player instead
970 Mutex::Autolock l(mLock);
971 if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
972 return NO_ERROR;
973}
974
975status_t MediaPlayerService::Client::setLooping(int loop)
976{
Steve Block3856b092011-10-20 11:56:00 +0100977 ALOGV("[%d] setLooping(%d)", mConnId, loop);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800978 mLoop = loop;
979 sp<MediaPlayerBase> p = getPlayer();
980 if (p != 0) return p->setLooping(loop);
981 return NO_ERROR;
982}
983
984status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
985{
Steve Block3856b092011-10-20 11:56:00 +0100986 ALOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
John Grossman761defc2012-02-09 15:09:05 -0800987
988 // for hardware output, call player instead
989 sp<MediaPlayerBase> p = getPlayer();
990 {
991 Mutex::Autolock l(mLock);
992 if (p != 0 && p->hardwareOutput()) {
993 MediaPlayerHWInterface* hwp =
994 reinterpret_cast<MediaPlayerHWInterface*>(p.get());
995 return hwp->setVolume(leftVolume, rightVolume);
996 } else {
997 if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
998 return NO_ERROR;
999 }
1000 }
1001
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001002 return NO_ERROR;
1003}
1004
Eric Laurent2beeb502010-07-16 07:43:46 -07001005status_t MediaPlayerService::Client::setAuxEffectSendLevel(float level)
1006{
Steve Block3856b092011-10-20 11:56:00 +01001007 ALOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
Eric Laurent2beeb502010-07-16 07:43:46 -07001008 Mutex::Autolock l(mLock);
1009 if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
1010 return NO_ERROR;
1011}
1012
1013status_t MediaPlayerService::Client::attachAuxEffect(int effectId)
1014{
Steve Block3856b092011-10-20 11:56:00 +01001015 ALOGV("[%d] attachAuxEffect(%d)", mConnId, effectId);
Eric Laurent2beeb502010-07-16 07:43:46 -07001016 Mutex::Autolock l(mLock);
1017 if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId);
1018 return NO_ERROR;
1019}
Nicolas Catania48290382009-07-10 13:53:06 -07001020
Gloria Wang4f9e47f2011-04-25 17:28:22 -07001021status_t MediaPlayerService::Client::setParameter(int key, const Parcel &request) {
Steve Block3856b092011-10-20 11:56:00 +01001022 ALOGV("[%d] setParameter(%d)", mConnId, key);
Gloria Wang4f9e47f2011-04-25 17:28:22 -07001023 sp<MediaPlayerBase> p = getPlayer();
1024 if (p == 0) return UNKNOWN_ERROR;
1025 return p->setParameter(key, request);
1026}
1027
1028status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) {
Steve Block3856b092011-10-20 11:56:00 +01001029 ALOGV("[%d] getParameter(%d)", mConnId, key);
Gloria Wang4f9e47f2011-04-25 17:28:22 -07001030 sp<MediaPlayerBase> p = getPlayer();
1031 if (p == 0) return UNKNOWN_ERROR;
1032 return p->getParameter(key, reply);
1033}
1034
John Grossmanc795b642012-02-22 15:38:35 -08001035status_t MediaPlayerService::Client::setRetransmitEndpoint(
1036 const struct sockaddr_in* endpoint) {
1037
1038 if (NULL != endpoint) {
1039 uint32_t a = ntohl(endpoint->sin_addr.s_addr);
1040 uint16_t p = ntohs(endpoint->sin_port);
1041 ALOGV("[%d] setRetransmitEndpoint(%u.%u.%u.%u:%hu)", mConnId,
1042 (a >> 24), (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a & 0xFF), p);
1043 } else {
1044 ALOGV("[%d] setRetransmitEndpoint = <none>", mConnId);
1045 }
1046
1047 sp<MediaPlayerBase> p = getPlayer();
1048
1049 // Right now, the only valid time to set a retransmit endpoint is before
1050 // player selection has been made (since the presence or absence of a
1051 // retransmit endpoint is going to determine which player is selected during
1052 // setDataSource).
1053 if (p != 0) return INVALID_OPERATION;
1054
1055 if (NULL != endpoint) {
1056 mRetransmitEndpoint = *endpoint;
1057 mRetransmitEndpointValid = true;
1058 } else {
1059 mRetransmitEndpointValid = false;
1060 }
1061
1062 return NO_ERROR;
1063}
1064
John Grossman44a7e422012-06-21 17:29:24 -07001065status_t MediaPlayerService::Client::getRetransmitEndpoint(
1066 struct sockaddr_in* endpoint)
1067{
1068 if (NULL == endpoint)
1069 return BAD_VALUE;
1070
1071 sp<MediaPlayerBase> p = getPlayer();
1072
1073 if (p != NULL)
1074 return p->getRetransmitEndpoint(endpoint);
1075
1076 if (!mRetransmitEndpointValid)
1077 return NO_INIT;
1078
1079 *endpoint = mRetransmitEndpoint;
1080
1081 return NO_ERROR;
1082}
1083
Gloria Wangb483c472011-04-11 17:23:27 -07001084void MediaPlayerService::Client::notify(
1085 void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001086{
1087 Client* client = static_cast<Client*>(cookie);
James Dongb8a98252012-08-26 16:13:03 -07001088 if (client == NULL) {
1089 return;
1090 }
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001091
James Dongb8a98252012-08-26 16:13:03 -07001092 sp<IMediaPlayerClient> c;
Marco Nelissen6b74d672012-02-28 16:07:44 -08001093 {
1094 Mutex::Autolock l(client->mLock);
James Dongb8a98252012-08-26 16:13:03 -07001095 c = client->mClient;
Marco Nelissen6b74d672012-02-28 16:07:44 -08001096 if (msg == MEDIA_PLAYBACK_COMPLETE && client->mNextClient != NULL) {
John Grossmancb0b7552012-08-23 17:47:31 -07001097 if (client->mAudioOutput != NULL)
1098 client->mAudioOutput->switchToNextOutput();
Marco Nelissen6b74d672012-02-28 16:07:44 -08001099 client->mNextClient->start();
1100 client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
1101 }
1102 }
1103
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001104 if (MEDIA_INFO == msg &&
Nicolas Catania48290382009-07-10 13:53:06 -07001105 MEDIA_INFO_METADATA_UPDATE == ext1) {
nikoa64c8c72009-07-20 15:07:26 -07001106 const media::Metadata::Type metadata_type = ext2;
Nicolas Catania48290382009-07-10 13:53:06 -07001107
1108 if(client->shouldDropMetadata(metadata_type)) {
1109 return;
1110 }
1111
1112 // Update the list of metadata that have changed. getMetadata
1113 // also access mMetadataUpdated and clears it.
1114 client->addNewMetadataUpdate(metadata_type);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001115 }
James Dongb8a98252012-08-26 16:13:03 -07001116
1117 if (c != NULL) {
1118 ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
1119 c->notify(msg, ext1, ext2, obj);
1120 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001121}
1122
Nicolas Catania48290382009-07-10 13:53:06 -07001123
nikoa64c8c72009-07-20 15:07:26 -07001124bool MediaPlayerService::Client::shouldDropMetadata(media::Metadata::Type code) const
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001125{
Nicolas Catania48290382009-07-10 13:53:06 -07001126 Mutex::Autolock lock(mLock);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001127
Nicolas Catania48290382009-07-10 13:53:06 -07001128 if (findMetadata(mMetadataDrop, code)) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001129 return true;
1130 }
1131
Nicolas Catania48290382009-07-10 13:53:06 -07001132 if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001133 return false;
Nicolas Catania48290382009-07-10 13:53:06 -07001134 } else {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001135 return true;
1136 }
1137}
1138
Nicolas Catania48290382009-07-10 13:53:06 -07001139
nikoa64c8c72009-07-20 15:07:26 -07001140void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
Nicolas Catania48290382009-07-10 13:53:06 -07001141 Mutex::Autolock lock(mLock);
1142 if (mMetadataUpdated.indexOf(metadata_type) < 0) {
1143 mMetadataUpdated.add(metadata_type);
1144 }
1145}
1146
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001147#if CALLBACK_ANTAGONIZER
1148const int Antagonizer::interval = 10000; // 10 msecs
1149
1150Antagonizer::Antagonizer(notify_callback_f cb, void* client) :
1151 mExit(false), mActive(false), mClient(client), mCb(cb)
1152{
1153 createThread(callbackThread, this);
1154}
1155
1156void Antagonizer::kill()
1157{
1158 Mutex::Autolock _l(mLock);
1159 mActive = false;
1160 mExit = true;
1161 mCondition.wait(mLock);
1162}
1163
1164int Antagonizer::callbackThread(void* user)
1165{
Steve Blockb8a80522011-12-20 16:23:08 +00001166 ALOGD("Antagonizer started");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001167 Antagonizer* p = reinterpret_cast<Antagonizer*>(user);
1168 while (!p->mExit) {
1169 if (p->mActive) {
Steve Block3856b092011-10-20 11:56:00 +01001170 ALOGV("send event");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001171 p->mCb(p->mClient, 0, 0, 0);
1172 }
1173 usleep(interval);
1174 }
1175 Mutex::Autolock _l(p->mLock);
1176 p->mCondition.signal();
Steve Blockb8a80522011-12-20 16:23:08 +00001177 ALOGD("Antagonizer stopped");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001178 return 0;
1179}
1180#endif
1181
Andreas Huber1b86fe02014-01-29 11:13:26 -08001182status_t MediaPlayerService::decode(
1183 const sp<IMediaHTTPService> &httpService,
1184 const char* url,
1185 uint32_t *pSampleRate,
1186 int* pNumChannels,
1187 audio_format_t* pFormat,
1188 const sp<IMemoryHeap>& heap,
1189 size_t *pSize)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001190{
Steve Block3856b092011-10-20 11:56:00 +01001191 ALOGV("decode(%s)", url);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001192 sp<MediaPlayerBase> player;
Eric Laurent3d00aa62013-09-24 09:53:27 -07001193 status_t status = BAD_VALUE;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001194
1195 // Protect our precious, precious DRMd ringtones by only allowing
1196 // decoding of http, but not filesystem paths or content Uris.
1197 // If the application wants to decode those, it should open a
1198 // filedescriptor for them and use that.
1199 if (url != NULL && strncmp(url, "http://", 7) != 0) {
Steve Blockb8a80522011-12-20 16:23:08 +00001200 ALOGD("Can't decode %s by path, use filedescriptor instead", url);
Eric Laurent3d00aa62013-09-24 09:53:27 -07001201 return BAD_VALUE;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001202 }
1203
John Grossman44a7e422012-06-21 17:29:24 -07001204 player_type playerType =
1205 MediaPlayerFactory::getPlayerType(NULL /* client */, url);
Steve Block3856b092011-10-20 11:56:00 +01001206 ALOGV("player type = %d", playerType);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001207
1208 // create the right type of player
Eric Laurent3d00aa62013-09-24 09:53:27 -07001209 sp<AudioCache> cache = new AudioCache(heap);
John Grossman44a7e422012-06-21 17:29:24 -07001210 player = MediaPlayerFactory::createPlayer(playerType, cache.get(), cache->notify);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001211 if (player == NULL) goto Exit;
1212 if (player->hardwareOutput()) goto Exit;
1213
1214 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1215
1216 // set data source
Andreas Huber1b86fe02014-01-29 11:13:26 -08001217 if (player->setDataSource(httpService, url) != NO_ERROR) goto Exit;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001218
Steve Block3856b092011-10-20 11:56:00 +01001219 ALOGV("prepare");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001220 player->prepareAsync();
1221
Steve Block3856b092011-10-20 11:56:00 +01001222 ALOGV("wait for prepare");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001223 if (cache->wait() != NO_ERROR) goto Exit;
1224
Steve Block3856b092011-10-20 11:56:00 +01001225 ALOGV("start");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001226 player->start();
1227
Steve Block3856b092011-10-20 11:56:00 +01001228 ALOGV("wait for playback complete");
Eric Laurent9cb839a2011-09-27 09:48:56 -07001229 cache->wait();
1230 // in case of error, return what was successfully decoded.
1231 if (cache->size() == 0) {
1232 goto Exit;
1233 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001234
Eric Laurent3d00aa62013-09-24 09:53:27 -07001235 *pSize = cache->size();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001236 *pSampleRate = cache->sampleRate();
1237 *pNumChannels = cache->channelCount();
Glenn Kastene1c39622012-01-04 09:36:37 -08001238 *pFormat = cache->format();
Eric Laurent3d00aa62013-09-24 09:53:27 -07001239 ALOGV("return size %d sampleRate=%u, channelCount = %d, format = %d",
1240 *pSize, *pSampleRate, *pNumChannels, *pFormat);
1241 status = NO_ERROR;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001242
1243Exit:
1244 if (player != 0) player->reset();
Eric Laurent3d00aa62013-09-24 09:53:27 -07001245 return status;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001246}
1247
Eric Laurent3d00aa62013-09-24 09:53:27 -07001248status_t MediaPlayerService::decode(int fd, int64_t offset, int64_t length,
1249 uint32_t *pSampleRate, int* pNumChannels,
1250 audio_format_t* pFormat,
1251 const sp<IMemoryHeap>& heap, size_t *pSize)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001252{
Steve Block3856b092011-10-20 11:56:00 +01001253 ALOGV("decode(%d, %lld, %lld)", fd, offset, length);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001254 sp<MediaPlayerBase> player;
Eric Laurent3d00aa62013-09-24 09:53:27 -07001255 status_t status = BAD_VALUE;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001256
John Grossman44a7e422012-06-21 17:29:24 -07001257 player_type playerType = MediaPlayerFactory::getPlayerType(NULL /* client */,
1258 fd,
1259 offset,
1260 length);
Steve Block3856b092011-10-20 11:56:00 +01001261 ALOGV("player type = %d", playerType);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001262
1263 // create the right type of player
Eric Laurent3d00aa62013-09-24 09:53:27 -07001264 sp<AudioCache> cache = new AudioCache(heap);
John Grossman44a7e422012-06-21 17:29:24 -07001265 player = MediaPlayerFactory::createPlayer(playerType, cache.get(), cache->notify);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001266 if (player == NULL) goto Exit;
1267 if (player->hardwareOutput()) goto Exit;
1268
1269 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1270
1271 // set data source
1272 if (player->setDataSource(fd, offset, length) != NO_ERROR) goto Exit;
1273
Steve Block3856b092011-10-20 11:56:00 +01001274 ALOGV("prepare");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001275 player->prepareAsync();
1276
Steve Block3856b092011-10-20 11:56:00 +01001277 ALOGV("wait for prepare");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001278 if (cache->wait() != NO_ERROR) goto Exit;
1279
Steve Block3856b092011-10-20 11:56:00 +01001280 ALOGV("start");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001281 player->start();
1282
Steve Block3856b092011-10-20 11:56:00 +01001283 ALOGV("wait for playback complete");
Eric Laurent9cb839a2011-09-27 09:48:56 -07001284 cache->wait();
1285 // in case of error, return what was successfully decoded.
1286 if (cache->size() == 0) {
1287 goto Exit;
1288 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001289
Eric Laurent3d00aa62013-09-24 09:53:27 -07001290 *pSize = cache->size();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001291 *pSampleRate = cache->sampleRate();
1292 *pNumChannels = cache->channelCount();
1293 *pFormat = cache->format();
Eric Laurent3d00aa62013-09-24 09:53:27 -07001294 ALOGV("return size %d, sampleRate=%u, channelCount = %d, format = %d",
1295 *pSize, *pSampleRate, *pNumChannels, *pFormat);
1296 status = NO_ERROR;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001297
1298Exit:
1299 if (player != 0) player->reset();
1300 ::close(fd);
Eric Laurent3d00aa62013-09-24 09:53:27 -07001301 return status;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001302}
1303
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001304
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001305#undef LOG_TAG
1306#define LOG_TAG "AudioSink"
Marco Nelissen462fd2f2013-01-14 14:12:05 -08001307MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid)
Andreas Huber20111aa2009-07-14 16:56:47 -07001308 : mCallback(NULL),
Eric Laurenta514bdb2010-06-21 09:27:30 -07001309 mCallbackCookie(NULL),
Marco Nelissen6b74d672012-02-28 16:07:44 -08001310 mCallbackData(NULL),
Marco Nelissen4110c102012-03-29 09:31:28 -07001311 mBytesWritten(0),
Eric Laurent1948eb32012-04-13 16:50:19 -07001312 mSessionId(sessionId),
Marco Nelissen462fd2f2013-01-14 14:12:05 -08001313 mUid(uid),
Eric Laurent1948eb32012-04-13 16:50:19 -07001314 mFlags(AUDIO_OUTPUT_FLAG_NONE) {
Steve Block3856b092011-10-20 11:56:00 +01001315 ALOGV("AudioOutput(%d)", sessionId);
Dima Zavinfce7a472011-04-19 22:30:36 -07001316 mStreamType = AUDIO_STREAM_MUSIC;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001317 mLeftVolume = 1.0;
1318 mRightVolume = 1.0;
Jean-Michel Trivi7a8b0ed2012-02-02 09:06:31 -08001319 mPlaybackRatePermille = 1000;
1320 mSampleRateHz = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001321 mMsecsPerFrame = 0;
Eric Laurent2beeb502010-07-16 07:43:46 -07001322 mAuxEffectId = 0;
1323 mSendLevel = 0.0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001324 setMinBufferCount();
1325}
1326
1327MediaPlayerService::AudioOutput::~AudioOutput()
1328{
1329 close();
Marco Nelissen6b74d672012-02-28 16:07:44 -08001330 delete mCallbackData;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001331}
1332
1333void MediaPlayerService::AudioOutput::setMinBufferCount()
1334{
1335 char value[PROPERTY_VALUE_MAX];
1336 if (property_get("ro.kernel.qemu", value, 0)) {
1337 mIsOnEmulator = true;
1338 mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
1339 }
1340}
1341
1342bool MediaPlayerService::AudioOutput::isOnEmulator()
1343{
1344 setMinBufferCount();
1345 return mIsOnEmulator;
1346}
1347
1348int MediaPlayerService::AudioOutput::getMinBufferCount()
1349{
1350 setMinBufferCount();
1351 return mMinBufferCount;
1352}
1353
1354ssize_t MediaPlayerService::AudioOutput::bufferSize() const
1355{
1356 if (mTrack == 0) return NO_INIT;
1357 return mTrack->frameCount() * frameSize();
1358}
1359
1360ssize_t MediaPlayerService::AudioOutput::frameCount() const
1361{
1362 if (mTrack == 0) return NO_INIT;
1363 return mTrack->frameCount();
1364}
1365
1366ssize_t MediaPlayerService::AudioOutput::channelCount() const
1367{
1368 if (mTrack == 0) return NO_INIT;
1369 return mTrack->channelCount();
1370}
1371
1372ssize_t MediaPlayerService::AudioOutput::frameSize() const
1373{
1374 if (mTrack == 0) return NO_INIT;
1375 return mTrack->frameSize();
1376}
1377
1378uint32_t MediaPlayerService::AudioOutput::latency () const
1379{
Eric Laurentdb354e52012-03-05 17:27:11 -08001380 if (mTrack == 0) return 0;
1381 return mTrack->latency();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001382}
1383
1384float MediaPlayerService::AudioOutput::msecsPerFrame() const
1385{
1386 return mMsecsPerFrame;
1387}
1388
Marco Nelissen4110c102012-03-29 09:31:28 -07001389status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) const
Eric Laurent342e9cf2010-01-19 17:37:09 -08001390{
1391 if (mTrack == 0) return NO_INIT;
1392 return mTrack->getPosition(position);
1393}
1394
Marco Nelissen4110c102012-03-29 09:31:28 -07001395status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
1396{
1397 if (mTrack == 0) return NO_INIT;
1398 *frameswritten = mBytesWritten / frameSize();
1399 return OK;
1400}
1401
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001402status_t MediaPlayerService::AudioOutput::setParameters(const String8& keyValuePairs)
1403{
1404 if (mTrack == 0) return NO_INIT;
1405 return mTrack->setParameters(keyValuePairs);
1406}
1407
1408String8 MediaPlayerService::AudioOutput::getParameters(const String8& keys)
1409{
1410 if (mTrack == 0) return String8::empty();
1411 return mTrack->getParameters(keys);
1412}
1413
1414void MediaPlayerService::AudioOutput::deleteRecycledTrack()
1415{
1416 ALOGV("deleteRecycledTrack");
1417
1418 if (mRecycledTrack != 0) {
1419
1420 if (mCallbackData != NULL) {
1421 mCallbackData->setOutput(NULL);
1422 mCallbackData->endTrackSwitch();
1423 }
1424
1425 if ((mRecycledTrack->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) {
1426 mRecycledTrack->flush();
1427 }
1428 // An offloaded track isn't flushed because the STREAM_END is reported
1429 // slightly prematurely to allow time for the gapless track switch
1430 // but this means that if we decide not to recycle the track there
1431 // could be a small amount of residual data still playing. We leave
1432 // AudioFlinger to drain the track.
1433
1434 mRecycledTrack.clear();
1435 delete mCallbackData;
1436 mCallbackData = NULL;
1437 close();
1438 }
1439}
1440
Andreas Huber20111aa2009-07-14 16:56:47 -07001441status_t MediaPlayerService::AudioOutput::open(
Jean-Michel Trivi786618f2012-03-02 14:54:07 -08001442 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
1443 audio_format_t format, int bufferCount,
Eric Laurent1948eb32012-04-13 16:50:19 -07001444 AudioCallback cb, void *cookie,
Richard Fitzgeraldad3af332013-03-25 16:54:37 +00001445 audio_output_flags_t flags,
1446 const audio_offload_info_t *offloadInfo)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001447{
Andreas Huber20111aa2009-07-14 16:56:47 -07001448 mCallback = cb;
1449 mCallbackCookie = cookie;
1450
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001451 // Check argument "bufferCount" against the mininum buffer count
1452 if (bufferCount < mMinBufferCount) {
Steve Blockb8a80522011-12-20 16:23:08 +00001453 ALOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001454 bufferCount = mMinBufferCount;
1455
1456 }
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001457 ALOGV("open(%u, %d, 0x%x, 0x%x, %d, %d 0x%x)", sampleRate, channelCount, channelMask,
1458 format, bufferCount, mSessionId, flags);
Glenn Kasten1127d652012-11-14 08:44:39 -08001459 uint32_t afSampleRate;
Glenn Kasten7da35f22012-11-14 12:54:39 -08001460 size_t afFrameCount;
Eric Laurent1948eb32012-04-13 16:50:19 -07001461 uint32_t frameCount;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001462
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001463 // offloading is only supported in callback mode for now.
1464 // offloadInfo must be present if offload flag is set
1465 if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
1466 ((cb == NULL) || (offloadInfo == NULL))) {
1467 return BAD_VALUE;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001468 }
1469
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001470 if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
1471 frameCount = 0; // AudioTrack will get frame count from AudioFlinger
1472 } else {
1473 uint32_t afSampleRate;
1474 size_t afFrameCount;
1475
1476 if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
1477 return NO_INIT;
1478 }
1479 if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
1480 return NO_INIT;
1481 }
1482
1483 frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
1484 }
Andreas Huber20111aa2009-07-14 16:56:47 -07001485
Jean-Michel Trivi786618f2012-03-02 14:54:07 -08001486 if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
Glenn Kastenab334fd2012-03-14 12:56:06 -07001487 channelMask = audio_channel_out_mask_from_count(channelCount);
Jean-Michel Trivi786618f2012-03-02 14:54:07 -08001488 if (0 == channelMask) {
1489 ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
1490 return NO_INIT;
1491 }
1492 }
Eric Laurent1948eb32012-04-13 16:50:19 -07001493
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001494 // Check whether we can recycle the track
1495 bool reuse = false;
1496 bool bothOffloaded = false;
Marco Nelissen67295b52012-06-11 14:52:53 -07001497
Glenn Kasten2799d742013-05-30 14:33:29 -07001498 if (mRecycledTrack != 0) {
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001499 // check whether we are switching between two offloaded tracks
1500 bothOffloaded = (flags & mRecycledTrack->getFlags()
1501 & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0;
Marco Nelissen67295b52012-06-11 14:52:53 -07001502
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001503 // check if the existing track can be reused as-is, or if a new track needs to be created.
1504 reuse = true;
1505
Marco Nelissen67295b52012-06-11 14:52:53 -07001506 if ((mCallbackData == NULL && mCallback != NULL) ||
1507 (mCallbackData != NULL && mCallback == NULL)) {
1508 // recycled track uses callbacks but the caller wants to use writes, or vice versa
1509 ALOGV("can't chain callback and write");
1510 reuse = false;
1511 } else if ((mRecycledTrack->getSampleRate() != sampleRate) ||
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001512 (mRecycledTrack->channelCount() != (uint32_t)channelCount) ) {
1513 ALOGV("samplerate, channelcount differ: %u/%u Hz, %u/%d ch",
Marco Nelissen67295b52012-06-11 14:52:53 -07001514 mRecycledTrack->getSampleRate(), sampleRate,
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001515 mRecycledTrack->channelCount(), channelCount);
Marco Nelissen67295b52012-06-11 14:52:53 -07001516 reuse = false;
1517 } else if (flags != mFlags) {
1518 ALOGV("output flags differ %08x/%08x", flags, mFlags);
1519 reuse = false;
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001520 } else if (mRecycledTrack->format() != format) {
1521 reuse = false;
Marco Nelissen67295b52012-06-11 14:52:53 -07001522 }
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001523 } else {
1524 ALOGV("no track available to recycle");
1525 }
1526
1527 ALOGV_IF(bothOffloaded, "both tracks offloaded");
1528
1529 // If we can't recycle and both tracks are offloaded
1530 // we must close the previous output before opening a new one
1531 if (bothOffloaded && !reuse) {
1532 ALOGV("both offloaded and not recycling");
1533 deleteRecycledTrack();
1534 }
1535
1536 sp<AudioTrack> t;
1537 CallbackData *newcbd = NULL;
1538
1539 // We don't attempt to create a new track if we are recycling an
1540 // offloaded track. But, if we are recycling a non-offloaded or we
1541 // are switching where one is offloaded and one isn't then we create
1542 // the new track in advance so that we can read additional stream info
1543
1544 if (!(reuse && bothOffloaded)) {
1545 ALOGV("creating new AudioTrack");
1546
1547 if (mCallback != NULL) {
1548 newcbd = new CallbackData(this);
1549 t = new AudioTrack(
1550 mStreamType,
1551 sampleRate,
1552 format,
1553 channelMask,
1554 frameCount,
1555 flags,
1556 CallbackWrapper,
1557 newcbd,
1558 0, // notification frames
1559 mSessionId,
1560 AudioTrack::TRANSFER_CALLBACK,
Marco Nelissen462fd2f2013-01-14 14:12:05 -08001561 offloadInfo,
1562 mUid);
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001563 } else {
1564 t = new AudioTrack(
1565 mStreamType,
1566 sampleRate,
1567 format,
1568 channelMask,
1569 frameCount,
1570 flags,
Marco Nelissen462fd2f2013-01-14 14:12:05 -08001571 NULL, // callback
1572 NULL, // user data
1573 0, // notification frames
1574 mSessionId,
1575 AudioTrack::TRANSFER_DEFAULT,
1576 NULL, // offload info
1577 mUid);
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001578 }
1579
1580 if ((t == 0) || (t->initCheck() != NO_ERROR)) {
1581 ALOGE("Unable to create audio track");
1582 delete newcbd;
1583 return NO_INIT;
1584 }
1585 }
1586
1587 if (reuse) {
1588 CHECK(mRecycledTrack != NULL);
1589
1590 if (!bothOffloaded) {
1591 if (mRecycledTrack->frameCount() != t->frameCount()) {
1592 ALOGV("framecount differs: %u/%u frames",
1593 mRecycledTrack->frameCount(), t->frameCount());
1594 reuse = false;
1595 }
1596 }
1597
Marco Nelissen67295b52012-06-11 14:52:53 -07001598 if (reuse) {
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001599 ALOGV("chaining to next output and recycling track");
Marco Nelissen67295b52012-06-11 14:52:53 -07001600 close();
1601 mTrack = mRecycledTrack;
Glenn Kasten2799d742013-05-30 14:33:29 -07001602 mRecycledTrack.clear();
Marco Nelissen67295b52012-06-11 14:52:53 -07001603 if (mCallbackData != NULL) {
1604 mCallbackData->setOutput(this);
1605 }
Marco Nelissen67295b52012-06-11 14:52:53 -07001606 delete newcbd;
1607 return OK;
1608 }
Marco Nelissen67295b52012-06-11 14:52:53 -07001609 }
1610
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001611 // we're not going to reuse the track, unblock and flush it
1612 // this was done earlier if both tracks are offloaded
1613 if (!bothOffloaded) {
1614 deleteRecycledTrack();
1615 }
1616
1617 CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
1618
Marco Nelissen67295b52012-06-11 14:52:53 -07001619 mCallbackData = newcbd;
Steve Block3856b092011-10-20 11:56:00 +01001620 ALOGV("setVolume");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001621 t->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -07001622
Jean-Michel Trivi7a8b0ed2012-02-02 09:06:31 -08001623 mSampleRateHz = sampleRate;
Eric Laurent1948eb32012-04-13 16:50:19 -07001624 mFlags = flags;
Jean-Michel Trivi7a8b0ed2012-02-02 09:06:31 -08001625 mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
Marco Nelissen99448602012-04-02 12:16:49 -07001626 uint32_t pos;
1627 if (t->getPosition(&pos) == OK) {
1628 mBytesWritten = uint64_t(pos) * t->frameSize();
1629 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001630 mTrack = t;
Eric Laurent2beeb502010-07-16 07:43:46 -07001631
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001632 status_t res = NO_ERROR;
1633 if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) {
1634 res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
1635 if (res == NO_ERROR) {
1636 t->setAuxEffectSendLevel(mSendLevel);
1637 res = t->attachAuxEffect(mAuxEffectId);
1638 }
Jean-Michel Trivi7a8b0ed2012-02-02 09:06:31 -08001639 }
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001640 ALOGV("open() DONE status %d", res);
1641 return res;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001642}
1643
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001644status_t MediaPlayerService::AudioOutput::start()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001645{
Steve Block3856b092011-10-20 11:56:00 +01001646 ALOGV("start");
Marco Nelissen6b74d672012-02-28 16:07:44 -08001647 if (mCallbackData != NULL) {
1648 mCallbackData->endTrackSwitch();
1649 }
Glenn Kasten2799d742013-05-30 14:33:29 -07001650 if (mTrack != 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001651 mTrack->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -07001652 mTrack->setAuxEffectSendLevel(mSendLevel);
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001653 return mTrack->start();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001654 }
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001655 return NO_INIT;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001656}
1657
Marco Nelissen6b74d672012-02-28 16:07:44 -08001658void MediaPlayerService::AudioOutput::setNextOutput(const sp<AudioOutput>& nextOutput) {
1659 mNextOutput = nextOutput;
1660}
Marco Nelissen7ee8ac92010-01-12 09:23:54 -08001661
1662
Marco Nelissen6b74d672012-02-28 16:07:44 -08001663void MediaPlayerService::AudioOutput::switchToNextOutput() {
1664 ALOGV("switchToNextOutput");
1665 if (mNextOutput != NULL) {
1666 if (mCallbackData != NULL) {
1667 mCallbackData->beginTrackSwitch();
1668 }
1669 delete mNextOutput->mCallbackData;
1670 mNextOutput->mCallbackData = mCallbackData;
1671 mCallbackData = NULL;
1672 mNextOutput->mRecycledTrack = mTrack;
Glenn Kasten2799d742013-05-30 14:33:29 -07001673 mTrack.clear();
Marco Nelissen6b74d672012-02-28 16:07:44 -08001674 mNextOutput->mSampleRateHz = mSampleRateHz;
1675 mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
Marco Nelissen4110c102012-03-29 09:31:28 -07001676 mNextOutput->mBytesWritten = mBytesWritten;
Marco Nelissend791e092012-06-11 17:00:59 -07001677 mNextOutput->mFlags = mFlags;
Marco Nelissen6b74d672012-02-28 16:07:44 -08001678 }
1679}
1680
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001681ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
1682{
Andreas Huber20111aa2009-07-14 16:56:47 -07001683 LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
1684
Steve Block3856b092011-10-20 11:56:00 +01001685 //ALOGV("write(%p, %u)", buffer, size);
Glenn Kasten2799d742013-05-30 14:33:29 -07001686 if (mTrack != 0) {
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001687 ssize_t ret = mTrack->write(buffer, size);
Marco Nelissen4110c102012-03-29 09:31:28 -07001688 mBytesWritten += ret;
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001689 return ret;
1690 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001691 return NO_INIT;
1692}
1693
1694void MediaPlayerService::AudioOutput::stop()
1695{
Steve Block3856b092011-10-20 11:56:00 +01001696 ALOGV("stop");
Glenn Kasten2799d742013-05-30 14:33:29 -07001697 if (mTrack != 0) mTrack->stop();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001698}
1699
1700void MediaPlayerService::AudioOutput::flush()
1701{
Steve Block3856b092011-10-20 11:56:00 +01001702 ALOGV("flush");
Glenn Kasten2799d742013-05-30 14:33:29 -07001703 if (mTrack != 0) mTrack->flush();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001704}
1705
1706void MediaPlayerService::AudioOutput::pause()
1707{
Steve Block3856b092011-10-20 11:56:00 +01001708 ALOGV("pause");
Glenn Kasten2799d742013-05-30 14:33:29 -07001709 if (mTrack != 0) mTrack->pause();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001710}
1711
1712void MediaPlayerService::AudioOutput::close()
1713{
Steve Block3856b092011-10-20 11:56:00 +01001714 ALOGV("close");
Glenn Kasten2799d742013-05-30 14:33:29 -07001715 mTrack.clear();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001716}
1717
1718void MediaPlayerService::AudioOutput::setVolume(float left, float right)
1719{
Steve Block3856b092011-10-20 11:56:00 +01001720 ALOGV("setVolume(%f, %f)", left, right);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001721 mLeftVolume = left;
1722 mRightVolume = right;
Glenn Kasten2799d742013-05-30 14:33:29 -07001723 if (mTrack != 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001724 mTrack->setVolume(left, right);
1725 }
1726}
1727
Jean-Michel Trivi7a8b0ed2012-02-02 09:06:31 -08001728status_t MediaPlayerService::AudioOutput::setPlaybackRatePermille(int32_t ratePermille)
1729{
1730 ALOGV("setPlaybackRatePermille(%d)", ratePermille);
1731 status_t res = NO_ERROR;
Glenn Kasten2799d742013-05-30 14:33:29 -07001732 if (mTrack != 0) {
Jean-Michel Trivi7a8b0ed2012-02-02 09:06:31 -08001733 res = mTrack->setSampleRate(ratePermille * mSampleRateHz / 1000);
1734 } else {
1735 res = NO_INIT;
1736 }
1737 mPlaybackRatePermille = ratePermille;
1738 if (mSampleRateHz != 0) {
1739 mMsecsPerFrame = mPlaybackRatePermille / (float) mSampleRateHz;
1740 }
1741 return res;
1742}
1743
Eric Laurent2beeb502010-07-16 07:43:46 -07001744status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
1745{
Steve Block3856b092011-10-20 11:56:00 +01001746 ALOGV("setAuxEffectSendLevel(%f)", level);
Eric Laurent2beeb502010-07-16 07:43:46 -07001747 mSendLevel = level;
Glenn Kasten2799d742013-05-30 14:33:29 -07001748 if (mTrack != 0) {
Eric Laurent2beeb502010-07-16 07:43:46 -07001749 return mTrack->setAuxEffectSendLevel(level);
1750 }
1751 return NO_ERROR;
1752}
1753
1754status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
1755{
Steve Block3856b092011-10-20 11:56:00 +01001756 ALOGV("attachAuxEffect(%d)", effectId);
Eric Laurent2beeb502010-07-16 07:43:46 -07001757 mAuxEffectId = effectId;
Glenn Kasten2799d742013-05-30 14:33:29 -07001758 if (mTrack != 0) {
Eric Laurent2beeb502010-07-16 07:43:46 -07001759 return mTrack->attachAuxEffect(effectId);
1760 }
1761 return NO_ERROR;
1762}
1763
Andreas Huber20111aa2009-07-14 16:56:47 -07001764// static
1765void MediaPlayerService::AudioOutput::CallbackWrapper(
Glenn Kastend217a8c2011-06-01 15:20:35 -07001766 int event, void *cookie, void *info) {
Steve Block3856b092011-10-20 11:56:00 +01001767 //ALOGV("callbackwrapper");
Marco Nelissen6b74d672012-02-28 16:07:44 -08001768 CallbackData *data = (CallbackData*)cookie;
1769 data->lock();
1770 AudioOutput *me = data->getOutput();
Andreas Huber20111aa2009-07-14 16:56:47 -07001771 AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
Marco Nelissen6b74d672012-02-28 16:07:44 -08001772 if (me == NULL) {
1773 // no output set, likely because the track was scheduled to be reused
1774 // by another player, but the format turned out to be incompatible.
1775 data->unlock();
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001776 if (buffer != NULL) {
1777 buffer->size = 0;
1778 }
Marco Nelissen6b74d672012-02-28 16:07:44 -08001779 return;
1780 }
Andreas Huber20111aa2009-07-14 16:56:47 -07001781
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001782 switch(event) {
1783 case AudioTrack::EVENT_MORE_DATA: {
1784 size_t actualSize = (*me->mCallback)(
1785 me, buffer->raw, buffer->size, me->mCallbackCookie,
1786 CB_EVENT_FILL_BUFFER);
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001787
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001788 if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
1789 // We've reached EOS but the audio track is not stopped yet,
1790 // keep playing silence.
Andreas Huber2e8ffaf2010-02-18 16:45:13 -08001791
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001792 memset(buffer->raw, 0, buffer->size);
1793 actualSize = buffer->size;
1794 }
1795
1796 buffer->size = actualSize;
1797 } break;
1798
1799
1800 case AudioTrack::EVENT_STREAM_END:
1801 ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
1802 (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
1803 me->mCallbackCookie, CB_EVENT_STREAM_END);
1804 break;
1805
1806 case AudioTrack::EVENT_NEW_IAUDIOTRACK :
1807 ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
1808 (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
1809 me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
1810 break;
1811
1812 default:
1813 ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
Andreas Huber51c1e0e2011-04-04 11:43:40 -07001814 }
1815
Marco Nelissen6b74d672012-02-28 16:07:44 -08001816 data->unlock();
Andreas Huber20111aa2009-07-14 16:56:47 -07001817}
1818
Marco Nelissen4110c102012-03-29 09:31:28 -07001819int MediaPlayerService::AudioOutput::getSessionId() const
Eric Laurent8c563ed2010-10-07 18:23:03 -07001820{
1821 return mSessionId;
1822}
1823
Eric Laurent6f59db12013-07-26 17:16:50 -07001824uint32_t MediaPlayerService::AudioOutput::getSampleRate() const
1825{
1826 if (mTrack == 0) return 0;
1827 return mTrack->getSampleRate();
1828}
1829
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001830#undef LOG_TAG
1831#define LOG_TAG "AudioCache"
Eric Laurent3d00aa62013-09-24 09:53:27 -07001832MediaPlayerService::AudioCache::AudioCache(const sp<IMemoryHeap>& heap) :
1833 mHeap(heap), mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
1834 mError(NO_ERROR), mCommandComplete(false)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001835{
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001836}
1837
1838uint32_t MediaPlayerService::AudioCache::latency () const
1839{
1840 return 0;
1841}
1842
1843float MediaPlayerService::AudioCache::msecsPerFrame() const
1844{
1845 return mMsecsPerFrame;
1846}
1847
Marco Nelissen4110c102012-03-29 09:31:28 -07001848status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) const
Eric Laurent342e9cf2010-01-19 17:37:09 -08001849{
1850 if (position == 0) return BAD_VALUE;
1851 *position = mSize;
1852 return NO_ERROR;
1853}
1854
Marco Nelissen4110c102012-03-29 09:31:28 -07001855status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const
1856{
1857 if (written == 0) return BAD_VALUE;
1858 *written = mSize;
1859 return NO_ERROR;
1860}
1861
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001862////////////////////////////////////////////////////////////////////////////////
1863
1864struct CallbackThread : public Thread {
1865 CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink,
1866 MediaPlayerBase::AudioSink::AudioCallback cb,
1867 void *cookie);
1868
1869protected:
1870 virtual ~CallbackThread();
1871
1872 virtual bool threadLoop();
1873
1874private:
1875 wp<MediaPlayerBase::AudioSink> mSink;
1876 MediaPlayerBase::AudioSink::AudioCallback mCallback;
1877 void *mCookie;
1878 void *mBuffer;
1879 size_t mBufferSize;
1880
1881 CallbackThread(const CallbackThread &);
1882 CallbackThread &operator=(const CallbackThread &);
1883};
1884
1885CallbackThread::CallbackThread(
1886 const wp<MediaPlayerBase::AudioSink> &sink,
1887 MediaPlayerBase::AudioSink::AudioCallback cb,
1888 void *cookie)
1889 : mSink(sink),
1890 mCallback(cb),
1891 mCookie(cookie),
1892 mBuffer(NULL),
1893 mBufferSize(0) {
1894}
1895
1896CallbackThread::~CallbackThread() {
1897 if (mBuffer) {
1898 free(mBuffer);
1899 mBuffer = NULL;
1900 }
1901}
1902
1903bool CallbackThread::threadLoop() {
1904 sp<MediaPlayerBase::AudioSink> sink = mSink.promote();
1905 if (sink == NULL) {
1906 return false;
1907 }
1908
1909 if (mBuffer == NULL) {
1910 mBufferSize = sink->bufferSize();
1911 mBuffer = malloc(mBufferSize);
1912 }
1913
1914 size_t actualSize =
Richard Fitzgeraldad3af332013-03-25 16:54:37 +00001915 (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie,
1916 MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER);
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001917
1918 if (actualSize > 0) {
1919 sink->write(mBuffer, actualSize);
1920 }
1921
1922 return true;
1923}
1924
1925////////////////////////////////////////////////////////////////////////////////
1926
Andreas Huber20111aa2009-07-14 16:56:47 -07001927status_t MediaPlayerService::AudioCache::open(
Jean-Michel Trivi786618f2012-03-02 14:54:07 -08001928 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
1929 audio_format_t format, int bufferCount,
Richard Fitzgeraldad3af332013-03-25 16:54:37 +00001930 AudioCallback cb, void *cookie, audio_output_flags_t flags,
1931 const audio_offload_info_t *offloadInfo)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001932{
Jean-Michel Trivi786618f2012-03-02 14:54:07 -08001933 ALOGV("open(%u, %d, 0x%x, %d, %d)", sampleRate, channelCount, channelMask, format, bufferCount);
Dave Sparks8eb80112009-12-09 20:20:26 -08001934 if (mHeap->getHeapID() < 0) {
1935 return NO_INIT;
1936 }
Andreas Huber20111aa2009-07-14 16:56:47 -07001937
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001938 mSampleRate = sampleRate;
1939 mChannelCount = (uint16_t)channelCount;
Glenn Kastene1c39622012-01-04 09:36:37 -08001940 mFormat = format;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001941 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001942
1943 if (cb != NULL) {
1944 mCallbackThread = new CallbackThread(this, cb, cookie);
1945 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001946 return NO_ERROR;
1947}
1948
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001949status_t MediaPlayerService::AudioCache::start() {
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001950 if (mCallbackThread != NULL) {
1951 mCallbackThread->run("AudioCache callback");
1952 }
Richard Fitzgeraldd89532e2013-05-14 13:18:21 +01001953 return NO_ERROR;
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001954}
1955
1956void MediaPlayerService::AudioCache::stop() {
1957 if (mCallbackThread != NULL) {
1958 mCallbackThread->requestExitAndWait();
1959 }
1960}
1961
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001962ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
1963{
Steve Block3856b092011-10-20 11:56:00 +01001964 ALOGV("write(%p, %u)", buffer, size);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001965 if ((buffer == 0) || (size == 0)) return size;
1966
1967 uint8_t* p = static_cast<uint8_t*>(mHeap->getBase());
1968 if (p == NULL) return NO_INIT;
1969 p += mSize;
Steve Block3856b092011-10-20 11:56:00 +01001970 ALOGV("memcpy(%p, %p, %u)", p, buffer, size);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001971 if (mSize + size > mHeap->getSize()) {
Steve Block29357bc2012-01-06 19:20:56 +00001972 ALOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001973 size = mHeap->getSize() - mSize;
1974 }
1975 memcpy(p, buffer, size);
1976 mSize += size;
1977 return size;
1978}
1979
1980// call with lock held
1981status_t MediaPlayerService::AudioCache::wait()
1982{
1983 Mutex::Autolock lock(mLock);
Dave Sparks4bbc0ba2010-03-01 19:29:58 -08001984 while (!mCommandComplete) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001985 mSignal.wait(mLock);
1986 }
1987 mCommandComplete = false;
1988
1989 if (mError == NO_ERROR) {
Steve Block3856b092011-10-20 11:56:00 +01001990 ALOGV("wait - success");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001991 } else {
Steve Block3856b092011-10-20 11:56:00 +01001992 ALOGV("wait - error");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001993 }
1994 return mError;
1995}
1996
Gloria Wangb483c472011-04-11 17:23:27 -07001997void MediaPlayerService::AudioCache::notify(
1998 void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001999{
Steve Block3856b092011-10-20 11:56:00 +01002000 ALOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002001 AudioCache* p = static_cast<AudioCache*>(cookie);
2002
2003 // ignore buffering messages
Dave Sparks8eb80112009-12-09 20:20:26 -08002004 switch (msg)
2005 {
2006 case MEDIA_ERROR:
Steve Block29357bc2012-01-06 19:20:56 +00002007 ALOGE("Error %d, %d occurred", ext1, ext2);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002008 p->mError = ext1;
Dave Sparks8eb80112009-12-09 20:20:26 -08002009 break;
2010 case MEDIA_PREPARED:
Steve Block3856b092011-10-20 11:56:00 +01002011 ALOGV("prepared");
Dave Sparks8eb80112009-12-09 20:20:26 -08002012 break;
2013 case MEDIA_PLAYBACK_COMPLETE:
Steve Block3856b092011-10-20 11:56:00 +01002014 ALOGV("playback complete");
Dave Sparks8eb80112009-12-09 20:20:26 -08002015 break;
2016 default:
Steve Block3856b092011-10-20 11:56:00 +01002017 ALOGV("ignored");
Dave Sparks8eb80112009-12-09 20:20:26 -08002018 return;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002019 }
2020
2021 // wake up thread
Dave Sparksfe4c6f02010-03-02 12:56:37 -08002022 Mutex::Autolock lock(p->mLock);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002023 p->mCommandComplete = true;
2024 p->mSignal.signal();
2025}
2026
Marco Nelissen4110c102012-03-29 09:31:28 -07002027int MediaPlayerService::AudioCache::getSessionId() const
Eric Laurent8c563ed2010-10-07 18:23:03 -07002028{
2029 return 0;
2030}
2031
Eric Laurent6f59db12013-07-26 17:16:50 -07002032uint32_t MediaPlayerService::AudioCache::getSampleRate() const
2033{
2034 if (mMsecsPerFrame == 0) {
2035 return 0;
2036 }
2037 return (uint32_t)(1.e3 / mMsecsPerFrame);
2038}
2039
Gloria Wang7cf180c2011-02-19 18:37:57 -08002040void MediaPlayerService::addBatteryData(uint32_t params)
2041{
2042 Mutex::Autolock lock(mLock);
Gloria Wang9ee159b2011-02-24 14:51:45 -08002043
2044 int32_t time = systemTime() / 1000000L;
2045
2046 // change audio output devices. This notification comes from AudioFlinger
2047 if ((params & kBatteryDataSpeakerOn)
2048 || (params & kBatteryDataOtherAudioDeviceOn)) {
2049
2050 int deviceOn[NUM_AUDIO_DEVICES];
2051 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
2052 deviceOn[i] = 0;
2053 }
2054
2055 if ((params & kBatteryDataSpeakerOn)
2056 && (params & kBatteryDataOtherAudioDeviceOn)) {
2057 deviceOn[SPEAKER_AND_OTHER] = 1;
2058 } else if (params & kBatteryDataSpeakerOn) {
2059 deviceOn[SPEAKER] = 1;
2060 } else {
2061 deviceOn[OTHER_AUDIO_DEVICE] = 1;
2062 }
2063
2064 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
2065 if (mBatteryAudio.deviceOn[i] != deviceOn[i]){
2066
2067 if (mBatteryAudio.refCount > 0) { // if playing audio
2068 if (!deviceOn[i]) {
2069 mBatteryAudio.lastTime[i] += time;
2070 mBatteryAudio.totalTime[i] += mBatteryAudio.lastTime[i];
2071 mBatteryAudio.lastTime[i] = 0;
2072 } else {
2073 mBatteryAudio.lastTime[i] = 0 - time;
2074 }
2075 }
2076
2077 mBatteryAudio.deviceOn[i] = deviceOn[i];
2078 }
2079 }
2080 return;
2081 }
2082
2083 // an sudio stream is started
2084 if (params & kBatteryDataAudioFlingerStart) {
2085 // record the start time only if currently no other audio
2086 // is being played
2087 if (mBatteryAudio.refCount == 0) {
2088 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
2089 if (mBatteryAudio.deviceOn[i]) {
2090 mBatteryAudio.lastTime[i] -= time;
2091 }
2092 }
2093 }
2094
2095 mBatteryAudio.refCount ++;
2096 return;
2097
2098 } else if (params & kBatteryDataAudioFlingerStop) {
2099 if (mBatteryAudio.refCount <= 0) {
Steve Block5ff1dd52012-01-05 23:22:43 +00002100 ALOGW("Battery track warning: refCount is <= 0");
Gloria Wang9ee159b2011-02-24 14:51:45 -08002101 return;
2102 }
2103
2104 // record the stop time only if currently this is the only
2105 // audio being played
2106 if (mBatteryAudio.refCount == 1) {
2107 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
2108 if (mBatteryAudio.deviceOn[i]) {
2109 mBatteryAudio.lastTime[i] += time;
2110 mBatteryAudio.totalTime[i] += mBatteryAudio.lastTime[i];
2111 mBatteryAudio.lastTime[i] = 0;
2112 }
2113 }
2114 }
2115
2116 mBatteryAudio.refCount --;
2117 return;
2118 }
2119
Gloria Wang7cf180c2011-02-19 18:37:57 -08002120 int uid = IPCThreadState::self()->getCallingUid();
2121 if (uid == AID_MEDIA) {
2122 return;
2123 }
2124 int index = mBatteryData.indexOfKey(uid);
Gloria Wang7cf180c2011-02-19 18:37:57 -08002125
2126 if (index < 0) { // create a new entry for this UID
2127 BatteryUsageInfo info;
2128 info.audioTotalTime = 0;
2129 info.videoTotalTime = 0;
2130 info.audioLastTime = 0;
2131 info.videoLastTime = 0;
2132 info.refCount = 0;
2133
Gloria Wang9ee159b2011-02-24 14:51:45 -08002134 if (mBatteryData.add(uid, info) == NO_MEMORY) {
Steve Block29357bc2012-01-06 19:20:56 +00002135 ALOGE("Battery track error: no memory for new app");
Gloria Wang9ee159b2011-02-24 14:51:45 -08002136 return;
2137 }
Gloria Wang7cf180c2011-02-19 18:37:57 -08002138 }
2139
2140 BatteryUsageInfo &info = mBatteryData.editValueFor(uid);
2141
2142 if (params & kBatteryDataCodecStarted) {
2143 if (params & kBatteryDataTrackAudio) {
2144 info.audioLastTime -= time;
2145 info.refCount ++;
2146 }
2147 if (params & kBatteryDataTrackVideo) {
2148 info.videoLastTime -= time;
2149 info.refCount ++;
2150 }
2151 } else {
2152 if (info.refCount == 0) {
Steve Block5ff1dd52012-01-05 23:22:43 +00002153 ALOGW("Battery track warning: refCount is already 0");
Gloria Wang7cf180c2011-02-19 18:37:57 -08002154 return;
2155 } else if (info.refCount < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00002156 ALOGE("Battery track error: refCount < 0");
Gloria Wang7cf180c2011-02-19 18:37:57 -08002157 mBatteryData.removeItem(uid);
2158 return;
2159 }
2160
2161 if (params & kBatteryDataTrackAudio) {
2162 info.audioLastTime += time;
2163 info.refCount --;
2164 }
2165 if (params & kBatteryDataTrackVideo) {
2166 info.videoLastTime += time;
2167 info.refCount --;
2168 }
2169
2170 // no stream is being played by this UID
2171 if (info.refCount == 0) {
2172 info.audioTotalTime += info.audioLastTime;
2173 info.audioLastTime = 0;
2174 info.videoTotalTime += info.videoLastTime;
2175 info.videoLastTime = 0;
2176 }
2177 }
2178}
2179
2180status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
2181 Mutex::Autolock lock(mLock);
Gloria Wang9ee159b2011-02-24 14:51:45 -08002182
2183 // audio output devices usage
2184 int32_t time = systemTime() / 1000000L; //in ms
2185 int32_t totalTime;
2186
2187 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
2188 totalTime = mBatteryAudio.totalTime[i];
2189
2190 if (mBatteryAudio.deviceOn[i]
2191 && (mBatteryAudio.lastTime[i] != 0)) {
2192 int32_t tmpTime = mBatteryAudio.lastTime[i] + time;
2193 totalTime += tmpTime;
2194 }
2195
2196 reply->writeInt32(totalTime);
2197 // reset the total time
2198 mBatteryAudio.totalTime[i] = 0;
2199 }
2200
2201 // codec usage
Gloria Wang7cf180c2011-02-19 18:37:57 -08002202 BatteryUsageInfo info;
2203 int size = mBatteryData.size();
2204
2205 reply->writeInt32(size);
2206 int i = 0;
2207
2208 while (i < size) {
2209 info = mBatteryData.valueAt(i);
2210
2211 reply->writeInt32(mBatteryData.keyAt(i)); //UID
2212 reply->writeInt32(info.audioTotalTime);
2213 reply->writeInt32(info.videoTotalTime);
2214
2215 info.audioTotalTime = 0;
2216 info.videoTotalTime = 0;
2217
2218 // remove the UID entry where no stream is being played
2219 if (info.refCount <= 0) {
2220 mBatteryData.removeItemsAt(i);
2221 size --;
2222 i --;
2223 }
2224 i++;
2225 }
2226 return NO_ERROR;
2227}
nikoa64c8c72009-07-20 15:07:26 -07002228} // namespace android