android多媒体框架之流媒体具体流程篇2----base on jellybean(十二)

上篇我们讲了流媒体RTSP部分的setdataSource方法,prepare没有实质的东西,我们直接讲start方法, 这个方法是它的核心方法,比较复杂,我们先来看下整个start方法的时序图吧,让大家有个大概的了解:

 

 

跟踪下代码,看看start里面有什么名堂?

NuPlayer.cpp

void NuPlayer::start() {

    (new AMessage(kWhatStart, id()))->post();

}

 

void NuPlayer::onMessageReceived(const sp &msg) {

    switch (msg->what()) {

case kWhatStart:

        {

            ALOGV("kWhatStart");

 

            mVideoIsAVC = false;

            mAudioEOS = false;

            mVideoEOS = false;

            mDecoderEOS = false;

            mSkipRenderingAudioUntilMediaTimeUs = -1;

            mSkipRenderingVideoUntilMediaTimeUs = -1;

            mVideoLateByUs = 0;

            mNumFramesTotal = 0;

            mNumFramesDropped = 0;

 

        (1)    mSource->start();-------RTSPSource

 

        (2)    mRenderer = new Renderer(

                    mAudioSink,

                    new AMessage(kWhatRendererNotify, id()));

 

         (3) postScanSources();

            break;

        }

}

从代码我们看到start分三步走:start(通过socket跟web服务器连接并通过HTTP协议从Web服务器获取所请求视频服务的演示描述等),创建Renderer(new Renderer),转载解码器并解码(posetScanSources).

首先我们来探讨下mSource->start()mSource就是RTSPSource,

先看下总的流程图吧(画得不怎么好,将就看吧):

 

void NuPlayer::RTSPSource::start() {

    if (mLooper == NULL) {

        mLooper = new ALooper;

        mLooper->setName("rtsp");

        mLooper->start();

 

        mReflector = new AHandlerReflector(this);

        mLooper->registerHandler(mReflector);-------创建一个‘rtsp’looper

    }

 

    CHECK(mHandler == NULL);

 

    sp notify = new AMessage(kWhatNotify, mReflector->id());-----记住这个消息

 

    mHandler = new MyHandler(mURL.c_str(),notify, mUIDValid, mUID);

    mLooper->registerHandler(mHandler);-----MyHandler,‘rtsplooper连接起来

 

    CHECK_EQ(mState, (int)DISCONNECTED);

    mState = CONNECTING;

 

    mHandler->connect();-------调用myhandlerconnect方法

}

 

我们来看这个Myhandler的构造函数:

 

 

MyHandler(

            const char *url,

            const sp ¬ify,

            bool uidValid = false, uid_t uid = 0)

        : mNotify(notify),

          mUIDValid(uidValid),

          mUID(uid),

          mNetLooper(new ALooper),

          mConn(new ARTSPConnection(mUIDValid, mUID)),-----创建ARTSPConnection,主要用来跟服务器连接

          mRTPConn(new ARTPConnection),

          ………………………..

          mKeepAliveGeneration(0) {

        mNetLooper->setName("rtsp net");

        mNetLooper->start(false /* runOnCallingThread */,

                          false /* canCallJava */,

                          PRIORITY_HIGHEST);-------自己创建一个looper

 

        ……………

    }

在MyHandler中我们创建了ARTSPConnection,这将在我们的connect方法中会用到:

 

void connect() {

        looper()->registerHandler(mConn);

        (1 ? mNetLooper : looper())->registerHandler(mRTPConn);

 

        sp notify = new AMessage('biny', id());

        mConn->observeBinaryData(notify);

 

        sp reply = new AMessage('conn', id());----记住这AMessage,这个将会传给ARTSPConnection,并传回来

        mConn->connect(mOriginalSessionURL.c_str(), reply);----mConn == ARTSPConnection

    }

 

void ARTSPConnection::connect(const char *url, const sp &reply) {

    sp msg = new AMessage(kWhatConnect, id());

    msg->setString("url", url);

    msg->setMessage("reply", reply);

    msg->post();

}

 

void ARTSPConnection::onMessageReceived(const sp &msg) {

    switch (msg->what()) {

        case kWhatConnect:

            onConnect(msg);

            break;

………..

}

 

void ARTSPConnection::onConnect(const sp &msg) {

    ++mConnectionID;

…………………

    AString url;

    CHECK(msg->findString("url", &url));

 

    sp reply;

    CHECK(msg->findMessage("reply", &reply));------reply == 'conn'

 

………………….

    mSocket = socket(AF_INET, SOCK_STREAM, 0); ------  建立一个socket

 

    if (mUIDValid) {

        HTTPBase::RegisterSocketUserTag(mSocket, mUID,

                                       (uint32_t)*(uint32_t*) "RTSP");

    }

 

    MakeSocketBlocking(mSocket, false);------设置socket为非阻

 

    struct sockaddr_in remote;

    memset(remote.sin_zero, 0, sizeof(remote.sin_zero));

    remote.sin_family = AF_INET;

    remote.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;

    remote.sin_port = htons(port);

 

    int err = ::connect(

            mSocket, (const struct sockaddr *)&remote, sizeof(remote));----连接

 

    reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr));

 

    if (err < 0) {

        if (errno == EINPROGRESS) {-----当非阻塞时,connect立刻返回-1,同时errno设置为EINPROGRESS。然后再检测socket是否可写,如果可写了,说明
 socket
已经建立的连

            sp msg = new AMessage(kWhatCompleteConnection, id());

            msg->setMessage("reply", reply);

            msg->setInt32("connection-id", mConnectionID);

            msg->post();

            return;

        }

 

……………………….

    reply->post();

}

 

void ARTSPConnection::onCompleteConnection(const sp &msg) {

    sp reply;

    CHECK(msg->findMessage("reply", &reply));

 

    int32_t connectionID;

    CHECK(msg->findInt32("connection-id", &connectionID));

 

    if ((connectionID != mConnectionID) || mState != CONNECTING) {

        // While we were attempting to connect, the attempt was

        // cancelled.

        reply->setInt32("result", -ECONNABORTED);

        reply->post();

        return;

    }

 

    struct timeval tv;

    tv.tv_sec = 0;

    tv.tv_usec = kSelectTimeoutUs;-----超时时间

 

    fd_set ws;

    FD_ZERO(&ws);

    FD_SET(mSocket, &ws);

 

    int res = select(mSocket + 1, NULL, &ws, NULL, &tv);

…………

    int err;

    socklen_t optionLen = sizeof(err);

    CHECK_EQ(getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &err, &optionLen), 0);

    CHECK_EQ(optionLen, (socklen_t)sizeof(err));

 

    if (err != 0) {

        ALOGE("err = %d (%s)", err, strerror(err));

 

        reply->setInt32("result", -err);

 

        mState = DISCONNECTED;

        if (mUIDValid) {

            HTTPBase::UnRegisterSocketUserTag(mSocket);

        }

        close(mSocket);

        mSocket = -1;

    } else {

        reply->setInt32("result", OK);

        mState = CONNECTED;

        mNextCSeq = 1;

 

        postReceiveReponseEvent();------处理从服务器回来的reponse

    }

 

    reply->post();-----postmyhandler处理

 

}

 

 

 

