1fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber/* 2fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * Copyright 2012, The Android Open Source Project 3fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * 4fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * you may not use this file except in compliance with the License. 6fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * You may obtain a copy of the License at 7fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * 8fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * 10fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * Unless required by applicable law or agreed to in writing, software 11fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * See the License for the specific language governing permissions and 14fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * limitations under the License. 15fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber */ 16fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 17fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber//#define LOG_NDEBUG 0 18fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#define LOG_TAG "TunnelRenderer" 19fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <utils/Log.h> 20fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 21fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include "TunnelRenderer.h" 22fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 23fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include "ATSParser.h" 24fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 25fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <binder/IMemory.h> 26fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <binder/IServiceManager.h> 27fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <gui/SurfaceComposerClient.h> 28fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/IMediaPlayerService.h> 29fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/IStreamSource.h> 30fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/foundation/ABuffer.h> 31fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/foundation/ADebug.h> 32fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/foundation/AMessage.h> 33fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <ui/DisplayInfo.h> 34fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 35fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubernamespace android { 36fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 37fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstruct TunnelRenderer::PlayerClient : public BnMediaPlayerClient { 38fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber PlayerClient() {} 39fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 40fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) { 41fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("notify %d, %d, %d", msg, ext1, ext2); 42fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 43fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 44fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberprotected: 45fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber virtual ~PlayerClient() {} 46fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 47fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberprivate: 48fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber DISALLOW_EVIL_CONSTRUCTORS(PlayerClient); 49fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber}; 50fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 51fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstruct TunnelRenderer::StreamSource : public BnStreamSource { 52fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber StreamSource(TunnelRenderer *owner); 53fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 54fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber virtual void setListener(const sp<IStreamListener> &listener); 55fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber virtual void setBuffers(const Vector<sp<IMemory> > &buffers); 56fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 57fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber virtual void onBufferAvailable(size_t index); 58fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 59fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber virtual uint32_t flags() const; 60fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 61fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber void doSomeWork(); 62fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 63fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberprotected: 64fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber virtual ~StreamSource(); 65fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 66fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberprivate: 67fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mutable Mutex mLock; 68fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 69fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber TunnelRenderer *mOwner; 70fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 71fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<IStreamListener> mListener; 72fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 73fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber Vector<sp<IMemory> > mBuffers; 74fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber List<size_t> mIndicesAvailable; 75fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 76fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t mNumDeqeued; 77fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 78fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber DISALLOW_EVIL_CONSTRUCTORS(StreamSource); 79fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber}; 80fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 81fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber//////////////////////////////////////////////////////////////////////////////// 82fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 83fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas HuberTunnelRenderer::StreamSource::StreamSource(TunnelRenderer *owner) 84fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber : mOwner(owner), 85fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNumDeqeued(0) { 86fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 87fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 88fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas HuberTunnelRenderer::StreamSource::~StreamSource() { 89fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 90fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 91fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid TunnelRenderer::StreamSource::setListener( 92fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const sp<IStreamListener> &listener) { 93fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mListener = listener; 94fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 95fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 96fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid TunnelRenderer::StreamSource::setBuffers( 97fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const Vector<sp<IMemory> > &buffers) { 98fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mBuffers = buffers; 99fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 100fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 101fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid TunnelRenderer::StreamSource::onBufferAvailable(size_t index) { 102fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK_LT(index, mBuffers.size()); 103fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 104fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 105fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber Mutex::Autolock autoLock(mLock); 106fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mIndicesAvailable.push_back(index); 107fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 108fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 109fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber doSomeWork(); 110fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 111fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 112fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberuint32_t TunnelRenderer::StreamSource::flags() const { 113fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return kFlagAlignedVideoData; 114fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 115fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 116fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid TunnelRenderer::StreamSource::doSomeWork() { 117fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber Mutex::Autolock autoLock(mLock); 118fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 119fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber while (!mIndicesAvailable.empty()) { 120fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<ABuffer> srcBuffer = mOwner->dequeueBuffer(); 121fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (srcBuffer == NULL) { 122fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 123fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 124fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 125fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ++mNumDeqeued; 126fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 127fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mNumDeqeued == 1) { 128fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("fixing real time now."); 129fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 130fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> extra = new AMessage; 131fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 132fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber extra->setInt32( 133fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber IStreamListener::kKeyDiscontinuityMask, 134fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ATSParser::DISCONTINUITY_ABSOLUTE_TIME); 135fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 136fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber extra->setInt64("timeUs", ALooper::GetNowUs()); 137fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 138fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mListener->issueCommand( 139fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber IStreamListener::DISCONTINUITY, 140fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber false /* synchronous */, 141fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber extra); 142fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 143fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 144fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGV("dequeue TS packet of size %d", srcBuffer->size()); 145fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 146fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t index = *mIndicesAvailable.begin(); 147fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mIndicesAvailable.erase(mIndicesAvailable.begin()); 148fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 149fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<IMemory> mem = mBuffers.itemAt(index); 150fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK_LE(srcBuffer->size(), mem->size()); 151fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK_EQ((srcBuffer->size() % 188), 0u); 152fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 153fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber memcpy(mem->pointer(), srcBuffer->data(), srcBuffer->size()); 154fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mListener->queueBuffer(index, srcBuffer->size()); 155fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 156fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 157fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 158fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber//////////////////////////////////////////////////////////////////////////////// 159fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 160fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas HuberTunnelRenderer::TunnelRenderer( 161fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const sp<AMessage> ¬ifyLost, 162fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const sp<ISurfaceTexture> &surfaceTex) 163fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber : mNotifyLost(notifyLost), 164fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSurfaceTex(surfaceTex), 165fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mTotalBytesQueued(0ll), 166fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mLastDequeuedExtSeqNo(-1), 167fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mFirstFailedAttemptUs(-1ll), 168fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRequestedRetransmission(false) { 169fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 170fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 171fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas HuberTunnelRenderer::~TunnelRenderer() { 172fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber destroyPlayer(); 173fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 174fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 175fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid TunnelRenderer::queueBuffer(const sp<ABuffer> &buffer) { 176fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber Mutex::Autolock autoLock(mLock); 177fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 178fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mTotalBytesQueued += buffer->size(); 179fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 180fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mPackets.empty()) { 181fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPackets.push_back(buffer); 182fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return; 183fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 184fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 185fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t newExtendedSeqNo = buffer->int32Data(); 186fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 187fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber List<sp<ABuffer> >::iterator firstIt = mPackets.begin(); 188fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber List<sp<ABuffer> >::iterator it = --mPackets.end(); 189fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber for (;;) { 190fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t extendedSeqNo = (*it)->int32Data(); 191fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 192fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (extendedSeqNo == newExtendedSeqNo) { 193fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Duplicate packet. 194fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return; 195fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 196fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 197fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (extendedSeqNo < newExtendedSeqNo) { 198fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Insert new packet after the one at "it". 199fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPackets.insert(++it, buffer); 200fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return; 201fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 202fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 203fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (it == firstIt) { 204fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Insert new packet before the first existing one. 205fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPackets.insert(it, buffer); 206fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return; 207fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 208fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 209fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber --it; 210fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 211fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 212fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 213fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubersp<ABuffer> TunnelRenderer::dequeueBuffer() { 214fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber Mutex::Autolock autoLock(mLock); 215fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 216fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<ABuffer> buffer; 217fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t extSeqNo; 218fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber while (!mPackets.empty()) { 219fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buffer = *mPackets.begin(); 220fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber extSeqNo = buffer->int32Data(); 221fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 222fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mLastDequeuedExtSeqNo < 0 || extSeqNo > mLastDequeuedExtSeqNo) { 223fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 224fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 225fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 226fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // This is a retransmission of a packet we've already returned. 227fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 228fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mTotalBytesQueued -= buffer->size(); 229fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buffer.clear(); 230fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber extSeqNo = -1; 231fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 232fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPackets.erase(mPackets.begin()); 233fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 234fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 235fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mPackets.empty()) { 236fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mFirstFailedAttemptUs < 0ll) { 237fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mFirstFailedAttemptUs = ALooper::GetNowUs(); 238fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRequestedRetransmission = false; 239fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 240fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGV("no packets available for %.2f secs", 241fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber (ALooper::GetNowUs() - mFirstFailedAttemptUs) / 1E6); 242fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 243fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 244fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return NULL; 245fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 246fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 247fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mLastDequeuedExtSeqNo < 0 || extSeqNo == mLastDequeuedExtSeqNo + 1) { 248fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mRequestedRetransmission) { 249fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("Recovered after requesting retransmission of %d", 250fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber extSeqNo); 251fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 252fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 253fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mLastDequeuedExtSeqNo = extSeqNo; 254fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mFirstFailedAttemptUs = -1ll; 255fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRequestedRetransmission = false; 256fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 257fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPackets.erase(mPackets.begin()); 258fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 259fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mTotalBytesQueued -= buffer->size(); 260fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 261fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return buffer; 262fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 263fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 264fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mFirstFailedAttemptUs < 0ll) { 265fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mFirstFailedAttemptUs = ALooper::GetNowUs(); 266fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 267fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("failed to get the correct packet the first time."); 268fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return NULL; 269fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 270fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 271fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mFirstFailedAttemptUs + 50000ll > ALooper::GetNowUs()) { 272fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // We're willing to wait a little while to get the right packet. 273fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 274fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (!mRequestedRetransmission) { 275fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("requesting retransmission of seqNo %d", 276fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber (mLastDequeuedExtSeqNo + 1) & 0xffff); 277fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 278fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> notify = mNotifyLost->dup(); 279fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber notify->setInt32("seqNo", (mLastDequeuedExtSeqNo + 1) & 0xffff); 280fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber notify->post(); 281fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 282fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRequestedRetransmission = true; 283fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 284fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("still waiting for the correct packet to arrive."); 285fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 286fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 287fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return NULL; 288fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 289fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 290fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("dropping packet. extSeqNo %d didn't arrive in time", 291fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mLastDequeuedExtSeqNo + 1); 292fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 293fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Permanent failure, we never received the packet. 294fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mLastDequeuedExtSeqNo = extSeqNo; 295fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mFirstFailedAttemptUs = -1ll; 296fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRequestedRetransmission = false; 297fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 298fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mTotalBytesQueued -= buffer->size(); 299fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 300fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPackets.erase(mPackets.begin()); 301fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 302fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return buffer; 303fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 304fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 305fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid TunnelRenderer::onMessageReceived(const sp<AMessage> &msg) { 306fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber switch (msg->what()) { 307fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case kWhatQueueBuffer: 308fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 309fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<ABuffer> buffer; 310fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findBuffer("buffer", &buffer)); 311fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 312fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber queueBuffer(buffer); 313fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 314fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mStreamSource == NULL) { 315fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mTotalBytesQueued > 0ll) { 316fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber initPlayer(); 317fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 318fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("Have %lld bytes queued...", mTotalBytesQueued); 319fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 320fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 321fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mStreamSource->doSomeWork(); 322fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 323fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 324fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 325fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 326fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber default: 327fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber TRESPASS(); 328fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 329fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 330fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 331fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid TunnelRenderer::initPlayer() { 332fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mSurfaceTex == NULL) { 333fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mComposerClient = new SurfaceComposerClient; 334fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK_EQ(mComposerClient->initCheck(), (status_t)OK); 335fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 336fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber DisplayInfo info; 337fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber SurfaceComposerClient::getDisplayInfo(0, &info); 338fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ssize_t displayWidth = info.w; 339fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ssize_t displayHeight = info.h; 340fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 341fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSurfaceControl = 342fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mComposerClient->createSurface( 343fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber String8("A Surface"), 344fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber displayWidth, 345fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber displayHeight, 346fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber PIXEL_FORMAT_RGB_565, 347fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 0); 348fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 349fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(mSurfaceControl != NULL); 350fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(mSurfaceControl->isValid()); 351fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 352fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber SurfaceComposerClient::openGlobalTransaction(); 353fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK_EQ(mSurfaceControl->setLayer(INT_MAX), (status_t)OK); 354fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK_EQ(mSurfaceControl->show(), (status_t)OK); 355fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber SurfaceComposerClient::closeGlobalTransaction(); 356fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 357fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSurface = mSurfaceControl->getSurface(); 358fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(mSurface != NULL); 359fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 360fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 361fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<IServiceManager> sm = defaultServiceManager(); 362fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<IBinder> binder = sm->getService(String16("media.player")); 363fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 364fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(service.get() != NULL); 365fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 366fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mStreamSource = new StreamSource(this); 367fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 368fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPlayerClient = new PlayerClient; 369fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 370fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPlayer = service->create(getpid(), mPlayerClient, 0); 371fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(mPlayer != NULL); 372fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK_EQ(mPlayer->setDataSource(mStreamSource), (status_t)OK); 373fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 374fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPlayer->setVideoSurfaceTexture( 375fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSurfaceTex != NULL ? mSurfaceTex : mSurface->getSurfaceTexture()); 376fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 377fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPlayer->start(); 378fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 379fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 380fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid TunnelRenderer::destroyPlayer() { 381fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mStreamSource.clear(); 382fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 383fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPlayer->stop(); 384fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPlayer.clear(); 385fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 386fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mSurfaceTex == NULL) { 387fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSurface.clear(); 388fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSurfaceControl.clear(); 389fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 390fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mComposerClient->dispose(); 391fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mComposerClient.clear(); 392fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 393fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 394fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 395fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} // namespace android 396fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 397