#define __CC_HELPER_H__
#include <stdint.h>
+#include <common_time/ICommonClock.h>
#include <utils/threads.h>
namespace android {
-class ICommonClock;
-
// CCHelper is a simple wrapper class to help with centralizing access to the
-// Common Clock service as well as to implement a simple policy of making a
-// basic attempt to reconnect to the common clock service when things go wrong.
+// Common Clock service and implementing lifetime managment, as well as to
+// implement a simple policy of making a basic attempt to reconnect to the
+// common clock service when things go wrong.
+//
+// On platforms which run the native common_time service in auto-diable mode,
+// the service will go into networkless mode whenever it has no active clients.
+// It tracks active clients using registered CommonClockListeners (the callback
+// interface for onTimelineChanged) since this provides a convienent death
+// handler notification for when the service's clients die unexpectedly. This
+// means that users of the common time service should really always have a
+// CommonClockListener, unless they know that the time service is not running in
+// auto disabled mode, or that there is at least one other registered listener
+// active in the system. The CCHelper makes this a little easier by sharing a
+// ref counted ICommonClock interface across all clients and automatically
+// registering and unregistering a listener whenever there are CCHelper
+// instances active in the process.
class CCHelper {
public:
- static status_t isCommonTimeValid(bool* valid, uint32_t* timelineID);
- static status_t commonTimeToLocalTime(int64_t commonTime, int64_t* localTime);
- static status_t localTimeToCommonTime(int64_t localTime, int64_t* commonTime);
- static status_t getCommonTime(int64_t* commonTime);
- static status_t getCommonFreq(uint64_t* freq);
- static status_t getLocalTime(int64_t* localTime);
- static status_t getLocalFreq(uint64_t* freq);
+ CCHelper();
+ ~CCHelper();
+
+ status_t isCommonTimeValid(bool* valid, uint32_t* timelineID);
+ status_t commonTimeToLocalTime(int64_t commonTime, int64_t* localTime);
+ status_t localTimeToCommonTime(int64_t localTime, int64_t* commonTime);
+ status_t getCommonTime(int64_t* commonTime);
+ status_t getCommonFreq(uint64_t* freq);
+ status_t getLocalTime(int64_t* localTime);
+ status_t getLocalFreq(uint64_t* freq);
private:
+ class CommonClockListener : public BnCommonClockListener {
+ public:
+ void onTimelineChanged(uint64_t timelineID);
+ };
+
static bool verifyClock_l();
static Mutex lock_;
static sp<ICommonClock> common_clock_;
+ static sp<ICommonClockListener> common_clock_listener_;
+ static uint32_t ref_count_;
};
Mutex CCHelper::lock_;
sp<ICommonClock> CCHelper::common_clock_;
+sp<ICommonClockListener> CCHelper::common_clock_listener_;
+uint32_t CCHelper::ref_count_ = 0;
bool CCHelper::verifyClock_l() {
+ bool ret = false;
+
if (common_clock_ == NULL) {
common_clock_ = ICommonClock::getInstance();
if (common_clock_ == NULL)
- return false;
+ goto bailout;
}
- return true;
+ if (ref_count_ > 0) {
+ if (common_clock_listener_ == NULL) {
+ common_clock_listener_ = new CommonClockListener();
+ if (common_clock_listener_ == NULL)
+ goto bailout;
+
+ if (OK != common_clock_->registerListener(common_clock_listener_))
+ goto bailout;
+ }
+ }
+
+ ret = true;
+
+bailout:
+ if (!ret) {
+ common_clock_listener_ = NULL;
+ common_clock_ = NULL;
+ }
+ return ret;
+}
+
+CCHelper::CCHelper() {
+ Mutex::Autolock lock(&lock_);
+ ref_count_++;
+ verifyClock_l();
}
+CCHelper::~CCHelper() {
+ Mutex::Autolock lock(&lock_);
+
+ assert(ref_count_ > 0);
+ ref_count_--;
+
+ // If we were the last CCHelper instance in the system, and we had
+ // previously register a listener, unregister it now so that the common time
+ // service has the chance to go into auto-disabled mode.
+ if (!ref_count_ &&
+ (common_clock_ != NULL) &&
+ (common_clock_listener_ != NULL)) {
+ common_clock_->unregisterListener(common_clock_listener_);
+ common_clock_listener_ = NULL;
+ }
+}
+
+void CCHelper::CommonClockListener::onTimelineChanged(uint64_t timelineID) {
+ // do nothing; listener is only really used as a token so the server can
+ // find out when clients die.
+}
// Helper methods which attempts to make calls to the common time binder
// service. If the first attempt fails with DEAD_OBJECT, the helpers will
// If the second attempt fails, or no connection can be made, the we let the
// error propagate up the stack and let the caller deal with the situation as
// best they can.
-
#define CCHELPER_METHOD(decl, call) \
status_t CCHelper::decl { \
Mutex::Autolock lock(&lock_); \
\
if (!verifyClock_l()) \
- return DEAD_OBJECT; \
+ return DEAD_OBJECT; \
\
status_t status = common_clock_->call; \
if (DEAD_OBJECT == status) { \
- common_clock_ = NULL; \
if (!verifyClock_l()) \
- return DEAD_OBJECT; \
- status_t status = common_clock_->call; \
+ return DEAD_OBJECT; \
+ status = common_clock_->call; \
} \
\
return status; \
// Since we cannot really tell if we are about to underflow or not, its
// probably best to assume that we are not and proceed accordingly.
int64_t tt_now;
- if (OK != CCHelper::getCommonTime(&tt_now)) {
+ if (OK != cc_helper_.getCommonTime(&tt_now)) {
return false;
}
#include <pthread.h>
+#include <common_time/cc_helper.h>
#include <media/stagefright/MediaSource.h>
#include <utils/LinearTransform.h>
#include <utils/List.h>
bool last_ts_transform_valid_;
LinearTransform last_ts_transform_;
uint8_t last_volume_;
+ CCHelper cc_helper_;
// protected by the thread_lock_
typedef List<MediaBuffer*> MBQueue;
#define LOG_TAG "LibAAH_RTP"
//#define LOG_NDEBUG 0
-#include <common_time/cc_helper.h>
#include <binder/IServiceManager.h>
#include <media/MediaPlayerInterface.h>
#include <utils/Log.h>
return NO_MEMORY;
}
- // Check for the presense of the A@H common time service by attempting to
- // query for CommonTime's frequency. If we get an error back, we cannot
- // talk to the service at all and should abort now.
+ // Check for the presense of the common time service by attempting to query
+ // for CommonTime's frequency. If we get an error back, we cannot talk to
+ // the service at all and should abort now.
status_t res;
uint64_t freq;
- res = CCHelper::getCommonFreq(&freq);
+ res = cc_helper_.getCommonFreq(&freq);
if (OK != res) {
LOGE("Failed to connect to common time service!");
return res;
#ifndef __AAH_RX_PLAYER_H__
#define __AAH_RX_PLAYER_H__
+#include <common_time/cc_helper.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
RXRingBuffer ring_buffer_;
SubstreamVec substreams_;
OMXClient omx_;
+ CCHelper cc_helper_;
// Connection to audio flinger used to hack a path to setMasterVolume.
sp<IAudioFlinger> audio_flinger_;
}
status_t AAH_TXPlayer::initCheck() {
- // Check for the presense of the A@H common time service by attempting to
- // query for CommonTime's frequency. If we get an error back, we cannot
- // talk to the service at all and should abort now.
+ // Check for the presense of the common time service by attempting to query
+ // for CommonTime's frequency. If we get an error back, we cannot talk to
+ // the service at all and should abort now.
status_t res;
uint64_t freq;
- res = CCHelper::getCommonFreq(&freq);
+ res = mCCHelper.getCommonFreq(&freq);
if (OK != res) {
- LOGE("Failed to connect to common time service!");
+ LOGE("Failed to connect to common time service! (res %d)", res);
return res;
}
// sample the current common time
int64_t commonTimeNow;
- if (OK != CCHelper::getCommonTime(&commonTimeNow)) {
+ if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
LOGE("updateClockTransform_l get common time failed");
mCurrentClockTransformValid = false;
return;
} else if (mCurrentClockTransformValid) {
// sample the current common time
int64_t commonTimeNow;
- if (OK != CCHelper::getCommonTime(&commonTimeNow)) {
+ if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
LOGE("getCurrentPosition get common time failed");
return INVALID_OPERATION;
}
// of good options here. For now, signal an error up to the app level
// and shut down the transmission pump.
int64_t commonTimeNow;
- if (OK != CCHelper::getCommonTime(&commonTimeNow)) {
+ if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
// Failed to get common time; either the service is down or common
// time is not synced. Raise an error and shutdown the player.
LOGE("*** Cannot pump audio, unable to fetch common time."
LOGV("*** timeUs=%lld", mediaTimeUs);
if (!mCurrentClockTransformValid) {
- if (OK == CCHelper::getCommonTime(&commonTimeNow)) {
+ if (OK == mCCHelper.getCommonTime(&commonTimeNow)) {
mCurrentClockTransform.a_zero = mediaTimeUs;
mCurrentClockTransform.b_zero = commonTimeNow +
kAAHStartupLeadTimeUs;
#ifndef __AAH_TX_PLAYER_H__
#define __AAH_TX_PLAYER_H__
+#include <common_time/cc_helper.h>
#include <libstagefright/include/HTTPBase.h>
#include <libstagefright/include/NuCachedSource2.h>
#include <libstagefright/include/TimedEventQueue.h>
int64_t mLastQueuedMediaTimePTS;
bool mLastQueuedMediaTimePTSValid;
bool mPlayRateIsPaused;
+ CCHelper mCCHelper;
Mutex mEndpointLock;
AAH_TXSender::Endpoint mEndpoint;
bool mEndpointValid;
bool mEndpointRegistered;
uint16_t mProgramID;
-
uint8_t mTRTPVolume;
DISALLOW_EVIL_CONSTRUCTORS(AAH_TXPlayer);
int64_t targetTimeNow;
status_t res = (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME)
- ? CCHelper::getCommonTime(&targetTimeNow)
- : CCHelper::getLocalTime(&targetTimeNow);
+ ? mCCHelper.getCommonTime(&targetTimeNow)
+ : mCCHelper.getLocalTime(&targetTimeNow);
if (OK != res)
return;
}
if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) {
- if (OK != CCHelper::commonTimeToLocalTime(transformedPTS,
+ if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS,
&headLocalPTS)) {
buffer->raw = 0;
buffer->frameCount = 0;
#include <sys/types.h>
#include <limits.h>
+#include <common_time/cc_helper.h>
+
#include <media/IAudioFlinger.h>
#include <media/IAudioFlingerClient.h>
#include <media/IAudioTrack.h>
uint32_t mTimedSilenceBufferSize;
mutable Mutex mTimedBufferQueueLock;
bool mTimedAudioOutputOnTime;
+ CCHelper mCCHelper;
Mutex mMediaTimeTransformLock;
LinearTransform mMediaTimeTransform;