又回到MyHandler.h,真够绕的啊!

 

virtual void onMessageReceived(const sp &msg) {

        switch (msg->what()) {

            case 'conn':

            {

                int32_t result;

                CHECK(msg->findInt32("result", &result));

 

                ALOGI("connection request completed with result %d (%s)",

                     result, strerror(-result));

 

                if (result == OK) {

                    AString request;

                    request = "DESCRIBE ";----DESCRIBE获得媒体文件的类型的请求类型

                    request.append(mSessionURL);

                    request.append(" RTSP/1.0\r\n");

                    request.append("Accept: application/sdp\r\n");

                    request.append("\r\n");   -----建立连接后,发送获得媒体文件的类型的request

 

                    sp reply = new AMessage('desc', id());

                    mConn->sendRequest(request.c_str(), reply);

                } else {

                    (new AMessage('disc', id()))->post();

                }

                break;

}

看到”DESRIBE”,我们可以回头看看流媒体的协议一张http://blog.csdn.net/tjy1985/article/details/7996121,在播放流媒体前,首先要从web服务器获取媒体文件的类型,要获取这些信息,就得往服务器发生“DESCRIBE”的请求,我们又得回到ARTSPConnection了:

 

void ARTSPConnection::sendRequest(

        const char *request, const sp &reply) {

    sp msg = new AMessage(kWhatSendRequest, id());

    msg->setString("request", request);

    msg->setMessage("reply", reply);

    msg->post();

}

 

 

void ARTSPConnection::onMessageReceived(const sp &msg) {

    switch (msg->what()) {

case kWhatSendRequest:

            onSendRequest(msg);

            break;

}

 

void ARTSPConnection::onSendRequest(const sp &msg) {

    sp reply;

    CHECK(msg->findMessage("reply", &reply));

 

    if (mState != CONNECTED) {

        reply->setInt32("result", -ENOTCONN);

        reply->post();

        return;

    }

 

    …………………..

    size_t numBytesSent = 0;

    while (numBytesSent < request.size()) {

        ssize_t n =

            send(mSocket, request.c_str() + numBytesSent,

                 request.size() - numBytesSent, 0);-------通过sendrequest通过socket发送给服务器端

 

        if (n < 0 && errno == EINTR) {

            continue;

        }

 

        if (n <= 0) {

            performDisconnect();

 

            if (n == 0) {

                // Server closed the connection.

                ALOGE("Server unexpectedly closed the connection.");

 

                reply->setInt32("result", ERROR_IO);

                reply->post();

            } else {

                ALOGE("Error sending rtsp request. (%s)", strerror(errno));

                reply->setInt32("result", -errno);

                reply->post();

            }

 

            return;

        }

 

        numBytesSent += (size_t)n;

    }

 

    mPendingRequests.add(cseq, reply);

}

 

在等待服务器的response后,我们又回到MyHandler.h的onMessageReceived函数:

 

  virtual void onMessageReceived(const sp &msg) {

        switch (msg->what()) {

            case 'desc':

            {

                int32_t result;

                CHECK(msg->findInt32("result", &result));

 

                ALOGI("DESCRIBE completed with result %d (%s)",

                     result, strerror(-result));

 

                if (result == OK) {

                    sp obj;

                    CHECK(msg->findObject("response", &obj));

                    sp response =

                        static_cast(obj.get());

…………………………….

                    if (response->mStatusCode != 200) {

                        result = UNKNOWN_ERROR;

                    } else {

                        mSessionDesc = new ASessionDescription; ---媒体流的演示描述,该文件提供的信息定位视频服务地址(包括视频服务器地址和端口号)及视频服务的编码方式等信息

                        mSessionDesc->setTo(

                               response->mContent->data(),

                               response->mContent->size());

 

…………..                        

                             if (mSessionDesc->countTracks() < 2) {

                                // There's no actual tracks in this session.

                                // The first "track" is merely session meta

                                // data.

 

                                ALOGW("Session doesn't contain any playable "

                                     "tracks. Aborting.");

                                result = ERROR_UNSUPPORTED;

                            } else {

                               setupTrack(1);--------此处到了我们RTSP中的所有的操作中SETUP步骤

                            }

                        }

                    }

                }

                if (result != OK) {

                    sp reply = new AMessage('disc', id());

                    mConn->disconnect(reply);

                }

                break;

            }

}

 

bool ASessionDescription::setTo(const void *data, size_t size) {

    mIsValid = parse(data, size);---解析该SessionDescription

 

    if (!mIsValid) {

        mTracks.clear();

        mFormats.clear();

    }

    return mIsValid;

}

 

 

 

到此我们连接上web服务器,并从web服务器获取sessionDescription分析完了,具体还得大伙慢慢琢磨。下篇我们将要开始跟流媒体服务打交道了!

你可能感兴趣的:(Android,Multimedia,Framework)