示例#1
0
文件: rtsp.c 项目: rainlake/shairport
static void *rtsp_conversation_thread_func(void *pconn) {
    // SIGUSR1 is used to interrupt this thread if blocked for read
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGUSR1);
    pthread_sigmask(SIG_UNBLOCK, &set, NULL);

    rtsp_conn_info *conn = pconn;

    rtsp_message *req, *resp;
    char *hdr, *auth_nonce = NULL;
    while ((req = rtsp_read_request(conn->fd))) {
        resp = msg_init();
        resp->respcode = 400;

        apple_challenge(conn->fd, req, resp);
        hdr = msg_get_header(req, "CSeq");
        if (hdr)
            msg_add_header(resp, "CSeq", hdr);
        msg_add_header(resp, "Audio-Jack-Status", "connected; type=analog");

        if (rtsp_auth(&auth_nonce, req, resp))
            goto respond;

        struct method_handler *mh;
        for (mh=method_handlers; mh->method; mh++) {
            if (!strcmp(mh->method, req->method)) {
                mh->handler(conn, req, resp);
                break;
            }
        }

respond:
        msg_write_response(conn->fd, resp);
        msg_free(req);
        msg_free(resp);
    }

    debug(1, "closing RTSP connection\n");
    if (conn->fd > 0)
        close(conn->fd);
    if (rtsp_playing()) {
        rtp_shutdown();
        debug(1, "stop player\n");
        player_stop();
        debug(1, "player stoped\n");
        please_shutdown = 0;
        pthread_mutex_unlock(&playing_mutex);
    }
    if (auth_nonce)
        free(auth_nonce);
    conn->running = 0;
    debug(2, "terminating RTSP thread\n");
    return NULL;
}
示例#2
0
static int rtsp_read_options(AVFormatContext *s)
{
    RTSPState *rt             = s->priv_data;
    RTSPMessageHeader request = { 0 };
    int ret                   = 0;

    /* Parsing headers */
    ret = rtsp_read_request(s, &request, "OPTIONS");
    if (ret)
        return ret;
    rt->seq++;
    /* Send Reply */
    rtsp_send_reply(s, RTSP_STATUS_OK,
                    "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, RECORD\r\n",
                    request.seq);
    return 0;
}
示例#3
0
static int rtsp_read_record(AVFormatContext *s)
{
    RTSPState *rt             = s->priv_data;
    RTSPMessageHeader request = { 0 };
    int ret                   = 0;
    char responseheaders[1024];

    ret = rtsp_read_request(s, &request, "RECORD");
    if (ret)
        return ret;
    ret = check_sessionid(s, &request);
    if (ret)
        return ret;
    rt->seq++;
    snprintf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
             rt->session_id);
    rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);

    rt->state = RTSP_STATE_STREAMING;
    return 0;
}
示例#4
0
int ff_rtsp_parse_streaming_commands(AVFormatContext *s)
{
    RTSPState *rt = s->priv_data;
    unsigned char rbuf[4096];
    unsigned char method[10];
    char uri[500];
    int ret;
    int rbuflen               = 0;
    RTSPMessageHeader request = { 0 };
    enum RTSPMethod methodcode;

    ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
    if (ret < 0)
        return ret;
    ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method,
                             sizeof(method), &methodcode);
    if (ret) {
        av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n");
        return ret;
    }

    ret = rtsp_read_request(s, &request, method);
    if (ret)
        return ret;
    rt->seq++;
    if (methodcode == PAUSE) {
        rt->state = RTSP_STATE_PAUSED;
        ret       = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
        // TODO: Missing date header in response
    } else if (methodcode == OPTIONS) {
        ret = rtsp_send_reply(s, RTSP_STATUS_OK,
                              "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, "
                              "RECORD\r\n", request.seq);
    } else if (methodcode == TEARDOWN) {
        rt->state = RTSP_STATE_IDLE;
        ret       = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
        return 0;
    }
    return ret;
}
示例#5
0
static int rtsp_read_announce(AVFormatContext *s)
{
    RTSPState *rt             = s->priv_data;
    RTSPMessageHeader request = { 0 };
    char sdp[4096];
    int  ret;

    ret = rtsp_read_request(s, &request, "ANNOUNCE");
    if (ret)
        return ret;
    rt->seq++;
    if (strcmp(request.content_type, "application/sdp")) {
        av_log(s, AV_LOG_ERROR, "Unexpected content type %s\n",
               request.content_type);
        rtsp_send_reply(s, RTSP_STATUS_SERVICE, NULL, request.seq);
        return AVERROR_OPTION_NOT_FOUND;
    }
    if (request.content_length && request.content_length < sizeof(sdp) - 1) {
        /* Read SDP */
        if (ffurl_read_complete(rt->rtsp_hd, sdp, request.content_length)
            < request.content_length) {
            av_log(s, AV_LOG_ERROR,
                   "Unable to get complete SDP Description in ANNOUNCE\n");
            rtsp_send_reply(s, RTSP_STATUS_INTERNAL, NULL, request.seq);
            return AVERROR(EIO);
        }
        sdp[request.content_length] = '\0';
        av_log(s, AV_LOG_VERBOSE, "SDP: %s\n", sdp);
        ret = ff_sdp_parse(s, sdp);
        if (ret)
            return ret;
        rtsp_send_reply(s, RTSP_STATUS_OK, NULL, request.seq);
        return 0;
    }
    av_log(s, AV_LOG_ERROR,
           "Content-Length header value exceeds sdp allocated buffer (4KB)\n");
    rtsp_send_reply(s, RTSP_STATUS_INTERNAL,
                    "Content-Length exceeds buffer size", request.seq);
    return AVERROR(EIO);
}
示例#6
0
static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl)
{
    RTSPState *rt             = s->priv_data;
    RTSPMessageHeader request = { 0 };
    int ret                   = 0;
    char url[1024];
    RTSPStream *rtsp_st;
    char responseheaders[1024];
    int localport    = -1;
    int transportidx = 0;
    int streamid     = 0;

    ret = rtsp_read_request(s, &request, "SETUP");
    if (ret)
        return ret;
    rt->seq++;
    if (!request.nb_transports) {
        av_log(s, AV_LOG_ERROR, "No transport defined in SETUP\n");
        return AVERROR_INVALIDDATA;
    }
    for (transportidx = 0; transportidx < request.nb_transports;
         transportidx++) {
        if (!request.transports[transportidx].mode_record ||
            (request.transports[transportidx].lower_transport !=
             RTSP_LOWER_TRANSPORT_UDP &&
             request.transports[transportidx].lower_transport !=
             RTSP_LOWER_TRANSPORT_TCP)) {
            av_log(s, AV_LOG_ERROR, "mode=record/receive not set or transport"
                   " protocol not supported (yet)\n");
            return AVERROR_INVALIDDATA;
        }
    }
    if (request.nb_transports > 1)
        av_log(s, AV_LOG_WARNING, "More than one transport not supported, "
               "using first of all\n");
    for (streamid = 0; streamid < rt->nb_rtsp_streams; streamid++) {
        if (!strcmp(rt->rtsp_streams[streamid]->control_url,
                    controlurl))
            break;
    }
    if (streamid == rt->nb_rtsp_streams) {
        av_log(s, AV_LOG_ERROR, "Unable to find requested track\n");
        return AVERROR_STREAM_NOT_FOUND;
    }
    rtsp_st   = rt->rtsp_streams[streamid];
    localport = rt->rtp_port_min;

    if (request.transports[0].lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
        rt->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
        if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
            return ret;
        }
        rtsp_st->interleaved_min = request.transports[0].interleaved_min;
        rtsp_st->interleaved_max = request.transports[0].interleaved_max;
        snprintf(responseheaders, sizeof(responseheaders), "Transport: "
                 "RTP/AVP/TCP;unicast;mode=receive;interleaved=%d-%d"
                 "\r\n", request.transports[0].interleaved_min,
                 request.transports[0].interleaved_max);
    } else {
        do {
            ff_url_join(url, sizeof(url), "rtp", NULL, host, localport, NULL);
            av_dlog(s, "Opening: %s", url);
            ret = ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
                             &s->interrupt_callback, NULL);
            if (ret)
                localport += 2;
        } while (ret || localport > rt->rtp_port_max);
        if (localport > rt->rtp_port_max) {
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
            return ret;
        }

        av_dlog(s, "Listening on: %d",
                ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle));
        if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
            return ret;
        }

        localport = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle);
        snprintf(responseheaders, sizeof(responseheaders), "Transport: "
                 "RTP/AVP/UDP;unicast;mode=receive;source=%s;"
                 "client_port=%d-%d;server_port=%d-%d\r\n",
                 host, request.transports[0].client_port_min,
                 request.transports[0].client_port_max, localport,
                 localport + 1);
    }

    /* Establish sessionid if not previously set */
    /* Put this in a function? */
    /* RFC 2326: session id must be at least 8 digits */
    while (strlen(rt->session_id) < 8)
        av_strlcatf(rt->session_id, 512, "%u", av_get_random_seed());

    av_strlcatf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
                rt->session_id);
    /* Send Reply */
    rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);

    rt->state = RTSP_STATE_PAUSED;
    return 0;
}