summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Grossman <johngro@google.com>2012-08-06 13:50:00 -0700
committerJohn Grossman <johngro@google.com>2012-08-13 09:48:56 -0700
commit8ec1f2a4f3c72fe7472f8b8fa227f6b7bbc9279b (patch)
tree5a85d007f81c1d09f68f3894f8cbb0a950372250
parent44a7e42f0310831e6a846d1b6bb40bf3a399bf6d (diff)
downloadframeworks_av-8ec1f2a4f3c72fe7472f8b8fa227f6b7bbc9279b.zip
frameworks_av-8ec1f2a4f3c72fe7472f8b8fa227f6b7bbc9279b.tar.gz
frameworks_av-8ec1f2a4f3c72fe7472f8b8fa227f6b7bbc9279b.tar.bz2
Move the AAH RTP code out of framework and into vendor.
Relocate the AAH RTP code from framework/av into vendor/google_devices/phantasm. This change is the deletion, there will be a separate CL which re-introduces on the vendor side of things. Change-Id: Ibe7e6d4b633a3886b87a615691a2692f2382af6c Signed-off-by: John Grossman <johngro@google.com>
-rw-r--r--include/media/MediaPlayerInterface.h3
-rw-r--r--media/libaah_rtp/Android.mk40
-rw-r--r--media/libaah_rtp/MODULE_LICENSE_APACHE20
-rw-r--r--media/libaah_rtp/NOTICE190
-rw-r--r--media/libaah_rtp/aah_decoder_pump.cpp519
-rw-r--r--media/libaah_rtp/aah_decoder_pump.h107
-rw-r--r--media/libaah_rtp/aah_rx_player.cpp288
-rw-r--r--media/libaah_rtp/aah_rx_player.h318
-rw-r--r--media/libaah_rtp/aah_rx_player_core.cpp809
-rw-r--r--media/libaah_rtp/aah_rx_player_ring_buffer.cpp366
-rw-r--r--media/libaah_rtp/aah_rx_player_substream.cpp677
-rw-r--r--media/libaah_rtp/aah_tx_packet.cpp344
-rw-r--r--media/libaah_rtp/aah_tx_packet.h213
-rw-r--r--media/libaah_rtp/aah_tx_player.cpp1177
-rw-r--r--media/libaah_rtp/aah_tx_player.h176
-rw-r--r--media/libaah_rtp/aah_tx_sender.cpp603
-rw-r--r--media/libaah_rtp/aah_tx_sender.h162
-rw-r--r--media/libaah_rtp/pipe_event.cpp86
-rw-r--r--media/libaah_rtp/pipe_event.h51
-rw-r--r--media/libmediaplayerservice/Android.mk3
-rw-r--r--media/libmediaplayerservice/MediaPlayerFactory.cpp65
21 files changed, 1 insertions, 6196 deletions
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 0498ed1..518948c 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -50,9 +50,6 @@ enum player_type {
// The shared library with the test player is passed passed as an
// argument to the 'test:' url in the setDataSource call.
TEST_PLAYER = 5,
-
- AAH_RX_PLAYER = 100,
- AAH_TX_PLAYER = 101,
};
diff --git a/media/libaah_rtp/Android.mk b/media/libaah_rtp/Android.mk
deleted file mode 100644
index df533ec..0000000
--- a/media/libaah_rtp/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-#
-# libaah_rtp
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaah_rtp
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
- aah_decoder_pump.cpp \
- aah_rx_player.cpp \
- aah_rx_player_core.cpp \
- aah_rx_player_ring_buffer.cpp \
- aah_rx_player_substream.cpp \
- aah_tx_packet.cpp \
- aah_tx_player.cpp \
- aah_tx_sender.cpp \
- pipe_event.cpp
-
-LOCAL_C_INCLUDES := \
- frameworks/av/include \
- frameworks/av/media \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES := \
- libcommon_time_client \
- libbinder \
- libmedia \
- libmedia_native \
- libstagefright \
- libstagefright_foundation \
- libutils
-
-LOCAL_LDLIBS := \
- -lpthread
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaah_rtp/MODULE_LICENSE_APACHE2 b/media/libaah_rtp/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/media/libaah_rtp/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/media/libaah_rtp/NOTICE b/media/libaah_rtp/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/media/libaah_rtp/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/media/libaah_rtp/aah_decoder_pump.cpp b/media/libaah_rtp/aah_decoder_pump.cpp
deleted file mode 100644
index bebba54..0000000
--- a/media/libaah_rtp/aah_decoder_pump.cpp
+++ /dev/null
@@ -1,519 +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"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <poll.h>
-#include <pthread.h>
-
-#include <common_time/cc_helper.h>
-#include <media/AudioSystem.h>
-#include <media/AudioTrack.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/Utils.h>
-#include <utils/Timers.h>
-#include <utils/threads.h>
-
-#include "aah_decoder_pump.h"
-
-namespace android {
-
-static const long long kLongDecodeErrorThreshold = 1000000ll;
-static const uint32_t kMaxLongErrorsBeforeFatal = 3;
-static const uint32_t kMaxErrorsBeforeFatal = 60;
-
-AAH_DecoderPump::AAH_DecoderPump(OMXClient& omx)
- : omx_(omx)
- , thread_status_(OK)
- , renderer_(NULL)
- , last_queued_pts_valid_(false)
- , last_queued_pts_(0)
- , last_ts_transform_valid_(false)
- , last_volume_(0xFF) {
- thread_ = new ThreadWrapper(this);
-}
-
-AAH_DecoderPump::~AAH_DecoderPump() {
- shutdown();
-}
-
-status_t AAH_DecoderPump::initCheck() {
- if (thread_ == NULL) {
- ALOGE("Failed to allocate thread");
- return NO_MEMORY;
- }
-
- return OK;
-}
-
-status_t AAH_DecoderPump::queueForDecode(MediaBuffer* buf) {
- if (NULL == buf) {
- return BAD_VALUE;
- }
-
- if (OK != thread_status_) {
- return thread_status_;
- }
-
- { // Explicit scope for AutoMutex pattern.
- AutoMutex lock(&thread_lock_);
- in_queue_.push_back(buf);
- }
-
- thread_cond_.signal();
-
- return OK;
-}
-
-void AAH_DecoderPump::queueToRenderer(MediaBuffer* decoded_sample) {
- Mutex::Autolock lock(&render_lock_);
- sp<MetaData> meta;
- int64_t ts;
- status_t res;
-
- // Fetch the metadata and make sure the sample has a timestamp. We
- // cannot render samples which are missing PTSs.
- meta = decoded_sample->meta_data();
- if ((meta == NULL) || (!meta->findInt64(kKeyTime, &ts))) {
- ALOGV("Decoded sample missing timestamp, cannot render.");
- CHECK(false);
- } else {
- // If we currently are not holding on to a renderer, go ahead and
- // make one now.
- if (NULL == renderer_) {
- renderer_ = new TimedAudioTrack();
- if (NULL != renderer_) {
- int frameCount;
- AudioTrack::getMinFrameCount(&frameCount,
- AUDIO_STREAM_DEFAULT,
- static_cast<int>(format_sample_rate_));
- audio_channel_mask_t ch_format =
- audio_channel_out_mask_from_count(format_channels_);
-
- res = renderer_->set(AUDIO_STREAM_DEFAULT,
- format_sample_rate_,
- AUDIO_FORMAT_PCM_16_BIT,
- ch_format,
- frameCount);
- if (res != OK) {
- ALOGE("Failed to setup audio renderer. (res = %d)", res);
- delete renderer_;
- renderer_ = NULL;
- } else {
- CHECK(last_ts_transform_valid_);
-
- res = renderer_->setMediaTimeTransform(
- last_ts_transform_, TimedAudioTrack::COMMON_TIME);
- if (res != NO_ERROR) {
- ALOGE("Failed to set media time transform on AudioTrack"
- " (res = %d)", res);
- delete renderer_;
- renderer_ = NULL;
- } else {
- float volume = static_cast<float>(last_volume_)
- / 255.0f;
- if (renderer_->setVolume(volume, volume) != OK) {
- ALOGW("%s: setVolume failed", __FUNCTION__);
- }
-
- renderer_->start();
- }
- }
- } else {
- ALOGE("Failed to allocate AudioTrack to use as a renderer.");
- }
- }
-
- if (NULL != renderer_) {
- uint8_t* decoded_data =
- reinterpret_cast<uint8_t*>(decoded_sample->data());
- uint32_t decoded_amt = decoded_sample->range_length();
- decoded_data += decoded_sample->range_offset();
-
- sp<IMemory> pcm_payload;
- res = renderer_->allocateTimedBuffer(decoded_amt, &pcm_payload);
- if (res != OK) {
- ALOGE("Failed to allocate %d byte audio track buffer."
- " (res = %d)", decoded_amt, res);
- } else {
- memcpy(pcm_payload->pointer(), decoded_data, decoded_amt);
-
- res = renderer_->queueTimedBuffer(pcm_payload, ts);
- if (res != OK) {
- ALOGE("Failed to queue %d byte audio track buffer with"
- " media PTS %lld. (res = %d)", decoded_amt, ts, res);
- } else {
- last_queued_pts_valid_ = true;
- last_queued_pts_ = ts;
- }
- }
-
- } else {
- ALOGE("No renderer, dropping audio payload.");
- }
- }
-}
-
-void AAH_DecoderPump::stopAndCleanupRenderer() {
- if (NULL == renderer_) {
- return;
- }
-
- renderer_->stop();
- delete renderer_;
- renderer_ = NULL;
-}
-
-void AAH_DecoderPump::setRenderTSTransform(const LinearTransform& trans) {
- Mutex::Autolock lock(&render_lock_);
-
- if (last_ts_transform_valid_ && !memcmp(&trans,
- &last_ts_transform_,
- sizeof(trans))) {
- return;
- }
-
- last_ts_transform_ = trans;
- last_ts_transform_valid_ = true;
-
- if (NULL != renderer_) {
- status_t res = renderer_->setMediaTimeTransform(
- last_ts_transform_, TimedAudioTrack::COMMON_TIME);
- if (res != NO_ERROR) {
- ALOGE("Failed to set media time transform on AudioTrack"
- " (res = %d)", res);
- }
- }
-}
-
-void AAH_DecoderPump::setRenderVolume(uint8_t volume) {
- Mutex::Autolock lock(&render_lock_);
-
- if (volume == last_volume_) {
- return;
- }
-
- last_volume_ = volume;
- if (renderer_ != NULL) {
- float volume = static_cast<float>(last_volume_) / 255.0f;
- if (renderer_->setVolume(volume, volume) != OK) {
- ALOGW("%s: setVolume failed", __FUNCTION__);
- }
- }
-}
-
-// isAboutToUnderflow is something of a hack used to figure out when it might be
-// time to give up on trying to fill in a gap in the RTP sequence and simply
-// move on with a discontinuity. If we had perfect knowledge of when we were
-// going to underflow, it would not be a hack, but unfortunately we do not.
-// Right now, we just take the PTS of the last sample queued, and check to see
-// if its presentation time is within kAboutToUnderflowThreshold from now. If
-// it is, then we say that we are about to underflow. This decision is based on
-// two (possibly invalid) assumptions.
-//
-// 1) The transmitter is leading the clock by more than
-// kAboutToUnderflowThreshold.
-// 2) The delta between the PTS of the last sample queued and the next sample
-// is less than the transmitter's clock lead amount.
-//
-// Right now, the default transmitter lead time is 1 second, which is a pretty
-// large number and greater than the 50mSec that kAboutToUnderflowThreshold is
-// currently set to. This should satisfy assumption #1 for now, but changes to
-// the transmitter clock lead time could effect this.
-//
-// For non-sparse streams with a homogeneous sample rate (the vast majority of
-// streams in the world), the delta between any two adjacent PTSs will always be
-// the homogeneous sample period. It is very uncommon to see a sample period
-// greater than the 1 second clock lead we are currently using, and you
-// certainly will not see it in an MP3 file which should satisfy assumption #2.
-// Sparse audio streams (where no audio is transmitted for long periods of
-// silence) and extremely low framerate video stream (like an MPEG-2 slideshow
-// or the video stream for a pay TV audio channel) are examples of streams which
-// might violate assumption #2.
-bool AAH_DecoderPump::isAboutToUnderflow(int64_t threshold) {
- Mutex::Autolock lock(&render_lock_);
-
- // If we have never queued anything to the decoder, we really don't know if
- // we are going to underflow or not.
- if (!last_queued_pts_valid_ || !last_ts_transform_valid_) {
- return false;
- }
-
- // Don't have access to Common Time? If so, then things are Very Bad
- // elsewhere in the system; it pretty much does not matter what we do here.
- // 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 != cc_helper_.getCommonTime(&tt_now)) {
- return false;
- }
-
- // Transform from media time to common time.
- int64_t last_queued_pts_tt;
- if (!last_ts_transform_.doForwardTransform(last_queued_pts_,
- &last_queued_pts_tt)) {
- return false;
- }
-
- // Check to see if we are underflowing.
- return ((tt_now + threshold - last_queued_pts_tt) > 0);
-}
-
-void* AAH_DecoderPump::workThread() {
- // No need to lock when accessing decoder_ from the thread. The
- // implementation of init and shutdown ensure that other threads never touch
- // decoder_ while the work thread is running.
- CHECK(decoder_ != NULL);
- CHECK(format_ != NULL);
-
- // Start the decoder and note its result code. If something goes horribly
- // wrong, callers of queueForDecode and getOutput will be able to detect
- // that the thread encountered a fatal error and shut down by examining
- // thread_status_.
- thread_status_ = decoder_->start(format_.get());
- if (OK != thread_status_) {
- ALOGE("AAH_DecoderPump's work thread failed to start decoder"
- " (res = %d)", thread_status_);
- return NULL;
- }
-
- DurationTimer decode_timer;
- uint32_t consecutive_long_errors = 0;
- uint32_t consecutive_errors = 0;
-
- while (!thread_->exitPending()) {
- status_t res;
- MediaBuffer* bufOut = NULL;
-
- decode_timer.start();
- res = decoder_->read(&bufOut);
- decode_timer.stop();
-
- if (res == INFO_FORMAT_CHANGED) {
- // Format has changed. Destroy our current renderer so that a new
- // one can be created during queueToRenderer with the proper format.
- //
- // TODO : In order to transition seamlessly, we should change this
- // to put the old renderer in a queue to play out completely before
- // we destroy it. We can still create a new renderer, the timed
- // nature of the renderer should ensure a seamless splice.
- stopAndCleanupRenderer();
- res = OK;
- }
-
- // Try to be a little nuanced in our handling of actual decode errors.
- // Errors could happen because of minor stream corruption or because of
- // transient resource limitations. In these cases, we would rather drop
- // a little bit of output and ride out the unpleasantness then throw up
- // our hands and abort everything.
- //
- // OTOH - When things are really bad (like we have a non-transient
- // resource or bookkeeping issue, or the stream being fed to us is just
- // complete and total garbage) we really want to terminate playback and
- // raise an error condition all the way up to the application level so
- // they can deal with it.
- //
- // Unfortunately, the error codes returned by the decoder can be a
- // little non-specific. For example, if an OMXCodec times out
- // attempting to obtain an output buffer, the error we get back is a
- // generic -1. Try to distinguish between this resource timeout error
- // and ES corruption error by timing how long the decode operation
- // takes. Maintain accounting for both errors and "long errors". If we
- // get more than a certain number consecutive errors of either type,
- // consider it fatal and shutdown (which will cause the error to
- // propagate all of the way up to the application level). The threshold
- // for "long errors" is deliberately much lower than that of normal
- // decode errors, both because of how long they take to happen and
- // because they generally indicate resource limitation errors which are
- // unlikely to go away in pathologically bad cases (in contrast to
- // stream corruption errors which might happen 20 times in a row and
- // then be suddenly OK again)
- if (res != OK) {
- consecutive_errors++;
- if (decode_timer.durationUsecs() >= kLongDecodeErrorThreshold)
- consecutive_long_errors++;
-
- CHECK(NULL == bufOut);
-
- ALOGW("%s: Failed to decode data (res = %d)",
- __PRETTY_FUNCTION__, res);
-
- if ((consecutive_errors >= kMaxErrorsBeforeFatal) ||
- (consecutive_long_errors >= kMaxLongErrorsBeforeFatal)) {
- ALOGE("%s: Maximum decode error threshold has been reached."
- " There have been %d consecutive decode errors, and %d"
- " consecutive decode operations which resulted in errors"
- " and took more than %lld uSec to process. The last"
- " decode operation took %lld uSec.",
- __PRETTY_FUNCTION__,
- consecutive_errors, consecutive_long_errors,
- kLongDecodeErrorThreshold, decode_timer.durationUsecs());
- thread_status_ = res;
- break;
- }
-
- continue;
- }
-
- if (NULL == bufOut) {
- ALOGW("%s: Successful decode, but no buffer produced",
- __PRETTY_FUNCTION__);
- continue;
- }
-
- // Successful decode (with actual output produced). Clear the error
- // counters.
- consecutive_errors = 0;
- consecutive_long_errors = 0;
-
- queueToRenderer(bufOut);
- bufOut->release();
- }
-
- decoder_->stop();
- stopAndCleanupRenderer();
-
- return NULL;
-}
-
-status_t AAH_DecoderPump::init(const sp<MetaData>& params) {
- Mutex::Autolock lock(&init_lock_);
-
- if (decoder_ != NULL) {
- // already inited
- return OK;
- }
-
- if (params == NULL) {
- return BAD_VALUE;
- }
-
- if (!params->findInt32(kKeyChannelCount, &format_channels_)) {
- return BAD_VALUE;
- }
-
- if (!params->findInt32(kKeySampleRate, &format_sample_rate_)) {
- return BAD_VALUE;
- }
-
- CHECK(OK == thread_status_);
- CHECK(decoder_ == NULL);
-
- status_t ret_val = UNKNOWN_ERROR;
-
- // Cache the format and attempt to create the decoder.
- format_ = params;
- decoder_ = OMXCodec::Create(
- omx_.interface(), // IOMX Handle
- format_, // Metadata for substream (indicates codec)
- false, // Make a decoder, not an encoder
- sp<MediaSource>(this)); // We will be the source for this codec.
-
- if (decoder_ == NULL) {
- ALOGE("Failed to allocate decoder in %s", __PRETTY_FUNCTION__);
- goto bailout;
- }
-
- // Fire up the pump thread. It will take care of starting and stopping the
- // decoder.
- ret_val = thread_->run("aah_decode_pump", ANDROID_PRIORITY_AUDIO);
- if (OK != ret_val) {
- ALOGE("Failed to start work thread in %s (res = %d)",
- __PRETTY_FUNCTION__, ret_val);
- goto bailout;
- }
-
-bailout:
- if (OK != ret_val) {
- decoder_ = NULL;
- format_ = NULL;
- }
-
- return OK;
-}
-
-status_t AAH_DecoderPump::shutdown() {
- Mutex::Autolock lock(&init_lock_);
- return shutdown_l();
-}
-
-status_t AAH_DecoderPump::shutdown_l() {
- thread_->requestExit();
- thread_cond_.signal();
- thread_->requestExitAndWait();
-
- for (MBQueue::iterator iter = in_queue_.begin();
- iter != in_queue_.end();
- ++iter) {
- (*iter)->release();
- }
- in_queue_.clear();
-
- last_queued_pts_valid_ = false;
- last_ts_transform_valid_ = false;
- last_volume_ = 0xFF;
- thread_status_ = OK;
-
- decoder_ = NULL;
- format_ = NULL;
-
- return OK;
-}
-
-status_t AAH_DecoderPump::read(MediaBuffer **buffer,
- const ReadOptions *options) {
- if (!buffer) {
- return BAD_VALUE;
- }
-
- *buffer = NULL;
-
- // While its not time to shut down, and we have no data to process, wait.
- AutoMutex lock(&thread_lock_);
- while (!thread_->exitPending() && in_queue_.empty())
- thread_cond_.wait(thread_lock_);
-
- // At this point, if its not time to shutdown then we must have something to
- // process. Go ahead and pop the front of the queue for processing.
- if (!thread_->exitPending()) {
- CHECK(!in_queue_.empty());
-
- *buffer = *(in_queue_.begin());
- in_queue_.erase(in_queue_.begin());
- }
-
- // If we managed to get a buffer, then everything must be OK. If not, then
- // we must be shutting down.
- return (NULL == *buffer) ? INVALID_OPERATION : OK;
-}
-
-AAH_DecoderPump::ThreadWrapper::ThreadWrapper(AAH_DecoderPump* owner)
- : Thread(false /* canCallJava*/ )
- , owner_(owner) {
-}
-
-bool AAH_DecoderPump::ThreadWrapper::threadLoop() {
- CHECK(NULL != owner_);
- owner_->workThread();
- return false;
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_decoder_pump.h b/media/libaah_rtp/aah_decoder_pump.h
deleted file mode 100644
index 4d57e49..0000000
--- a/media/libaah_rtp/aah_decoder_pump.h
+++ /dev/null
@@ -1,107 +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.
- */
-
-#ifndef __DECODER_PUMP_H__
-#define __DECODER_PUMP_H__
-
-#include <pthread.h>
-
-#include <common_time/cc_helper.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/LinearTransform.h>
-#include <utils/List.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class MetaData;
-class OMXClient;
-class TimedAudioTrack;
-
-class AAH_DecoderPump : public MediaSource {
- public:
- explicit AAH_DecoderPump(OMXClient& omx);
- status_t initCheck();
-
- status_t queueForDecode(MediaBuffer* buf);
-
- status_t init(const sp<MetaData>& params);
- status_t shutdown();
-
- void setRenderTSTransform(const LinearTransform& trans);
- void setRenderVolume(uint8_t volume);
- bool isAboutToUnderflow(int64_t threshold);
- bool getStatus() const { return thread_status_; }
-
- // MediaSource methods
- virtual status_t start(MetaData *params) { return OK; }
- virtual sp<MetaData> getFormat() { return format_; }
- virtual status_t stop() { return OK; }
- virtual status_t read(MediaBuffer **buffer,
- const ReadOptions *options);
-
- protected:
- virtual ~AAH_DecoderPump();
-
- private:
- class ThreadWrapper : public Thread {
- public:
- friend class AAH_DecoderPump;
- explicit ThreadWrapper(AAH_DecoderPump* owner);
-
- private:
- virtual bool threadLoop();
- AAH_DecoderPump* owner_;
-
- DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper);
- };
-
- void* workThread();
- virtual status_t shutdown_l();
- void queueToRenderer(MediaBuffer* decoded_sample);
- void stopAndCleanupRenderer();
-
- sp<MetaData> format_;
- int32_t format_channels_; // channel count, not channel mask
- int32_t format_sample_rate_;
-
- sp<MediaSource> decoder_;
- OMXClient& omx_;
- Mutex init_lock_;
-
- sp<ThreadWrapper> thread_;
- Condition thread_cond_;
- Mutex thread_lock_;
- status_t thread_status_;
-
- Mutex render_lock_;
- TimedAudioTrack* renderer_;
- bool last_queued_pts_valid_;
- int64_t last_queued_pts_;
- 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;
- MBQueue in_queue_;
-
- DISALLOW_EVIL_CONSTRUCTORS(AAH_DecoderPump);
-};
-
-} // namespace android
-#endif // __DECODER_PUMP_H__
diff --git a/media/libaah_rtp/aah_rx_player.cpp b/media/libaah_rtp/aah_rx_player.cpp
deleted file mode 100644
index 9dd79fd..0000000
--- a/media/libaah_rtp/aah_rx_player.cpp
+++ /dev/null
@@ -1,288 +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"
-//#define LOG_NDEBUG 0
-
-#include <binder/IServiceManager.h>
-#include <media/MediaPlayerInterface.h>
-#include <utils/Log.h>
-
-#include "aah_rx_player.h"
-
-namespace android {
-
-const uint32_t AAH_RXPlayer::kRTPRingBufferSize = 1 << 10;
-
-sp<MediaPlayerBase> createAAH_RXPlayer() {
- sp<MediaPlayerBase> ret = new AAH_RXPlayer();
- return ret;
-}
-
-AAH_RXPlayer::AAH_RXPlayer()
- : ring_buffer_(kRTPRingBufferSize)
- , substreams_(NULL) {
- thread_wrapper_ = new ThreadWrapper(*this);
-
- is_playing_ = false;
- multicast_joined_ = false;
- transmitter_known_ = false;
- current_epoch_known_ = false;
- data_source_set_ = false;
- sock_fd_ = -1;
-
- substreams_.setCapacity(4);
-
- memset(&listen_addr_, 0, sizeof(listen_addr_));
- memset(&transmitter_addr_, 0, sizeof(transmitter_addr_));
-
- fetchAudioFlinger();
-}
-
-AAH_RXPlayer::~AAH_RXPlayer() {
- reset_l();
- CHECK(substreams_.size() == 0);
- omx_.disconnect();
-}
-
-status_t AAH_RXPlayer::initCheck() {
- if (thread_wrapper_ == NULL) {
- ALOGE("Failed to allocate thread wrapper!");
- return NO_MEMORY;
- }
-
- if (!ring_buffer_.initCheck()) {
- ALOGE("Failed to allocate reassembly ring buffer!");
- return NO_MEMORY;
- }
-
- // 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 = cc_helper_.getCommonFreq(&freq);
- if (OK != res) {
- ALOGE("Failed to connect to common time service!");
- return res;
- }
-
- return omx_.connect();
-}
-
-status_t AAH_RXPlayer::setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- AutoMutex api_lock(&api_lock_);
- uint32_t a, b, c, d;
- uint16_t port;
-
- if (data_source_set_) {
- return INVALID_OPERATION;
- }
-
- if (NULL == url) {
- return BAD_VALUE;
- }
-
- if (5 != sscanf(url, "%*[^:/]://%u.%u.%u.%u:%hu", &a, &b, &c, &d, &port)) {
- ALOGE("Failed to parse URL \"%s\"", url);
- return BAD_VALUE;
- }
-
- if ((a > 255) || (b > 255) || (c > 255) || (d > 255) || (port == 0)) {
- ALOGE("Bad multicast address \"%s\"", url);
- return BAD_VALUE;
- }
-
- ALOGI("setDataSource :: %u.%u.%u.%u:%hu", a, b, c, d, port);
-
- a = (a << 24) | (b << 16) | (c << 8) | d;
-
- memset(&listen_addr_, 0, sizeof(listen_addr_));
- listen_addr_.sin_family = AF_INET;
- listen_addr_.sin_port = htons(port);
- listen_addr_.sin_addr.s_addr = htonl(a);
- data_source_set_ = true;
-
- return OK;
-}
-
-status_t AAH_RXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
- return INVALID_OPERATION;
-}
-
-status_t AAH_RXPlayer::setVideoSurface(const sp<Surface>& surface) {
- return OK;
-}
-
-status_t AAH_RXPlayer::setVideoSurfaceTexture(
- const sp<ISurfaceTexture>& surfaceTexture) {
- return OK;
-}
-
-status_t AAH_RXPlayer::prepare() {
- return OK;
-}
-
-status_t AAH_RXPlayer::prepareAsync() {
- sendEvent(MEDIA_PREPARED);
- return OK;
-}
-
-status_t AAH_RXPlayer::start() {
- AutoMutex api_lock(&api_lock_);
-
- if (is_playing_) {
- return OK;
- }
-
- status_t res = startWorkThread();
- is_playing_ = (res == OK);
- return res;
-}
-
-status_t AAH_RXPlayer::stop() {
- return pause();
-}
-
-status_t AAH_RXPlayer::pause() {
- AutoMutex api_lock(&api_lock_);
- stopWorkThread();
- CHECK(sock_fd_ < 0);
- is_playing_ = false;
- return OK;
-}
-
-bool AAH_RXPlayer::isPlaying() {
- AutoMutex api_lock(&api_lock_);
- return is_playing_;
-}
-
-status_t AAH_RXPlayer::seekTo(int msec) {
- sendEvent(MEDIA_SEEK_COMPLETE);
- return OK;
-}
-
-status_t AAH_RXPlayer::getCurrentPosition(int *msec) {
- if (NULL != msec) {
- *msec = 0;
- }
- return OK;
-}
-
-status_t AAH_RXPlayer::getDuration(int *msec) {
- if (NULL != msec) {
- *msec = 1;
- }
- return OK;
-}
-
-status_t AAH_RXPlayer::reset() {
- AutoMutex api_lock(&api_lock_);
- reset_l();
- return OK;
-}
-
-void AAH_RXPlayer::reset_l() {
- stopWorkThread();
- CHECK(sock_fd_ < 0);
- CHECK(!multicast_joined_);
- is_playing_ = false;
- data_source_set_ = false;
- transmitter_known_ = false;
- memset(&listen_addr_, 0, sizeof(listen_addr_));
-}
-
-status_t AAH_RXPlayer::setLooping(int loop) {
- return OK;
-}
-
-player_type AAH_RXPlayer::playerType() {
- return AAH_RX_PLAYER;
-}
-
-status_t AAH_RXPlayer::setParameter(int key, const Parcel &request) {
- return ERROR_UNSUPPORTED;
-}
-
-status_t AAH_RXPlayer::getParameter(int key, Parcel *reply) {
- return ERROR_UNSUPPORTED;
-}
-
-status_t AAH_RXPlayer::invoke(const Parcel& request, Parcel *reply) {
- if (!reply) {
- return BAD_VALUE;
- }
-
- int32_t magic;
- status_t err = request.readInt32(&magic);
- if (err != OK) {
- reply->writeInt32(err);
- return OK;
- }
-
- if (magic != 0x12345) {
- reply->writeInt32(BAD_VALUE);
- return OK;
- }
-
- int32_t methodID;
- err = request.readInt32(&methodID);
- if (err != OK) {
- reply->writeInt32(err);
- return OK;
- }
-
- switch (methodID) {
- // Get Volume
- case INVOKE_GET_MASTER_VOLUME: {
- if (audio_flinger_ != NULL) {
- reply->writeInt32(OK);
- reply->writeFloat(audio_flinger_->masterVolume());
- } else {
- reply->writeInt32(UNKNOWN_ERROR);
- }
- } break;
-
- // Set Volume
- case INVOKE_SET_MASTER_VOLUME: {
- float targetVol = request.readFloat();
- reply->writeInt32(audio_flinger_->setMasterVolume(targetVol));
- } break;
-
- default: return BAD_VALUE;
- }
-
- return OK;
-}
-
-void AAH_RXPlayer::fetchAudioFlinger() {
- if (audio_flinger_ == NULL) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- binder = sm->getService(String16("media.audio_flinger"));
-
- if (binder == NULL) {
- ALOGW("AAH_RXPlayer failed to fetch handle to audio flinger."
- " Master volume control will not be possible.");
- }
-
- audio_flinger_ = interface_cast<IAudioFlinger>(binder);
- }
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player.h b/media/libaah_rtp/aah_rx_player.h
deleted file mode 100644
index ba5617e..0000000
--- a/media/libaah_rtp/aah_rx_player.h
+++ /dev/null
@@ -1,318 +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.
- */
-
-#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>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <netinet/in.h>
-#include <utils/KeyedVector.h>
-#include <utils/LinearTransform.h>
-#include <utils/threads.h>
-
-#include "aah_decoder_pump.h"
-#include "pipe_event.h"
-
-namespace android {
-
-class AAH_RXPlayer : public MediaPlayerInterface {
- public:
- AAH_RXPlayer();
-
- virtual status_t initCheck();
- virtual status_t setDataSource(const char *url,
- const KeyedVector<String8, String8>*
- headers);
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setVideoSurface(const sp<Surface>& surface);
- virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>&
- surfaceTexture);
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t seekTo(int msec);
- virtual status_t getCurrentPosition(int *msec);
- virtual status_t getDuration(int *msec);
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType();
- virtual status_t setParameter(int key, const Parcel &request);
- virtual status_t getParameter(int key, Parcel *reply);
- virtual status_t invoke(const Parcel& request, Parcel *reply);
-
- protected:
- virtual ~AAH_RXPlayer();
-
- private:
- class ThreadWrapper : public Thread {
- public:
- friend class AAH_RXPlayer;
- explicit ThreadWrapper(AAH_RXPlayer& player)
- : Thread(false /* canCallJava */ )
- , player_(player) { }
-
- virtual bool threadLoop() { return player_.threadLoop(); }
-
- private:
- AAH_RXPlayer& player_;
-
- DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper);
- };
-
-#pragma pack(push, 1)
- // PacketBuffers are structures used by the RX ring buffer. The ring buffer
- // is a ring of pointers to PacketBuffer structures which act as variable
- // length byte arrays and hold the contents of received UDP packets. Rather
- // than make this a structure which hold a length and a pointer to another
- // allocated structure (which would require two allocations), this struct
- // uses a structure overlay pattern where allocation for the byte array
- // consists of allocating (arrayLen + sizeof(ssize_t)) bytes of data from
- // whatever pool/heap the packet buffer pulls from, and then overlaying the
- // packed PacketBuffer structure on top of the allocation. The one-byte
- // array at the end of the structure serves as an offset to the the data
- // portion of the allocation; packet buffers are never allocated on the
- // stack or using the new operator. Instead, the static allocate-byte-array
- // and destroy methods handle the allocate and overlay pattern. They also
- // allow for a potential future optimization where instead of just
- // allocating blocks from the process global heap and overlaying, the
- // allocator is replaced with a different implementation (private heap,
- // free-list, circular buffer, etc) which reduces potential heap
- // fragmentation issues which might arise from the frequent allocation and
- // destruction of the received UDP traffic.
- struct PacketBuffer {
- ssize_t length_;
- uint8_t data_[1];
-
- // TODO : consider changing this to be some form of ring buffer or free
- // pool system instead of just using the heap in order to avoid heap
- // fragmentation.
- static PacketBuffer* allocate(ssize_t length);
- static void destroy(PacketBuffer* pb);
-
- private:
- // Force people to use allocate/destroy instead of new/delete.
- PacketBuffer() { }
- ~PacketBuffer() { }
- };
-
- struct RetransRequest {
- uint32_t magic_;
- uint32_t mcast_ip_;
- uint16_t mcast_port_;
- uint16_t start_seq_;
- uint16_t end_seq_;
- };
-#pragma pack(pop)
-
- enum GapStatus {
- kGS_NoGap = 0,
- kGS_NormalGap,
- kGS_FastStartGap,
- };
-
- struct SeqNoGap {
- uint16_t start_seq_;
- uint16_t end_seq_;
- };
-
- class RXRingBuffer {
- public:
- explicit RXRingBuffer(uint32_t capacity);
- ~RXRingBuffer();
-
- bool initCheck() const { return (ring_ != NULL); }
- void reset();
-
- // Push a packet buffer with a given sequence number into the ring
- // buffer. pushBuffer will always consume the buffer pushed to it,
- // either destroying it because it was a duplicate or overflow, or
- // holding on to it in the ring. Callers should not hold any references
- // to PacketBuffers after they have been pushed to the ring. Returns
- // false in the case of a serious error (such as ring overflow).
- // Callers should consider resetting the pipeline entirely in the event
- // of a serious error.
- bool pushBuffer(PacketBuffer* buf, uint16_t seq);
-
- // Fetch the next buffer in the RTP sequence. Returns NULL if there is
- // no buffer to fetch. If a non-NULL PacketBuffer is returned,
- // is_discon will be set to indicate whether or not this PacketBuffer is
- // discontiuous with any previously returned packet buffers. Packet
- // buffers returned by fetchBuffer are the caller's responsibility; they
- // must be certain to destroy the buffers when they are done.
- PacketBuffer* fetchBuffer(bool* is_discon);
-
- // Returns true and fills out the gap structure if the read pointer of
- // the ring buffer is currently pointing to a gap which would stall a
- // fetchBuffer operation. Returns false if the read pointer is not
- // pointing to a gap in the sequence currently.
- GapStatus fetchCurrentGap(SeqNoGap* gap);
-
- // Causes the read pointer to skip over any portion of a gap indicated
- // by nak. If nak is NULL, any gap currently blocking the read pointer
- // will be completely skipped. If any portion of a gap is skipped, the
- // next successful read from fetch buffer will indicate a discontinuity.
- void processNAK(const SeqNoGap* nak = NULL);
-
- // Compute the number of milliseconds until the inactivity timer for
- // this RTP stream. Returns -1 if there is no active timeout, or 0 if
- // the system has already timed out.
- int computeInactivityTimeout();
-
- private:
- Mutex lock_;
- PacketBuffer** ring_;
- uint32_t capacity_;
- uint32_t rd_;
- uint32_t wr_;
-
- uint16_t rd_seq_;
- bool rd_seq_known_;
- bool waiting_for_fast_start_;
- bool fetched_first_packet_;
-
- uint64_t rtp_activity_timeout_;
- bool rtp_activity_timeout_valid_;
-
- DISALLOW_EVIL_CONSTRUCTORS(RXRingBuffer);
- };
-
- class Substream : public virtual RefBase {
- public:
- Substream(uint32_t ssrc, OMXClient& omx);
-
- void cleanupBufferInProgress();
- void shutdown();
- void processPayloadStart(uint8_t* buf,
- uint32_t amt,
- int32_t ts_lower);
- void processPayloadCont (uint8_t* buf,
- uint32_t amt);
- void processTSTransform(const LinearTransform& trans);
-
- bool isAboutToUnderflow();
- uint32_t getSSRC() const { return ssrc_; }
- uint16_t getProgramID() const { return (ssrc_ >> 5) & 0x1F; }
- status_t getStatus() const { return status_; }
-
- protected:
- virtual ~Substream();
-
- private:
- void cleanupDecoder();
- bool shouldAbort(const char* log_tag);
- void processCompletedBuffer();
- bool setupSubstreamMeta();
- bool setupMP3SubstreamMeta();
- bool setupAACSubstreamMeta();
- bool setupSubstreamType(uint8_t substream_type,
- uint8_t codec_type);
-
- uint32_t ssrc_;
- bool waiting_for_rap_;
- status_t status_;
-
- bool substream_details_known_;
- uint8_t substream_type_;
- uint8_t codec_type_;
- const char* codec_mime_type_;
- sp<MetaData> substream_meta_;
-
- MediaBuffer* buffer_in_progress_;
- uint32_t expected_buffer_size_;
- uint32_t buffer_filled_;
-
- Vector<uint8_t> aux_data_in_progress_;
- uint32_t aux_data_expected_size_;
-
- sp<AAH_DecoderPump> decoder_;
-
- static int64_t kAboutToUnderflowThreshold;
-
- DISALLOW_EVIL_CONSTRUCTORS(Substream);
- };
-
- typedef DefaultKeyedVector< uint32_t, sp<Substream> > SubstreamVec;
-
- status_t startWorkThread();
- void stopWorkThread();
- virtual bool threadLoop();
- bool setupSocket();
- void cleanupSocket();
- void resetPipeline();
- void reset_l();
- bool processRX(PacketBuffer* pb);
- void processRingBuffer();
- void processCommandPacket(PacketBuffer* pb);
- bool processGaps();
- int computeNextGapRetransmitTimeout();
- void fetchAudioFlinger();
-
- PipeEvent wakeup_work_thread_evt_;
- sp<ThreadWrapper> thread_wrapper_;
- Mutex api_lock_;
- bool is_playing_;
- bool data_source_set_;
-
- struct sockaddr_in listen_addr_;
- int sock_fd_;
- bool multicast_joined_;
-
- struct sockaddr_in transmitter_addr_;
- bool transmitter_known_;
-
- uint32_t current_epoch_;
- bool current_epoch_known_;
-
- SeqNoGap current_gap_;
- GapStatus current_gap_status_;
- uint64_t next_retrans_req_time_;
-
- 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_;
-
- static const uint32_t kRTPRingBufferSize;
- static const uint32_t kRetransRequestMagic;
- static const uint32_t kFastStartRequestMagic;
- static const uint32_t kRetransNAKMagic;
- static const uint32_t kGapRerequestTimeoutUSec;
- static const uint32_t kFastStartTimeoutUSec;
- static const uint32_t kRTPActivityTimeoutUSec;
-
- static const uint32_t INVOKE_GET_MASTER_VOLUME = 3;
- static const uint32_t INVOKE_SET_MASTER_VOLUME = 4;
-
- static uint64_t monotonicUSecNow();
-
- DISALLOW_EVIL_CONSTRUCTORS(AAH_RXPlayer);
-};
-
-} // namespace android
-
-#endif // __AAH_RX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_rx_player_core.cpp b/media/libaah_rtp/aah_rx_player_core.cpp
deleted file mode 100644
index d6b31fd..0000000
--- a/media/libaah_rtp/aah_rx_player_core.cpp
+++ /dev/null
@@ -1,809 +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"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <fcntl.h>
-#include <poll.h>
-#include <sys/socket.h>
-#include <time.h>
-#include <utils/misc.h>
-
-#include <media/stagefright/Utils.h>
-
-#include "aah_rx_player.h"
-#include "aah_tx_packet.h"
-
-namespace android {
-
-const uint32_t AAH_RXPlayer::kRetransRequestMagic =
- FOURCC('T','r','e','q');
-const uint32_t AAH_RXPlayer::kRetransNAKMagic =
- FOURCC('T','n','a','k');
-const uint32_t AAH_RXPlayer::kFastStartRequestMagic =
- FOURCC('T','f','s','t');
-const uint32_t AAH_RXPlayer::kGapRerequestTimeoutUSec = 75000;
-const uint32_t AAH_RXPlayer::kFastStartTimeoutUSec = 800000;
-const uint32_t AAH_RXPlayer::kRTPActivityTimeoutUSec = 10000000;
-
-static inline int16_t fetchInt16(uint8_t* data) {
- return static_cast<int16_t>(U16_AT(data));
-}
-
-static inline int32_t fetchInt32(uint8_t* data) {
- return static_cast<int32_t>(U32_AT(data));
-}
-
-static inline int64_t fetchInt64(uint8_t* data) {
- return static_cast<int64_t>(U64_AT(data));
-}
-
-uint64_t AAH_RXPlayer::monotonicUSecNow() {
- struct timespec now;
- int res = clock_gettime(CLOCK_MONOTONIC, &now);
- CHECK(res >= 0);
-
- uint64_t ret = static_cast<uint64_t>(now.tv_sec) * 1000000;
- ret += now.tv_nsec / 1000;
-
- return ret;
-}
-
-status_t AAH_RXPlayer::startWorkThread() {
- status_t res;
- stopWorkThread();
- res = thread_wrapper_->run("TRX_Player", PRIORITY_AUDIO);
-
- if (res != OK) {
- ALOGE("Failed to start work thread (res = %d)", res);
- }
-
- return res;
-}
-
-void AAH_RXPlayer::stopWorkThread() {
- thread_wrapper_->requestExit(); // set the exit pending flag
- wakeup_work_thread_evt_.setEvent();
-
- status_t res;
- res = thread_wrapper_->requestExitAndWait(); // block until thread exit.
- if (res != OK) {
- ALOGE("Failed to stop work thread (res = %d)", res);
- }
-
- wakeup_work_thread_evt_.clearPendingEvents();
-}
-
-void AAH_RXPlayer::cleanupSocket() {
- if (sock_fd_ >= 0) {
- if (multicast_joined_) {
- int res;
- struct ip_mreq mreq;
- mreq.imr_multiaddr = listen_addr_.sin_addr;
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- res = setsockopt(sock_fd_,
- IPPROTO_IP,
- IP_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq));
- if (res < 0) {
- ALOGW("Failed to leave multicast group. (%d, %d)", res, errno);
- }
- multicast_joined_ = false;
- }
-
- close(sock_fd_);
- sock_fd_ = -1;
- }
-
- resetPipeline();
-}
-
-void AAH_RXPlayer::resetPipeline() {
- ring_buffer_.reset();
-
- // Explicitly shudown all of the active substreams, then call clear out the
- // collection. Failure to clear out a substream can result in its decoder
- // holding a reference to itself and therefor not going away when the
- // collection is cleared.
- for (size_t i = 0; i < substreams_.size(); ++i)
- substreams_.valueAt(i)->shutdown();
-
- substreams_.clear();
-
- current_gap_status_ = kGS_NoGap;
-}
-
-bool AAH_RXPlayer::setupSocket() {
- long flags;
- int res, buf_size;
- socklen_t opt_size;
-
- cleanupSocket();
- CHECK(sock_fd_ < 0);
-
- // Make the socket
- sock_fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (sock_fd_ < 0) {
- ALOGE("Failed to create listen socket (errno %d)", errno);
- goto bailout;
- }
-
- // Set non-blocking operation
- flags = fcntl(sock_fd_, F_GETFL);
- res = fcntl(sock_fd_, F_SETFL, flags | O_NONBLOCK);
- if (res < 0) {
- ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)",
- sock_fd_, errno);
- goto bailout;
- }
-
- // Bind to our port
- struct sockaddr_in bind_addr;
- memset(&bind_addr, 0, sizeof(bind_addr));
- bind_addr.sin_family = AF_INET;
- bind_addr.sin_addr.s_addr = INADDR_ANY;
- bind_addr.sin_port = listen_addr_.sin_port;
- res = bind(sock_fd_,
- reinterpret_cast<const sockaddr*>(&bind_addr),
- sizeof(bind_addr));
- if (res < 0) {
- uint32_t a = ntohl(bind_addr.sin_addr.s_addr);
- uint16_t p = ntohs(bind_addr.sin_port);
- ALOGE("Failed to bind socket (%d) to %d.%d.%d.%d:%hd. (errno %d)",
- sock_fd_,
- (a >> 24) & 0xFF,
- (a >> 16) & 0xFF,
- (a >> 8) & 0xFF,
- (a ) & 0xFF,
- p,
- errno);
-
- goto bailout;
- }
-
- buf_size = 1 << 16; // 64k
- res = setsockopt(sock_fd_,
- SOL_SOCKET, SO_RCVBUF,
- &buf_size, sizeof(buf_size));
- if (res < 0) {
- ALOGW("Failed to increase socket buffer size to %d. (errno %d)",
- buf_size, errno);
- }
-
- buf_size = 0;
- opt_size = sizeof(buf_size);
- res = getsockopt(sock_fd_,
- SOL_SOCKET, SO_RCVBUF,
- &buf_size, &opt_size);
- if (res < 0) {
- ALOGW("Failed to fetch socket buffer size. (errno %d)", errno);
- } else {
- ALOGI("RX socket buffer size is now %d bytes", buf_size);
- }
-
- if (listen_addr_.sin_addr.s_addr) {
- // Join the multicast group and we should be good to go.
- struct ip_mreq mreq;
- mreq.imr_multiaddr = listen_addr_.sin_addr;
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- res = setsockopt(sock_fd_,
- IPPROTO_IP,
- IP_ADD_MEMBERSHIP,
- &mreq, sizeof(mreq));
- if (res < 0) {
- ALOGE("Failed to join multicast group. (errno %d)", errno);
- goto bailout;
- }
- multicast_joined_ = true;
- }
-
- return true;
-
-bailout:
- cleanupSocket();
- return false;
-}
-
-bool AAH_RXPlayer::threadLoop() {
- struct pollfd poll_fds[2];
- bool process_more_right_now = false;
-
- if (!setupSocket()) {
- sendEvent(MEDIA_ERROR);
- goto bailout;
- }
-
- while (!thread_wrapper_->exitPending()) {
- // Step 1: Wait until there is something to do.
- int gap_timeout = computeNextGapRetransmitTimeout();
- int ring_timeout = ring_buffer_.computeInactivityTimeout();
- int timeout = -1;
-
- if (!ring_timeout) {
- ALOGW("RTP inactivity timeout reached, resetting pipeline.");
- resetPipeline();
- timeout = gap_timeout;
- } else {
- if (gap_timeout < 0) {
- timeout = ring_timeout;
- } else if (ring_timeout < 0) {
- timeout = gap_timeout;
- } else {
- timeout = (gap_timeout < ring_timeout) ? gap_timeout
- : ring_timeout;
- }
- }
-
- if ((0 != timeout) && (!process_more_right_now)) {
- // Set up the events to wait on. Start with the wakeup pipe.
- memset(&poll_fds, 0, sizeof(poll_fds));
- poll_fds[0].fd = wakeup_work_thread_evt_.getWakeupHandle();
- poll_fds[0].events = POLLIN;
-
- // Add the RX socket.
- poll_fds[1].fd = sock_fd_;
- poll_fds[1].events = POLLIN;
-
- // Wait for something interesing to happen.
- int poll_res = poll(poll_fds, NELEM(poll_fds), timeout);
- if (poll_res < 0) {
- ALOGE("Fatal error (%d,%d) while waiting on events",
- poll_res, errno);
- sendEvent(MEDIA_ERROR);
- goto bailout;
- }
- }
-
- if (thread_wrapper_->exitPending()) {
- break;
- }
-
- wakeup_work_thread_evt_.clearPendingEvents();
- process_more_right_now = false;
-
- // Step 2: Do we have data waiting in the socket? If so, drain the
- // socket moving valid RTP information into the ring buffer to be
- // processed.
- if (poll_fds[1].revents) {
- struct sockaddr_in from;
- socklen_t from_len;
-
- ssize_t res = 0;
- while (!thread_wrapper_->exitPending()) {
- // Check the size of any pending packet.
- res = recv(sock_fd_, NULL, 0, MSG_PEEK | MSG_TRUNC);
-
- // Error?
- if (res < 0) {
- // If the error is anything other than would block,
- // something has gone very wrong.
- if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) {
- ALOGE("Fatal socket error during recvfrom (%d, %d)",
- (int)res, errno);
- goto bailout;
- }
-
- // Socket is out of data, just break out of processing and
- // wait for more.
- break;
- }
-
- // Allocate a payload.
- PacketBuffer* pb = PacketBuffer::allocate(res);
- if (NULL == pb) {
- ALOGE("Fatal error, failed to allocate packet buffer of"
- " length %u", static_cast<uint32_t>(res));
- goto bailout;
- }
-
- // Fetch the data.
- from_len = sizeof(from);
- res = recvfrom(sock_fd_, pb->data_, pb->length_, 0,
- reinterpret_cast<struct sockaddr*>(&from),
- &from_len);
- if (res != pb->length_) {
- ALOGE("Fatal error, fetched packet length (%d) does not"
- " match peeked packet length (%u). This should never"
- " happen. (errno = %d)",
- static_cast<int>(res),
- static_cast<uint32_t>(pb->length_),
- errno);
- }
-
- bool drop_packet = false;
- if (transmitter_known_) {
- if (from.sin_addr.s_addr !=
- transmitter_addr_.sin_addr.s_addr) {
- uint32_t a = ntohl(from.sin_addr.s_addr);
- uint16_t p = ntohs(from.sin_port);
- ALOGV("Dropping packet from unknown transmitter"
- " %u.%u.%u.%u:%hu",
- ((a >> 24) & 0xFF),
- ((a >> 16) & 0xFF),
- ((a >> 8) & 0xFF),
- ( a & 0xFF),
- p);
-
- drop_packet = true;
- } else {
- transmitter_addr_.sin_port = from.sin_port;
- }
- } else {
- memcpy(&transmitter_addr_, &from, sizeof(from));
- transmitter_known_ = true;
- }
-
- if (!drop_packet) {
- bool serious_error = !processRX(pb);
-
- if (serious_error) {
- // Something went "seriously wrong". Currently, the
- // only trigger for this should be a ring buffer
- // overflow. The current failsafe behavior for when
- // something goes seriously wrong is to just reset the
- // pipeline. The system should behave as if this
- // AAH_RXPlayer was just set up for the first time.
- ALOGE("Something just went seriously wrong with the"
- " pipeline. Resetting.");
- resetPipeline();
- }
- } else {
- PacketBuffer::destroy(pb);
- }
- }
- }
-
- // Step 3: Process any data we mave have accumulated in the ring buffer
- // so far.
- if (!thread_wrapper_->exitPending()) {
- processRingBuffer();
- }
-
- // Step 4: At this point in time, the ring buffer should either be
- // empty, or stalled in front of a gap caused by some dropped packets.
- // Check on the current gap situation and deal with it in an appropriate
- // fashion. If processGaps returns true, it means that it has given up
- // on a gap and that we should try to process some more data
- // immediately.
- if (!thread_wrapper_->exitPending()) {
- process_more_right_now = processGaps();
- }
-
- // Step 5: Check for fatal errors. If any of our substreams has
- // encountered a fatal, unrecoverable, error, then propagate the error
- // up to user level and shut down.
- for (size_t i = 0; i < substreams_.size(); ++i) {
- status_t status;
- CHECK(substreams_.valueAt(i) != NULL);
-
- status = substreams_.valueAt(i)->getStatus();
- if (OK != status) {
- ALOGE("Substream index %d has encountered an unrecoverable"
- " error (%d). Signalling application level and shutting"
- " down.", i, status);
- sendEvent(MEDIA_ERROR);
- goto bailout;
- }
- }
- }
-
-bailout:
- cleanupSocket();
- return false;
-}
-
-bool AAH_RXPlayer::processRX(PacketBuffer* pb) {
- CHECK(NULL != pb);
-
- uint8_t* data = pb->data_;
- ssize_t amt = pb->length_;
- uint32_t nak_magic;
- uint16_t seq_no;
- uint32_t epoch;
-
- // Every packet either starts with an RTP header which is at least 12 bytes
- // long or is a retry NAK which is 14 bytes long. If there are fewer than
- // 12 bytes here, this cannot be a proper RTP packet.
- if (amt < 12) {
- ALOGV("Dropping packet, too short to contain RTP header (%u bytes)",
- static_cast<uint32_t>(amt));
- goto drop_packet;
- }
-
- // Check to see if this is the special case of a NAK packet.
- nak_magic = ntohl(*(reinterpret_cast<uint32_t*>(data)));
- if (nak_magic == kRetransNAKMagic) {
- // Looks like a NAK packet; make sure its long enough.
-
- if (amt < static_cast<ssize_t>(sizeof(RetransRequest))) {
- ALOGV("Dropping packet, too short to contain NAK payload"
- " (%u bytes)", static_cast<uint32_t>(amt));
- goto drop_packet;
- }
-
- SeqNoGap gap;
- RetransRequest* rtr = reinterpret_cast<RetransRequest*>(data);
- gap.start_seq_ = ntohs(rtr->start_seq_);
- gap.end_seq_ = ntohs(rtr->end_seq_);
-
- ALOGV("Process NAK for gap at [%hu, %hu]",
- gap.start_seq_, gap.end_seq_);
- ring_buffer_.processNAK(&gap);
-
- return true;
- }
-
- // According to the TRTP spec, version should be 2, padding should be 0,
- // extension should be 0 and CSRCCnt should be 0. If any of these tests
- // fail, we chuck the packet.
- if (data[0] != 0x80) {
- ALOGV("Dropping packet, bad V/P/X/CSRCCnt field (0x%02x)",
- data[0]);
- goto drop_packet;
- }
-
- // Check the payload type. For TRTP, it should always be 100.
- if ((data[1] & 0x7F) != 100) {
- ALOGV("Dropping packet, bad payload type. (%u)",
- data[1] & 0x7F);
- goto drop_packet;
- }
-
- // Check whether the transmitter has begun a new epoch.
- epoch = (U32_AT(data + 8) >> 10) & 0x3FFFFF;
- if (current_epoch_known_) {
- if (epoch != current_epoch_) {
- ALOGV("%s: new epoch %u", __PRETTY_FUNCTION__, epoch);
- current_epoch_ = epoch;
- resetPipeline();
- }
- } else {
- current_epoch_ = epoch;
- current_epoch_known_ = true;
- }
-
- // Extract the sequence number and hand the packet off to the ring buffer
- // for dropped packet detection and later processing.
- seq_no = U16_AT(data + 2);
- return ring_buffer_.pushBuffer(pb, seq_no);
-
-drop_packet:
- PacketBuffer::destroy(pb);
- return true;
-}
-
-void AAH_RXPlayer::processRingBuffer() {
- PacketBuffer* pb;
- bool is_discon;
- sp<Substream> substream;
- LinearTransform trans;
- bool foundTrans = false;
-
- while (NULL != (pb = ring_buffer_.fetchBuffer(&is_discon))) {
- if (is_discon) {
- // Abort all partially assembled payloads.
- for (size_t i = 0; i < substreams_.size(); ++i) {
- CHECK(substreams_.valueAt(i) != NULL);
- substreams_.valueAt(i)->cleanupBufferInProgress();
- }
- }
-
- uint8_t* data = pb->data_;
- ssize_t amt = pb->length_;
-
- // Should not have any non-RTP packets in the ring buffer. RTP packets
- // must be at least 12 bytes long.
- CHECK(amt >= 12);
-
- // Extract the marker bit and the SSRC field.
- bool marker = (data[1] & 0x80) != 0;
- uint32_t ssrc = U32_AT(data + 8);
-
- // Is this the start of a new TRTP payload? If so, the marker bit
- // should be set and there are some things we should be checking for.
- if (marker) {
- // TRTP headers need to have at least a byte for version, a byte for
- // payload type and flags, and 4 bytes for length.
- if (amt < 18) {
- ALOGV("Dropping packet, too short to contain TRTP header"
- " (%u bytes)", static_cast<uint32_t>(amt));
- goto process_next_packet;
- }
-
- // Check the TRTP version and extract the payload type/flags.
- uint8_t trtp_version = data[12];
- uint8_t payload_type = (data[13] >> 4) & 0xF;
- uint8_t trtp_flags = data[13] & 0xF;
-
- if (1 != trtp_version) {
- ALOGV("Dropping packet, bad trtp version %hhu", trtp_version);
- goto process_next_packet;
- }
-
- // Is there a timestamp transformation present on this packet? If
- // so, extract it and pass it to the appropriate substreams.
- if (trtp_flags & 0x02) {
- ssize_t offset = 18 + ((trtp_flags & 0x01) ? 4 : 0);
- if (amt < (offset + 24)) {
- ALOGV("Dropping packet, too short to contain TRTP Timestamp"
- " Transformation (%u bytes)",
- static_cast<uint32_t>(amt));
- goto process_next_packet;
- }
-
- trans.a_zero = fetchInt64(data + offset);
- trans.b_zero = fetchInt64(data + offset + 16);
- trans.a_to_b_numer = static_cast<int32_t>(
- fetchInt32 (data + offset + 8));
- trans.a_to_b_denom = U32_AT(data + offset + 12);
- foundTrans = true;
-
- uint32_t program_id = (ssrc >> 5) & 0x1F;
- for (size_t i = 0; i < substreams_.size(); ++i) {
- sp<Substream> iter = substreams_.valueAt(i);
- CHECK(iter != NULL);
-
- if (iter->getProgramID() == program_id) {
- iter->processTSTransform(trans);
- }
- }
- }
-
- // Is this a command packet? If so, its not necessarily associate
- // with one particular substream. Just give it to the command
- // packet handler and then move on.
- if (4 == payload_type) {
- processCommandPacket(pb);
- goto process_next_packet;
- }
- }
-
- // If we got to here, then we are a normal packet. Find (or allocate)
- // the substream we belong to and send the packet off to be processed.
- substream = substreams_.valueFor(ssrc);
- if (substream == NULL) {
- substream = new Substream(ssrc, omx_);
- if (substream == NULL) {
- ALOGE("Failed to allocate substream for SSRC 0x%08x", ssrc);
- goto process_next_packet;
- }
- substreams_.add(ssrc, substream);
-
- if (foundTrans) {
- substream->processTSTransform(trans);
- }
- }
-
- CHECK(substream != NULL);
-
- if (marker) {
- // Start of a new TRTP payload for this substream. Extract the
- // lower 32 bits of the timestamp and hand the buffer to the
- // substream for processing.
- uint32_t ts_lower = U32_AT(data + 4);
- substream->processPayloadStart(data + 12, amt - 12, ts_lower);
- } else {
- // Continuation of an existing TRTP payload. Just hand it off to
- // the substream for processing.
- substream->processPayloadCont(data + 12, amt - 12);
- }
-
-process_next_packet:
- PacketBuffer::destroy(pb);
- } // end of main processing while loop.
-}
-
-void AAH_RXPlayer::processCommandPacket(PacketBuffer* pb) {
- CHECK(NULL != pb);
-
- uint8_t* data = pb->data_;
- ssize_t amt = pb->length_;
-
- // verify that this packet meets the minimum length of a command packet
- if (amt < 20) {
- return;
- }
-
- uint8_t trtp_version = data[12];
- uint8_t trtp_flags = data[13] & 0xF;
-
- if (1 != trtp_version) {
- ALOGV("Dropping packet, bad trtp version %hhu", trtp_version);
- return;
- }
-
- // calculate the start of the command payload
- ssize_t offset = 18;
- if (trtp_flags & 0x01) {
- // timestamp is present (4 bytes)
- offset += 4;
- }
- if (trtp_flags & 0x02) {
- // transform is present (24 bytes)
- offset += 24;
- }
-
- // the packet must contain 2 bytes of command payload beyond the TRTP header
- if (amt < offset + 2) {
- return;
- }
-
- uint16_t command_id = U16_AT(data + offset);
-
- switch (command_id) {
- case TRTPControlPacket::kCommandNop:
- break;
-
- case TRTPControlPacket::kCommandEOS:
- case TRTPControlPacket::kCommandFlush: {
- uint16_t program_id = (U32_AT(data + 8) >> 5) & 0x1F;
- ALOGI("*** %s flushing program_id=%d",
- __PRETTY_FUNCTION__, program_id);
-
- Vector<uint32_t> substreams_to_remove;
- for (size_t i = 0; i < substreams_.size(); ++i) {
- sp<Substream> iter = substreams_.valueAt(i);
- if (iter->getProgramID() == program_id) {
- iter->shutdown();
- substreams_to_remove.add(iter->getSSRC());
- }
- }
-
- for (size_t i = 0; i < substreams_to_remove.size(); ++i) {
- substreams_.removeItem(substreams_to_remove[i]);
- }
- } break;
- }
-}
-
-bool AAH_RXPlayer::processGaps() {
- // Deal with the current gap situation. Specifically...
- //
- // 1) If a new gap has shown up, send a retransmit request to the
- // transmitter.
- // 2) If a gap we were working on has had a packet in the middle or at
- // the end filled in, send another retransmit request for the begining
- // portion of the gap. TRTP was designed for LANs where packet
- // re-ordering is very unlikely; so see the middle or end of a gap
- // filled in before the begining is an almost certain indication that
- // a retransmission packet was also dropped.
- // 3) If we have been working on a gap for a while and it still has not
- // been filled in, send another retransmit request.
- // 4) If the are no more gaps in the ring, clear the current_gap_status_
- // flag to indicate that all is well again.
-
- // Start by fetching the active gap status.
- SeqNoGap gap;
- bool send_retransmit_request = false;
- bool ret_val = false;
- GapStatus gap_status;
- if (kGS_NoGap != (gap_status = ring_buffer_.fetchCurrentGap(&gap))) {
- // Note: checking for a change in the end sequence number should cover
- // moving on to an entirely new gap for case #1 as well as resending the
- // begining of a gap range for case #2.
- send_retransmit_request = (kGS_NoGap == current_gap_status_) ||
- (current_gap_.end_seq_ != gap.end_seq_);
-
- // If this is the same gap we have been working on, and it has timed
- // out, then check to see if our substreams are about to underflow. If
- // so, instead of sending another retransmit request, just give up on
- // this gap and move on.
- if (!send_retransmit_request &&
- (kGS_NoGap != current_gap_status_) &&
- (0 == computeNextGapRetransmitTimeout())) {
-
- // If out current gap is the fast-start gap, don't bother to skip it
- // because substreams look like the are about to underflow.
- if ((kGS_FastStartGap != gap_status) ||
- (current_gap_.end_seq_ != gap.end_seq_)) {
- for (size_t i = 0; i < substreams_.size(); ++i) {
- if (substreams_.valueAt(i)->isAboutToUnderflow()) {
- ALOGV("About to underflow, giving up on gap [%hu, %hu]",
- gap.start_seq_, gap.end_seq_);
- ring_buffer_.processNAK();
- current_gap_status_ = kGS_NoGap;
- return true;
- }
- }
- }
-
- // Looks like no one is about to underflow. Just go ahead and send
- // the request.
- send_retransmit_request = true;
- }
- } else {
- current_gap_status_ = kGS_NoGap;
- }
-
- if (send_retransmit_request) {
- // If we have been working on a fast start, and it is still not filled
- // in, even after the extended retransmit time out, give up and skip it.
- // The system should fall back into its normal slow-start behavior.
- if ((kGS_FastStartGap == current_gap_status_) &&
- (current_gap_.end_seq_ == gap.end_seq_)) {
- ALOGV("Fast start is taking forever; giving up.");
- ring_buffer_.processNAK();
- current_gap_status_ = kGS_NoGap;
- return true;
- }
-
- // Send the request.
- RetransRequest req;
- uint32_t magic = (kGS_FastStartGap == gap_status)
- ? kFastStartRequestMagic
- : kRetransRequestMagic;
- req.magic_ = htonl(magic);
- req.mcast_ip_ = listen_addr_.sin_addr.s_addr;
- req.mcast_port_ = listen_addr_.sin_port;
- req.start_seq_ = htons(gap.start_seq_);
- req.end_seq_ = htons(gap.end_seq_);
-
- {
- uint32_t a = ntohl(transmitter_addr_.sin_addr.s_addr);
- uint16_t p = ntohs(transmitter_addr_.sin_port);
- ALOGV("Sending to transmitter %u.%u.%u.%u:%hu",
- ((a >> 24) & 0xFF),
- ((a >> 16) & 0xFF),
- ((a >> 8) & 0xFF),
- ( a & 0xFF),
- p);
- }
-
- int res = sendto(sock_fd_, &req, sizeof(req), 0,
- reinterpret_cast<struct sockaddr*>(&transmitter_addr_),
- sizeof(transmitter_addr_));
- if (res < 0) {
- ALOGE("Error when sending retransmit request (%d)", errno);
- } else {
- ALOGV("%s request for range [%hu, %hu] sent",
- (kGS_FastStartGap == gap_status) ? "Fast Start"
- : "Retransmit",
- gap.start_seq_, gap.end_seq_);
- }
-
- // Update the current gap info.
- current_gap_ = gap;
- current_gap_status_ = gap_status;
- next_retrans_req_time_ = monotonicUSecNow() +
- ((kGS_FastStartGap == current_gap_status_)
- ? kFastStartTimeoutUSec
- : kGapRerequestTimeoutUSec);
- }
-
- return false;
-}
-
-// Compute when its time to send the next gap retransmission in milliseconds.
-// Returns < 0 for an infinite timeout (no gap) and 0 if its time to retransmit
-// right now.
-int AAH_RXPlayer::computeNextGapRetransmitTimeout() {
- if (kGS_NoGap == current_gap_status_) {
- return -1;
- }
-
- int64_t timeout_delta = next_retrans_req_time_ - monotonicUSecNow();
-
- timeout_delta /= 1000;
- if (timeout_delta <= 0) {
- return 0;
- }
-
- return static_cast<uint32_t>(timeout_delta);
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
deleted file mode 100644
index 779405e..0000000
--- a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
+++ /dev/null
@@ -1,366 +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"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "aah_rx_player.h"
-
-namespace android {
-
-AAH_RXPlayer::RXRingBuffer::RXRingBuffer(uint32_t capacity) {
- capacity_ = capacity;
- rd_ = wr_ = 0;
- ring_ = new PacketBuffer*[capacity];
- memset(ring_, 0, sizeof(PacketBuffer*) * capacity);
- reset();
-}
-
-AAH_RXPlayer::RXRingBuffer::~RXRingBuffer() {
- reset();
- delete[] ring_;
-}
-
-void AAH_RXPlayer::RXRingBuffer::reset() {
- AutoMutex lock(&lock_);
-
- if (NULL != ring_) {
- while (rd_ != wr_) {
- CHECK(rd_ < capacity_);
- if (NULL != ring_[rd_]) {
- PacketBuffer::destroy(ring_[rd_]);
- ring_[rd_] = NULL;
- }
- rd_ = (rd_ + 1) % capacity_;
- }
- }
-
- rd_ = wr_ = 0;
- rd_seq_known_ = false;
- waiting_for_fast_start_ = true;
- fetched_first_packet_ = false;
- rtp_activity_timeout_valid_ = false;
-}
-
-bool AAH_RXPlayer::RXRingBuffer::pushBuffer(PacketBuffer* buf,
- uint16_t seq) {
- AutoMutex lock(&lock_);
- CHECK(NULL != ring_);
- CHECK(NULL != buf);
-
- rtp_activity_timeout_valid_ = true;
- rtp_activity_timeout_ = monotonicUSecNow() + kRTPActivityTimeoutUSec;
-
- // If the ring buffer is totally reset (we have never received a single
- // payload) then we don't know the rd sequence number and this should be
- // simple. We just store the payload, advance the wr pointer and record the
- // initial sequence number.
- if (!rd_seq_known_) {
- CHECK(rd_ == wr_);
- CHECK(NULL == ring_[wr_]);
- CHECK(wr_ < capacity_);
-
- ring_[wr_] = buf;
- wr_ = (wr_ + 1) % capacity_;
- rd_seq_ = seq;
- rd_seq_known_ = true;
- return true;
- }
-
- // Compute the seqence number of this payload and of the write pointer,
- // normalized around the read pointer. IOW - transform the payload seq no
- // and the wr pointer seq no into a space where the rd pointer seq no is
- // zero. This will define 4 cases we can consider...
- //
- // 1) norm_seq == norm_wr_seq
- // This payload is contiguous with the last. All is good.
- //
- // 2) ((norm_seq < norm_wr_seq) && (norm_seq >= norm_rd_seq)
- // aka ((norm_seq < norm_wr_seq) && (norm_seq >= 0)
- // This payload is in the past, in the unprocessed region of the ring
- // buffer. It is probably a retransmit intended to fill in a dropped
- // payload; it may be a duplicate.
- //
- // 3) ((norm_seq - norm_wr_seq) & 0x8000) != 0
- // This payload is in the past compared to the write pointer (or so very
- // far in the future that it has wrapped the seq no space), but not in
- // the unprocessed region of the ring buffer. This could be a duplicate
- // retransmit; we just drop these payloads unless we are waiting for our
- // first fast start packet. If we are waiting for fast start, than this
- // packet is probably the first packet of the fast start retransmission.
- // If it will fit in the buffer, back up the read pointer to its position
- // and clear the fast start flag, otherwise just drop it.
- //
- // 4) ((norm_seq - norm_wr_seq) & 0x8000) == 0
- // This payload which is ahead of the next write pointer. This indicates
- // that we have missed some payloads and need to request a retransmit.
- // If norm_seq >= (capacity - 1), then the gap is so large that it would
- // overflow the ring buffer and we should probably start to panic.
-
- uint16_t norm_wr_seq = ((wr_ + capacity_ - rd_) % capacity_);
- uint16_t norm_seq = seq - rd_seq_;
-
- // Check for overflow first.
- if ((!(norm_seq & 0x8000)) && (norm_seq >= (capacity_ - 1))) {
- ALOGW("Ring buffer overflow; cap = %u, [rd, wr] = [%hu, %hu],"
- " seq = %hu", capacity_, rd_seq_, norm_wr_seq + rd_seq_, seq);
- PacketBuffer::destroy(buf);
- return false;
- }
-
- // Check for case #1
- if (norm_seq == norm_wr_seq) {
- CHECK(wr_ < capacity_);
- CHECK(NULL == ring_[wr_]);
-
- ring_[wr_] = buf;
- wr_ = (wr_ + 1) % capacity_;
-
- CHECK(wr_ != rd_);
- return true;
- }
-
- // Check case #2
- uint32_t ring_pos = (rd_ + norm_seq) % capacity_;
- if ((norm_seq < norm_wr_seq) && (!(norm_seq & 0x8000))) {
- // Do we already have a payload for this slot? If so, then this looks
- // like a duplicate retransmit. Just ignore it.
- if (NULL != ring_[ring_pos]) {
- ALOGD("RXed duplicate retransmit, seq = %hu", seq);
- PacketBuffer::destroy(buf);
- } else {
- // Looks like we were missing this payload. Go ahead and store it.
- ring_[ring_pos] = buf;
- }
-
- return true;
- }
-
- // Check case #3
- if ((norm_seq - norm_wr_seq) & 0x8000) {
- if (!waiting_for_fast_start_) {
- ALOGD("RXed duplicate retransmit from before rd pointer, seq = %hu",
- seq);
- PacketBuffer::destroy(buf);
- } else {
- // Looks like a fast start fill-in. Go ahead and store it, assuming
- // that we can fit it in the buffer.
- uint32_t implied_ring_size = static_cast<uint32_t>(norm_wr_seq)
- + (rd_seq_ - seq);
-
- if (implied_ring_size >= (capacity_ - 1)) {
- ALOGD("RXed what looks like a fast start packet (seq = %hu),"
- " but packet is too far in the past to fit into the ring"
- " buffer. Dropping.", seq);
- PacketBuffer::destroy(buf);
- } else {
- ring_pos = (rd_ + capacity_ + seq - rd_seq_) % capacity_;
- rd_seq_ = seq;
- rd_ = ring_pos;
- waiting_for_fast_start_ = false;
-
- CHECK(ring_pos < capacity_);
- CHECK(NULL == ring_[ring_pos]);
- ring_[ring_pos] = buf;
- }
-
- }
- return true;
- }
-
- // Must be in case #4 with no overflow. This packet fits in the current
- // ring buffer, but is discontiuguous. Advance the write pointer leaving a
- // gap behind.
- uint32_t gap_len = (ring_pos + capacity_ - wr_) % capacity_;
- ALOGD("Drop detected; %u packets, seq_range [%hu, %hu]",
- gap_len,
- rd_seq_ + norm_wr_seq,
- rd_seq_ + norm_wr_seq + gap_len - 1);
-
- CHECK(NULL == ring_[ring_pos]);
- ring_[ring_pos] = buf;
- wr_ = (ring_pos + 1) % capacity_;
- CHECK(wr_ != rd_);
-
- return true;
-}
-
-AAH_RXPlayer::PacketBuffer*
-AAH_RXPlayer::RXRingBuffer::fetchBuffer(bool* is_discon) {
- AutoMutex lock(&lock_);
- CHECK(NULL != ring_);
- CHECK(NULL != is_discon);
-
- // If the read seqence number is not known, then this ring buffer has not
- // received a packet since being reset and there cannot be any packets to
- // return. If we are still waiting for the first fast start packet to show
- // up, we don't want to let any buffer be consumed yet because we expect to
- // see a packet before the initial read sequence number show up shortly.
- if (!rd_seq_known_ || waiting_for_fast_start_) {
- *is_discon = false;
- return NULL;
- }
-
- PacketBuffer* ret = NULL;
- *is_discon = !fetched_first_packet_;
-
- while ((rd_ != wr_) && (NULL == ret)) {
- CHECK(rd_ < capacity_);
-
- // If we hit a gap, stall and do not advance the read pointer. Let the
- // higher level code deal with requesting retries and/or deciding to
- // skip the current gap.
- ret = ring_[rd_];
- if (NULL == ret) {
- break;
- }
-
- ring_[rd_] = NULL;
- rd_ = (rd_ + 1) % capacity_;
- ++rd_seq_;
- }
-
- if (NULL != ret) {
- fetched_first_packet_ = true;
- }
-
- return ret;
-}
-
-AAH_RXPlayer::GapStatus
-AAH_RXPlayer::RXRingBuffer::fetchCurrentGap(SeqNoGap* gap) {
- AutoMutex lock(&lock_);
- CHECK(NULL != ring_);
- CHECK(NULL != gap);
-
- // If the read seqence number is not known, then this ring buffer has not
- // received a packet since being reset and there cannot be any gaps.
- if (!rd_seq_known_) {
- return kGS_NoGap;
- }
-
- // If we are waiting for fast start, then the current gap is a fast start
- // gap and it includes all packets before the read sequence number.
- if (waiting_for_fast_start_) {
- gap->start_seq_ =
- gap->end_seq_ = rd_seq_ - 1;
- return kGS_FastStartGap;
- }
-
- // If rd == wr, then the buffer is empty and there cannot be any gaps.
- if (rd_ == wr_) {
- return kGS_NoGap;
- }
-
- // If rd_ is currently pointing at an unprocessed packet, then there is no
- // current gap.
- CHECK(rd_ < capacity_);
- if (NULL != ring_[rd_]) {
- return kGS_NoGap;
- }
-
- // Looks like there must be a gap here. The start of the gap is the current
- // rd sequence number, all we need to do now is determine its length in
- // order to compute the end sequence number.
- gap->start_seq_ = rd_seq_;
- uint16_t end = rd_seq_;
- uint32_t tmp = (rd_ + 1) % capacity_;
- while ((tmp != wr_) && (NULL == ring_[tmp])) {
- ++end;
- tmp = (tmp + 1) % capacity_;
- }
- gap->end_seq_ = end;
-
- return kGS_NormalGap;
-}
-
-void AAH_RXPlayer::RXRingBuffer::processNAK(const SeqNoGap* nak) {
- AutoMutex lock(&lock_);
- CHECK(NULL != ring_);
-
- // If we were waiting for our first fast start fill-in packet, and we
- // received a NAK, then apparantly we are not getting our fast start. Just
- // clear the waiting flag and go back to normal behavior.
- if (waiting_for_fast_start_) {
- waiting_for_fast_start_ = false;
- }
-
- // If we have not received a packet since last reset, or there is no data in
- // the ring, then there is nothing to skip.
- if ((!rd_seq_known_) || (rd_ == wr_)) {
- return;
- }
-
- // If rd_ is currently pointing at an unprocessed packet, then there is no
- // gap to skip.
- CHECK(rd_ < capacity_);
- if (NULL != ring_[rd_]) {
- return;
- }
-
- // Looks like there must be a gap here. Advance rd until we have passed
- // over the portion of it indicated by nak (or all of the gap if nak is
- // NULL). Then reset fetched_first_packet_ so that the next read will show
- // up as being discontiguous.
- uint16_t seq_after_gap = (NULL == nak) ? 0 : nak->end_seq_ + 1;
- while ((rd_ != wr_) &&
- (NULL == ring_[rd_]) &&
- ((NULL == nak) || (seq_after_gap != rd_seq_))) {
- rd_ = (rd_ + 1) % capacity_;
- ++rd_seq_;
- }
- fetched_first_packet_ = false;
-}
-
-int AAH_RXPlayer::RXRingBuffer::computeInactivityTimeout() {
- AutoMutex lock(&lock_);
-
- if (!rtp_activity_timeout_valid_) {
- return -1;
- }
-
- uint64_t now = monotonicUSecNow();
- if (rtp_activity_timeout_ <= now) {
- return 0;
- }
-
- return (rtp_activity_timeout_ - now) / 1000;
-}
-
-AAH_RXPlayer::PacketBuffer*
-AAH_RXPlayer::PacketBuffer::allocate(ssize_t length) {
- if (length <= 0) {
- return NULL;
- }
-
- uint32_t alloc_len = sizeof(PacketBuffer) + length;
- PacketBuffer* ret = reinterpret_cast<PacketBuffer*>(
- new uint8_t[alloc_len]);
-
- if (NULL != ret) {
- ret->length_ = length;
- }
-
- return ret;
-}
-
-void AAH_RXPlayer::PacketBuffer::destroy(PacketBuffer* pb) {
- uint8_t* kill_me = reinterpret_cast<uint8_t*>(pb);
- delete[] kill_me;
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player_substream.cpp b/media/libaah_rtp/aah_rx_player_substream.cpp
deleted file mode 100644
index 18b0e2b..0000000
--- a/media/libaah_rtp/aah_rx_player_substream.cpp
+++ /dev/null
@@ -1,677 +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"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include <include/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/Utils.h>
-
-#include "aah_rx_player.h"
-#include "aah_tx_packet.h"
-
-inline uint32_t min(uint32_t a, uint32_t b) {
- return (a < b ? a : b);
-}
-
-namespace android {
-
-int64_t AAH_RXPlayer::Substream::kAboutToUnderflowThreshold =
- 50ull * 1000;
-
-AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
- ssrc_ = ssrc;
- substream_details_known_ = false;
- buffer_in_progress_ = NULL;
- status_ = OK;
- codec_mime_type_ = "";
-
- decoder_ = new AAH_DecoderPump(omx);
- if (decoder_ == NULL) {
- ALOGE("%s failed to allocate decoder pump!", __PRETTY_FUNCTION__);
- }
- if (OK != decoder_->initCheck()) {
- ALOGE("%s failed to initialize decoder pump!", __PRETTY_FUNCTION__);
- }
-
- // cleanupBufferInProgress will reset most of the internal state variables.
- // Just need to make sure that buffer_in_progress_ is NULL before calling.
- cleanupBufferInProgress();
-}
-
-AAH_RXPlayer::Substream::~Substream() {
- shutdown();
-}
-
-void AAH_RXPlayer::Substream::shutdown() {
- substream_meta_ = NULL;
- status_ = OK;
- cleanupBufferInProgress();
- cleanupDecoder();
-}
-
-void AAH_RXPlayer::Substream::cleanupBufferInProgress() {
- if (NULL != buffer_in_progress_) {
- buffer_in_progress_->release();
- buffer_in_progress_ = NULL;
- }
-
- expected_buffer_size_ = 0;
- buffer_filled_ = 0;
- waiting_for_rap_ = true;
-
- aux_data_in_progress_.clear();
- aux_data_expected_size_ = 0;
-}
-
-void AAH_RXPlayer::Substream::cleanupDecoder() {
- if (decoder_ != NULL) {
- decoder_->shutdown();
- }
-}
-
-bool AAH_RXPlayer::Substream::shouldAbort(const char* log_tag) {
- // If we have already encountered a fatal error, do nothing. We are just
- // waiting for our owner to shut us down now.
- if (OK != status_) {
- ALOGV("Skipping %s, substream has encountered fatal error (%d).",
- log_tag, status_);
- return true;
- }
-
- return false;
-}
-
-void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
- uint32_t amt,
- int32_t ts_lower) {
- uint32_t min_length = 6;
-
- if (shouldAbort(__PRETTY_FUNCTION__)) {
- return;
- }
-
- // Do we have a buffer in progress already? If so, abort the buffer. In
- // theory, this should never happen. If there were a discontinutity in the
- // stream, the discon in the seq_nos at the RTP level should have already
- // triggered a cleanup of the buffer in progress. To see a problem at this
- // level is an indication either of a bug in the transmitter, or some form
- // of terrible corruption/tampering on the wire.
- if (NULL != buffer_in_progress_) {
- ALOGE("processPayloadStart is aborting payload already in progress.");
- cleanupBufferInProgress();
- }
-
- // Parse enough of the header to know where we stand. Since this is a
- // payload start, it should begin with a TRTP header which has to be at
- // least 6 bytes long.
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP header (len = %u)",
- amt);
- return;
- }
-
- // Check the TRTP version number.
- if (0x01 != buf[0]) {
- ALOGV("Unexpected TRTP version (%u) in header. Expected %u.",
- buf[0], 1);
- return;
- }
-
- // Extract the substream type field and make sure its one we understand (and
- // one that does not conflict with any previously received substream type.
- uint8_t header_type = (buf[1] >> 4) & 0xF;
- switch (header_type) {
- case TRTPPacket::kHeaderTypeAudio:
- // Audio, yay! Just break. We understand audio payloads.
- break;
- case TRTPPacket::kHeaderTypeVideo:
- ALOGV("RXed packet with unhandled TRTP header type (Video).");
- return;
- case TRTPPacket::kHeaderTypeSubpicture:
- ALOGV("RXed packet with unhandled TRTP header type (Subpicture).");
- return;
- case TRTPPacket::kHeaderTypeControl:
- ALOGV("RXed packet with unhandled TRTP header type (Control).");
- return;
- default:
- ALOGV("RXed packet with unhandled TRTP header type (%u).",
- header_type);
- return;
- }
-
- if (substream_details_known_ && (header_type != substream_type_)) {
- ALOGV("RXed TRTP Payload for SSRC=0x%08x where header type (%u) does"
- " not match previously received header type (%u)",
- ssrc_, header_type, substream_type_);
- return;
- }
-
- // Check the flags to see if there is another 32 bits of timestamp present.
- uint32_t trtp_header_len = 6;
- bool ts_valid = buf[1] & TRTPPacket::kFlag_TSValid;
- if (ts_valid) {
- min_length += 4;
- trtp_header_len += 4;
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP timestamp"
- " (len = %u)", amt);
- return;
- }
- }
-
- // Extract the TRTP length field and sanity check it.
- uint32_t trtp_len = U32_AT(buf + 2);
- if (trtp_len < min_length) {
- ALOGV("TRTP length (%u) is too short to be valid. Must be at least %u"
- " bytes.", trtp_len, min_length);
- return;
- }
-
- // Extract the rest of the timestamp field if valid.
- int64_t ts = 0;
- uint32_t parse_offset = 6;
- if (ts_valid) {
- uint32_t ts_upper = U32_AT(buf + parse_offset);
- parse_offset += 4;
- ts = (static_cast<int64_t>(ts_upper) << 32) | ts_lower;
- }
-
- // Check the flags to see if there is another 24 bytes of timestamp
- // transformation present.
- if (buf[1] & TRTPPacket::kFlag_TSTransformPresent) {
- min_length += 24;
- parse_offset += 24;
- trtp_header_len += 24;
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP timestamp"
- " transformation (len = %u)", amt);
- return;
- }
- }
-
- // TODO : break the parsing into individual parsers for the different
- // payload types (audio, video, etc).
- //
- // At this point in time, we know that this is audio. Go ahead and parse
- // the basic header, check the codec type, and find the payload portion of
- // the packet.
- min_length += 3;
- if (trtp_len < min_length) {
- ALOGV("TRTP length (%u) is too short to be a valid audio payload. Must"
- " be at least %u bytes.", trtp_len, min_length);
- return;
- }
-
- if (amt < min_length) {
- ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
- " entire TRTP header. TRTP does not currently support"
- " fragmenting TRTP headers across RTP payloads", amt);
- return;
- }
-
- uint8_t codec_type = buf[parse_offset ];
- uint8_t flags = buf[parse_offset + 1];
- uint8_t volume = buf[parse_offset + 2];
- parse_offset += 3;
- trtp_header_len += 3;
-
- if (!setupSubstreamType(header_type, codec_type)) {
- return;
- }
-
- if (decoder_ != NULL) {
- decoder_->setRenderVolume(volume);
- }
-
- if (waiting_for_rap_ && !(flags & TRTPAudioPacket::kFlag_RandomAccessPoint)) {
- ALOGV("Dropping non-RAP TRTP Audio Payload while waiting for RAP.");
- return;
- }
-
- // Check for the presence of codec aux data.
- if (flags & TRTPAudioPacket::kFlag_AuxLengthPresent) {
- min_length += 4;
- trtp_header_len += 4;
-
- if (trtp_len < min_length) {
- ALOGV("TRTP length (%u) is too short to be a valid audio payload. "
- "Must be at least %u bytes.", trtp_len, min_length);
- return;
- }
-
- if (amt < min_length) {
- ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
- " entire TRTP header. TRTP does not currently support"
- " fragmenting TRTP headers across RTP payloads", amt);
- return;
- }
-
- aux_data_expected_size_ = U32_AT(buf + parse_offset);
- aux_data_in_progress_.clear();
- if (aux_data_in_progress_.capacity() < aux_data_expected_size_) {
- aux_data_in_progress_.setCapacity(aux_data_expected_size_);
- }
- } else {
- aux_data_expected_size_ = 0;
- }
-
- if ((aux_data_expected_size_ + trtp_header_len) > trtp_len) {
- ALOGV("Expected codec aux data length (%u) and TRTP header overhead"
- " (%u) too large for total TRTP payload length (%u).",
- aux_data_expected_size_, trtp_header_len, trtp_len);
- return;
- }
-
- // OK - everything left is just payload. Compute the payload size, start
- // the buffer in progress and pack as much payload as we can into it. If
- // the payload is finished once we are done, go ahead and send the payload
- // to the decoder.
- expected_buffer_size_ = trtp_len
- - trtp_header_len
- - aux_data_expected_size_;
- if (!expected_buffer_size_) {
- ALOGV("Dropping TRTP Audio Payload with 0 Access Unit length");
- return;
- }
-
- CHECK(amt >= trtp_header_len);
- uint32_t todo = amt - trtp_header_len;
- if ((expected_buffer_size_ + aux_data_expected_size_) < todo) {
- ALOGV("Extra data (%u > %u) present in initial TRTP Audio Payload;"
- " dropping payload.", todo,
- expected_buffer_size_ + aux_data_expected_size_);
- return;
- }
-
- buffer_filled_ = 0;
- buffer_in_progress_ = new MediaBuffer(expected_buffer_size_);
- if ((NULL == buffer_in_progress_) ||
- (NULL == buffer_in_progress_->data())) {
- ALOGV("Failed to allocate MediaBuffer of length %u",
- expected_buffer_size_);
- cleanupBufferInProgress();
- return;
- }
-
- sp<MetaData> meta = buffer_in_progress_->meta_data();
- if (meta == NULL) {
- ALOGV("Missing metadata structure in allocated MediaBuffer; dropping"
- " payload");
- cleanupBufferInProgress();
- return;
- }
-
- meta->setCString(kKeyMIMEType, codec_mime_type_);
- if (ts_valid) {
- meta->setInt64(kKeyTime, ts);
- }
-
- // Skip over the header we have already extracted.
- amt -= trtp_header_len;
- buf += trtp_header_len;
-
- // Extract as much of the expected aux data as we can.
- todo = min(aux_data_expected_size_, amt);
- if (todo) {
- aux_data_in_progress_.appendArray(buf, todo);
- buf += todo;
- amt -= todo;
- }
-
- // Extract as much of the expected payload as we can.
- todo = min(expected_buffer_size_, amt);
- if (todo > 0) {
- uint8_t* tgt =
- reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
- memcpy(tgt, buf, todo);
- buffer_filled_ = amt;
- buf += todo;
- amt -= todo;
- }
-
- if (buffer_filled_ >= expected_buffer_size_) {
- processCompletedBuffer();
- }
-}
-
-void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf,
- uint32_t amt) {
- if (shouldAbort(__PRETTY_FUNCTION__)) {
- return;
- }
-
- if (NULL == buffer_in_progress_) {
- ALOGV("TRTP Receiver skipping payload continuation; no buffer currently"
- " in progress.");
- return;
- }
-
- CHECK(aux_data_in_progress_.size() <= aux_data_expected_size_);
- uint32_t aux_left = aux_data_expected_size_ - aux_data_in_progress_.size();
- if (aux_left) {
- uint32_t todo = min(aux_left, amt);
- aux_data_in_progress_.appendArray(buf, todo);
- amt -= todo;
- buf += todo;
-
- if (!amt)
- return;
- }
-
- CHECK(buffer_filled_ < expected_buffer_size_);
- uint32_t buffer_left = expected_buffer_size_ - buffer_filled_;
- if (amt > buffer_left) {
- ALOGV("Extra data (%u > %u) present in continued TRTP Audio Payload;"
- " dropping payload.", amt, buffer_left);
- cleanupBufferInProgress();
- return;
- }
-
- if (amt > 0) {
- uint8_t* tgt =
- reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
- memcpy(tgt + buffer_filled_, buf, amt);
- buffer_filled_ += amt;
- }
-
- if (buffer_filled_ >= expected_buffer_size_) {
- processCompletedBuffer();
- }
-}
-
-void AAH_RXPlayer::Substream::processCompletedBuffer() {
- status_t res;
-
- CHECK(NULL != buffer_in_progress_);
-
- if (decoder_ == NULL) {
- ALOGV("Dropping complete buffer, no decoder pump allocated");
- goto bailout;
- }
-
- // Make sure our metadata used to initialize the decoder has been properly
- // set up.
- if (!setupSubstreamMeta())
- goto bailout;
-
- // If our decoder has not be set up, do so now.
- res = decoder_->init(substream_meta_);
- if (OK != res) {
- ALOGE("Failed to init decoder (res = %d)", res);
- cleanupDecoder();
- substream_meta_ = NULL;
- goto bailout;
- }
-
- // Queue the payload for decode.
- res = decoder_->queueForDecode(buffer_in_progress_);
-
- if (res != OK) {
- ALOGD("Failed to queue payload for decode, resetting decoder pump!"
- " (res = %d)", res);
- status_ = res;
- cleanupDecoder();
- cleanupBufferInProgress();
- }
-
- // NULL out buffer_in_progress before calling the cleanup helper.
- //
- // MediaBuffers use something of a hybrid ref-counting pattern which prevent
- // the AAH_DecoderPump's input queue from adding their own reference to the
- // MediaBuffer. MediaBuffers start life with a reference count of 0, as
- // well as an observer which starts as NULL. Before being given an
- // observer, the ref count cannot be allowed to become non-zero as it will
- // cause calls to release() to assert. Basically, before a MediaBuffer has
- // an observer, they behave like non-ref counted obects where release()
- // serves the roll of delete. After a MediaBuffer has an observer, they
- // become more like ref counted objects where add ref and release can be
- // used, and when the ref count hits zero, the MediaBuffer is handed off to
- // the observer.
- //
- // Given all of this, when we give the buffer to the decoder pump to wait in
- // the to-be-processed queue, the decoder cannot add a ref to the buffer as
- // it would in a traditional ref counting system. Instead it needs to
- // "steal" the non-existent ref. In the case of queue failure, we need to
- // make certain to release this non-existent reference so that the buffer is
- // cleaned up during the cleanupBufferInProgress helper. In the case of a
- // successful queue operation, we need to make certain that the
- // cleanupBufferInProgress helper does not release the buffer since it needs
- // to remain alive in the queue. We acomplish this by NULLing out the
- // buffer pointer before calling the cleanup helper.
- buffer_in_progress_ = NULL;
-
-bailout:
- cleanupBufferInProgress();
-}
-
-bool AAH_RXPlayer::Substream::setupSubstreamMeta() {
- switch (codec_type_) {
- case TRTPAudioPacket::kCodecMPEG1Audio:
- codec_mime_type_ = MEDIA_MIMETYPE_AUDIO_MPEG;
- return setupMP3SubstreamMeta();
-
- case TRTPAudioPacket::kCodecAACAudio:
- codec_mime_type_ = MEDIA_MIMETYPE_AUDIO_AAC;
- return setupAACSubstreamMeta();
-
- default:
- ALOGV("Failed to setup substream metadata for unsupported codec"
- " type (%u)", codec_type_);
- break;
- }
-
- return false;
-}
-
-bool AAH_RXPlayer::Substream::setupMP3SubstreamMeta() {
- const uint8_t* buffer_data = NULL;
- int sample_rate;
- int channel_count;
- size_t frame_size;
- status_t res;
-
- buffer_data = reinterpret_cast<const uint8_t*>(buffer_in_progress_->data());
- if (buffer_in_progress_->size() < 4) {
- ALOGV("MP3 payload too short to contain header, dropping payload.");
- return false;
- }
-
- // Extract the channel count and the sample rate from the MP3 header. The
- // stagefright MP3 requires that these be delivered before decoing can
- // begin.
- if (!GetMPEGAudioFrameSize(U32_AT(buffer_data),
- &frame_size,
- &sample_rate,
- &channel_count,
- NULL,
- NULL)) {
- ALOGV("Failed to parse MP3 header in payload, droping payload.");
- return false;
- }
-
-
- // Make sure that our substream metadata is set up properly. If there has
- // been a format change, be sure to reset the underlying decoder. In
- // stagefright, it seems like the only way to do this is to destroy and
- // recreate the decoder.
- if (substream_meta_ == NULL) {
- substream_meta_ = new MetaData();
-
- if (substream_meta_ == NULL) {
- ALOGE("Failed to allocate MetaData structure for MP3 substream");
- return false;
- }
-
- substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
- substream_meta_->setInt32 (kKeyChannelCount, channel_count);
- substream_meta_->setInt32 (kKeySampleRate, sample_rate);
- } else {
- int32_t prev_sample_rate;
- int32_t prev_channel_count;
- substream_meta_->findInt32(kKeySampleRate, &prev_sample_rate);
- substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
-
- if ((prev_channel_count != channel_count) ||
- (prev_sample_rate != sample_rate)) {
- ALOGW("MP3 format change detected, forcing decoder reset.");
- cleanupDecoder();
-
- substream_meta_->setInt32(kKeyChannelCount, channel_count);
- substream_meta_->setInt32(kKeySampleRate, sample_rate);
- }
- }
-
- return true;
-}
-
-bool AAH_RXPlayer::Substream::setupAACSubstreamMeta() {
- int32_t sample_rate, channel_cnt;
- static const size_t overhead = sizeof(sample_rate)
- + sizeof(channel_cnt);
-
- if (aux_data_in_progress_.size() < overhead) {
- ALOGE("Not enough aux data (%u) to initialize AAC substream decoder",
- aux_data_in_progress_.size());
- return false;
- }
-
- const uint8_t* aux_data = aux_data_in_progress_.array();
- size_t aux_data_size = aux_data_in_progress_.size();
- sample_rate = U32_AT(aux_data);
- channel_cnt = U32_AT(aux_data + sizeof(sample_rate));
-
- const uint8_t* esds_data = NULL;
- size_t esds_data_size = 0;
- if (aux_data_size > overhead) {
- esds_data = aux_data + overhead;
- esds_data_size = aux_data_size - overhead;
- }
-
- // Do we already have metadata? If so, has it changed at all? If not, then
- // there should be nothing else to do. Otherwise, release our old stream
- // metadata and make new metadata.
- if (substream_meta_ != NULL) {
- uint32_t type;
- const void* data;
- size_t size;
- int32_t prev_sample_rate;
- int32_t prev_channel_count;
- bool res;
-
- res = substream_meta_->findInt32(kKeySampleRate, &prev_sample_rate);
- CHECK(res);
- res = substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
- CHECK(res);
-
- // If nothing has changed about the codec aux data (esds, sample rate,
- // channel count), then we can just do nothing and get out. Otherwise,
- // we will need to reset the decoder and make a new metadata object to
- // deal with the format change.
- bool hasData = (esds_data != NULL);
- bool hadData = substream_meta_->findData(kKeyESDS, &type, &data, &size);
- bool esds_change = (hadData != hasData);
-
- if (!esds_change && hasData)
- esds_change = ((size != esds_data_size) ||
- memcmp(data, esds_data, size));
-
- if (!esds_change &&
- (prev_sample_rate == sample_rate) &&
- (prev_channel_count == channel_cnt)) {
- return true; // no change, just get out.
- }
-
- ALOGW("AAC format change detected, forcing decoder reset.");
- cleanupDecoder();
- substream_meta_ = NULL;
- }
-
- CHECK(substream_meta_ == NULL);
-
- substream_meta_ = new MetaData();
- if (substream_meta_ == NULL) {
- ALOGE("Failed to allocate MetaData structure for AAC substream");
- return false;
- }
-
- substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
- substream_meta_->setInt32 (kKeySampleRate, sample_rate);
- substream_meta_->setInt32 (kKeyChannelCount, channel_cnt);
-
- if (esds_data) {
- substream_meta_->setData(kKeyESDS, kTypeESDS,
- esds_data, esds_data_size);
- }
-
- return true;
-}
-
-void AAH_RXPlayer::Substream::processTSTransform(const LinearTransform& trans) {
- if (decoder_ != NULL) {
- decoder_->setRenderTSTransform(trans);
- }
-}
-
-bool AAH_RXPlayer::Substream::isAboutToUnderflow() {
- if (decoder_ == NULL) {
- return false;
- }
-
- return decoder_->isAboutToUnderflow(kAboutToUnderflowThreshold);
-}
-
-bool AAH_RXPlayer::Substream::setupSubstreamType(uint8_t substream_type,
- uint8_t codec_type) {
- // Sanity check the codec type. Right now we only support MP3 and AAC.
- // Also check for conflicts with previously delivered codec types.
- if (substream_details_known_) {
- if (codec_type != codec_type_) {
- ALOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does"
- " not match previously received codec type (%u)",
- ssrc_, codec_type, codec_type_);
- return false;
- }
-
- return true;
- }
-
- switch (codec_type) {
- // MP3 and AAC are all we support right now.
- case TRTPAudioPacket::kCodecMPEG1Audio:
- case TRTPAudioPacket::kCodecAACAudio:
- break;
-
- default:
- ALOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported"
- " codec type (%u)", ssrc_, codec_type);
- return false;
- }
-
- substream_type_ = substream_type;
- codec_type_ = codec_type;
- substream_details_known_ = true;
-
- return true;
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_tx_packet.cpp b/media/libaah_rtp/aah_tx_packet.cpp
deleted file mode 100644
index 4cd6e47..0000000
--- a/media/libaah_rtp/aah_tx_packet.cpp
+++ /dev/null
@@ -1,344 +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>
-
-#include <arpa/inet.h>
-#include <string.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-#include "aah_tx_packet.h"
-
-namespace android {
-
-const int TRTPPacket::kRTPHeaderLen;
-const uint32_t TRTPPacket::kTRTPEpochMask;
-
-TRTPPacket::~TRTPPacket() {
- delete mPacket;
-}
-
-/*** TRTP packet properties ***/
-
-void TRTPPacket::setSeqNumber(uint16_t val) {
- mSeqNumber = val;
-
- if (mIsPacked) {
- const int kTRTPSeqNumberOffset = 2;
- uint16_t* buf = reinterpret_cast<uint16_t*>(
- mPacket + kTRTPSeqNumberOffset);
- *buf = htons(mSeqNumber);
- }
-}
-
-uint16_t TRTPPacket::getSeqNumber() const {
- return mSeqNumber;
-}
-
-void TRTPPacket::setPTS(int64_t val) {
- CHECK(!mIsPacked);
- mPTS = val;
- mPTSValid = true;
-}
-
-int64_t TRTPPacket::getPTS() const {
- return mPTS;
-}
-
-void TRTPPacket::setEpoch(uint32_t val) {
- mEpoch = val;
-
- if (mIsPacked) {
- const int kTRTPEpochOffset = 8;
- uint32_t* buf = reinterpret_cast<uint32_t*>(
- mPacket + kTRTPEpochOffset);
- uint32_t val = ntohl(*buf);
- val &= ~(kTRTPEpochMask << kTRTPEpochShift);
- val |= (mEpoch & kTRTPEpochMask) << kTRTPEpochShift;
- *buf = htonl(val);
- }
-}
-
-void TRTPPacket::setProgramID(uint16_t val) {
- CHECK(!mIsPacked);
- mProgramID = val;
-}
-
-void TRTPPacket::setSubstreamID(uint16_t val) {
- CHECK(!mIsPacked);
- mSubstreamID = val;
-}
-
-
-void TRTPPacket::setClockTransform(const LinearTransform& trans) {
- CHECK(!mIsPacked);
- mClockTranform = trans;
- mClockTranformValid = true;
-}
-
-uint8_t* TRTPPacket::getPacket() const {
- CHECK(mIsPacked);
- return mPacket;
-}
-
-int TRTPPacket::getPacketLen() const {
- CHECK(mIsPacked);
- return mPacketLen;
-}
-
-void TRTPPacket::setExpireTime(nsecs_t val) {
- CHECK(!mIsPacked);
- mExpireTime = val;
-}
-
-nsecs_t TRTPPacket::getExpireTime() const {
- return mExpireTime;
-}
-
-/*** TRTP audio packet properties ***/
-
-void TRTPAudioPacket::setCodecType(TRTPAudioCodecType val) {
- CHECK(!mIsPacked);
- mCodecType = val;
-}
-
-void TRTPAudioPacket::setRandomAccessPoint(bool val) {
- CHECK(!mIsPacked);
- mRandomAccessPoint = val;
-}
-
-void TRTPAudioPacket::setDropable(bool val) {
- CHECK(!mIsPacked);
- mDropable = val;
-}
-
-void TRTPAudioPacket::setDiscontinuity(bool val) {
- CHECK(!mIsPacked);
- mDiscontinuity = val;
-}
-
-void TRTPAudioPacket::setEndOfStream(bool val) {
- CHECK(!mIsPacked);
- mEndOfStream = val;
-}
-
-void TRTPAudioPacket::setVolume(uint8_t val) {
- CHECK(!mIsPacked);
- mVolume = val;
-}
-
-void TRTPAudioPacket::setAccessUnitData(const void* data, size_t len) {
- CHECK(!mIsPacked);
- mAccessUnitData = data;
- mAccessUnitLen = len;
-}
-
-void TRTPAudioPacket::setAuxData(const void* data, size_t len) {
- CHECK(!mIsPacked);
- mAuxData = data;
- mAuxDataLen = len;
-}
-
-/*** TRTP control packet properties ***/
-
-void TRTPControlPacket::setCommandID(TRTPCommandID val) {
- CHECK(!mIsPacked);
- mCommandID = val;
-}
-
-/*** TRTP packet serializers ***/
-
-void TRTPPacket::writeU8(uint8_t*& buf, uint8_t val) {
- *buf = val;
- buf++;
-}
-
-void TRTPPacket::writeU16(uint8_t*& buf, uint16_t val) {
- *reinterpret_cast<uint16_t*>(buf) = htons(val);
- buf += 2;
-}
-
-void TRTPPacket::writeU32(uint8_t*& buf, uint32_t val) {
- *reinterpret_cast<uint32_t*>(buf) = htonl(val);
- buf += 4;
-}
-
-void TRTPPacket::writeU64(uint8_t*& buf, uint64_t val) {
- buf[0] = static_cast<uint8_t>(val >> 56);
- buf[1] = static_cast<uint8_t>(val >> 48);
- buf[2] = static_cast<uint8_t>(val >> 40);
- buf[3] = static_cast<uint8_t>(val >> 32);
- buf[4] = static_cast<uint8_t>(val >> 24);
- buf[5] = static_cast<uint8_t>(val >> 16);
- buf[6] = static_cast<uint8_t>(val >> 8);
- buf[7] = static_cast<uint8_t>(val);
- buf += 8;
-}
-
-void TRTPPacket::writeTRTPHeader(uint8_t*& buf,
- bool isFirstFragment,
- int totalPacketLen) {
- // RTP header
- writeU8(buf,
- ((mVersion & 0x03) << 6) |
- (static_cast<int>(mPadding) << 5) |
- (static_cast<int>(mExtension) << 4) |
- (mCsrcCount & 0x0F));
- writeU8(buf,
- (static_cast<int>(isFirstFragment) << 7) |
- (mPayloadType & 0x7F));
- writeU16(buf, mSeqNumber);
- if (isFirstFragment && mPTSValid) {
- writeU32(buf, mPTS & 0xFFFFFFFF);
- } else {
- writeU32(buf, 0);
- }
- writeU32(buf,
- ((mEpoch & kTRTPEpochMask) << kTRTPEpochShift) |
- ((mProgramID & 0x1F) << 5) |
- (mSubstreamID & 0x1F));
-
- // TRTP header
- writeU8(buf, mTRTPVersion);
- writeU8(buf,
- ((mTRTPHeaderType & 0x0F) << 4) |
- (mClockTranformValid ? 0x02 : 0x00) |
- (mPTSValid ? 0x01 : 0x00));
- writeU32(buf, totalPacketLen - kRTPHeaderLen);
- if (mPTSValid) {
- writeU32(buf, mPTS >> 32);
- }
-
- if (mClockTranformValid) {
- writeU64(buf, mClockTranform.a_zero);
- writeU32(buf, mClockTranform.a_to_b_numer);
- writeU32(buf, mClockTranform.a_to_b_denom);
- writeU64(buf, mClockTranform.b_zero);
- }
-}
-
-bool TRTPAudioPacket::pack() {
- if (mIsPacked) {
- return false;
- }
-
- int packetLen = kRTPHeaderLen +
- mAuxDataLen +
- mAccessUnitLen +
- TRTPHeaderLen();
-
- // TODO : support multiple fragments
- const int kMaxUDPPayloadLen = 65507;
- if (packetLen > kMaxUDPPayloadLen) {
- return false;
- }
-
- mPacket = new uint8_t[packetLen];
- if (!mPacket) {
- return false;
- }
-
- mPacketLen = packetLen;
-
- uint8_t* cur = mPacket;
- bool hasAux = mAuxData && mAuxDataLen;
- uint8_t flags = (static_cast<int>(hasAux) << 4) |
- (static_cast<int>(mRandomAccessPoint) << 3) |
- (static_cast<int>(mDropable) << 2) |
- (static_cast<int>(mDiscontinuity) << 1) |
- (static_cast<int>(mEndOfStream));
-
- writeTRTPHeader(cur, true, packetLen);
- writeU8(cur, mCodecType);
- writeU8(cur, flags);
- writeU8(cur, mVolume);
-
- if (hasAux) {
- writeU32(cur, mAuxDataLen);
- memcpy(cur, mAuxData, mAuxDataLen);
- cur += mAuxDataLen;
- }
-
- memcpy(cur, mAccessUnitData, mAccessUnitLen);
-
- mIsPacked = true;
- return true;
-}
-
-int TRTPPacket::TRTPHeaderLen() const {
- // 6 bytes for version, payload type, flags and length. An additional 4 if
- // there are upper timestamp bits present and another 24 if there is a clock
- // transformation present.
- return 6 +
- (mClockTranformValid ? 24 : 0) +
- (mPTSValid ? 4 : 0);
-}
-
-int TRTPAudioPacket::TRTPHeaderLen() const {
- // TRTPPacket::TRTPHeaderLen() for the base TRTPHeader. 3 bytes for audio's
- // codec type, flags and volume field. Another 5 bytes if the codec type is
- // PCM and we are sending sample rate/channel count. as well as however long
- // the aux data (if present) is.
-
- int pcmParamLength;
- switch(mCodecType) {
- case kCodecPCMBigEndian:
- case kCodecPCMLittleEndian:
- pcmParamLength = 5;
- break;
-
- default:
- pcmParamLength = 0;
- break;
- }
-
-
- int auxDataLenField = (NULL != mAuxData) ? sizeof(uint32_t) : 0;
- return TRTPPacket::TRTPHeaderLen() +
- 3 +
- auxDataLenField +
- pcmParamLength;
-}
-
-bool TRTPControlPacket::pack() {
- if (mIsPacked) {
- return false;
- }
-
- // command packets contain a 2-byte command ID
- int packetLen = kRTPHeaderLen +
- TRTPHeaderLen() +
- 2;
-
- mPacket = new uint8_t[packetLen];
- if (!mPacket) {
- return false;
- }
-
- mPacketLen = packetLen;
-
- uint8_t* cur = mPacket;
-
- writeTRTPHeader(cur, true, packetLen);
- writeU16(cur, mCommandID);
-
- mIsPacked = true;
- return true;
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_tx_packet.h b/media/libaah_rtp/aah_tx_packet.h
deleted file mode 100644
index 7f78ea0..0000000
--- a/media/libaah_rtp/aah_tx_packet.h
+++ /dev/null
@@ -1,213 +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.
- */
-
-#ifndef __AAH_TX_PACKET_H__
-#define __AAH_TX_PACKET_H__
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/LinearTransform.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-class TRTPPacket : public RefBase {
- public:
- enum TRTPHeaderType {
- kHeaderTypeAudio = 1,
- kHeaderTypeVideo = 2,
- kHeaderTypeSubpicture = 3,
- kHeaderTypeControl = 4,
- };
-
- enum TRTPPayloadFlags {
- kFlag_TSTransformPresent = 0x02,
- kFlag_TSValid = 0x01,
- };
-
- protected:
- TRTPPacket(TRTPHeaderType headerType)
- : mIsPacked(false)
- , mVersion(2)
- , mPadding(false)
- , mExtension(false)
- , mCsrcCount(0)
- , mPayloadType(100)
- , mSeqNumber(0)
- , mPTSValid(false)
- , mPTS(0)
- , mEpoch(0)
- , mProgramID(0)
- , mSubstreamID(0)
- , mClockTranformValid(false)
- , mTRTPVersion(1)
- , mTRTPLength(0)
- , mTRTPHeaderType(headerType)
- , mPacket(NULL)
- , mPacketLen(0) { }
-
- public:
- virtual ~TRTPPacket();
-
- void setSeqNumber(uint16_t val);
- uint16_t getSeqNumber() const;
-
- void setPTS(int64_t val);
- int64_t getPTS() const;
-
- void setEpoch(uint32_t val);
- void setProgramID(uint16_t val);
- void setSubstreamID(uint16_t val);
- void setClockTransform(const LinearTransform& trans);
-
- uint8_t* getPacket() const;
- int getPacketLen() const;
-
- void setExpireTime(nsecs_t val);
- nsecs_t getExpireTime() const;
-
- virtual bool pack() = 0;
-
- // mask for the number of bits in a TRTP epoch
- static const uint32_t kTRTPEpochMask = (1 << 22) - 1;
- static const int kTRTPEpochShift = 10;
-
- protected:
- static const int kRTPHeaderLen = 12;
- virtual int TRTPHeaderLen() const;
-
- void writeTRTPHeader(uint8_t*& buf,
- bool isFirstFragment,
- int totalPacketLen);
-
- void writeU8(uint8_t*& buf, uint8_t val);
- void writeU16(uint8_t*& buf, uint16_t val);
- void writeU32(uint8_t*& buf, uint32_t val);
- void writeU64(uint8_t*& buf, uint64_t val);
-
- bool mIsPacked;
-
- uint8_t mVersion;
- bool mPadding;
- bool mExtension;
- uint8_t mCsrcCount;
- uint8_t mPayloadType;
- uint16_t mSeqNumber;
- bool mPTSValid;
- int64_t mPTS;
- uint32_t mEpoch;
- uint16_t mProgramID;
- uint16_t mSubstreamID;
- LinearTransform mClockTranform;
- bool mClockTranformValid;
- uint8_t mTRTPVersion;
- uint32_t mTRTPLength;
- TRTPHeaderType mTRTPHeaderType;
-
- uint8_t* mPacket;
- int mPacketLen;
-
- nsecs_t mExpireTime;
-
- DISALLOW_EVIL_CONSTRUCTORS(TRTPPacket);
-};
-
-class TRTPAudioPacket : public TRTPPacket {
- public:
- enum AudioPayloadFlags {
- kFlag_AuxLengthPresent = 0x10,
- kFlag_RandomAccessPoint = 0x08,
- kFlag_Dropable = 0x04,
- kFlag_Discontinuity = 0x02,
- kFlag_EndOfStream = 0x01,
- };
-
- TRTPAudioPacket()
- : TRTPPacket(kHeaderTypeAudio)
- , mCodecType(kCodecInvalid)
- , mRandomAccessPoint(false)
- , mDropable(false)
- , mDiscontinuity(false)
- , mEndOfStream(false)
- , mVolume(0)
- , mAccessUnitData(NULL)
- , mAccessUnitLen(0)
- , mAuxData(NULL)
- , mAuxDataLen(0) { }
-
- enum TRTPAudioCodecType {
- kCodecInvalid = 0,
- kCodecPCMBigEndian = 1,
- kCodecPCMLittleEndian = 2,
- kCodecMPEG1Audio = 3,
- kCodecAACAudio = 4,
- };
-
- void setCodecType(TRTPAudioCodecType val);
- void setRandomAccessPoint(bool val);
- void setDropable(bool val);
- void setDiscontinuity(bool val);
- void setEndOfStream(bool val);
- void setVolume(uint8_t val);
- void setAccessUnitData(const void* data, size_t len);
- void setAuxData(const void* data, size_t len);
-
- virtual bool pack();
-
- protected:
- virtual int TRTPHeaderLen() const;
-
- private:
- TRTPAudioCodecType mCodecType;
- bool mRandomAccessPoint;
- bool mDropable;
- bool mDiscontinuity;
- bool mEndOfStream;
- uint8_t mVolume;
-
- const void* mAccessUnitData;
- size_t mAccessUnitLen;
- const void* mAuxData;
- size_t mAuxDataLen;
-
- DISALLOW_EVIL_CONSTRUCTORS(TRTPAudioPacket);
-};
-
-class TRTPControlPacket : public TRTPPacket {
- public:
- TRTPControlPacket()
- : TRTPPacket(kHeaderTypeControl)
- , mCommandID(kCommandNop) {}
-
- enum TRTPCommandID {
- kCommandNop = 1,
- kCommandFlush = 2,
- kCommandEOS = 3,
- };
-
- void setCommandID(TRTPCommandID val);
-
- virtual bool pack();
-
- private:
- TRTPCommandID mCommandID;
-
- DISALLOW_EVIL_CONSTRUCTORS(TRTPControlPacket);
-};
-
-} // namespace android
-
-#endif // __AAH_TX_PLAYER_H__
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
diff --git a/media/libaah_rtp/aah_tx_player.h b/media/libaah_rtp/aah_tx_player.h
deleted file mode 100644
index 2e4b1f7..0000000
--- a/media/libaah_rtp/aah_tx_player.h
+++ /dev/null
@@ -1,176 +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.
- */
-
-#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>
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/LinearTransform.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-
-#include "aah_tx_sender.h"
-
-namespace android {
-
-class AAH_TXPlayer : public MediaPlayerHWInterface {
- public:
- AAH_TXPlayer();
-
- virtual status_t initCheck();
- virtual status_t setDataSource(const char *url,
- const KeyedVector<String8, String8>*
- headers);
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setVideoSurface(const sp<Surface>& surface);
- virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>&
- surfaceTexture);
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t seekTo(int msec);
- virtual status_t getCurrentPosition(int *msec);
- virtual status_t getDuration(int *msec);
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType();
- virtual status_t setParameter(int key, const Parcel &request);
- virtual status_t getParameter(int key, Parcel *reply);
- virtual status_t invoke(const Parcel& request, Parcel *reply);
- virtual status_t getMetadata(const media::Metadata::Filter& ids,
- Parcel* records);
- virtual status_t setVolume(float leftVolume, float rightVolume);
- virtual status_t setAudioStreamType(audio_stream_type_t streamType);
- virtual status_t setRetransmitEndpoint(
- const struct sockaddr_in* endpoint);
-
- static const int64_t kAAHRetryKeepAroundTimeNs;
-
- protected:
- virtual ~AAH_TXPlayer();
-
- private:
- friend struct AwesomeEvent;
-
- enum {
- PLAYING = 1,
- PREPARING = 8,
- PREPARED = 16,
- PREPARE_CANCELLED = 64,
- CACHE_UNDERRUN = 128,
-
- // We are basically done preparing but are currently buffering
- // sufficient data to begin playback and finish the preparation
- // phase for good.
- PREPARING_CONNECTED = 2048,
-
- INCOGNITO = 32768,
- };
-
- status_t setDataSource_l(const char *url,
- const KeyedVector<String8, String8> *headers);
- status_t setDataSource_l(const sp<MediaExtractor>& extractor);
- status_t finishSetDataSource_l();
- status_t prepareAsync_l();
- void onPrepareAsyncEvent();
- void finishAsyncPrepare_l();
- void abortPrepare(status_t err);
- status_t play_l();
- status_t pause_l(bool doClockUpdate = true);
- status_t seekTo_l(int64_t timeUs);
- void updateClockTransform_l(bool pause);
- void sendEOS_l();
- void cancelPlayerEvents(bool keepBufferingGoing = false);
- void reset_l();
- void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
- bool getBitrate_l(int64_t* bitrate);
- status_t getDuration_l(int* msec);
- bool getCachedDuration_l(int64_t* durationUs, bool* eos);
- void ensureCacheIsFetching_l();
- void postBufferingEvent_l();
- void postPumpAudioEvent_l(int64_t delayUs);
- void onBufferingUpdate();
- void onPumpAudio();
- void queuePacketToSender_l(const sp<TRTPPacket>& packet);
-
- Mutex mLock;
-
- TimedEventQueue mQueue;
- bool mQueueStarted;
-
- sp<TimedEventQueue::Event> mBufferingEvent;
- bool mBufferingEventPending;
-
- uint32_t mFlags;
- uint32_t mExtractorFlags;
-
- String8 mUri;
- KeyedVector<String8, String8> mUriHeaders;
-
- sp<DataSource> mFileSource;
-
- sp<TimedEventQueue::Event> mAsyncPrepareEvent;
- Condition mPreparedCondition;
- status_t mPrepareResult;
-
- bool mIsSeeking;
- int64_t mSeekTimeUs;
-
- sp<TimedEventQueue::Event> mPumpAudioEvent;
- bool mPumpAudioEventPending;
-
- sp<HTTPBase> mConnectingDataSource;
- sp<NuCachedSource2> mCachedSource;
-
- sp<MediaSource> mAudioSource;
- TRTPAudioPacket::TRTPAudioCodecType mAudioCodec;
- sp<MetaData> mAudioFormat;
- uint8_t* mAudioCodecData;
- size_t mAudioCodecDataSize;
-
- int64_t mDurationUs;
- int64_t mBitrate;
-
- sp<AAH_TXSender> mAAH_Sender;
- LinearTransform mCurrentClockTransform;
- bool mCurrentClockTransformValid;
- 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);
-};
-
-} // namespace android
-
-#endif // __AAH_TX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_tx_sender.cpp b/media/libaah_rtp/aah_tx_sender.cpp
deleted file mode 100644
index 08e32d2..0000000
--- a/media/libaah_rtp/aah_tx_sender.cpp
+++ /dev/null
@@ -1,603 +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 <media/stagefright/foundation/ADebug.h>
-
-#include <netinet/in.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <media/stagefright/foundation/AMessage.h>
-#include <utils/misc.h>
-
-#include "aah_tx_player.h"
-#include "aah_tx_sender.h"
-
-namespace android {
-
-const char* AAH_TXSender::kSendPacketIPAddr = "ipaddr";
-const char* AAH_TXSender::kSendPacketPort = "port";
-const char* AAH_TXSender::kSendPacketTRTPPacket = "trtp";
-
-const int AAH_TXSender::kRetryTrimIntervalUs = 100000;
-const int AAH_TXSender::kHeartbeatIntervalUs = 1000000;
-const int AAH_TXSender::kRetryBufferCapacity = 100;
-const nsecs_t AAH_TXSender::kHeartbeatTimeout = 600ull * 1000000000ull;
-
-Mutex AAH_TXSender::sLock;
-wp<AAH_TXSender> AAH_TXSender::sInstance;
-uint32_t AAH_TXSender::sNextEpoch;
-bool AAH_TXSender::sNextEpochValid = false;
-
-AAH_TXSender::AAH_TXSender() : mSocket(-1) {
- mLastSentPacketTime = systemTime();
-}
-
-sp<AAH_TXSender> AAH_TXSender::GetInstance() {
- Mutex::Autolock autoLock(sLock);
-
- sp<AAH_TXSender> sender = sInstance.promote();
-
- if (sender == NULL) {
- sender = new AAH_TXSender();
- if (sender == NULL) {
- return NULL;
- }
-
- sender->mLooper = new ALooper();
- if (sender->mLooper == NULL) {
- return NULL;
- }
-
- sender->mReflector = new AHandlerReflector<AAH_TXSender>(sender.get());
- if (sender->mReflector == NULL) {
- return NULL;
- }
-
- sender->mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (sender->mSocket == -1) {
- ALOGW("%s unable to create socket", __PRETTY_FUNCTION__);
- return NULL;
- }
-
- struct sockaddr_in bind_addr;
- memset(&bind_addr, 0, sizeof(bind_addr));
- bind_addr.sin_family = AF_INET;
- if (bind(sender->mSocket,
- reinterpret_cast<const sockaddr*>(&bind_addr),
- sizeof(bind_addr)) < 0) {
- ALOGW("%s unable to bind socket (errno %d)",
- __PRETTY_FUNCTION__, errno);
- return NULL;
- }
-
- sender->mRetryReceiver = new RetryReceiver(sender.get());
- if (sender->mRetryReceiver == NULL) {
- return NULL;
- }
-
- sender->mLooper->setName("AAH_TXSender");
- sender->mLooper->registerHandler(sender->mReflector);
- sender->mLooper->start(false, false, PRIORITY_AUDIO);
-
- if (sender->mRetryReceiver->run("AAH_TXSenderRetry", PRIORITY_AUDIO)
- != OK) {
- ALOGW("%s unable to start retry thread", __PRETTY_FUNCTION__);
- return NULL;
- }
-
- sInstance = sender;
- }
-
- return sender;
-}
-
-AAH_TXSender::~AAH_TXSender() {
- mLooper->stop();
- mLooper->unregisterHandler(mReflector->id());
-
- if (mRetryReceiver != NULL) {
- mRetryReceiver->requestExit();
- mRetryReceiver->mWakeupEvent.setEvent();
- if (mRetryReceiver->requestExitAndWait() != OK) {
- ALOGW("%s shutdown of retry receiver failed", __PRETTY_FUNCTION__);
- }
- mRetryReceiver->mSender = NULL;
- mRetryReceiver.clear();
- }
-
- if (mSocket != -1) {
- close(mSocket);
- }
-}
-
-// Return the next epoch number usable for a newly instantiated endpoint.
-uint32_t AAH_TXSender::getNextEpoch() {
- Mutex::Autolock autoLock(sLock);
-
- if (sNextEpochValid) {
- sNextEpoch = (sNextEpoch + 1) & TRTPPacket::kTRTPEpochMask;
- } else {
- sNextEpoch = ns2ms(systemTime()) & TRTPPacket::kTRTPEpochMask;
- sNextEpochValid = true;
- }
-
- return sNextEpoch;
-}
-
-// Notify the sender that a player has started sending to this endpoint.
-// Returns a program ID for use by the calling player.
-uint16_t AAH_TXSender::registerEndpoint(const Endpoint& endpoint) {
- Mutex::Autolock lock(mEndpointLock);
-
- EndpointState* eps = mEndpointMap.valueFor(endpoint);
- if (eps) {
- eps->playerRefCount++;
- } else {
- eps = new EndpointState(getNextEpoch());
- mEndpointMap.add(endpoint, eps);
- }
-
- // if this is the first registered endpoint, then send a message to start
- // trimming retry buffers and a message to start sending heartbeats.
- if (mEndpointMap.size() == 1) {
- sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers,
- handlerID());
- trimMessage->post(kRetryTrimIntervalUs);
-
- sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats,
- handlerID());
- heartbeatMessage->post(kHeartbeatIntervalUs);
- }
-
- eps->nextProgramID++;
- return eps->nextProgramID;
-}
-
-// Notify the sender that a player has ceased sending to this endpoint.
-// An endpoint's state can not be deleted until all of the endpoint's
-// registered players have called unregisterEndpoint.
-void AAH_TXSender::unregisterEndpoint(const Endpoint& endpoint) {
- Mutex::Autolock lock(mEndpointLock);
-
- EndpointState* eps = mEndpointMap.valueFor(endpoint);
- if (eps) {
- eps->playerRefCount--;
- CHECK(eps->playerRefCount >= 0);
- }
-}
-
-void AAH_TXSender::onMessageReceived(const sp<AMessage>& msg) {
- switch (msg->what()) {
- case kWhatSendPacket:
- onSendPacket(msg);
- break;
-
- case kWhatTrimRetryBuffers:
- trimRetryBuffers();
- break;
-
- case kWhatSendHeartbeats:
- sendHeartbeats();
- break;
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void AAH_TXSender::onSendPacket(const sp<AMessage>& msg) {
- sp<RefBase> obj;
- CHECK(msg->findObject(kSendPacketTRTPPacket, &obj));
- sp<TRTPPacket> packet = static_cast<TRTPPacket*>(obj.get());
-
- uint32_t ipAddr;
- CHECK(msg->findInt32(kSendPacketIPAddr,
- reinterpret_cast<int32_t*>(&ipAddr)));
-
- int32_t port32;
- CHECK(msg->findInt32(kSendPacketPort, &port32));
- uint16_t port = port32;
-
- Mutex::Autolock lock(mEndpointLock);
- doSendPacket_l(packet, Endpoint(ipAddr, port));
- mLastSentPacketTime = systemTime();
-}
-
-void AAH_TXSender::doSendPacket_l(const sp<TRTPPacket>& packet,
- const Endpoint& endpoint) {
- EndpointState* eps = mEndpointMap.valueFor(endpoint);
- if (!eps) {
- // the endpoint state has disappeared, so the player that sent this
- // packet must be dead.
- return;
- }
-
- // assign the packet's sequence number
- packet->setEpoch(eps->epoch);
- packet->setSeqNumber(eps->trtpSeqNumber++);
-
- // add the packet to the retry buffer
- RetryBuffer& retry = eps->retry;
- retry.push_back(packet);
-
- // send the packet
- struct sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = endpoint.addr;
- addr.sin_port = endpoint.port;
-
- ssize_t result = sendto(mSocket,
- packet->getPacket(),
- packet->getPacketLen(),
- 0,
- (const struct sockaddr *) &addr,
- sizeof(addr));
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
-}
-
-void AAH_TXSender::trimRetryBuffers() {
- Mutex::Autolock lock(mEndpointLock);
-
- nsecs_t localTimeNow = systemTime();
-
- Vector<Endpoint> endpointsToRemove;
-
- for (size_t i = 0; i < mEndpointMap.size(); i++) {
- EndpointState* eps = mEndpointMap.editValueAt(i);
- RetryBuffer& retry = eps->retry;
-
- while (!retry.isEmpty()) {
- if (retry[0]->getExpireTime() < localTimeNow) {
- retry.pop_front();
- } else {
- break;
- }
- }
-
- if (retry.isEmpty() && eps->playerRefCount == 0) {
- endpointsToRemove.add(mEndpointMap.keyAt(i));
- }
- }
-
- // remove the state for any endpoints that are no longer in use
- for (size_t i = 0; i < endpointsToRemove.size(); i++) {
- Endpoint& e = endpointsToRemove.editItemAt(i);
- ALOGD("*** %s removing endpoint addr=%08x",
- __PRETTY_FUNCTION__, e.addr);
- size_t index = mEndpointMap.indexOfKey(e);
- delete mEndpointMap.valueAt(index);
- mEndpointMap.removeItemsAt(index);
- }
-
- // schedule the next trim
- if (mEndpointMap.size()) {
- sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers,
- handlerID());
- trimMessage->post(kRetryTrimIntervalUs);
- }
-}
-
-void AAH_TXSender::sendHeartbeats() {
- Mutex::Autolock lock(mEndpointLock);
-
- if (shouldSendHeartbeats_l()) {
- for (size_t i = 0; i < mEndpointMap.size(); i++) {
- EndpointState* eps = mEndpointMap.editValueAt(i);
- const Endpoint& ep = mEndpointMap.keyAt(i);
-
- sp<TRTPControlPacket> packet = new TRTPControlPacket();
- packet->setCommandID(TRTPControlPacket::kCommandNop);
-
- packet->setExpireTime(systemTime() +
- AAH_TXPlayer::kAAHRetryKeepAroundTimeNs);
- packet->pack();
-
- doSendPacket_l(packet, ep);
- }
- }
-
- // schedule the next heartbeat
- if (mEndpointMap.size()) {
- sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats,
- handlerID());
- heartbeatMessage->post(kHeartbeatIntervalUs);
- }
-}
-
-bool AAH_TXSender::shouldSendHeartbeats_l() {
- // assert(holding endpoint lock)
- return (systemTime() < (mLastSentPacketTime + kHeartbeatTimeout));
-}
-
-// Receiver
-
-// initial 4-byte ID of a retry request packet
-const uint32_t AAH_TXSender::RetryReceiver::kRetryRequestID = 'Treq';
-
-// initial 4-byte ID of a retry NAK packet
-const uint32_t AAH_TXSender::RetryReceiver::kRetryNakID = 'Tnak';
-
-// initial 4-byte ID of a fast start request packet
-const uint32_t AAH_TXSender::RetryReceiver::kFastStartRequestID = 'Tfst';
-
-AAH_TXSender::RetryReceiver::RetryReceiver(AAH_TXSender* sender)
- : Thread(false),
- mSender(sender) {}
-
- AAH_TXSender::RetryReceiver::~RetryReceiver() {
- mWakeupEvent.clearPendingEvents();
- }
-
-// Returns true if val is within the interval bounded inclusively by
-// start and end. Also handles the case where there is a rollover of the
-// range between start and end.
-template <typename T>
-static inline bool withinIntervalWithRollover(T val, T start, T end) {
- return ((start <= end && val >= start && val <= end) ||
- (start > end && (val >= start || val <= end)));
-}
-
-bool AAH_TXSender::RetryReceiver::threadLoop() {
- struct pollfd pollFds[2];
- pollFds[0].fd = mSender->mSocket;
- pollFds[0].events = POLLIN;
- pollFds[0].revents = 0;
- pollFds[1].fd = mWakeupEvent.getWakeupHandle();
- pollFds[1].events = POLLIN;
- pollFds[1].revents = 0;
-
- int pollResult = poll(pollFds, NELEM(pollFds), -1);
- if (pollResult == -1) {
- ALOGE("%s poll failed", __PRETTY_FUNCTION__);
- return false;
- }
-
- if (exitPending()) {
- ALOGI("*** %s exiting", __PRETTY_FUNCTION__);
- return false;
- }
-
- if (pollFds[0].revents) {
- handleRetryRequest();
- }
-
- return true;
-}
-
-void AAH_TXSender::RetryReceiver::handleRetryRequest() {
- ALOGV("*** RX %s start", __PRETTY_FUNCTION__);
-
- RetryPacket request;
- struct sockaddr requestSrcAddr;
- socklen_t requestSrcAddrLen = sizeof(requestSrcAddr);
-
- ssize_t result = recvfrom(mSender->mSocket, &request, sizeof(request), 0,
- &requestSrcAddr, &requestSrcAddrLen);
- if (result == -1) {
- ALOGE("%s recvfrom failed, errno=%d", __PRETTY_FUNCTION__, errno);
- return;
- }
-
- if (static_cast<size_t>(result) < sizeof(RetryPacket)) {
- ALOGW("%s short packet received", __PRETTY_FUNCTION__);
- return;
- }
-
- uint32_t host_request_id = ntohl(request.id);
- if ((host_request_id != kRetryRequestID) &&
- (host_request_id != kFastStartRequestID)) {
- ALOGW("%s received retry request with bogus ID (%08x)",
- __PRETTY_FUNCTION__, host_request_id);
- return;
- }
-
- Endpoint endpoint(request.endpointIP, request.endpointPort);
-
- Mutex::Autolock lock(mSender->mEndpointLock);
-
- EndpointState* eps = mSender->mEndpointMap.valueFor(endpoint);
-
- if (eps == NULL || eps->retry.isEmpty()) {
- // we have no retry buffer or an empty retry buffer for this endpoint,
- // so NAK the entire request
- RetryPacket nak = request;
- nak.id = htonl(kRetryNakID);
- result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
- &requestSrcAddr, requestSrcAddrLen);
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
- return;
- }
-
- RetryBuffer& retry = eps->retry;
-
- uint16_t startSeq = ntohs(request.seqStart);
- uint16_t endSeq = ntohs(request.seqEnd);
-
- uint16_t retryFirstSeq = retry[0]->getSeqNumber();
- uint16_t retryLastSeq = retry[retry.size() - 1]->getSeqNumber();
-
- // If this is a fast start, then force the start of the retry to match the
- // start of the retransmit ring buffer (unless the end of the retransmit
- // ring buffer is already past the point of fast start)
- if ((host_request_id == kFastStartRequestID) &&
- !((startSeq - retryFirstSeq) & 0x8000)) {
- startSeq = retryFirstSeq;
- }
-
- int startIndex;
- if (withinIntervalWithRollover(startSeq, retryFirstSeq, retryLastSeq)) {
- startIndex = static_cast<uint16_t>(startSeq - retryFirstSeq);
- } else {
- startIndex = -1;
- }
-
- int endIndex;
- if (withinIntervalWithRollover(endSeq, retryFirstSeq, retryLastSeq)) {
- endIndex = static_cast<uint16_t>(endSeq - retryFirstSeq);
- } else {
- endIndex = -1;
- }
-
- if (startIndex == -1 && endIndex == -1) {
- // no part of the request range is found in the retry buffer
- RetryPacket nak = request;
- nak.id = htonl(kRetryNakID);
- result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
- &requestSrcAddr, requestSrcAddrLen);
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
- return;
- }
-
- if (startIndex == -1) {
- // NAK a subrange at the front of the request range
- RetryPacket nak = request;
- nak.id = htonl(kRetryNakID);
- nak.seqEnd = htons(retryFirstSeq - 1);
- result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
- &requestSrcAddr, requestSrcAddrLen);
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
-
- startIndex = 0;
- } else if (endIndex == -1) {
- // NAK a subrange at the back of the request range
- RetryPacket nak = request;
- nak.id = htonl(kRetryNakID);
- nak.seqStart = htons(retryLastSeq + 1);
- result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
- &requestSrcAddr, requestSrcAddrLen);
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
-
- endIndex = retry.size() - 1;
- }
-
- // send the retry packets
- for (int i = startIndex; i <= endIndex; i++) {
- const sp<TRTPPacket>& replyPacket = retry[i];
-
- result = sendto(mSender->mSocket,
- replyPacket->getPacket(),
- replyPacket->getPacketLen(),
- 0,
- &requestSrcAddr,
- requestSrcAddrLen);
-
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
- }
-}
-
-// Endpoint
-
-AAH_TXSender::Endpoint::Endpoint()
- : addr(0)
- , port(0) { }
-
-AAH_TXSender::Endpoint::Endpoint(uint32_t a, uint16_t p)
- : addr(a)
- , port(p) {}
-
-bool AAH_TXSender::Endpoint::operator<(const Endpoint& other) const {
- return ((addr < other.addr) ||
- (addr == other.addr && port < other.port));
-}
-
-// EndpointState
-
-AAH_TXSender::EndpointState::EndpointState(uint32_t _epoch)
- : retry(kRetryBufferCapacity)
- , playerRefCount(1)
- , trtpSeqNumber(0)
- , nextProgramID(0)
- , epoch(_epoch) { }
-
-// CircularBuffer
-
-template <typename T>
-CircularBuffer<T>::CircularBuffer(size_t capacity)
- : mCapacity(capacity)
- , mHead(0)
- , mTail(0)
- , mFillCount(0) {
- mBuffer = new T[capacity];
-}
-
-template <typename T>
-CircularBuffer<T>::~CircularBuffer() {
- delete [] mBuffer;
-}
-
-template <typename T>
-void CircularBuffer<T>::push_back(const T& item) {
- if (this->isFull()) {
- this->pop_front();
- }
- mBuffer[mHead] = item;
- mHead = (mHead + 1) % mCapacity;
- mFillCount++;
-}
-
-template <typename T>
-void CircularBuffer<T>::pop_front() {
- CHECK(!isEmpty());
- mBuffer[mTail] = T();
- mTail = (mTail + 1) % mCapacity;
- mFillCount--;
-}
-
-template <typename T>
-size_t CircularBuffer<T>::size() const {
- return mFillCount;
-}
-
-template <typename T>
-bool CircularBuffer<T>::isFull() const {
- return (mFillCount == mCapacity);
-}
-
-template <typename T>
-bool CircularBuffer<T>::isEmpty() const {
- return (mFillCount == 0);
-}
-
-template <typename T>
-const T& CircularBuffer<T>::itemAt(size_t index) const {
- CHECK(index < mFillCount);
- return mBuffer[(mTail + index) % mCapacity];
-}
-
-template <typename T>
-const T& CircularBuffer<T>::operator[](size_t index) const {
- return itemAt(index);
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_tx_sender.h b/media/libaah_rtp/aah_tx_sender.h
deleted file mode 100644
index 74206c4..0000000
--- a/media/libaah_rtp/aah_tx_sender.h
+++ /dev/null
@@ -1,162 +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.
- */
-
-#ifndef __AAH_TX_SENDER_H__
-#define __AAH_TX_SENDER_H__
-
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-
-#include "aah_tx_packet.h"
-#include "pipe_event.h"
-
-namespace android {
-
-template <typename T> class CircularBuffer {
- public:
- CircularBuffer(size_t capacity);
- ~CircularBuffer();
- void push_back(const T& item);;
- void pop_front();
- size_t size() const;
- bool isFull() const;
- bool isEmpty() const;
- const T& itemAt(size_t index) const;
- const T& operator[](size_t index) const;
-
- private:
- T* mBuffer;
- size_t mCapacity;
- size_t mHead;
- size_t mTail;
- size_t mFillCount;
-
- DISALLOW_EVIL_CONSTRUCTORS(CircularBuffer);
-};
-
-class AAH_TXSender : public virtual RefBase {
- public:
- ~AAH_TXSender();
-
- static sp<AAH_TXSender> GetInstance();
-
- ALooper::handler_id handlerID() { return mReflector->id(); }
-
- // an IP address and port
- struct Endpoint {
- Endpoint();
- Endpoint(uint32_t a, uint16_t p);
- bool operator<(const Endpoint& other) const;
-
- uint32_t addr;
- uint16_t port;
- };
-
- uint16_t registerEndpoint(const Endpoint& endpoint);
- void unregisterEndpoint(const Endpoint& endpoint);
-
- enum {
- kWhatSendPacket,
- kWhatTrimRetryBuffers,
- kWhatSendHeartbeats,
- };
-
- // fields for SendPacket messages
- static const char* kSendPacketIPAddr;
- static const char* kSendPacketPort;
- static const char* kSendPacketTRTPPacket;
-
- private:
- AAH_TXSender();
-
- static Mutex sLock;
- static wp<AAH_TXSender> sInstance;
- static uint32_t sNextEpoch;
- static bool sNextEpochValid;
-
- static uint32_t getNextEpoch();
-
- typedef CircularBuffer<sp<TRTPPacket> > RetryBuffer;
-
- // state maintained on a per-endpoint basis
- struct EndpointState {
- EndpointState(uint32_t epoch);
- RetryBuffer retry;
- int playerRefCount;
- uint16_t trtpSeqNumber;
- uint16_t nextProgramID;
- uint32_t epoch;
- };
-
- friend class AHandlerReflector<AAH_TXSender>;
- void onMessageReceived(const sp<AMessage>& msg);
- void onSendPacket(const sp<AMessage>& msg);
- void doSendPacket_l(const sp<TRTPPacket>& packet,
- const Endpoint& endpoint);
- void trimRetryBuffers();
- void sendHeartbeats();
- bool shouldSendHeartbeats_l();
-
- sp<ALooper> mLooper;
- sp<AHandlerReflector<AAH_TXSender> > mReflector;
-
- int mSocket;
- nsecs_t mLastSentPacketTime;
-
- DefaultKeyedVector<Endpoint, EndpointState*> mEndpointMap;
- Mutex mEndpointLock;
-
- static const int kRetryTrimIntervalUs;
- static const int kHeartbeatIntervalUs;
- static const int kRetryBufferCapacity;
- static const nsecs_t kHeartbeatTimeout;
-
- class RetryReceiver : public Thread {
- private:
- friend class AAH_TXSender;
-
- RetryReceiver(AAH_TXSender* sender);
- virtual ~RetryReceiver();
- virtual bool threadLoop();
- void handleRetryRequest();
-
- static const int kMaxReceiverPacketLen;
- static const uint32_t kRetryRequestID;
- static const uint32_t kFastStartRequestID;
- static const uint32_t kRetryNakID;
-
- AAH_TXSender* mSender;
- PipeEvent mWakeupEvent;
- };
-
- sp<RetryReceiver> mRetryReceiver;
-
- DISALLOW_EVIL_CONSTRUCTORS(AAH_TXSender);
-};
-
-struct RetryPacket {
- uint32_t id;
- uint32_t endpointIP;
- uint16_t endpointPort;
- uint16_t seqStart;
- uint16_t seqEnd;
-} __attribute__((packed));
-
-} // namespace android
-
-#endif // __AAH_TX_SENDER_H__
diff --git a/media/libaah_rtp/pipe_event.cpp b/media/libaah_rtp/pipe_event.cpp
deleted file mode 100644
index b8e6960..0000000
--- a/media/libaah_rtp/pipe_event.cpp
+++ /dev/null
@@ -1,86 +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>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <unistd.h>
-
-#include "pipe_event.h"
-
-namespace android {
-
-PipeEvent::PipeEvent() {
- pipe_[0] = -1;
- pipe_[1] = -1;
-
- // Create the pipe.
- if (pipe(pipe_) >= 0) {
- // Set non-blocking mode on the read side of the pipe so we can
- // easily drain it whenever we wakeup.
- fcntl(pipe_[0], F_SETFL, O_NONBLOCK);
- } else {
- ALOGE("Failed to create pipe event %d %d %d",
- pipe_[0], pipe_[1], errno);
- pipe_[0] = -1;
- pipe_[1] = -1;
- }
-}
-
-PipeEvent::~PipeEvent() {
- if (pipe_[0] >= 0) {
- close(pipe_[0]);
- }
-
- if (pipe_[1] >= 0) {
- close(pipe_[1]);
- }
-}
-
-void PipeEvent::clearPendingEvents() {
- char drain_buffer[16];
- while (read(pipe_[0], drain_buffer, sizeof(drain_buffer)) > 0) {
- // No body.
- }
-}
-
-bool PipeEvent::wait(int timeout) {
- struct pollfd wait_fd;
-
- wait_fd.fd = getWakeupHandle();
- wait_fd.events = POLLIN;
- wait_fd.revents = 0;
-
- int res = poll(&wait_fd, 1, timeout);
-
- if (res < 0) {
- ALOGE("Wait error in PipeEvent; sleeping to prevent overload!");
- usleep(1000);
- }
-
- return (res > 0);
-}
-
-void PipeEvent::setEvent() {
- char foo = 'q';
- write(pipe_[1], &foo, 1);
-}
-
-} // namespace android
-
diff --git a/media/libaah_rtp/pipe_event.h b/media/libaah_rtp/pipe_event.h
deleted file mode 100644
index e53b0fd..0000000
--- a/media/libaah_rtp/pipe_event.h
+++ /dev/null
@@ -1,51 +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.
- */
-
-#ifndef __PIPE_EVENT_H__
-#define __PIPE_EVENT_H__
-
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-class PipeEvent {
- public:
- PipeEvent();
- ~PipeEvent();
-
- bool initCheck() const {
- return ((pipe_[0] >= 0) && (pipe_[1] >= 0));
- }
-
- int getWakeupHandle() const { return pipe_[0]; }
-
- // block until the event fires; returns true if the event fired and false if
- // the wait timed out. Timeout is expressed in milliseconds; negative
- // values mean wait forever.
- bool wait(int timeout = -1);
-
- void clearPendingEvents();
- void setEvent();
-
- private:
- int pipe_[2];
-
- DISALLOW_EVIL_CONSTRUCTORS(PipeEvent);
-};
-
-} // namespace android
-
-#endif // __PIPE_EVENT_H__
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index e3134d1..1373d3c 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -32,8 +32,7 @@ LOCAL_SHARED_LIBRARIES := \
libstagefright_omx \
libstagefright_foundation \
libgui \
- libdl \
- libaah_rtp
+ libdl
LOCAL_STATIC_LIBRARIES := \
libstagefright_nuplayer \
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index dcb347f..f821cc3 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -33,9 +33,6 @@
namespace android {
-extern sp<MediaPlayerBase> createAAH_TXPlayer();
-extern sp<MediaPlayerBase> createAAH_RXPlayer();
-
Mutex MediaPlayerFactory::sLock;
MediaPlayerFactory::tFactoryMap MediaPlayerFactory::sFactoryMap;
bool MediaPlayerFactory::sInitComplete = false;
@@ -325,63 +322,6 @@ class TestPlayerFactory : public MediaPlayerFactory::IFactory {
}
};
-class AAH_RX_PlayerFactory : public MediaPlayerFactory::IFactory {
- public:
- virtual float scoreFactory(const sp<IMediaPlayer>& client,
- const char* url,
- float curScore) {
- static const float kOurScore = 0.6;
-
- if (kOurScore <= curScore)
- return 0.0;
-
- if (!strncasecmp("aahRX://", url, 8)) {
- return kOurScore;
- }
-
- return 0.0;
- }
-
- virtual sp<MediaPlayerBase> createPlayer() {
- ALOGV(" create A@H RX Player");
- return createAAH_RXPlayer();
- }
-};
-
-class AAH_TX_PlayerFactory : public MediaPlayerFactory::IFactory {
- public:
- virtual float scoreFactory(const sp<IMediaPlayer>& client,
- const char* url,
- float curScore) {
- return checkRetransmitEndpoint(client) ? 1.1 : 0.0;
- }
-
- virtual float scoreFactory(const sp<IMediaPlayer>& client,
- int fd,
- int64_t offset,
- int64_t length,
- float curScore) {
- return checkRetransmitEndpoint(client) ? 1.1 : 0.0;
- }
-
- virtual sp<MediaPlayerBase> createPlayer() {
- ALOGV(" create A@H TX Player");
- return createAAH_TXPlayer();
- }
-
- private:
- bool checkRetransmitEndpoint(const sp<IMediaPlayer>& client) {
- if (client == NULL)
- return false;
-
- struct sockaddr_in junk;
- if (OK != client->getRetransmitEndpoint(&junk))
- return false;
-
- return true;
- }
-};
-
void MediaPlayerFactory::registerBuiltinFactories() {
Mutex::Autolock lock_(&sLock);
@@ -393,11 +333,6 @@ void MediaPlayerFactory::registerBuiltinFactories() {
registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
- // TODO: remove this once AAH players have been relocated from
- // framework/base and into vendor/google_devices/phantasm
- registerFactory_l(new AAH_RX_PlayerFactory(), AAH_RX_PLAYER);
- registerFactory_l(new AAH_TX_PlayerFactory(), AAH_TX_PLAYER);
-
sInitComplete = true;
}