ARTPSession.cpp revision f8ca90452ff3e252f20de38f1c3eee524c808c3e
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
1739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "ARTPSession.h"
1839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
1939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
2039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <media/stagefright/foundation/ADebug.h>
2139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <media/stagefright/foundation/AMessage.h>
2239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <media/stagefright/foundation/hexdump.h>
2339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
2439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <ctype.h>
2539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <arpa/inet.h>
2639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include <sys/socket.h>
2739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
2839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "APacketSource.h"
2939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "ARTPConnection.h"
3039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "ASessionDescription.h"
3139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
3239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Hubernamespace android {
3339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
3439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas HuberARTPSession::ARTPSession()
3539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    : mInitCheck(NO_INIT) {
3639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
3739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
3839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huberstatus_t ARTPSession::setup(const sp<ASessionDescription> &desc) {
3939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_EQ(mInitCheck, (status_t)NO_INIT);
4039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
4139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mDesc = desc;
4239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
43f8ca90452ff3e252f20de38f1c3eee524c808c3eAndreas Huber    mRTPConn = new ARTPConnection(
44f8ca90452ff3e252f20de38f1c3eee524c808c3eAndreas Huber            ARTPConnection::kFakeTimestamps
45f8ca90452ff3e252f20de38f1c3eee524c808c3eAndreas Huber                | ARTPConnection::kRegularlyRequestFIR);
46f8ca90452ff3e252f20de38f1c3eee524c808c3eAndreas Huber
4739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    looper()->registerHandler(mRTPConn);
4839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
4939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    for (size_t i = 1; i < mDesc->countTracks(); ++i) {
5039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        AString connection;
5139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (!mDesc->findAttribute(i, "c=", &connection)) {
5239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            // No per-stream connection information, try global fallback.
5339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            if (!mDesc->findAttribute(0, "c=", &connection)) {
5439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                LOG(ERROR) << "Unable to find connection attribtue.";
5539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                return mInitCheck;
5639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            }
5739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
5839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (!(connection == "IN IP4 127.0.0.1")) {
5939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            LOG(ERROR) << "We only support localhost connections for now.";
6039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return mInitCheck;
6139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
6239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
6339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        unsigned port;
6439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (!validateMediaFormat(i, &port) || (port & 1) != 0) {
6539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            LOG(ERROR) << "Invalid media format.";
6639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return mInitCheck;
6739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
6839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
6939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        sp<APacketSource> source = new APacketSource(mDesc, i);
7039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (source->initCheck() != OK) {
7139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            LOG(ERROR) << "Unsupported format.";
7239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return mInitCheck;
7339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
7439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
7539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        int rtpSocket = MakeUDPSocket(port);
7639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        int rtcpSocket = MakeUDPSocket(port + 1);
7739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
7839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        mTracks.push(TrackInfo());
7939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
8039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mRTPSocket = rtpSocket;
8139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mRTCPSocket = rtcpSocket;
8239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
8339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        sp<AMessage> notify = new AMessage(kWhatAccessUnitComplete, id());
8439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        notify->setSize("track-index", mTracks.size() - 1);
8539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
8639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        mRTPConn->addStream(rtpSocket, rtcpSocket, mDesc, i, notify);
8739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
8839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mPacketSource = source;
8939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
9039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
9139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mInitCheck = OK;
9239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
9339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return OK;
9439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
9539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
9639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber// static
9739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huberint ARTPSession::MakeUDPSocket(unsigned port) {
9839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    int s = socket(AF_INET, SOCK_DGRAM, 0);
9939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_GE(s, 0);
10039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
10139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    struct sockaddr_in addr;
10239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
10339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    addr.sin_family = AF_INET;
10439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    addr.sin_addr.s_addr = INADDR_ANY;
10539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    addr.sin_port = htons(port);
10639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
10739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_EQ(0, bind(s, (const struct sockaddr *)&addr, sizeof(addr)));
10839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
10939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return s;
11039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
11139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
11239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas HuberARTPSession::~ARTPSession() {
11339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    for (size_t i = 0; i < mTracks.size(); ++i) {
11439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        TrackInfo *info = &mTracks.editItemAt(i);
11539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
11639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mPacketSource->signalEOS(UNKNOWN_ERROR);
11739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
11839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        close(info->mRTPSocket);
11939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        close(info->mRTCPSocket);
12039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
12139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
12239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
12339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Hubervoid ARTPSession::onMessageReceived(const sp<AMessage> &msg) {
12439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    switch (msg->what()) {
12539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        case kWhatAccessUnitComplete:
12639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        {
12739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            size_t trackIndex;
12839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK(msg->findSize("track-index", &trackIndex));
12939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
13039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            int32_t eos;
13139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            if (msg->findInt32("eos", &eos) && eos) {
13239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                TrackInfo *info = &mTracks.editItemAt(trackIndex);
13339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
13439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                break;
13539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            }
13639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
13739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            sp<RefBase> obj;
13839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK(msg->findObject("access-unit", &obj));
13939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
14039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
14139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
14239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            uint64_t ntpTime;
14339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK(accessUnit->meta()->findInt64(
14439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                        "ntp-time", (int64_t *)&ntpTime));
14539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
14639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#if 0
14739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#if 0
14839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            printf("access unit complete size=%d\tntp-time=0x%016llx\n",
14939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                   accessUnit->size(), ntpTime);
15039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#else
15139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            LOG(INFO) << "access unit complete, "
15239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                      << "size=" << accessUnit->size() << ", "
15339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                      << "ntp-time=" << ntpTime;
15439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            hexdump(accessUnit->data(), accessUnit->size());
15539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#endif
15639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#endif
15739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
15839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#if 0
15939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK_GE(accessUnit->size(), 5u);
16039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            CHECK(!memcmp("\x00\x00\x00\x01", accessUnit->data(), 4));
16139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            unsigned x = accessUnit->data()[4];
16239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
16339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            LOG(INFO) << "access unit complete: "
16439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                      << StringPrintf("nalType=0x%02x, nalRefIdc=0x%02x",
16539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                                      x & 0x1f, (x & 0x60) >> 5);
16639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#endif
16739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
16839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            accessUnit->meta()->setInt64("ntp-time", ntpTime);
16939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
17039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#if 0
17139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            int32_t damaged;
17239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            if (accessUnit->meta()->findInt32("damaged", &damaged)
17339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    && damaged != 0) {
17439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                LOG(INFO) << "ignoring damaged AU";
17539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            } else
17639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#endif
17739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            {
17839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                TrackInfo *info = &mTracks.editItemAt(trackIndex);
17939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                info->mPacketSource->queueAccessUnit(accessUnit);
18039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            }
18139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            break;
18239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
18339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
18439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        default:
18539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            TRESPASS();
18639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            break;
18739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
18839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
18939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
19039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huberbool ARTPSession::validateMediaFormat(size_t index, unsigned *port) const {
19139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    AString format;
19239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mDesc->getFormat(index, &format);
19339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
19439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    ssize_t i = format.find(" ");
19539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (i < 0) {
19639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return false;
19739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
19839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
19939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    ++i;
20039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    size_t j = i;
20139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    while (isdigit(format.c_str()[j])) {
20239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        ++j;
20339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
20439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (format.c_str()[j] != ' ') {
20539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return false;
20639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
20739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
20839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    AString portString(format, i, j - i);
20939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
21039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    char *end;
21139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    unsigned long x = strtoul(portString.c_str(), &end, 10);
21239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (end == portString.c_str() || *end != '\0') {
21339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return false;
21439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
21539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
21639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (x == 0 || x > 65535) {
21739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return false;
21839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
21939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
22039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    *port = x;
22139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
22239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return true;
22339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
22439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
22539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Hubersize_t ARTPSession::countTracks() {
22639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return mTracks.size();
22739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
22839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
22939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Hubersp<MediaSource> ARTPSession::trackAt(size_t index) {
23039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_LT(index, mTracks.size());
23139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return mTracks.editItemAt(index).mPacketSource;
23239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
23339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
23439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}  // namespace android
235