/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // This class provides a way to split a single media source into multiple sources. // The constructor takes in the real mediaSource and createClient() can then be // used to create multiple sources served from this real mediaSource. // // Usage: // - Create MediaSourceSplitter by passing in a real mediaSource from which // multiple duplicate channels are needed. // - Create a client using createClient() and use it as any other mediaSource. // // Note that multiple clients can be created using createClient() and // started/stopped in any order. MediaSourceSplitter stops the real source only // when all clients have been stopped. // // If a new client is created/started after some existing clients have already // started, the new client will start getting its read frames from the current // time. #ifndef MEDIA_SOURCE_SPLITTER_H_ #define MEDIA_SOURCE_SPLITTER_H_ #include #include #include #include namespace android { class MediaBuffer; class MetaData; class MediaSourceSplitter : public RefBase { public: // Constructor // mediaSource: The real mediaSource. The class keeps a reference to it to // implement the various clients. MediaSourceSplitter(sp mediaSource); ~MediaSourceSplitter(); // Creates a new client of base type MediaSource. Multiple clients can be // created which get their data through the same real mediaSource. These // clients can then be used like any other MediaSource, all of which provide // data from the same real source. sp createClient(); private: // Total number of clients created through createClient(). int32_t mNumberOfClients; // reference to the real MediaSource passed to the constructor. sp mSource; // Stores pointer to the MediaBuffer read from the real MediaSource. // All clients use this to implement the read() call. MediaBuffer *mLastReadMediaBuffer; // Status code for read from the real MediaSource. All clients return // this for their read(). status_t mLastReadStatus; // Boolean telling whether the real MediaSource has started. bool mSourceStarted; // List of booleans, one for each client, storing whether the corresponding // client's start() has been called. Vector mClientsStarted; // Stores the number of clients which are currently started. int32_t mNumberOfClientsStarted; // Since different clients call read() asynchronously, we need to keep track // of what data is currently read into the mLastReadMediaBuffer. // mCurrentReadBit stores the bit for the current read buffer. This bit // flips each time a new buffer is read from the source. // mClientsDesiredReadBit stores the bit for the next desired read buffer // for each client. This bit flips each time read() is completed for this // client. bool mCurrentReadBit; Vector mClientsDesiredReadBit; // Number of clients whose current read has been completed. int32_t mNumberOfCurrentReads; // Boolean telling whether the last read has been completed for all clients. // The variable is reset to false each time buffer is read from the real // source. bool mLastReadCompleted; // A global mutex for access to critical sections. Mutex mLock; // Condition variable for waiting on read from source to complete. Condition mReadFromSourceCondition; // Condition variable for waiting on all client's last read to complete. Condition mAllReadsCompleteCondition; // Functions used by Client to implement the MediaSource interface. // If the real source has not been started yet by any client, starts it. status_t start(int clientId, MetaData *params); // Stops the real source after all clients have called stop(). status_t stop(int clientId); // returns the real source's getFormat(). sp getFormat(int clientId); // If the client's desired buffer has already been read into // mLastReadMediaBuffer, points the buffer to that. Otherwise if it is the // master client, reads the buffer from source or else waits for the master // client to read the buffer and uses that. status_t read(int clientId, MediaBuffer **buffer, const MediaSource::ReadOptions *options = NULL); // Not implemented right now. status_t pause(int clientId); // Function which reads a buffer from the real source into // mLastReadMediaBuffer void readFromSource_lock(const MediaSource::ReadOptions *options); // Waits until read from the real source has been completed. // _lock means that the function should be called when the thread has already // obtained the lock for the mutex mLock. void waitForReadFromSource_lock(int32_t clientId); // Waits until all clients have read the current buffer in // mLastReadCompleted. void waitForAllClientsLastRead_lock(int32_t clientId); // Each client calls this after it completes its read(). Once all clients // have called this for the current buffer, the function calls // mAllReadsCompleteCondition.broadcast() to signal the waiting clients. void signalReadComplete_lock(bool readAborted); // Make these constructors private. MediaSourceSplitter(); MediaSourceSplitter(const MediaSourceSplitter &); MediaSourceSplitter &operator=(const MediaSourceSplitter &); // This class implements the MediaSource interface. Each client stores a // reference to the parent MediaSourceSplitter and uses it to complete the // various calls. class Client : public MediaSource { public: // Constructor stores reference to the parent MediaSourceSplitter and it // client id. Client(sp splitter, int32_t clientId); // MediaSource interface virtual status_t start(MetaData *params = NULL); virtual status_t stop(); virtual sp getFormat(); virtual status_t read( MediaBuffer **buffer, const ReadOptions *options = NULL); virtual status_t pause(); private: // Refernce to the parent MediaSourceSplitter sp mSplitter; // Id of this client. int32_t mClientId; }; friend class Client; }; } // namespace android #endif // MEDIA_SOURCE_SPLITTER_H_