summaryrefslogtreecommitdiffstats
path: root/media/libaah_rtp/aah_tx_player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libaah_rtp/aah_tx_player.cpp')
-rw-r--r--media/libaah_rtp/aah_tx_player.cpp1177
1 files changed, 0 insertions, 1177 deletions
diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp
deleted file mode 100644
index 974805b..0000000
--- a/media/libaah_rtp/aah_tx_player.cpp
+++ /dev/null
@@ -1,1177 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#define LOG_TAG "LibAAH_RTP"
-#include <utils/Log.h>
-
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-#include <netdb.h>
-#include <netinet/ip.h>
-
-#include <common_time/cc_helper.h>
-#include <media/IMediaPlayer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <utils/Timers.h>
-
-#include "aah_tx_packet.h"
-#include "aah_tx_player.h"
-
-namespace android {
-
-static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
-static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
-static const size_t kLowWaterMarkBytes = 40000;
-static const size_t kHighWaterMarkBytes = 200000;
-
-// When we start up, how much lead time should we put on the first access unit?
-static const int64_t kAAHStartupLeadTimeUs = 300000LL;
-
-// How much time do we attempt to lead the clock by in steady state?
-static const int64_t kAAHBufferTimeUs = 1000000LL;
-
-// how long do we keep data in our retransmit buffer after sending it.
-const int64_t AAH_TXPlayer::kAAHRetryKeepAroundTimeNs =
- kAAHBufferTimeUs * 1100;
-
-sp<MediaPlayerBase> createAAH_TXPlayer() {
- sp<MediaPlayerBase> ret = new AAH_TXPlayer();
- return ret;
-}
-
-template <typename T> static T clamp(T val, T min, T max) {
- if (val < min) {
- return min;
- } else if (val > max) {
- return max;
- } else {
- return val;
- }
-}
-
-struct AAH_TXEvent : public TimedEventQueue::Event {
- AAH_TXEvent(AAH_TXPlayer *player,
- void (AAH_TXPlayer::*method)()) : mPlayer(player)
- , mMethod(method) {}
-
- protected:
- virtual ~AAH_TXEvent() {}
-
- virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
- (mPlayer->*mMethod)();
- }
-
- private:
- AAH_TXPlayer *mPlayer;
- void (AAH_TXPlayer::*mMethod)();
-
- AAH_TXEvent(const AAH_TXEvent &);
- AAH_TXEvent& operator=(const AAH_TXEvent &);
-};
-
-AAH_TXPlayer::AAH_TXPlayer()
- : mQueueStarted(false)
- , mFlags(0)
- , mExtractorFlags(0) {
- DataSource::RegisterDefaultSniffers();
-
- mBufferingEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onBufferingUpdate);
- mBufferingEventPending = false;
-
- mPumpAudioEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onPumpAudio);
- mPumpAudioEventPending = false;
-
- mAudioCodecData = NULL;
-
- reset_l();
-}
-
-AAH_TXPlayer::~AAH_TXPlayer() {
- if (mQueueStarted) {
- mQueue.stop();
- }
-
- reset_l();
-}
-
-void AAH_TXPlayer::cancelPlayerEvents(bool keepBufferingGoing) {
- if (!keepBufferingGoing) {
- mQueue.cancelEvent(mBufferingEvent->eventID());
- mBufferingEventPending = false;
-
- mQueue.cancelEvent(mPumpAudioEvent->eventID());
- mPumpAudioEventPending = false;
- }
-}
-
-status_t AAH_TXPlayer::initCheck() {
- // 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 = mCCHelper.getCommonFreq(&freq);
- if (OK != res) {
- ALOGE("Failed to connect to common time service! (res %d)", res);
- return res;
- }
-
- return OK;
-}
-
-status_t AAH_TXPlayer::setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- Mutex::Autolock autoLock(mLock);
- return setDataSource_l(url, headers);
-}
-
-status_t AAH_TXPlayer::setDataSource_l(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- reset_l();
-
- mUri.setTo(url);
-
- if (headers) {
- mUriHeaders = *headers;
-
- ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
- if (index >= 0) {
- // Browser is in "incognito" mode, suppress logging URLs.
-
- // This isn't something that should be passed to the server.
- mUriHeaders.removeItemsAt(index);
-
- mFlags |= INCOGNITO;
- }
- }
-
- // The URL may optionally contain a "#" character followed by a Skyjam
- // cookie. Ideally the cookie header should just be passed in the headers
- // argument, but the Java API for supplying headers is apparently not yet
- // exposed in the SDK used by application developers.
- const char kSkyjamCookieDelimiter = '#';
- char* skyjamCookie = strrchr(mUri.string(), kSkyjamCookieDelimiter);
- if (skyjamCookie) {
- skyjamCookie++;
- mUriHeaders.add(String8("Cookie"), String8(skyjamCookie));
- mUri = String8(mUri.string(), skyjamCookie - mUri.string());
- }
-
- return OK;
-}
-
-status_t AAH_TXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
- Mutex::Autolock autoLock(mLock);
-
- reset_l();
-
- sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
-
- status_t err = dataSource->initCheck();
-
- if (err != OK) {
- return err;
- }
-
- mFileSource = dataSource;
-
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
-
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
-
- return setDataSource_l(extractor);
-}
-
-status_t AAH_TXPlayer::setVideoSurface(const sp<Surface>& surface) {
- return OK;
-}
-
-status_t AAH_TXPlayer::setVideoSurfaceTexture(
- const sp<ISurfaceTexture>& surfaceTexture) {
- return OK;
-}
-
-status_t AAH_TXPlayer::prepare() {
- return INVALID_OPERATION;
-}
-
-status_t AAH_TXPlayer::prepareAsync() {
- Mutex::Autolock autoLock(mLock);
-
- return prepareAsync_l();
-}
-
-status_t AAH_TXPlayer::prepareAsync_l() {
- if (mFlags & PREPARING) {
- return UNKNOWN_ERROR; // async prepare already pending
- }
-
- mAAH_Sender = AAH_TXSender::GetInstance();
- if (mAAH_Sender == NULL) {
- return NO_MEMORY;
- }
-
- if (!mQueueStarted) {
- mQueue.start();
- mQueueStarted = true;
- }
-
- mFlags |= PREPARING;
- mAsyncPrepareEvent = new AAH_TXEvent(
- this, &AAH_TXPlayer::onPrepareAsyncEvent);
-
- mQueue.postEvent(mAsyncPrepareEvent);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::finishSetDataSource_l() {
- sp<DataSource> dataSource;
-
- if (!strncasecmp("http://", mUri.string(), 7) ||
- !strncasecmp("https://", mUri.string(), 8)) {
-
- mConnectingDataSource = HTTPBase::Create(
- (mFlags & INCOGNITO)
- ? HTTPBase::kFlagIncognito
- : 0);
-
- mLock.unlock();
- status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
- mLock.lock();
-
- if (err != OK) {
- mConnectingDataSource.clear();
-
- ALOGI("mConnectingDataSource->connect() returned %d", err);
- return err;
- }
-
- mCachedSource = new NuCachedSource2(mConnectingDataSource);
- mConnectingDataSource.clear();
-
- dataSource = mCachedSource;
-
- // We're going to prefill the cache before trying to instantiate
- // the extractor below, as the latter is an operation that otherwise
- // could block on the datasource for a significant amount of time.
- // During that time we'd be unable to abort the preparation phase
- // without this prefill.
-
- mLock.unlock();
-
- for (;;) {
- status_t finalStatus;
- size_t cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
-
- if (finalStatus != OK ||
- cachedDataRemaining >= kHighWaterMarkBytes ||
- (mFlags & PREPARE_CANCELLED)) {
- break;
- }
-
- usleep(200000);
- }
-
- mLock.lock();
-
- if (mFlags & PREPARE_CANCELLED) {
- ALOGI("Prepare cancelled while waiting for initial cache fill.");
- return UNKNOWN_ERROR;
- }
- } else {
- dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
- }
-
- if (dataSource == NULL) {
- return UNKNOWN_ERROR;
- }
-
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
-
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
-
- return setDataSource_l(extractor);
-}
-
-status_t AAH_TXPlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
- // Attempt to approximate overall stream bitrate by summing all
- // tracks' individual bitrates, if not all of them advertise bitrate,
- // we have to fail.
-
- int64_t totalBitRate = 0;
-
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- int32_t bitrate;
- if (!meta->findInt32(kKeyBitRate, &bitrate)) {
- totalBitRate = -1;
- break;
- }
-
- totalBitRate += bitrate;
- }
-
- mBitrate = totalBitRate;
-
- ALOGV("mBitrate = %lld bits/sec", mBitrate);
-
- bool haveAudio = false;
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- if (!strncasecmp(mime, "audio/", 6)) {
- mAudioSource = extractor->getTrack(i);
- CHECK(mAudioSource != NULL);
- haveAudio = true;
- break;
- }
- }
-
- if (!haveAudio) {
- return UNKNOWN_ERROR;
- }
-
- mExtractorFlags = extractor->flags();
-
- return OK;
-}
-
-void AAH_TXPlayer::abortPrepare(status_t err) {
- CHECK(err != OK);
-
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
-
- mPrepareResult = err;
- mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
- mPreparedCondition.broadcast();
-}
-
-void AAH_TXPlayer::onPrepareAsyncEvent() {
- Mutex::Autolock autoLock(mLock);
-
- if (mFlags & PREPARE_CANCELLED) {
- ALOGI("prepare was cancelled before doing anything");
- abortPrepare(UNKNOWN_ERROR);
- return;
- }
-
- if (mUri.size() > 0) {
- status_t err = finishSetDataSource_l();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- mAudioFormat = mAudioSource->getFormat();
- if (!mAudioFormat->findInt64(kKeyDuration, &mDurationUs))
- mDurationUs = 1;
-
- const char* mime_type = NULL;
- if (!mAudioFormat->findCString(kKeyMIMEType, &mime_type)) {
- ALOGE("Failed to find audio substream MIME type during prepare.");
- abortPrepare(BAD_VALUE);
- return;
- }
-
- if (!strcmp(mime_type, MEDIA_MIMETYPE_AUDIO_MPEG)) {
- mAudioCodec = TRTPAudioPacket::kCodecMPEG1Audio;
- } else
- if (!strcmp(mime_type, MEDIA_MIMETYPE_AUDIO_AAC)) {
- mAudioCodec = TRTPAudioPacket::kCodecAACAudio;
-
- uint32_t type;
- int32_t sample_rate;
- int32_t channel_count;
- const void* esds_data;
- size_t esds_len;
-
- if (!mAudioFormat->findInt32(kKeySampleRate, &sample_rate)) {
- ALOGE("Failed to find sample rate for AAC substream.");
- abortPrepare(BAD_VALUE);
- return;
- }
-
- if (!mAudioFormat->findInt32(kKeyChannelCount, &channel_count)) {
- ALOGE("Failed to find channel count for AAC substream.");
- abortPrepare(BAD_VALUE);
- return;
- }
-
- if (!mAudioFormat->findData(kKeyESDS, &type, &esds_data, &esds_len)) {
- ALOGE("Failed to find codec init data for AAC substream.");
- abortPrepare(BAD_VALUE);
- return;
- }
-
- CHECK(NULL == mAudioCodecData);
- mAudioCodecDataSize = esds_len
- + sizeof(sample_rate)
- + sizeof(channel_count);
- mAudioCodecData = new uint8_t[mAudioCodecDataSize];
- if (NULL == mAudioCodecData) {
- ALOGE("Failed to allocate %u bytes for AAC substream codec aux"
- " data.", mAudioCodecDataSize);
- mAudioCodecDataSize = 0;
- abortPrepare(BAD_VALUE);
- return;
- }
-
- uint8_t* tmp = mAudioCodecData;
- tmp[0] = static_cast<uint8_t>((sample_rate >> 24) & 0xFF);
- tmp[1] = static_cast<uint8_t>((sample_rate >> 16) & 0xFF);
- tmp[2] = static_cast<uint8_t>((sample_rate >> 8) & 0xFF);
- tmp[3] = static_cast<uint8_t>((sample_rate ) & 0xFF);
- tmp[4] = static_cast<uint8_t>((channel_count >> 24) & 0xFF);
- tmp[5] = static_cast<uint8_t>((channel_count >> 16) & 0xFF);
- tmp[6] = static_cast<uint8_t>((channel_count >> 8) & 0xFF);
- tmp[7] = static_cast<uint8_t>((channel_count ) & 0xFF);
-
- memcpy(tmp + 8, esds_data, esds_len);
- } else {
- ALOGE("Unsupported MIME type \"%s\" in audio substream", mime_type);
- abortPrepare(BAD_VALUE);
- return;
- }
-
- status_t err = mAudioSource->start();
- if (err != OK) {
- ALOGI("failed to start audio source, err=%d", err);
- abortPrepare(err);
- return;
- }
-
- mFlags |= PREPARING_CONNECTED;
-
- if (mCachedSource != NULL) {
- postBufferingEvent_l();
- } else {
- finishAsyncPrepare_l();
- }
-}
-
-void AAH_TXPlayer::finishAsyncPrepare_l() {
- notifyListener_l(MEDIA_PREPARED);
-
- mPrepareResult = OK;
- mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
- mFlags |= PREPARED;
- mPreparedCondition.broadcast();
-}
-
-status_t AAH_TXPlayer::start() {
- Mutex::Autolock autoLock(mLock);
-
- mFlags &= ~CACHE_UNDERRUN;
-
- return play_l();
-}
-
-status_t AAH_TXPlayer::play_l() {
- if (mFlags & PLAYING) {
- return OK;
- }
-
- if (!(mFlags & PREPARED)) {
- return INVALID_OPERATION;
- }
-
- {
- Mutex::Autolock lock(mEndpointLock);
- if (!mEndpointValid) {
- return INVALID_OPERATION;
- }
- if (!mEndpointRegistered) {
- mProgramID = mAAH_Sender->registerEndpoint(mEndpoint);
- mEndpointRegistered = true;
- }
- }
-
- mFlags |= PLAYING;
-
- updateClockTransform_l(false);
-
- postPumpAudioEvent_l(-1);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::stop() {
- status_t ret = pause();
- sendEOS_l();
- return ret;
-}
-
-status_t AAH_TXPlayer::pause() {
- Mutex::Autolock autoLock(mLock);
-
- mFlags &= ~CACHE_UNDERRUN;
-
- return pause_l();
-}
-
-status_t AAH_TXPlayer::pause_l(bool doClockUpdate) {
- if (!(mFlags & PLAYING)) {
- return OK;
- }
-
- cancelPlayerEvents(true /* keepBufferingGoing */);
-
- mFlags &= ~PLAYING;
-
- if (doClockUpdate) {
- updateClockTransform_l(true);
- }
-
- return OK;
-}
-
-void AAH_TXPlayer::updateClockTransform_l(bool pause) {
- // record the new pause status so that onPumpAudio knows what rate to apply
- // when it initializes the transform
- mPlayRateIsPaused = pause;
-
- // if we haven't yet established a valid clock transform, then we can't
- // do anything here
- if (!mCurrentClockTransformValid) {
- return;
- }
-
- // sample the current common time
- int64_t commonTimeNow;
- if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
- ALOGE("updateClockTransform_l get common time failed");
- mCurrentClockTransformValid = false;
- return;
- }
-
- // convert the current common time to media time using the old
- // transform
- int64_t mediaTimeNow;
- if (!mCurrentClockTransform.doReverseTransform(
- commonTimeNow, &mediaTimeNow)) {
- ALOGE("updateClockTransform_l reverse transform failed");
- mCurrentClockTransformValid = false;
- return;
- }
-
- // calculate a new transform that preserves the old transform's
- // result for the current time
- mCurrentClockTransform.a_zero = mediaTimeNow;
- mCurrentClockTransform.b_zero = commonTimeNow;
- mCurrentClockTransform.a_to_b_numer = 1;
- mCurrentClockTransform.a_to_b_denom = pause ? 0 : 1;
-
- // send a packet announcing the new transform
- sp<TRTPControlPacket> packet = new TRTPControlPacket();
- packet->setClockTransform(mCurrentClockTransform);
- packet->setCommandID(TRTPControlPacket::kCommandNop);
- queuePacketToSender_l(packet);
-}
-
-void AAH_TXPlayer::sendEOS_l() {
- sp<TRTPControlPacket> packet = new TRTPControlPacket();
- packet->setCommandID(TRTPControlPacket::kCommandEOS);
- queuePacketToSender_l(packet);
-}
-
-bool AAH_TXPlayer::isPlaying() {
- return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
-}
-
-status_t AAH_TXPlayer::seekTo(int msec) {
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
- Mutex::Autolock autoLock(mLock);
- return seekTo_l(static_cast<int64_t>(msec) * 1000);
- }
-
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- return OK;
-}
-
-status_t AAH_TXPlayer::seekTo_l(int64_t timeUs) {
- mIsSeeking = true;
- mSeekTimeUs = timeUs;
-
- mCurrentClockTransformValid = false;
- mLastQueuedMediaTimePTSValid = false;
-
- // send a flush command packet
- sp<TRTPControlPacket> packet = new TRTPControlPacket();
- packet->setCommandID(TRTPControlPacket::kCommandFlush);
- queuePacketToSender_l(packet);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::getCurrentPosition(int *msec) {
- if (!msec) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mLock);
-
- int position;
-
- if (mIsSeeking) {
- position = mSeekTimeUs / 1000;
- } else if (mCurrentClockTransformValid) {
- // sample the current common time
- int64_t commonTimeNow;
- if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
- ALOGE("getCurrentPosition get common time failed");
- return INVALID_OPERATION;
- }
-
- int64_t mediaTimeNow;
- if (!mCurrentClockTransform.doReverseTransform(commonTimeNow,
- &mediaTimeNow)) {
- ALOGE("getCurrentPosition reverse transform failed");
- return INVALID_OPERATION;
- }
-
- position = static_cast<int>(mediaTimeNow / 1000);
- } else {
- position = 0;
- }
-
- int duration;
- if (getDuration_l(&duration) == OK) {
- *msec = clamp(position, 0, duration);
- } else {
- *msec = (position >= 0) ? position : 0;
- }
-
- return OK;
-}
-
-status_t AAH_TXPlayer::getDuration(int* msec) {
- if (!msec) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mLock);
-
- return getDuration_l(msec);
-}
-
-status_t AAH_TXPlayer::getDuration_l(int* msec) {
- if (mDurationUs < 0) {
- return UNKNOWN_ERROR;
- }
-
- *msec = (mDurationUs + 500) / 1000;
-
- return OK;
-}
-
-status_t AAH_TXPlayer::reset() {
- Mutex::Autolock autoLock(mLock);
- reset_l();
- return OK;
-}
-
-void AAH_TXPlayer::reset_l() {
- if (mFlags & PREPARING) {
- mFlags |= PREPARE_CANCELLED;
- if (mConnectingDataSource != NULL) {
- ALOGI("interrupting the connection process");
- mConnectingDataSource->disconnect();
- }
-
- if (mFlags & PREPARING_CONNECTED) {
- // We are basically done preparing, we're just buffering
- // enough data to start playback, we can safely interrupt that.
- finishAsyncPrepare_l();
- }
- }
-
- while (mFlags & PREPARING) {
- mPreparedCondition.wait(mLock);
- }
-
- cancelPlayerEvents();
-
- sendEOS_l();
-
- mCachedSource.clear();
-
- if (mAudioSource != NULL) {
- mAudioSource->stop();
- }
- mAudioSource.clear();
- mAudioCodec = TRTPAudioPacket::kCodecInvalid;
- mAudioFormat = NULL;
- delete[] mAudioCodecData;
- mAudioCodecData = NULL;
- mAudioCodecDataSize = 0;
-
- mFlags = 0;
- mExtractorFlags = 0;
-
- mDurationUs = -1;
- mIsSeeking = false;
- mSeekTimeUs = 0;
-
- mUri.setTo("");
- mUriHeaders.clear();
-
- mFileSource.clear();
-
- mBitrate = -1;
-
- {
- Mutex::Autolock lock(mEndpointLock);
- if (mAAH_Sender != NULL && mEndpointRegistered) {
- mAAH_Sender->unregisterEndpoint(mEndpoint);
- }
- mEndpointRegistered = false;
- mEndpointValid = false;
- }
-
- mProgramID = 0;
-
- mAAH_Sender.clear();
- mLastQueuedMediaTimePTSValid = false;
- mCurrentClockTransformValid = false;
- mPlayRateIsPaused = false;
-
- mTRTPVolume = 255;
-}
-
-status_t AAH_TXPlayer::setLooping(int loop) {
- return OK;
-}
-
-player_type AAH_TXPlayer::playerType() {
- return AAH_TX_PLAYER;
-}
-
-status_t AAH_TXPlayer::setParameter(int key, const Parcel &request) {
- return ERROR_UNSUPPORTED;
-}
-
-status_t AAH_TXPlayer::getParameter(int key, Parcel *reply) {
- return ERROR_UNSUPPORTED;
-}
-
-status_t AAH_TXPlayer::invoke(const Parcel& request, Parcel *reply) {
- return INVALID_OPERATION;
-}
-
-status_t AAH_TXPlayer::getMetadata(const media::Metadata::Filter& ids,
- Parcel* records) {
- using media::Metadata;
-
- Metadata metadata(records);
-
- metadata.appendBool(Metadata::kPauseAvailable, true);
- metadata.appendBool(Metadata::kSeekBackwardAvailable, false);
- metadata.appendBool(Metadata::kSeekForwardAvailable, false);
- metadata.appendBool(Metadata::kSeekAvailable, false);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::setVolume(float leftVolume, float rightVolume) {
- if (leftVolume != rightVolume) {
- ALOGE("%s does not support per channel volume: %f, %f",
- __PRETTY_FUNCTION__, leftVolume, rightVolume);
- }
-
- float volume = clamp(leftVolume, 0.0f, 1.0f);
-
- Mutex::Autolock lock(mLock);
- mTRTPVolume = static_cast<uint8_t>((leftVolume * 255.0) + 0.5);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::setAudioStreamType(audio_stream_type_t streamType) {
- return OK;
-}
-
-status_t AAH_TXPlayer::setRetransmitEndpoint(
- const struct sockaddr_in* endpoint) {
- Mutex::Autolock lock(mLock);
-
- if (NULL == endpoint)
- return BAD_VALUE;
-
- // Once the endpoint has been registered, it may not be changed.
- if (mEndpointRegistered)
- return INVALID_OPERATION;
-
- mEndpoint.addr = endpoint->sin_addr.s_addr;
- mEndpoint.port = endpoint->sin_port;
- mEndpointValid = true;
-
- return OK;
-}
-
-void AAH_TXPlayer::notifyListener_l(int msg, int ext1, int ext2) {
- sendEvent(msg, ext1, ext2);
-}
-
-bool AAH_TXPlayer::getBitrate_l(int64_t *bitrate) {
- off64_t size;
- if (mDurationUs >= 0 &&
- mCachedSource != NULL &&
- mCachedSource->getSize(&size) == OK) {
- *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
- return true;
- }
-
- if (mBitrate >= 0) {
- *bitrate = mBitrate;
- return true;
- }
-
- *bitrate = 0;
-
- return false;
-}
-
-// Returns true iff cached duration is available/applicable.
-bool AAH_TXPlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
- int64_t bitrate;
-
- if (mCachedSource != NULL && getBitrate_l(&bitrate)) {
- status_t finalStatus;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(
- &finalStatus);
- *durationUs = cachedDataRemaining * 8000000ll / bitrate;
- *eos = (finalStatus != OK);
- return true;
- }
-
- return false;
-}
-
-void AAH_TXPlayer::ensureCacheIsFetching_l() {
- if (mCachedSource != NULL) {
- mCachedSource->resumeFetchingIfNecessary();
- }
-}
-
-void AAH_TXPlayer::postBufferingEvent_l() {
- if (mBufferingEventPending) {
- return;
- }
- mBufferingEventPending = true;
- mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
-}
-
-void AAH_TXPlayer::postPumpAudioEvent_l(int64_t delayUs) {
- if (mPumpAudioEventPending) {
- return;
- }
- mPumpAudioEventPending = true;
- mQueue.postEventWithDelay(mPumpAudioEvent, delayUs < 0 ? 10000 : delayUs);
-}
-
-void AAH_TXPlayer::onBufferingUpdate() {
- Mutex::Autolock autoLock(mLock);
- if (!mBufferingEventPending) {
- return;
- }
- mBufferingEventPending = false;
-
- if (mCachedSource != NULL) {
- status_t finalStatus;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(
- &finalStatus);
- bool eos = (finalStatus != OK);
-
- if (eos) {
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- }
- if (mFlags & PREPARING) {
- ALOGV("cache has reached EOS, prepare is done.");
- finishAsyncPrepare_l();
- }
- } else {
- int64_t bitrate;
- if (getBitrate_l(&bitrate)) {
- size_t cachedSize = mCachedSource->cachedSize();
- int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
-
- int percentage = (100.0 * (double) cachedDurationUs)
- / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
- } else {
- // We don't know the bitrate of the stream, use absolute size
- // limits to maintain the cache.
-
- if ((mFlags & PLAYING) &&
- !eos &&
- (cachedDataRemaining < kLowWaterMarkBytes)) {
- ALOGI("cache is running low (< %d) , pausing.",
- kLowWaterMarkBytes);
- mFlags |= CACHE_UNDERRUN;
- pause_l();
- ensureCacheIsFetching_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
- if (mFlags & CACHE_UNDERRUN) {
- ALOGI("cache has filled up (> %d), resuming.",
- kHighWaterMarkBytes);
- mFlags &= ~CACHE_UNDERRUN;
- play_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
- } else if (mFlags & PREPARING) {
- ALOGV("cache has filled up (> %d), prepare is done",
- kHighWaterMarkBytes);
- finishAsyncPrepare_l();
- }
- }
- }
- }
- }
-
- int64_t cachedDurationUs;
- bool eos;
- if (getCachedDuration_l(&cachedDurationUs, &eos)) {
- ALOGV("cachedDurationUs = %.2f secs, eos=%d",
- cachedDurationUs / 1E6, eos);
-
- if ((mFlags & PLAYING) &&
- !eos &&
- (cachedDurationUs < kLowWaterMarkUs)) {
- ALOGI("cache is running low (%.2f secs) , pausing.",
- cachedDurationUs / 1E6);
- mFlags |= CACHE_UNDERRUN;
- pause_l();
- ensureCacheIsFetching_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
- if (mFlags & CACHE_UNDERRUN) {
- ALOGI("cache has filled up (%.2f secs), resuming.",
- cachedDurationUs / 1E6);
- mFlags &= ~CACHE_UNDERRUN;
- play_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
- } else if (mFlags & PREPARING) {
- ALOGV("cache has filled up (%.2f secs), prepare is done",
- cachedDurationUs / 1E6);
- finishAsyncPrepare_l();
- }
- }
- }
-
- postBufferingEvent_l();
-}
-
-void AAH_TXPlayer::onPumpAudio() {
- while (true) {
- Mutex::Autolock autoLock(mLock);
- // If this flag is clear, its because someone has externally canceled
- // this pump operation (probably because we a resetting/shutting down).
- // Get out immediately, do not reschedule ourselves.
- if (!mPumpAudioEventPending) {
- return;
- }
-
- // Start by checking if there is still work to be doing. If we have
- // never queued a payload (so we don't know what the last queued PTS is)
- // or we have never established a MediaTime->CommonTime transformation,
- // then we have work to do (one time through this loop should establish
- // both). Otherwise, we want to keep a fixed amt of presentation time
- // worth of data buffered. If we cannot get common time (service is
- // unavailable, or common time is undefined)) then we don't have a lot
- // 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 != 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.
- ALOGE("*** Cannot pump audio, unable to fetch common time."
- " Shutting down.");
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, UNKNOWN_ERROR);
- mPumpAudioEventPending = false;
- break;
- }
-
- if (mCurrentClockTransformValid && mLastQueuedMediaTimePTSValid) {
- int64_t mediaTimeNow;
- bool conversionResult = mCurrentClockTransform.doReverseTransform(
- commonTimeNow,
- &mediaTimeNow);
- CHECK(conversionResult);
-
- if ((mediaTimeNow +
- kAAHBufferTimeUs -
- mLastQueuedMediaTimePTS) <= 0) {
- break;
- }
- }
-
- MediaSource::ReadOptions options;
- if (mIsSeeking) {
- options.setSeekTo(mSeekTimeUs);
- }
-
- MediaBuffer* mediaBuffer;
- status_t err = mAudioSource->read(&mediaBuffer, &options);
- if (err != NO_ERROR) {
- if (err == ERROR_END_OF_STREAM) {
- ALOGI("*** %s reached end of stream", __PRETTY_FUNCTION__);
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
- pause_l(false);
- sendEOS_l();
- } else {
- ALOGE("*** %s read failed err=%d", __PRETTY_FUNCTION__, err);
- }
- return;
- }
-
- if (mIsSeeking) {
- mIsSeeking = false;
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- }
-
- uint8_t* data = (static_cast<uint8_t*>(mediaBuffer->data()) +
- mediaBuffer->range_offset());
- ALOGV("*** %s got media buffer data=[%02hhx %02hhx %02hhx %02hhx]"
- " offset=%d length=%d", __PRETTY_FUNCTION__,
- data[0], data[1], data[2], data[3],
- mediaBuffer->range_offset(), mediaBuffer->range_length());
-
- int64_t mediaTimeUs;
- CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &mediaTimeUs));
- ALOGV("*** timeUs=%lld", mediaTimeUs);
-
- if (!mCurrentClockTransformValid) {
- if (OK == mCCHelper.getCommonTime(&commonTimeNow)) {
- mCurrentClockTransform.a_zero = mediaTimeUs;
- mCurrentClockTransform.b_zero = commonTimeNow +
- kAAHStartupLeadTimeUs;
- mCurrentClockTransform.a_to_b_numer = 1;
- mCurrentClockTransform.a_to_b_denom = mPlayRateIsPaused ? 0 : 1;
- mCurrentClockTransformValid = true;
- } else {
- // Failed to get common time; either the service is down or
- // common time is not synced. Raise an error and shutdown the
- // player.
- ALOGE("*** Cannot begin transmission, unable to fetch common"
- " time. Dropping sample with pts=%lld", mediaTimeUs);
- notifyListener_l(MEDIA_ERROR,
- MEDIA_ERROR_UNKNOWN,
- UNKNOWN_ERROR);
- mPumpAudioEventPending = false;
- break;
- }
- }
-
- ALOGV("*** transmitting packet with pts=%lld", mediaTimeUs);
-
- sp<TRTPAudioPacket> packet = new TRTPAudioPacket();
- packet->setPTS(mediaTimeUs);
- packet->setSubstreamID(1);
-
- packet->setCodecType(mAudioCodec);
- packet->setVolume(mTRTPVolume);
- // TODO : introduce a throttle for this so we can control the
- // frequency with which transforms get sent.
- packet->setClockTransform(mCurrentClockTransform);
- packet->setAccessUnitData(data, mediaBuffer->range_length());
-
- // TODO : while its pretty much universally true that audio ES payloads
- // are all RAPs across all codecs, it might be a good idea to throttle
- // the frequency with which we send codec out of band data to the RXers.
- // If/when we do, we need to flag only those payloads which have
- // required out of band data attached to them as RAPs.
- packet->setRandomAccessPoint(true);
-
- if (mAudioCodecData && mAudioCodecDataSize) {
- packet->setAuxData(mAudioCodecData, mAudioCodecDataSize);
- }
-
- queuePacketToSender_l(packet);
- mediaBuffer->release();
-
- mLastQueuedMediaTimePTSValid = true;
- mLastQueuedMediaTimePTS = mediaTimeUs;
- }
-
- { // Explicit scope for the autolock pattern.
- Mutex::Autolock autoLock(mLock);
-
- // If someone externally has cleared this flag, its because we should be
- // shutting down. Do not reschedule ourselves.
- if (!mPumpAudioEventPending) {
- return;
- }
-
- // Looks like no one canceled us explicitly. Clear our flag and post a
- // new event to ourselves.
- mPumpAudioEventPending = false;
- postPumpAudioEvent_l(10000);
- }
-}
-
-void AAH_TXPlayer::queuePacketToSender_l(const sp<TRTPPacket>& packet) {
- if (mAAH_Sender == NULL) {
- return;
- }
-
- sp<AMessage> message = new AMessage(AAH_TXSender::kWhatSendPacket,
- mAAH_Sender->handlerID());
-
- {
- Mutex::Autolock lock(mEndpointLock);
- if (!mEndpointValid) {
- return;
- }
-
- message->setInt32(AAH_TXSender::kSendPacketIPAddr, mEndpoint.addr);
- message->setInt32(AAH_TXSender::kSendPacketPort, mEndpoint.port);
- }
-
- packet->setProgramID(mProgramID);
- packet->setExpireTime(systemTime() + kAAHRetryKeepAroundTimeNs);
- packet->pack();
-
- message->setObject(AAH_TXSender::kSendPacketTRTPPacket, packet);
-
- message->post();
-}
-
-} // namespace android