PlaybackSession.cpp revision 0b73d4730202fcad53aefc4314a06e7b95f442f0
1d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber/* 2d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * Copyright 2012, The Android Open Source Project 3d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * 4d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * you may not use this file except in compliance with the License. 6d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * You may obtain a copy of the License at 7d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * 8d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * 10d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * Unless required by applicable law or agreed to in writing, software 11d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * See the License for the specific language governing permissions and 14d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber * limitations under the License. 15d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber */ 16d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 17d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber//#define LOG_NDEBUG 0 18d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#define LOG_TAG "PlaybackSession" 19d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <utils/Log.h> 20d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 21d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include "PlaybackSession.h" 22d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 23d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include "Converter.h" 24d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include "RepeaterSource.h" 25d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include "Serializer.h" 26d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include "TSPacketizer.h" 27d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 28d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <binder/IServiceManager.h> 29d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <gui/ISurfaceComposer.h> 30d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <gui/SurfaceComposerClient.h> 31d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/foundation/ABuffer.h> 32d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/foundation/ADebug.h> 33d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/foundation/AMessage.h> 34d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/foundation/hexdump.h> 35082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber#include <media/stagefright/AudioSource.h> 36d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/DataSource.h> 37d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/MediaDefs.h> 38d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/MediaErrors.h> 39d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/MediaExtractor.h> 40d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/MediaSource.h> 41d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/MetaData.h> 42d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/MPEG2TSWriter.h> 43d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/SurfaceMediaSource.h> 44d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <media/stagefright/Utils.h> 45d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <ui/DisplayInfo.h> 46d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 47d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#include <OMX_IVCommon.h> 48d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 49d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#define FAKE_VIDEO 0 50d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 51d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubernamespace android { 52d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 53d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstatic size_t kMaxRTPPacketSize = 1500; 54d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstatic size_t kMaxNumTSPacketsPerRTPPacket = (kMaxRTPPacketSize - 12) / 188; 55d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 56d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstruct WifiDisplaySource::PlaybackSession::Track : public RefBase { 57d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber Track(const sp<Converter> &converter); 58d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber Track(const sp<AMessage> &format); 59d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 60d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> getFormat(); 61d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 62d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const sp<Converter> &converter() const; 63d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ssize_t packetizerTrackIndex() const; 64d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 65d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber void setPacketizerTrackIndex(size_t index); 66d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 67d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberprotected: 68d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber virtual ~Track(); 69d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 70d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberprivate: 71d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<Converter> mConverter; 72d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> mFormat; 73d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ssize_t mPacketizerTrackIndex; 74d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 75d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber DISALLOW_EVIL_CONSTRUCTORS(Track); 76d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber}; 77d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 78d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas HuberWifiDisplaySource::PlaybackSession::Track::Track(const sp<Converter> &converter) 79d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber : mConverter(converter), 80d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPacketizerTrackIndex(-1) { 81d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 82d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 83d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas HuberWifiDisplaySource::PlaybackSession::Track::Track(const sp<AMessage> &format) 84d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber : mFormat(format), 85d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPacketizerTrackIndex(-1) { 86d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 87d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 88d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas HuberWifiDisplaySource::PlaybackSession::Track::~Track() { 89d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 90d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 91d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubersp<AMessage> WifiDisplaySource::PlaybackSession::Track::getFormat() { 92d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mFormat != NULL) { 93d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return mFormat; 94d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 95d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 96d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return mConverter->getOutputFormat(); 97d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 98d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 99d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberconst sp<Converter> &WifiDisplaySource::PlaybackSession::Track::converter() const { 100d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return mConverter; 101d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 102d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 103d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberssize_t WifiDisplaySource::PlaybackSession::Track::packetizerTrackIndex() const { 104d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return mPacketizerTrackIndex; 105d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 106d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 107d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubervoid WifiDisplaySource::PlaybackSession::Track::setPacketizerTrackIndex(size_t index) { 108d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_LT(mPacketizerTrackIndex, 0); 109d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPacketizerTrackIndex = index; 110d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 111d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 112d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber//////////////////////////////////////////////////////////////////////////////// 113d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 114d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas HuberWifiDisplaySource::PlaybackSession::PlaybackSession( 115d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const sp<ANetworkSession> &netSession, 1160b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber const sp<AMessage> ¬ify, 1170b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber bool legacyMode) 118d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber : mNetSession(netSession), 119d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNotify(notify), 1200b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber mLegacyMode(legacyMode), 121d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mLastLifesignUs(), 122d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTSQueue(new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188)), 123d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPrevTimeUs(-1ll), 124d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mUseInterleavedTCP(false), 125d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPChannel(0), 126d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPChannel(0), 127d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPPort(0), 128d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPSessionID(0), 129d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPSessionID(0), 130d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPSeqNo(0), 131d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mLastNTPTime(0), 132d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mLastRTPTime(0), 133d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNumRTPSent(0), 134d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNumRTPOctetsSent(0), 135d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNumSRsSent(0), 136d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSendSRPending(false), 137d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mFirstPacketTimeUs(-1ll), 138774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber mHistoryLength(0) 139774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber#if LOG_TRANSPORT_STREAM 140774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber ,mLogFile(NULL) 141774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber#endif 142774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber{ 143d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTSQueue->setRange(0, 12); 144774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber 145774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber#if LOG_TRANSPORT_STREAM 146774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber mLogFile = fopen("/system/etc/log.ts", "wb"); 147774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber#endif 148d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 149d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 150d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstatus_t WifiDisplaySource::PlaybackSession::init( 151d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const char *clientIP, int32_t clientRtp, int32_t clientRtcp, 152d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber bool useInterleavedTCP) { 153d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber status_t err = setupPacketizer(); 154d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 155d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (err != OK) { 156d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return err; 157d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 158d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 159d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (useInterleavedTCP) { 160d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mUseInterleavedTCP = true; 161d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPChannel = clientRtp; 162d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPChannel = clientRtcp; 163d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPPort = 0; 164d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPSessionID = 0; 165d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPSessionID = 0; 166d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 167d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber updateLiveness(); 168d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return OK; 169d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 170d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 171d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mUseInterleavedTCP = false; 172d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPChannel = 0; 173d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPChannel = 0; 174d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 175d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int serverRtp; 176d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 177d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, id()); 178d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> rtcpNotify = new AMessage(kWhatRTCPNotify, id()); 179d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber for (serverRtp = 15550;; serverRtp += 2) { 180d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t rtpSession; 181d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber err = mNetSession->createUDPSession( 182d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber serverRtp, clientIP, clientRtp, 183d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtpNotify, &rtpSession); 184d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 185d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (err != OK) { 186d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("failed to create RTP socket on port %d", serverRtp); 187d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber continue; 188d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 189d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 190d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (clientRtcp < 0) { 191d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // No RTCP. 192d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 193d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPPort = serverRtp; 194d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPSessionID = rtpSession; 195d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPSessionID = 0; 196d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 197d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("rtpSessionId = %d", rtpSession); 198d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 199d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 200d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 201d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t rtcpSession; 202d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber err = mNetSession->createUDPSession( 203d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber serverRtp + 1, clientIP, clientRtcp, 204d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtcpNotify, &rtcpSession); 205d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 206d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (err == OK) { 207d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPPort = serverRtp; 208d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPSessionID = rtpSession; 209d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPSessionID = rtcpSession; 210d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 211d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("rtpSessionID = %d, rtcpSessionID = %d", rtpSession, rtcpSession); 212d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 213d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 214d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 215d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("failed to create RTCP socket on port %d", serverRtp + 1); 216d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNetSession->destroySession(rtpSession); 217d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 218d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 219d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mRTPPort == 0) { 220d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return UNKNOWN_ERROR; 221d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 222d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 223d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber updateLiveness(); 224d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 225d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return OK; 226d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 227d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 228d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas HuberWifiDisplaySource::PlaybackSession::~PlaybackSession() { 229774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber#if LOG_TRANSPORT_STREAM 230774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber if (mLogFile != NULL) { 231774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber fclose(mLogFile); 232774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber mLogFile = NULL; 233774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber } 234774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber#endif 235774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber 236d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTracks.clear(); 237d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 238d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mCodecLooper != NULL) { 239d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mCodecLooper->stop(); 240d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mCodecLooper.clear(); 241d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 242d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 243d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPacketizer.clear(); 244d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 245d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mSerializer != NULL) { 246d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSerializer->stop(); 247d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 248d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber looper()->unregisterHandler(mSerializer->id()); 249d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSerializer.clear(); 250d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 251d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 252d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mSerializerLooper != NULL) { 253d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSerializerLooper->stop(); 254d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSerializerLooper.clear(); 255d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 256d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 2570b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber if (mLegacyMode) { 2580b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber sp<IServiceManager> sm = defaultServiceManager(); 2590b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber sp<IBinder> binder = sm->getService(String16("SurfaceFlinger")); 2600b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber sp<ISurfaceComposer> service = interface_cast<ISurfaceComposer>(binder); 2610b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber CHECK(service != NULL); 2620b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber 2630b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber service->connectDisplay(NULL); 2640b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber } 2652dff0f6a7bf06a878ad0890d93dc9c1ef0b5a107Andreas Huber 266d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mRTCPSessionID != 0) { 267d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNetSession->destroySession(mRTCPSessionID); 268d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 269d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 270d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mRTPSessionID != 0) { 271d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNetSession->destroySession(mRTPSessionID); 272d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 273d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 274d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 275d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberint32_t WifiDisplaySource::PlaybackSession::getRTPPort() const { 276d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return mRTPPort; 277d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 278d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 279d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberint64_t WifiDisplaySource::PlaybackSession::getLastLifesignUs() const { 280d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return mLastLifesignUs; 281d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 282d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 283d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubervoid WifiDisplaySource::PlaybackSession::updateLiveness() { 284d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mLastLifesignUs = ALooper::GetNowUs(); 285d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 286d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 287d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstatus_t WifiDisplaySource::PlaybackSession::play() { 288d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber updateLiveness(); 289d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 290d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mRTCPSessionID != 0) { 291d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber scheduleSendSR(); 292d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 293d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 294d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return mSerializer->start(); 295d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 296d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 297d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstatus_t WifiDisplaySource::PlaybackSession::pause() { 298d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber updateLiveness(); 299d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 300d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return OK; 301d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 302d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 303d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubervoid WifiDisplaySource::PlaybackSession::onMessageReceived( 304d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const sp<AMessage> &msg) { 305d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber switch (msg->what()) { 306d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case kWhatRTPNotify: 307d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case kWhatRTCPNotify: 308d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber { 309d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t reason; 310d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findInt32("reason", &reason)); 311d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 312d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber switch (reason) { 313d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case ANetworkSession::kWhatError: 314d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber { 315d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t sessionID; 316d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findInt32("sessionID", &sessionID)); 317d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 318d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t err; 319d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findInt32("err", &err)); 320d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 321d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t errorOccuredDuringSend; 322d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findInt32("send", &errorOccuredDuringSend)); 323d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 324d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber AString detail; 325d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findString("detail", &detail)); 326d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 327d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (msg->what() == kWhatRTPNotify 328d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber && !errorOccuredDuringSend) { 329d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // This is ok, we don't expect to receive anything on 330d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // the RTP socket. 331d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 332d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 333d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 334d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGE("An error occurred during %s in session %d " 335d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber "(%d, '%s' (%s)).", 336d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber errorOccuredDuringSend ? "send" : "receive", 337d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sessionID, 338d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber err, 339d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber detail.c_str(), 340d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber strerror(-err)); 341d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 342d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNetSession->destroySession(sessionID); 343d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 344d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (sessionID == mRTPSessionID) { 345d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPSessionID = 0; 346d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else if (sessionID == mRTCPSessionID) { 347d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPSessionID = 0; 348d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 349d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 350d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // Inform WifiDisplaySource of our premature death (wish). 351d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> notify = mNotify->dup(); 352d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->setInt32("what", kWhatSessionDead); 353d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->post(); 354d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 355d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 356d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 357d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case ANetworkSession::kWhatDatagram: 358d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber { 359d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t sessionID; 360d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findInt32("sessionID", &sessionID)); 361d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 362d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<ABuffer> data; 363d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findBuffer("data", &data)); 364d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 365d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber status_t err; 366d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (msg->what() == kWhatRTCPNotify) { 367d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber err = parseRTCP(data); 368d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 369d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 370d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 371d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 372d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber default: 373d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber TRESPASS(); 374d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 375d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 376d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 377d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 378d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case kWhatSendSR: 379d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber { 380d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSendSRPending = false; 381d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 382d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mRTCPSessionID == 0) { 383d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 384d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 385d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 386d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber onSendSR(); 387d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 388d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber scheduleSendSR(); 389d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 390d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 391d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 392d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case kWhatSerializerNotify: 393d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber { 394d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t what; 395d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findInt32("what", &what)); 396d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 397d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (what == Serializer::kWhatEOS) { 398d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("input eos"); 399d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 400d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber for (size_t i = 0; i < mTracks.size(); ++i) { 401d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#if FAKE_VIDEO 402d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> msg = new AMessage(kWhatConverterNotify, id()); 403d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber msg->setInt32("what", Converter::kWhatEOS); 404d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber msg->setSize("trackIndex", i); 405d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber msg->post(); 406d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#else 407d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTracks.valueAt(i)->converter()->signalEOS(); 408d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#endif 409d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 410d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else { 411d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_EQ(what, Serializer::kWhatAccessUnit); 412d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 413d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size_t trackIndex; 414d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findSize("trackIndex", &trackIndex)); 415d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 416d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<ABuffer> accessUnit; 417d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findBuffer("accessUnit", &accessUnit)); 418d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 419d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#if FAKE_VIDEO 420d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int64_t timeUs; 421d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); 422d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 423d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber void *mbuf; 424d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(accessUnit->meta()->findPointer("mediaBuffer", &mbuf)); 425d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 426d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ((MediaBuffer *)mbuf)->release(); 427d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mbuf = NULL; 428d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 429d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> msg = new AMessage(kWhatConverterNotify, id()); 430d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber msg->setInt32("what", Converter::kWhatAccessUnit); 431d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber msg->setSize("trackIndex", trackIndex); 432d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber msg->setBuffer("accessUnit", accessUnit); 433d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber msg->post(); 434d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#else 435d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTracks.valueFor(trackIndex)->converter() 436d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ->feedAccessUnit(accessUnit); 437d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#endif 438d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 439d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 440d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 441d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 442d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case kWhatConverterNotify: 443d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber { 444d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int32_t what; 445d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findInt32("what", &what)); 446d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 447d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size_t trackIndex; 448d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findSize("trackIndex", &trackIndex)); 449d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 450d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (what == Converter::kWhatAccessUnit) { 451d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const sp<Track> &track = mTracks.valueFor(trackIndex); 452d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 453d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint32_t flags = 0; 454d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 455d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ssize_t packetizerTrackIndex = track->packetizerTrackIndex(); 456d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (packetizerTrackIndex < 0) { 457d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber flags = TSPacketizer::EMIT_PAT_AND_PMT; 458d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 459d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber packetizerTrackIndex = 460d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPacketizer->addTrack(track->getFormat()); 461d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 462d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (packetizerTrackIndex >= 0) { 463d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber track->setPacketizerTrackIndex(packetizerTrackIndex); 464d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 465d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 466d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 467d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (packetizerTrackIndex >= 0) { 468d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<ABuffer> accessUnit; 469d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findBuffer("accessUnit", &accessUnit)); 470d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 471d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int64_t timeUs; 472d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); 473d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 474d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll >= timeUs) { 475d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber flags |= TSPacketizer::EMIT_PCR; 476d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPrevTimeUs = timeUs; 477d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 478d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 479d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<ABuffer> packets; 480d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPacketizer->packetize( 481d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber packetizerTrackIndex, accessUnit, &packets, flags); 482d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 483d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber for (size_t offset = 0; 484d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber offset < packets->size(); offset += 188) { 485d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber bool lastTSPacket = (offset + 188 >= packets->size()); 486d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 487d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber appendTSData( 488d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber packets->data() + offset, 489d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 188, 490d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber true /* timeDiscontinuity */, 491d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber lastTSPacket /* flush */); 492d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 493774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber 494774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber#if LOG_TRANSPORT_STREAM 495774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber if (mLogFile != NULL) { 496774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber fwrite(packets->data(), 1, packets->size(), mLogFile); 497774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber } 498774df0dce0116c69b6d17f2e4a4912e06138e575Andreas Huber#endif 499d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 500d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else if (what == Converter::kWhatEOS) { 501d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_EQ(what, Converter::kWhatEOS); 502d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 503d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("output EOS on track %d", trackIndex); 504d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 505d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ssize_t index = mTracks.indexOfKey(trackIndex); 506d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_GE(index, 0); 507d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 508d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#if !FAKE_VIDEO 509d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const sp<Converter> &converter = 510d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTracks.valueAt(index)->converter(); 511d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber looper()->unregisterHandler(converter->id()); 512d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#endif 513d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 514d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTracks.removeItemsAt(index); 515d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 516d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mTracks.isEmpty()) { 517d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("Reached EOS"); 518d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 519d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else { 520d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_EQ(what, Converter::kWhatError); 521d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 522d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber status_t err; 523d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(msg->findInt32("err", &err)); 524d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 525d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGE("converter signaled error %d", err); 526d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 527d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 528d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 529d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 530d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber default: 531d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber TRESPASS(); 532d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 533d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 534d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 535d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstatus_t WifiDisplaySource::PlaybackSession::setupPacketizer() { 536d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> msg = new AMessage(kWhatSerializerNotify, id()); 537d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 538d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSerializerLooper = new ALooper; 539d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSerializerLooper->start(); 540d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 541d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSerializer = new Serializer( 542d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#if FAKE_VIDEO 543d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber true /* throttled */ 544d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#else 545d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber false /* throttled */ 546d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#endif 547d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber , msg); 548d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSerializerLooper->registerHandler(mSerializer); 549d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 550d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mPacketizer = new TSPacketizer; 551d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 552d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#if FAKE_VIDEO 553d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber DataSource::RegisterDefaultSniffers(); 554d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 555d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<DataSource> dataSource = 556d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber DataSource::CreateFromURI( 557d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber "/system/etc/inception_1500.mp4"); 558d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 559d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(dataSource != NULL); 560d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 561d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 562d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(extractor != NULL); 563d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 564d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber bool haveAudio = false; 565d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber bool haveVideo = false; 566d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber for (size_t i = 0; i < extractor->countTracks(); ++i) { 567d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<MetaData> meta = extractor->getTrackMetaData(i); 568d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 569d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const char *mime; 570d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(meta->findCString(kKeyMIMEType, &mime)); 571d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 572d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber bool useTrack = false; 573d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (!strncasecmp(mime, "audio/", 6) && !haveAudio) { 574d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber useTrack = true; 575d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber haveAudio = true; 576d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else if (!strncasecmp(mime, "video/", 6) && !haveVideo) { 577d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber useTrack = true; 578d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber haveVideo = true; 579d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 580d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 581d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (!useTrack) { 582d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber continue; 583d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 584d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 585d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<MediaSource> source = extractor->getTrack(i); 586d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 587d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ssize_t index = mSerializer->addSource(source); 588d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_GE(index, 0); 589d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 590d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> format; 591d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber status_t err = convertMetaDataToMessage(source->getFormat(), &format); 592d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_EQ(err, (status_t)OK); 593d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 594d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTracks.add(index, new Track(format)); 595d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 596d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK(haveAudio || haveVideo); 597d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#else 598d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mCodecLooper = new ALooper; 599d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mCodecLooper->start(); 600d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 601d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber DisplayInfo info; 602d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber SurfaceComposerClient::getDisplayInfo(0, &info); 603d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 604d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // sp<SurfaceMediaSource> source = new SurfaceMediaSource(info.w, info.h); 6050b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber sp<SurfaceMediaSource> source = new SurfaceMediaSource(width(), height()); 606d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 607d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#if 0 608d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ssize_t index = mSerializer->addSource(source); 609d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#else 610d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ssize_t index = mSerializer->addSource( 611bcf09f8c995221e75c7cd328f25c7cc6d2b5f7c9Andreas Huber new RepeaterSource(source, 30.0 /* rateHz */)); 612d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#endif 613d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 614d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_GE(index, 0); 615d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 616d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> format; 617d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber status_t err = convertMetaDataToMessage(source->getFormat(), &format); 618d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_EQ(err, (status_t)OK); 619d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 620d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber format->setInt32("store-metadata-in-buffers", true); 621d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 622d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber format->setInt32( 623d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber "color-format", OMX_COLOR_FormatAndroidOpaque); 624d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 625d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> notify = new AMessage(kWhatConverterNotify, id()); 626d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->setSize("trackIndex", index); 627d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 628d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<Converter> converter = 629d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber new Converter(notify, mCodecLooper, format); 63066e72bc85fb762876baff60ef29de729da93cf26Andreas Huber CHECK_EQ(converter->initCheck(), (status_t)OK); 63166e72bc85fb762876baff60ef29de729da93cf26Andreas Huber 63266e72bc85fb762876baff60ef29de729da93cf26Andreas Huber size_t numInputBuffers = converter->getInputBufferCount(); 63366e72bc85fb762876baff60ef29de729da93cf26Andreas Huber ALOGI("numInputBuffers to the encoder is %d", numInputBuffers); 634d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 635d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber looper()->registerHandler(converter); 636d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 637d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTracks.add(index, new Track(converter)); 63866e72bc85fb762876baff60ef29de729da93cf26Andreas Huber 63966e72bc85fb762876baff60ef29de729da93cf26Andreas Huber sp<IServiceManager> sm = defaultServiceManager(); 64066e72bc85fb762876baff60ef29de729da93cf26Andreas Huber sp<IBinder> binder = sm->getService(String16("SurfaceFlinger")); 64166e72bc85fb762876baff60ef29de729da93cf26Andreas Huber sp<ISurfaceComposer> service = interface_cast<ISurfaceComposer>(binder); 64266e72bc85fb762876baff60ef29de729da93cf26Andreas Huber CHECK(service != NULL); 64366e72bc85fb762876baff60ef29de729da93cf26Andreas Huber 64466e72bc85fb762876baff60ef29de729da93cf26Andreas Huber // Add one reference to account for the serializer. 64566e72bc85fb762876baff60ef29de729da93cf26Andreas Huber err = source->setMaxAcquiredBufferCount(numInputBuffers + 1); 64666e72bc85fb762876baff60ef29de729da93cf26Andreas Huber CHECK_EQ(err, (status_t)OK); 64766e72bc85fb762876baff60ef29de729da93cf26Andreas Huber 6480b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber mBufferQueue = source->getBufferQueue(); 6490b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber 6500b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber if (mLegacyMode) { 6510b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber service->connectDisplay(mBufferQueue); 6520b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber } 653d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber#endif 654d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 655082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber#if 0 656082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber sp<AudioSource> audioSource = new AudioSource( 657082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber AUDIO_SOURCE_MIC, 658082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 48000 /* sampleRate */, 659082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 2 /* channelCount */); // XXX AUDIO_CHANNEL_IN_STEREO? 660082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 661082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber CHECK_EQ((status_t)OK, audioSource->initCheck()); 662082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 663082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber audioSource->setUseLooperTime(true); 664082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 665082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber index = mSerializer->addSource(audioSource); 666082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber CHECK_GE(index, 0); 667082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 668082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber sp<AMessage> audioFormat; 669082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber err = convertMetaDataToMessage(audioSource->getFormat(), &audioFormat); 670082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber CHECK_EQ(err, (status_t)OK); 671082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 672082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber sp<AMessage> audioNotify = new AMessage(kWhatConverterNotify, id()); 673082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber audioNotify->setSize("trackIndex", index); 674082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 675082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber converter = new Converter(audioNotify, mCodecLooper, audioFormat); 676082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber looper()->registerHandler(converter); 677082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 678082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber mTracks.add(index, new Track(converter)); 679082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber#endif 680082830f92373a1b9e512dbbfb940187ffa1c2c6fAndreas Huber 681d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return OK; 682d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 683d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 6840b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Hubersp<ISurfaceTexture> WifiDisplaySource::PlaybackSession::getSurfaceTexture() { 6850b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber return mBufferQueue; 6860b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber} 6870b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber 6880b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huberint32_t WifiDisplaySource::PlaybackSession::width() const { 6890b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber return 720; 6900b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber} 6910b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber 6920b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huberint32_t WifiDisplaySource::PlaybackSession::height() const { 6930b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber return 1280; 6940b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber} 6950b73d4730202fcad53aefc4314a06e7b95f442f0Andreas Huber 696d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubervoid WifiDisplaySource::PlaybackSession::scheduleSendSR() { 697d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mSendSRPending) { 698d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return; 699d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 700d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 701d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mSendSRPending = true; 702d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber (new AMessage(kWhatSendSR, id()))->post(kSendSRIntervalUs); 703d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 704d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 705d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubervoid WifiDisplaySource::PlaybackSession::addSR(const sp<ABuffer> &buffer) { 706d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint8_t *data = buffer->data() + buffer->size(); 707d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 708d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // TODO: Use macros/utility functions to clean up all the bitshifts below. 709d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 710d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[0] = 0x80 | 0; 711d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[1] = 200; // SR 712d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[2] = 0; 713d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[3] = 6; 714d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[4] = kSourceID >> 24; 715d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[5] = (kSourceID >> 16) & 0xff; 716d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[6] = (kSourceID >> 8) & 0xff; 717d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[7] = kSourceID & 0xff; 718d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 719d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[8] = mLastNTPTime >> (64 - 8); 720d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[9] = (mLastNTPTime >> (64 - 16)) & 0xff; 721d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[10] = (mLastNTPTime >> (64 - 24)) & 0xff; 722d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[11] = (mLastNTPTime >> 32) & 0xff; 723d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[12] = (mLastNTPTime >> 24) & 0xff; 724d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[13] = (mLastNTPTime >> 16) & 0xff; 725d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[14] = (mLastNTPTime >> 8) & 0xff; 726d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[15] = mLastNTPTime & 0xff; 727d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 728d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[16] = (mLastRTPTime >> 24) & 0xff; 729d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[17] = (mLastRTPTime >> 16) & 0xff; 730d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[18] = (mLastRTPTime >> 8) & 0xff; 731d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[19] = mLastRTPTime & 0xff; 732d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 733d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[20] = mNumRTPSent >> 24; 734d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[21] = (mNumRTPSent >> 16) & 0xff; 735d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[22] = (mNumRTPSent >> 8) & 0xff; 736d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[23] = mNumRTPSent & 0xff; 737d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 738d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[24] = mNumRTPOctetsSent >> 24; 739d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[25] = (mNumRTPOctetsSent >> 16) & 0xff; 740d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[26] = (mNumRTPOctetsSent >> 8) & 0xff; 741d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[27] = mNumRTPOctetsSent & 0xff; 742d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 743d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber buffer->setRange(buffer->offset(), buffer->size() + 28); 744d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 745d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 746d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubervoid WifiDisplaySource::PlaybackSession::addSDES(const sp<ABuffer> &buffer) { 747d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint8_t *data = buffer->data() + buffer->size(); 748d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[0] = 0x80 | 1; 749d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[1] = 202; // SDES 750d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[4] = kSourceID >> 24; 751d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[5] = (kSourceID >> 16) & 0xff; 752d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[6] = (kSourceID >> 8) & 0xff; 753d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[7] = kSourceID & 0xff; 754d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 755d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size_t offset = 8; 756d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 757d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[offset++] = 1; // CNAME 758d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 759d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber static const char *kCNAME = "someone@somewhere"; 760d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[offset++] = strlen(kCNAME); 761d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 762d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber memcpy(&data[offset], kCNAME, strlen(kCNAME)); 763d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber offset += strlen(kCNAME); 764d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 765d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[offset++] = 7; // NOTE 766d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 767d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber static const char *kNOTE = "Hell's frozen over."; 768d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[offset++] = strlen(kNOTE); 769d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 770d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber memcpy(&data[offset], kNOTE, strlen(kNOTE)); 771d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber offset += strlen(kNOTE); 772d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 773d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[offset++] = 0; 774d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 775d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if ((offset % 4) > 0) { 776d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size_t count = 4 - (offset % 4); 777d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber switch (count) { 778d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 3: 779d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[offset++] = 0; 780d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 2: 781d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[offset++] = 0; 782d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 1: 783d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[offset++] = 0; 784d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 785d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 786d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 787d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size_t numWords = (offset / 4) - 1; 788d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[2] = numWords >> 8; 789d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data[3] = numWords & 0xff; 790d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 791d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber buffer->setRange(buffer->offset(), buffer->size() + offset); 792d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 793d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 794d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber// static 795d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberuint64_t WifiDisplaySource::PlaybackSession::GetNowNTP() { 796d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint64_t nowUs = ALooper::GetNowUs(); 797d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 798d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber nowUs += ((70ll * 365 + 17) * 24) * 60 * 60 * 1000000ll; 799d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 800d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint64_t hi = nowUs / 1000000ll; 801d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint64_t lo = ((1ll << 32) * (nowUs % 1000000ll)) / 1000000ll; 802d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 803d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return (hi << 32) | lo; 804d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 805d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 806d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Hubervoid WifiDisplaySource::PlaybackSession::onSendSR() { 807d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<ABuffer> buffer = new ABuffer(1500); 808d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber buffer->setRange(0, 0); 809d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 810d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber addSR(buffer); 811d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber addSDES(buffer); 812d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 813d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mUseInterleavedTCP) { 814d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> notify = mNotify->dup(); 815d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->setInt32("what", kWhatBinaryData); 816d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->setInt32("channel", mRTCPChannel); 817d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->setBuffer("data", buffer); 818d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->post(); 819d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else { 820d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNetSession->sendRequest( 821d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTCPSessionID, buffer->data(), buffer->size()); 822d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 823d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 824d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ++mNumSRsSent; 825d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 826d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 827d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberssize_t WifiDisplaySource::PlaybackSession::appendTSData( 828d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const void *data, size_t size, bool timeDiscontinuity, bool flush) { 829d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_EQ(size, 188); 830d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 831d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber CHECK_LE(mTSQueue->size() + size, mTSQueue->capacity()); 832d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 833d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber memcpy(mTSQueue->data() + mTSQueue->size(), data, size); 834d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTSQueue->setRange(0, mTSQueue->size() + size); 835d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 836d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (flush || mTSQueue->size() == mTSQueue->capacity()) { 837d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // flush 838d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 839d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber int64_t nowUs = ALooper::GetNowUs(); 840d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mFirstPacketTimeUs < 0ll) { 841d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mFirstPacketTimeUs = nowUs; 842d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 843d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 844d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // 90kHz time scale 845d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint32_t rtpTime = ((nowUs - mFirstPacketTimeUs) * 9ll) / 100ll; 846d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 847d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint8_t *rtp = mTSQueue->data(); 848d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[0] = 0x80; 849d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[1] = 33 | (timeDiscontinuity ? (1 << 7) : 0); // M-bit 850d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[2] = (mRTPSeqNo >> 8) & 0xff; 851d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[3] = mRTPSeqNo & 0xff; 852d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[4] = rtpTime >> 24; 853d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[5] = (rtpTime >> 16) & 0xff; 854d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[6] = (rtpTime >> 8) & 0xff; 855d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[7] = rtpTime & 0xff; 856d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[8] = kSourceID >> 24; 857d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[9] = (kSourceID >> 16) & 0xff; 858d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[10] = (kSourceID >> 8) & 0xff; 859d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber rtp[11] = kSourceID & 0xff; 860d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 861d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ++mRTPSeqNo; 862d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ++mNumRTPSent; 863d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNumRTPOctetsSent += mTSQueue->size() - 12; 864d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 865d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mLastRTPTime = rtpTime; 866d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mLastNTPTime = GetNowNTP(); 867d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 868d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mUseInterleavedTCP) { 869d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<AMessage> notify = mNotify->dup(); 870d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->setInt32("what", kWhatBinaryData); 871d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 872d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber sp<ABuffer> data = new ABuffer(mTSQueue->size()); 873d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber memcpy(data->data(), rtp, mTSQueue->size()); 874d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 875d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->setInt32("channel", mRTPChannel); 876d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->setBuffer("data", data); 877d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber notify->post(); 878d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else { 879d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNetSession->sendRequest( 880d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPSessionID, rtp, mTSQueue->size()); 881d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 882d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 883d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTSQueue->setInt32Data(mRTPSeqNo - 1); 884d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mHistory.push_back(mTSQueue); 885d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ++mHistoryLength; 886d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 887d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (mHistoryLength > kMaxHistoryLength) { 888d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTSQueue = *mHistory.begin(); 889d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mHistory.erase(mHistory.begin()); 890d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 891d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber --mHistoryLength; 892d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else { 893d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTSQueue = new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188); 894d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 895d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 896d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mTSQueue->setRange(0, 12); 897d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 898d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 899d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return size; 900d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 901d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 902d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstatus_t WifiDisplaySource::PlaybackSession::parseRTCP( 903d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const sp<ABuffer> &buffer) { 904d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const uint8_t *data = buffer->data(); 905d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size_t size = buffer->size(); 906d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 907d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber while (size > 0) { 908d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (size < 8) { 909d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // Too short to be a valid RTCP header 910d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return ERROR_MALFORMED; 911d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 912d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 913d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if ((data[0] >> 6) != 2) { 914d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // Unsupported version. 915d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return ERROR_UNSUPPORTED; 916d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 917d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 918d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (data[0] & 0x20) { 919d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // Padding present. 920d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 921d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size_t paddingLength = data[size - 1]; 922d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 923d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (paddingLength + 12 > size) { 924d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // If we removed this much padding we'd end up with something 925d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // that's too short to be a valid RTP header. 926d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return ERROR_MALFORMED; 927d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 928d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 929d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size -= paddingLength; 930d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 931d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 932d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size_t headerLength = 4 * (data[2] << 8 | data[3]) + 4; 933d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 934d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (size < headerLength) { 935d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber // Only received a partial packet? 936d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return ERROR_MALFORMED; 937d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 938d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 939d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber switch (data[1]) { 940d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 200: 941d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 201: // RR 942d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 202: // SDES 943d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 203: 944d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 204: // APP 945d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 946d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 947d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 205: // TSFB (transport layer specific feedback) 948d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber parseTSFB(data, headerLength); 949d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 950d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 951d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber case 206: // PSFB (payload specific feedback) 952d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber hexdump(data, headerLength); 953d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 954d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 955d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber default: 956d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber { 957d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGW("Unknown RTCP packet type %u of size %d", 958d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber (unsigned)data[1], headerLength); 959d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 960d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 961d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 962d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 963d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber data += headerLength; 964d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber size -= headerLength; 965d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 966d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 967d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return OK; 968d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 969d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 970d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huberstatus_t WifiDisplaySource::PlaybackSession::parseTSFB( 971d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const uint8_t *data, size_t size) { 972d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if ((data[0] & 0x1f) != 1) { 973d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return ERROR_UNSUPPORTED; // We only support NACK for now. 974d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 975d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 976d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint32_t srcId = U32_AT(&data[8]); 977d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (srcId != kSourceID) { 978d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return ERROR_MALFORMED; 979d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 980d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 981d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber for (size_t i = 12; i < size; i += 4) { 982d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint16_t seqNo = U16_AT(&data[i]); 983d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint16_t blp = U16_AT(&data[i + 2]); 984d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 985d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber List<sp<ABuffer> >::iterator it = mHistory.begin(); 986d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber bool found = false; 987d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber while (it != mHistory.end()) { 988d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber const sp<ABuffer> &buffer = *it; 989d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 990d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber uint16_t bufferSeqNo = buffer->int32Data() & 0xffff; 991d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 992d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (bufferSeqNo == seqNo) { 993d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mNetSession->sendRequest( 994d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber mRTPSessionID, buffer->data(), buffer->size()); 995d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 996d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber found = true; 997d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber break; 998d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 999d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 1000d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ++it; 1001d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 1002d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 1003d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber if (found) { 1004d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("retransmitting seqNo %d", seqNo); 1005d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } else { 1006d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber ALOGI("seqNo %d no longer available", seqNo); 1007d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 1008d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber } 1009d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 1010d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber return OK; 1011d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} 1012d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 1013d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber} // namespace android 1014d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480cAndreas Huber 1015