139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber/*
239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * Copyright (C) 2010 The Android Open Source Project
339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber *
439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * you may not use this file except in compliance with the License.
639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * You may obtain a copy of the License at
739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber *
839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber *
1039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * Unless required by applicable law or agreed to in writing, software
1139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * See the License for the specific language governing permissions and
1439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber * limitations under the License.
1539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber */
1639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
176e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber//#define LOG_NDEBUG 0
186e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber#define LOG_TAG "ARTPSession"
196e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber#include <utils/Log.h>
206e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber
2139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "ARTPSession.h"
2239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
2339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
2439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <media/stagefright/foundation/ADebug.h>
2539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <media/stagefright/foundation/AMessage.h>
2639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <media/stagefright/foundation/hexdump.h>
2739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
2839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <ctype.h>
2939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <arpa/inet.h>
3039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <sys/socket.h>
3139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
3239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "APacketSource.h"
3339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "ARTPConnection.h"
3439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "ASessionDescription.h"
3539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
3639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Hubernamespace android {
3739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
3839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas HuberARTPSession::ARTPSession()
3939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    : mInitCheck(NO_INIT) {
4039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
4139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
4239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huberstatus_t ARTPSession::setup(const sp<ASessionDescription> &desc) {
4339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_EQ(mInitCheck, (status_t)NO_INIT);
4439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
4539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mDesc = desc;
4639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
47100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    mRTPConn = new ARTPConnection(ARTPConnection::kRegularlyRequestFIR);
48f8ca90452ff3e252f20de38f1c3eee524c808c3eAndreas Huber
4939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    looper()->registerHandler(mRTPConn);
5039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
5139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    for (size_t i = 1; i < mDesc->countTracks(); ++i) {
5239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        AString connection;
5339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (!mDesc->findAttribute(i, "c=", &connection)) {
5439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            // No per-stream connection information, try global fallback.
5539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            if (!mDesc->findAttribute(0, "c=", &connection)) {
5629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("Unable to find connection attribute.");
5739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                return mInitCheck;
5839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            }
5939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
6039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (!(connection == "IN IP4 127.0.0.1")) {
6129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("We only support localhost connections for now.");
6239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return mInitCheck;
6339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
6439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
6539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        unsigned port;
6639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (!validateMediaFormat(i, &port) || (port & 1) != 0) {
6729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Invalid media format.");
6839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return mInitCheck;
6939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
7039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
7139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        sp<APacketSource> source = new APacketSource(mDesc, i);
7239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (source->initCheck() != OK) {
7329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Unsupported format.");
7439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return mInitCheck;
7539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
7639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
7739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        int rtpSocket = MakeUDPSocket(port);
7839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        int rtcpSocket = MakeUDPSocket(port + 1);
7939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
8039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        mTracks.push(TrackInfo());
8139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
8239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mRTPSocket = rtpSocket;
8339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mRTCPSocket = rtcpSocket;
8439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
8539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        sp<AMessage> notify = new AMessage(kWhatAccessUnitComplete, id());
8639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        notify->setSize("track-index", mTracks.size() - 1);
8739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
880792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        mRTPConn->addStream(
890792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                rtpSocket, rtcpSocket, mDesc, i, notify, false /* injected */);
9039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
9139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mPacketSource = source;
9239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
9339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
9439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mInitCheck = OK;
9539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
9639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return OK;
9739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
9839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
9939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber// static
10039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huberint ARTPSession::MakeUDPSocket(unsigned port) {
10139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    int s = socket(AF_INET, SOCK_DGRAM, 0);
10239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_GE(s, 0);
10339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
10439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    struct sockaddr_in addr;
10539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
10639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    addr.sin_family = AF_INET;
10739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    addr.sin_addr.s_addr = INADDR_ANY;
10839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    addr.sin_port = htons(port);
10939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
11039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_EQ(0, bind(s, (const struct sockaddr *)&addr, sizeof(addr)));
11139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
11239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return s;
11339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
11439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
11539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas HuberARTPSession::~ARTPSession() {
11639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    for (size_t i = 0; i < mTracks.size(); ++i) {
11739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        TrackInfo *info = &mTracks.editItemAt(i);
11839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
11939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mPacketSource->signalEOS(UNKNOWN_ERROR);
12039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
12139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        close(info->mRTPSocket);
12239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        close(info->mRTCPSocket);
12339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
12439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
12539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
12639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Hubervoid ARTPSession::onMessageReceived(const sp<AMessage> &msg) {
12739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    switch (msg->what()) {
12839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        case kWhatAccessUnitComplete:
12939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        {
130389636ce967af15e72817e2133907a2cb2efd1aeAndreas Huber            int32_t firstRTCP;
131389636ce967af15e72817e2133907a2cb2efd1aeAndreas Huber            if (msg->findInt32("first-rtcp", &firstRTCP)) {
132389636ce967af15e72817e2133907a2cb2efd1aeAndreas Huber                // There won't be an access unit here, it's just a notification
133389636ce967af15e72817e2133907a2cb2efd1aeAndreas Huber                // that the data communication worked since we got the first
134389636ce967af15e72817e2133907a2cb2efd1aeAndreas Huber                // rtcp packet.
135389636ce967af15e72817e2133907a2cb2efd1aeAndreas Huber                break;
136389636ce967af15e72817e2133907a2cb2efd1aeAndreas Huber            }
137389636ce967af15e72817e2133907a2cb2efd1aeAndreas Huber
13839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            size_t trackIndex;
13939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK(msg->findSize("track-index", &trackIndex));
14039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
14139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            int32_t eos;
14239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            if (msg->findInt32("eos", &eos) && eos) {
14339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                TrackInfo *info = &mTracks.editItemAt(trackIndex);
14439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
14539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                break;
14639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            }
14739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
1482d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber            sp<ABuffer> accessUnit;
1492d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber            CHECK(msg->findBuffer("access-unit", &accessUnit));
15039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
15139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            uint64_t ntpTime;
15239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK(accessUnit->meta()->findInt64(
15339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                        "ntp-time", (int64_t *)&ntpTime));
15439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
15539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#if 0
15639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#if 0
15739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            printf("access unit complete size=%d\tntp-time=0x%016llx\n",
15839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                   accessUnit->size(), ntpTime);
15939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#else
160df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("access unit complete, size=%d, ntp-time=%llu",
1616e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                 accessUnit->size(), ntpTime);
16239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            hexdump(accessUnit->data(), accessUnit->size());
16339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#endif
16439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#endif
16539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
16639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#if 0
16739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK_GE(accessUnit->size(), 5u);
16839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK(!memcmp("\x00\x00\x00\x01", accessUnit->data(), 4));
16939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            unsigned x = accessUnit->data()[4];
17039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
171df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("access unit complete: nalType=0x%02x, nalRefIdc=0x%02x",
1726e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                 x & 0x1f, (x & 0x60) >> 5);
17339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#endif
17439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
17539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            accessUnit->meta()->setInt64("ntp-time", ntpTime);
176b186054757f4743eb9a6d6e81d262b9c7b36bec7Andreas Huber            accessUnit->meta()->setInt64("timeUs", 0);
17739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
17839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#if 0
17939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            int32_t damaged;
18039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            if (accessUnit->meta()->findInt32("damaged", &damaged)
18139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    && damaged != 0) {
182df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("ignoring damaged AU");
18339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            } else
18439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#endif
18539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            {
18639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                TrackInfo *info = &mTracks.editItemAt(trackIndex);
18739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                info->mPacketSource->queueAccessUnit(accessUnit);
18839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            }
18939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            break;
19039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
19139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
19239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        default:
19339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            TRESPASS();
19439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            break;
19539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
19639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
19739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
19839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huberbool ARTPSession::validateMediaFormat(size_t index, unsigned *port) const {
19939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    AString format;
20039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mDesc->getFormat(index, &format);
20139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
20239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    ssize_t i = format.find(" ");
20339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (i < 0) {
20439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return false;
20539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
20639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
20739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    ++i;
20839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    size_t j = i;
20939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    while (isdigit(format.c_str()[j])) {
21039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        ++j;
21139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
21239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (format.c_str()[j] != ' ') {
21339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return false;
21439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
21539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
21639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    AString portString(format, i, j - i);
21739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
21839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    char *end;
21939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    unsigned long x = strtoul(portString.c_str(), &end, 10);
22039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (end == portString.c_str() || *end != '\0') {
22139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return false;
22239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
22339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
22439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (x == 0 || x > 65535) {
22539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return false;
22639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
22739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
22839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    *port = x;
22939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
23039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return true;
23139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
23239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
23339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Hubersize_t ARTPSession::countTracks() {
23439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return mTracks.size();
23539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
23639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
23739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Hubersp<MediaSource> ARTPSession::trackAt(size_t index) {
23839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_LT(index, mTracks.size());
23939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return mTracks.editItemAt(index).mPacketSource;
24039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
24139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
24239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}  // namespace android
243