示例#1
0
// disconnect(): close the socket and alert.
void
NSocketX::disconnect()
{
    sysClose();
    onDisconnected();
}
示例#2
0
ISocketMultiplexerJob*
CTCPSocket::serviceConnected(ISocketMultiplexerJob* job,
				bool read, bool write, bool error)
{
	CLock lock(&m_mutex);

	if (error) {
		sendEvent(getDisconnectedEvent());
		onDisconnected();
		return newJob();
	}

	bool needNewJob = false;

	if (write) {
		try {
			// write data
			UInt32 n = m_outputBuffer.getSize();
			const void* buffer = m_outputBuffer.peek(n);
			n = (UInt32)ARCH->writeSocket(m_socket, buffer, n);

			// discard written data
			if (n > 0) {
				m_outputBuffer.pop(n);
				if (m_outputBuffer.getSize() == 0) {
					sendEvent(getOutputFlushedEvent());
					m_flushed = true;
					m_flushed.broadcast();
					needNewJob = true;
				}
			}
		}
		catch (XArchNetworkShutdown&) {
			// remote read end of stream hungup.  our output side
			// has therefore shutdown.
			onOutputShutdown();
			sendEvent(getOutputShutdownEvent());
			if (!m_readable && m_inputBuffer.getSize() == 0) {
				sendEvent(getDisconnectedEvent());
				m_connected = false;
			}
			needNewJob = true;
		}
		catch (XArchNetworkDisconnected&) {
			// stream hungup
			onDisconnected();
			sendEvent(getDisconnectedEvent());
			needNewJob = true;
		}
		catch (XArchNetwork&) {
			// other write error
			onDisconnected();
			sendEvent(getOutputErrorEvent());
			sendEvent(getDisconnectedEvent());
			needNewJob = true;
		}
	}

	if (read && m_readable) {
		try {
			UInt8 buffer[4096];
			size_t n = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
			if (n > 0) {
				bool wasEmpty = (m_inputBuffer.getSize() == 0);

				// slurp up as much as possible
				do {
					m_inputBuffer.write(buffer, n);
					n = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
				} while (n > 0);

				// send input ready if input buffer was empty
				if (wasEmpty) {
					sendEvent(getInputReadyEvent());
				}
			}
			else {
				// remote write end of stream hungup.  our input side
				// has therefore shutdown but don't flush our buffer
				// since there's still data to be read.
				sendEvent(getInputShutdownEvent());
				if (!m_writable && m_inputBuffer.getSize() == 0) {
					sendEvent(getDisconnectedEvent());
					m_connected = false;
				}
				m_readable = false;
				needNewJob = true;
			}
		}
		catch (XArchNetworkDisconnected&) {
			// stream hungup
			sendEvent(getDisconnectedEvent());
			onDisconnected();
			needNewJob = true;
		}
		catch (XArchNetwork&) {
			// ignore other read error
		}
	}

	return needNewJob ? newJob() : job;
}
void InsteonNetwork::disconnect()
{
	connection = NULL;
	onDisconnected();
}
示例#4
0
bool
NSocketX::sysRecv()
{
    int read_retrycount = 3; // +1 (first time)
read_again:
    if (from_ssaddr)
    { // this must be a udp socket
        fromlen=sizeof(from_ssaddr);
        sys_result = recvfrom(fd,recvbuffer,NSBUFLEN,0,(struct sockaddr *) from_ssaddr,&fromlen);
    }
    else
    {
        sys_result = recv(fd,recvbuffer,NSBUFLEN,0);
    }
    if (sys_result == SOCKET_ERROR)
    {
        error=GET_NET_ERROR();
        switch (error)
        {
            case NET_ERROR_EINTR:
                if (read_retrycount--)
                    goto read_again;
            case NET_ERROR_EAGAIN:
                return true;
            case NET_ERROR_ENOTCONN:
//                onInternalError("recv: Tryed to receive on an unconected socket (and should be connected)");
//                break;
            case NET_ERROR_ENOTSOCK:
//                onInternalError("recv: The socket is not a socket");
//                break;
            case NET_ERROR_EFAULT:
//                onInternalError("recv: The internal buffer pointer is out of range");
//                break;
            case NET_ERROR_EINVAL:
//                onInternalError("recv: Invalid parameters passed");
//                break;
            case NET_ERROR_ECONNREFUSED:
//                onConnectError();
                sysClose();
                break;
            default:
                printf("[%d] Receive error %s\n", fd, strerror(error));
                listener->onSocketError(this); // XXX receive error
        }
        return false;
    }
    if (sys_result == 0)
    {
        onDisconnected();
        return false;
    }
    if (!onDataReceived(recvbuffer, sys_result))
    {
        disconnect();
        return false;
    }
    else
    {
        return true;
    }
//    return true;
}
void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    if (msg->what() == kWhatDisconnect) {
        sp<AReplyToken> replyID;
        CHECK(msg->senderAwaitsResponse(&replyID));

        mDisconnectReplyID = replyID;
        finishDisconnectIfPossible();
        return;
    } else if (msg->what() == kWhatPerformSeek) {
        int32_t generation;
        CHECK(msg->findInt32("generation", &generation));
        CHECK(msg->senderAwaitsResponse(&mSeekReplyID));

        if (generation != mSeekGeneration) {
            // obsolete.
            finishSeek(OK);
            return;
        }

        int64_t seekTimeUs;
        CHECK(msg->findInt64("timeUs", &seekTimeUs));

        performSeek(seekTimeUs);
        return;
    }

    CHECK_EQ(msg->what(), (int)kWhatNotify);

    int32_t what;
    CHECK(msg->findInt32("what", &what));

    switch (what) {
        case MyHandler::kWhatConnected:
        {
            onConnected();

            notifyVideoSizeChanged();

            uint32_t flags = 0;

            if (mHandler->isSeekable()) {
                flags = FLAG_CAN_PAUSE
                        | FLAG_CAN_SEEK
                        | FLAG_CAN_SEEK_BACKWARD
                        | FLAG_CAN_SEEK_FORWARD;
            }

            notifyFlagsChanged(flags);
            notifyPrepared();
            break;
        }

        case MyHandler::kWhatDisconnected:
        {
            onDisconnected(msg);
            break;
        }

        case MyHandler::kWhatSeekDone:
        {
            mState = CONNECTED;
            if (mSeekReplyID != NULL) {
                // Unblock seekTo here in case we attempted to seek in a live stream
                finishSeek(OK);
            }
            break;
        }

        case MyHandler::kWhatSeekPaused:
        {
            sp<AnotherPacketSource> source = getSource(true /* audio */);
            if (source != NULL) {
                source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
                        /* extra */ NULL,
                        /* discard */ true);
            }
            source = getSource(false /* video */);
            if (source != NULL) {
                source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
                        /* extra */ NULL,
                        /* discard */ true);
            };

            status_t err = OK;
            msg->findInt32("err", &err);
            finishSeek(err);

            if (err == OK) {
                int64_t timeUs;
                CHECK(msg->findInt64("time", &timeUs));
                mHandler->continueSeekAfterPause(timeUs);
            }
            break;
        }

        case MyHandler::kWhatAccessUnit:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));

            if (mTSParser == NULL) {
                CHECK_LT(trackIndex, mTracks.size());
            } else {
                CHECK_EQ(trackIndex, 0u);
            }

            sp<ABuffer> accessUnit;
            CHECK(msg->findBuffer("accessUnit", &accessUnit));

            int32_t damaged;
            if (accessUnit->meta()->findInt32("damaged", &damaged)
                    && damaged) {
                ALOGI("dropping damaged access unit.");
                break;
            }

            if (mTSParser != NULL) {
                size_t offset = 0;
                status_t err = OK;
                while (offset + 188 <= accessUnit->size()) {
                    err = mTSParser->feedTSPacket(
                            accessUnit->data() + offset, 188);
                    if (err != OK) {
                        break;
                    }

                    offset += 188;
                }

                if (offset < accessUnit->size()) {
                    err = ERROR_MALFORMED;
                }

                if (err != OK) {
                    sp<AnotherPacketSource> source = getSource(false /* audio */);
                    if (source != NULL) {
                        source->signalEOS(err);
                    }

                    source = getSource(true /* audio */);
                    if (source != NULL) {
                        source->signalEOS(err);
                    }
                }
                break;
            }

            TrackInfo *info = &mTracks.editItemAt(trackIndex);

            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                uint32_t rtpTime;
                CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));

                if (!info->mNPTMappingValid) {
                    // This is a live stream, we didn't receive any normal
                    // playtime mapping. We won't map to npt time.
                    source->queueAccessUnit(accessUnit);
                    break;
                }

                int64_t nptUs =
                    ((double)rtpTime - (double)info->mRTPTime)
                        / info->mTimeScale
                        * 1000000ll
                        + info->mNormalPlaytimeUs;

                accessUnit->meta()->setInt64("timeUs", nptUs);

                source->queueAccessUnit(accessUnit);
            }
            break;
        }

        case MyHandler::kWhatEOS:
        {
            int32_t finalResult;
            CHECK(msg->findInt32("finalResult", &finalResult));
            CHECK_NE(finalResult, (status_t)OK);

            if (mTSParser != NULL) {
                sp<AnotherPacketSource> source = getSource(false /* audio */);
                if (source != NULL) {
                    source->signalEOS(finalResult);
                }

                source = getSource(true /* audio */);
                if (source != NULL) {
                    source->signalEOS(finalResult);
                }

                return;
            }

            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                source->signalEOS(finalResult);
            }

            break;
        }

        case MyHandler::kWhatSeekDiscontinuity:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                source->queueDiscontinuity(
                        ATSParser::DISCONTINUITY_TIME,
                        NULL,
                        true /* discard */);
            }

            break;
        }

        case MyHandler::kWhatNormalPlayTimeMapping:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            uint32_t rtpTime;
            CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));

            int64_t nptUs;
            CHECK(msg->findInt64("nptUs", &nptUs));

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            info->mRTPTime = rtpTime;
            info->mNormalPlaytimeUs = nptUs;
            info->mNPTMappingValid = true;
            break;
        }

        case SDPLoader::kWhatSDPLoaded:
        {
            onSDPLoaded(msg);
            break;
        }

        default:
            TRESPASS();
    }
}
void QwwSmtpClientPrivate::onError(QAbstractSocket::SocketError e)
{
    emit q->socketError(e, socket->errorString());
    onDisconnected();
}
示例#7
0
ISocketMultiplexerJob*
TCPSocket::serviceConnected(ISocketMultiplexerJob* job,
                bool read, bool write, bool error)
{
    Lock lock(&m_mutex);

    if (error) {
        sendEvent(m_events->forISocket().disconnected());
        onDisconnected();
        return newJob();
    }

    EJobResult result = kRetry;
    if (write) {
        try {
            result = doWrite();
        }
        catch (XArchNetworkShutdown&) {
            // remote read end of stream hungup.  our output side
            // has therefore shutdown.
            onOutputShutdown();
            sendEvent(m_events->forIStream().outputShutdown());
            if (!m_readable && m_inputBuffer.getSize() == 0) {
                sendEvent(m_events->forISocket().disconnected());
                m_connected = false;
            }
            result = kNew;
        }
        catch (XArchNetworkDisconnected&) {
            // stream hungup
            onDisconnected();
            sendEvent(m_events->forISocket().disconnected());
            result = kNew;
        }
        catch (XArchNetwork& e) {
            // other write error
            LOG((CLOG_WARN "error writing socket: %s", e.what()));
            onDisconnected();
            sendEvent(m_events->forIStream().outputError());
            sendEvent(m_events->forISocket().disconnected());
            result = kNew;
        }
    }

    if (read && m_readable) {
        try {
            result = doRead();
        }
        catch (XArchNetworkDisconnected&) {
            // stream hungup
            sendEvent(m_events->forISocket().disconnected());
            onDisconnected();
            result = kNew;
        }
        catch (XArchNetwork& e) {
            // ignore other read error
            LOG((CLOG_WARN "error reading socket: %s", e.what()));
        }
    }

    return result == kBreak ? nullptr : result == kNew ? newJob() : job;
}
示例#8
0
void RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    if (msg->what() == kWhatDisconnect) {
        uint32_t replyID;
        CHECK(msg->senderAwaitsResponse(&replyID));

        mDisconnectReplyID = replyID;
        finishDisconnectIfPossible();
        return;
    } else if (msg->what() == kWhatPerformSeek) {
        int32_t generation;
        CHECK(msg->findInt32("generation", &generation));

        if (generation != mSeekGeneration) {
            // obsolete.
            return;
        }

        int64_t seekTimeUs;
        CHECK(msg->findInt64("timeUs", &seekTimeUs));

        performSeek(seekTimeUs);
        return;
    } else if (msg->what() == kWhatPerformPlay) {
        int64_t playTimeUs;
        CHECK(msg->findInt64("timeUs", &playTimeUs));
        performPlay(playTimeUs);
        return;
    } else if (msg->what() == kWhatPerformPause) {
        performPause();
        return;
    } else if (msg->what() == kWhatPerformResume) {
        performResume();
        return;
    } else if (msg->what() == kWhatPerformSuspend) {
        performSuspend();
        return;
    } else if (msg->what() == kWhatPerformPlaybackEnded) {
        performPlaybackEnded();
        return;
    }

    CHECK_EQ(msg->what(), (uint32_t)kWhatNotify);

    int32_t what;
    int32_t isSeekable = 0;
    CHECK(msg->findInt32("what", &what));

    switch (what) {
        case RtspConnectionHandler::kWhatConnected:
            CHECK(msg->findInt32("isSeekable", &isSeekable));
            onConnected((isSeekable ? true:false));
            break;

        case RtspConnectionHandler::kWhatDisconnected:
            onDisconnected(msg);
            break;

        case RtspConnectionHandler::kWhatSeekDone:
        {
            mState = PLAYING;
            // Even if we have reset mLatestPausedUnit in performSeek(),
            // it's still possible that kWhatPausedDone event may arrive
            // because of previous performPause() command.
            for (size_t i = 0; i < mTracks.size(); ++i) {
                TrackInfo *info = &mTracks.editItemAt(i);
                info->mLatestPausedUnit = 0;
            }
            mLatestPausedUnit = 0;
            break;
        }

        case RtspConnectionHandler::kWhatPausedDone:
        {
            // Reject invalid state transition.
            if (mState != PAUSING) {
                return;
            }
            mState = PAUSED;

            for (size_t i = 0; i < mTracks.size(); ++i) {
                TrackInfo *info = &mTracks.editItemAt(i);
                info->mLatestPausedUnit = info->mLatestReceivedUnit;
            }

            // The timestamp after a 'Pause' is done is the earliest
            // timestamp among all of the latest received units.
            TrackInfo *info = &mTracks.editItemAt(0);
            mLatestPausedUnit = info->mLatestReceivedUnit;
            for (size_t i = 1; i < mTracks.size(); ++i) {
                TrackInfo *info = &mTracks.editItemAt(i);
                if (mLatestPausedUnit > info->mLatestReceivedUnit) {
                    mLatestPausedUnit = info->mLatestReceivedUnit;
                }
            }

            if (mPlayPending) {
                mPlayPending = false;
                performPlay(mLatestPausedUnit);
            }
            break;
        }

        case RtspConnectionHandler::kWhatAccessUnitComplete:
        {
            if (!isValidState()) {
                LOGI("We're disconnected, dropping access unit.");
                break;
            }
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            sp<RefBase> obj;
            CHECK(msg->findObject("accessUnit", &obj));

            sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());

            int32_t damaged;
            if (accessUnit->meta()->findInt32("damaged", &damaged)
                    && damaged) {
                LOGI("dropping damaged access unit.");
                break;
            }

            TrackInfo *info = &mTracks.editItemAt(trackIndex);

            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                uint32_t rtpTime;
                CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));

                if (!info->mNPTMappingValid) {
                    // This is a live stream, we didn't receive any normal
                    // playtime mapping. Assume the first packets correspond
                    // to time 0.

                    LOGV("This is a live stream, assuming time = 0");

                    info->mRTPTime = rtpTime;
                    info->mNormalPlaytimeUs = 0ll;
                    info->mNPTMappingValid = true;
                }

                int64_t nptUs =
                    ((double)rtpTime - (double)info->mRTPTime)
                        / info->mTimeScale
                        * 1000000ll
                        + info->mNormalPlaytimeUs;

                accessUnit->meta()->setInt64("timeUs", nptUs);
                info->mLatestReceivedUnit = nptUs;
                // Drop the frames that are older than the frames in the queue.
                if (info->mLatestPausedUnit && (int64_t)info->mLatestPausedUnit > nptUs) {
                    break;
                }
                source->queueAccessUnit(accessUnit);
            }

            onTrackDataAvailable(trackIndex);
            break;
        }

        case RtspConnectionHandler::kWhatEOS:
        {
            if (!isValidState()) {
                LOGI("We're disconnected, dropping end-of-stream message.");
                break;
            }
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            int32_t finalResult;
            CHECK(msg->findInt32("finalResult", &finalResult));
            CHECK_NE(finalResult, (status_t)OK);

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                source->signalEOS(finalResult);
            }

            onTrackEndOfStream(trackIndex);
            break;
        }

        case RtspConnectionHandler::kWhatSeekDiscontinuity:
        {
            if (!isValidState()) {
                LOGI("We're disconnected, dropping seek discontinuity message.");
                break;
            }
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
#if ANDROID_VERSION >= 21
                source->queueDiscontinuity(ATSParser::DISCONTINUITY_TIME, NULL,
                                           true /* discard */);
#else
                source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
#endif
            }

            break;
        }

        case RtspConnectionHandler::kWhatNormalPlayTimeMapping:
        {
            if (!isValidState()) {
                LOGI("We're disconnected, dropping normal play time mapping "
                     "message.");
                break;
            }
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            uint32_t rtpTime;
            CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));

            int64_t nptUs;
            CHECK(msg->findInt64("nptUs", &nptUs));

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            info->mRTPTime = rtpTime;
            info->mNormalPlaytimeUs = nptUs;
            info->mNPTMappingValid = true;
            break;
        }

        case RtspConnectionHandler::kWhatTryTCPInterleaving:
        {
            // By default, we will request to deliver RTP over UDP. If the play
            // request timed out and we didn't receive any RTP packet, we will
            // fail back to use RTP interleaved in the existing RTSP/TCP
            // connection. And in this case, we have to explicitly perform
            // another play event to request the server to start streaming
            // again.
            int64_t playTimeUs;
            if (!msg->findInt64("timeUs", &playTimeUs)) {
                playTimeUs = 0;
            }
            performPlay(playTimeUs);
            break;
        }

        default:
            TRESPASS();
    }
}
示例#9
0
void TLSConnection::handleRawDisconnected(const boost::optional<Error>& error) {
	onDisconnected(error);
}
示例#10
0
void Hub::handleDisconnected()
{
    onDisconnected();
}
示例#11
0
void RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    if (msg->what() == kWhatDisconnect) {
        uint32_t replyID;
        CHECK(msg->senderAwaitsResponse(&replyID));

        mDisconnectReplyID = replyID;
        finishDisconnectIfPossible();
        return;
    } else if (msg->what() == kWhatPerformSeek) {
        int32_t generation;
        CHECK(msg->findInt32("generation", &generation));

        if (generation != mSeekGeneration) {
            // obsolete.
            return;
        }

        int64_t seekTimeUs;
        CHECK(msg->findInt64("timeUs", &seekTimeUs));

        performSeek(seekTimeUs);
        return;
    } else if (msg->what() == kWhatPerformPlay) {
        int64_t playTimeUs;
        CHECK(msg->findInt64("timeUs", &playTimeUs));
        performPlay(playTimeUs);
        return;
    } else if (msg->what() == kWhatPerformPause) {
        performPause();
        return;
    } else if (msg->what() == kWhatPerformResume) {
        performResume();
        return;
    } else if (msg->what() == kWhatPerformSuspend) {
        performSuspend();
        return;
    }

    CHECK_EQ(msg->what(), (uint32_t)kWhatNotify);

    int32_t what;
    int32_t isSeekable = 0;
    CHECK(msg->findInt32("what", &what));

    switch (what) {
        case RtspConnectionHandler::kWhatConnected:
            CHECK(msg->findInt32("isSeekable", &isSeekable));
            onConnected((isSeekable ? true:false));
            break;

        case RtspConnectionHandler::kWhatDisconnected:
            onDisconnected(msg);
            break;

        case RtspConnectionHandler::kWhatSeekDone:
        {
            mState = PLAYING;
            break;
        }

        case RtspConnectionHandler::kWhatPausedDone:
        {
            for (size_t i = 0; i < mTracks.size(); ++i) {
                TrackInfo *info = &mTracks.editItemAt(i);
                info->mLatestPausedUnit = info->mLatestReceivedUnit;
            }

            // The timestamp after a 'Pause' is done is the earliest
            // timestamp among all of the latest received units.
            TrackInfo *info = &mTracks.editItemAt(0);
            mLatestPausedUnit = info->mLatestReceivedUnit;
            for (size_t i = 1; i < mTracks.size(); ++i) {
                TrackInfo *info = &mTracks.editItemAt(i);
                if (mLatestPausedUnit > info->mLatestReceivedUnit) {
                    mLatestPausedUnit = info->mLatestReceivedUnit;
                }
            }
            break;
        }

        case RtspConnectionHandler::kWhatAccessUnit:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            sp<RefBase> obj;
            CHECK(msg->findObject("accessUnit", &obj));

            sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());

            int32_t damaged;
            if (accessUnit->meta()->findInt32("damaged", &damaged)
                    && damaged) {
                LOGI("dropping damaged access unit.");
                break;
            }

            TrackInfo *info = &mTracks.editItemAt(trackIndex);

            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                uint32_t rtpTime;
                CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));

                if (!info->mNPTMappingValid) {
                    // This is a live stream, we didn't receive any normal
                    // playtime mapping. Assume the first packets correspond
                    // to time 0.

                    LOGV("This is a live stream, assuming time = 0");

                    info->mRTPTime = rtpTime;
                    info->mNormalPlaytimeUs = 0ll;
                    info->mNPTMappingValid = true;
                }

                int64_t nptUs =
                    ((double)rtpTime - (double)info->mRTPTime)
                        / info->mTimeScale
                        * 1000000ll
                        + info->mNormalPlaytimeUs;

                accessUnit->meta()->setInt64("timeUs", nptUs);
                info->mLatestReceivedUnit = nptUs;
                // Drop the frames that are older than the frames in the queue.
                if (info->mLatestPausedUnit && (int64_t)info->mLatestPausedUnit > nptUs) {
                  break;
                }
                source->queueAccessUnit(accessUnit);
            }

            onTrackDataAvailable(trackIndex);
            break;
        }

        case RtspConnectionHandler::kWhatEOS:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            int32_t finalResult;
            CHECK(msg->findInt32("finalResult", &finalResult));
            CHECK_NE(finalResult, (status_t)OK);

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                source->signalEOS(finalResult);
            }

            break;
        }

        case RtspConnectionHandler::kWhatSeekDiscontinuity:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
            }

            break;
        }

        case RtspConnectionHandler::kWhatNormalPlayTimeMapping:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            uint32_t rtpTime;
            CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));

            int64_t nptUs;
            CHECK(msg->findInt64("nptUs", &nptUs));

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            info->mRTPTime = rtpTime;
            info->mNormalPlaytimeUs = nptUs;
            info->mNPTMappingValid = true;
            break;
        }

        default:
            TRESPASS();
    }
}