blob: 3b64ded7338bb4693819f175c41287875162160d [file] [log] [blame]
Nipun Kwatraf83cba72010-08-26 15:59:19 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaSourceSplitter"
19#include <utils/Log.h>
20
James Dong8e9d67a2012-02-06 23:46:37 -080021#include <media/stagefright/foundation/ADebug.h>
Nipun Kwatraf83cba72010-08-26 15:59:19 -070022#include <media/stagefright/MediaSourceSplitter.h>
Nipun Kwatraf83cba72010-08-26 15:59:19 -070023#include <media/stagefright/MediaBuffer.h>
24#include <media/stagefright/MetaData.h>
25
26namespace android {
27
28MediaSourceSplitter::MediaSourceSplitter(sp<MediaSource> mediaSource) {
29 mNumberOfClients = 0;
30 mSource = mediaSource;
31 mSourceStarted = false;
32
33 mNumberOfClientsStarted = 0;
34 mNumberOfCurrentReads = 0;
35 mCurrentReadBit = 0;
36 mLastReadCompleted = true;
37}
38
39MediaSourceSplitter::~MediaSourceSplitter() {
40}
41
42sp<MediaSource> MediaSourceSplitter::createClient() {
43 Mutex::Autolock autoLock(mLock);
44
45 sp<MediaSource> client = new Client(this, mNumberOfClients++);
46 mClientsStarted.push(false);
47 mClientsDesiredReadBit.push(0);
48 return client;
49}
50
Nipun Kwatraea434da2010-08-27 14:19:01 -070051status_t MediaSourceSplitter::start(int clientId, MetaData *params) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -070052 Mutex::Autolock autoLock(mLock);
53
Steve Block71f2cf12011-10-20 11:56:00 +010054 ALOGV("start client (%d)", clientId);
Nipun Kwatraea434da2010-08-27 14:19:01 -070055 if (mClientsStarted[clientId]) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -070056 return OK;
57 }
58
59 mNumberOfClientsStarted++;
60
61 if (!mSourceStarted) {
Steve Block71f2cf12011-10-20 11:56:00 +010062 ALOGV("Starting real source from client (%d)", clientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -070063 status_t err = mSource->start(params);
64
65 if (err == OK) {
66 mSourceStarted = true;
Nipun Kwatraea434da2010-08-27 14:19:01 -070067 mClientsStarted.editItemAt(clientId) = true;
68 mClientsDesiredReadBit.editItemAt(clientId) = !mCurrentReadBit;
Nipun Kwatraf83cba72010-08-26 15:59:19 -070069 }
70
71 return err;
72 } else {
Nipun Kwatraea434da2010-08-27 14:19:01 -070073 mClientsStarted.editItemAt(clientId) = true;
Nipun Kwatraf83cba72010-08-26 15:59:19 -070074 if (mLastReadCompleted) {
75 // Last read was completed. So join in the threads for the next read.
Nipun Kwatraea434da2010-08-27 14:19:01 -070076 mClientsDesiredReadBit.editItemAt(clientId) = !mCurrentReadBit;
Nipun Kwatraf83cba72010-08-26 15:59:19 -070077 } else {
78 // Last read is ongoing. So join in the threads for the current read.
Nipun Kwatraea434da2010-08-27 14:19:01 -070079 mClientsDesiredReadBit.editItemAt(clientId) = mCurrentReadBit;
Nipun Kwatraf83cba72010-08-26 15:59:19 -070080 }
81 return OK;
82 }
83}
84
Nipun Kwatraea434da2010-08-27 14:19:01 -070085status_t MediaSourceSplitter::stop(int clientId) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -070086 Mutex::Autolock autoLock(mLock);
87
Steve Block71f2cf12011-10-20 11:56:00 +010088 ALOGV("stop client (%d)", clientId);
Nipun Kwatraea434da2010-08-27 14:19:01 -070089 CHECK(clientId >= 0 && clientId < mNumberOfClients);
90 CHECK(mClientsStarted[clientId]);
Nipun Kwatraf83cba72010-08-26 15:59:19 -070091
92 if (--mNumberOfClientsStarted == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +010093 ALOGV("Stopping real source from client (%d)", clientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -070094 status_t err = mSource->stop();
95 mSourceStarted = false;
Nipun Kwatraea434da2010-08-27 14:19:01 -070096 mClientsStarted.editItemAt(clientId) = false;
Nipun Kwatraf83cba72010-08-26 15:59:19 -070097 return err;
98 } else {
Nipun Kwatraea434da2010-08-27 14:19:01 -070099 mClientsStarted.editItemAt(clientId) = false;
100 if (!mLastReadCompleted && (mClientsDesiredReadBit[clientId] == mCurrentReadBit)) {
101 // !mLastReadCompleted implies that buffer has been read from source, but all
102 // clients haven't read it.
103 // mClientsDesiredReadBit[clientId] == mCurrentReadBit implies that this
104 // client would have wanted to read from this buffer. (i.e. it has not yet
105 // called read() for the current read buffer.)
106 // Since other threads may be waiting for all the clients' reads to complete,
107 // signal that this read has been aborted.
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700108 signalReadComplete_lock(true);
109 }
110 return OK;
111 }
112}
113
Nipun Kwatraea434da2010-08-27 14:19:01 -0700114sp<MetaData> MediaSourceSplitter::getFormat(int clientId) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700115 Mutex::Autolock autoLock(mLock);
116
Steve Block71f2cf12011-10-20 11:56:00 +0100117 ALOGV("getFormat client (%d)", clientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700118 return mSource->getFormat();
119}
120
Nipun Kwatraea434da2010-08-27 14:19:01 -0700121status_t MediaSourceSplitter::read(int clientId,
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700122 MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
123 Mutex::Autolock autoLock(mLock);
124
Nipun Kwatraea434da2010-08-27 14:19:01 -0700125 CHECK(clientId >= 0 && clientId < mNumberOfClients);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700126
Steve Block71f2cf12011-10-20 11:56:00 +0100127 ALOGV("read client (%d)", clientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700128 *buffer = NULL;
129
Nipun Kwatraea434da2010-08-27 14:19:01 -0700130 if (!mClientsStarted[clientId]) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700131 return OK;
132 }
133
Nipun Kwatraea434da2010-08-27 14:19:01 -0700134 if (mCurrentReadBit != mClientsDesiredReadBit[clientId]) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700135 // Desired buffer has not been read from source yet.
136
Nipun Kwatraea434da2010-08-27 14:19:01 -0700137 // If the current client is the special client with clientId = 0
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700138 // then read from source, else wait until the client 0 has finished
139 // reading from source.
Nipun Kwatraea434da2010-08-27 14:19:01 -0700140 if (clientId == 0) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700141 // Wait for all client's last read to complete first so as to not
142 // corrupt the buffer at mLastReadMediaBuffer.
Nipun Kwatraea434da2010-08-27 14:19:01 -0700143 waitForAllClientsLastRead_lock(clientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700144
145 readFromSource_lock(options);
146 *buffer = mLastReadMediaBuffer;
147 } else {
Nipun Kwatraea434da2010-08-27 14:19:01 -0700148 waitForReadFromSource_lock(clientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700149
150 *buffer = mLastReadMediaBuffer;
151 (*buffer)->add_ref();
152 }
Nipun Kwatraea434da2010-08-27 14:19:01 -0700153 CHECK(mCurrentReadBit == mClientsDesiredReadBit[clientId]);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700154 } else {
155 // Desired buffer has already been read from source. Use the cached data.
Nipun Kwatraea434da2010-08-27 14:19:01 -0700156 CHECK(clientId != 0);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700157
158 *buffer = mLastReadMediaBuffer;
159 (*buffer)->add_ref();
160 }
161
Nipun Kwatraea434da2010-08-27 14:19:01 -0700162 mClientsDesiredReadBit.editItemAt(clientId) = !mClientsDesiredReadBit[clientId];
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700163 signalReadComplete_lock(false);
164
165 return mLastReadStatus;
166}
167
168void MediaSourceSplitter::readFromSource_lock(const MediaSource::ReadOptions *options) {
169 mLastReadStatus = mSource->read(&mLastReadMediaBuffer , options);
170
171 mCurrentReadBit = !mCurrentReadBit;
172 mLastReadCompleted = false;
173 mReadFromSourceCondition.broadcast();
174}
175
Nipun Kwatraea434da2010-08-27 14:19:01 -0700176void MediaSourceSplitter::waitForReadFromSource_lock(int32_t clientId) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700177 mReadFromSourceCondition.wait(mLock);
178}
179
Nipun Kwatraea434da2010-08-27 14:19:01 -0700180void MediaSourceSplitter::waitForAllClientsLastRead_lock(int32_t clientId) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700181 if (mLastReadCompleted) {
182 return;
183 }
184 mAllReadsCompleteCondition.wait(mLock);
185 CHECK(mLastReadCompleted);
186}
187
188void MediaSourceSplitter::signalReadComplete_lock(bool readAborted) {
189 if (!readAborted) {
190 mNumberOfCurrentReads++;
191 }
192
193 if (mNumberOfCurrentReads == mNumberOfClientsStarted) {
194 mLastReadCompleted = true;
195 mNumberOfCurrentReads = 0;
196 mAllReadsCompleteCondition.broadcast();
197 }
198}
199
Nipun Kwatraea434da2010-08-27 14:19:01 -0700200status_t MediaSourceSplitter::pause(int clientId) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700201 return ERROR_UNSUPPORTED;
202}
203
204// Client
205
206MediaSourceSplitter::Client::Client(
207 sp<MediaSourceSplitter> splitter,
Nipun Kwatraea434da2010-08-27 14:19:01 -0700208 int32_t clientId) {
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700209 mSplitter = splitter;
Nipun Kwatraea434da2010-08-27 14:19:01 -0700210 mClientId = clientId;
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700211}
212
213status_t MediaSourceSplitter::Client::start(MetaData *params) {
Nipun Kwatraea434da2010-08-27 14:19:01 -0700214 return mSplitter->start(mClientId, params);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700215}
216
217status_t MediaSourceSplitter::Client::stop() {
Nipun Kwatraea434da2010-08-27 14:19:01 -0700218 return mSplitter->stop(mClientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700219}
220
221sp<MetaData> MediaSourceSplitter::Client::getFormat() {
Nipun Kwatraea434da2010-08-27 14:19:01 -0700222 return mSplitter->getFormat(mClientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700223}
224
225status_t MediaSourceSplitter::Client::read(
226 MediaBuffer **buffer, const ReadOptions *options) {
Nipun Kwatraea434da2010-08-27 14:19:01 -0700227 return mSplitter->read(mClientId, buffer, options);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700228}
229
230status_t MediaSourceSplitter::Client::pause() {
Nipun Kwatraea434da2010-08-27 14:19:01 -0700231 return mSplitter->pause(mClientId);
Nipun Kwatraf83cba72010-08-26 15:59:19 -0700232}
233
234} // namespace android