Esempio n. 1
0
static ngx_int_t
ngx_rtmp_cmd_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v)
{
    ngx_rtmp_send_user_stream_eof(s, NGX_RTMP_CMD_MSID);

    /* Whatever happens return OK
     * since we should be careful with destruction */
    return NGX_OK;
}
static ngx_int_t
ngx_rtmp_cmd_seek(ngx_rtmp_session_t *s, ngx_rtmp_seek_t *v)
{
    ngx_rtmp_header_t               h;

    static double                   trans;

    static ngx_rtmp_amf_elt_t       out_inf[] = {

        { NGX_RTMP_AMF_STRING,
          ngx_string("code"),
          "NetStream.Play.Reset", 0 },

        { NGX_RTMP_AMF_STRING,
          ngx_string("level"),
          "status", 0 },

        { NGX_RTMP_AMF_STRING,
          ngx_string("description"),
          "Paused.", 0 },
    };

    static ngx_rtmp_amf_elt_t       out_elts[] = {

        { NGX_RTMP_AMF_STRING,
          ngx_null_string,
          "onStatus", 0 },

        { NGX_RTMP_AMF_NUMBER, 
          ngx_null_string,
          &trans, 0 },

        { NGX_RTMP_AMF_NULL, 
          ngx_null_string,
          NULL, 0 },

        { NGX_RTMP_AMF_OBJECT, 
          ngx_null_string,
          out_inf, sizeof(out_inf) },
    };

    ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
            "seek: offset=%i", (ngx_int_t) v->offset);

    /* send onStatus reply */
    ngx_memzero(&h, sizeof(h));
    h.type = NGX_RTMP_MSG_AMF_CMD;
    h.csid = NGX_RTMP_CMD_CSID_AMF;
    h.msid = NGX_RTMP_CMD_MSID;

    return (ngx_rtmp_send_user_stream_eof(s, NGX_RTMP_CMD_MSID) != NGX_OK
        || ngx_rtmp_send_user_stream_begin(s, NGX_RTMP_CMD_MSID) != NGX_OK
        || ngx_rtmp_send_amf(s, &h, out_elts,
            sizeof(out_elts) / sizeof(out_elts[0])) != NGX_OK)
        ? NGX_ERROR
        : NGX_OK;
}
Esempio n. 3
0
static void
ngx_rtmp_play_send(ngx_event_t *e)
{
    ngx_rtmp_session_t     *s = e->data;
    ngx_rtmp_play_ctx_t    *ctx;
    ngx_int_t               rc;

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module);

    if (ctx == NULL || ctx->fmt == NULL || ctx->fmt->send == NULL) {
        return;
    }

    rc = ctx->fmt->send(s, &ctx->file);

    if (rc > 0) {
        ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                       "play: send schedule %i", rc);

        ngx_add_timer(e, rc);
        return;
    }

    if (rc == NGX_AGAIN) {
        ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                       "play: send buffer full");

        ngx_post_event(e, &s->posted_dry_events);
        return;
    }

    if (rc == NGX_OK) {
        ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                       "play: send restart");

        ngx_post_event(e, &ngx_posted_events);
        return;
    }


    ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "play: send done");

    ngx_rtmp_send_user_stream_eof(s, NGX_RTMP_MSID);

    ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", "Stopped");
}
static void
ngx_rtmp_play_send(ngx_event_t *e)
{
    ngx_rtmp_session_t             *s;
    ngx_rtmp_play_ctx_t            *ctx;
    uint32_t                        last_timestamp;
    ngx_rtmp_header_t               h, lh;
    ngx_rtmp_core_srv_conf_t       *cscf;
    ngx_chain_t                    *out, in;
    ngx_buf_t                       in_buf;
    ssize_t                         n;
    uint32_t                        buflen, end_timestamp, size;

    s = e->data;

    cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module);
    if (ctx == NULL) {
        return;
    }

    if (ctx->offset == -1) {
        ctx->offset = ngx_rtmp_play_timestamp_to_offset(s,
                                                        ctx->start_timestamp);
        ctx->start_timestamp = -1; /* set later from actual timestamp */
    }

    ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                  "play: read tag at offset=%i", ctx->offset);

    /* read tag header */
    n = ngx_read_file(&ctx->file, ngx_rtmp_play_header, 
                      sizeof(ngx_rtmp_play_header), ctx->offset);
    if (n != sizeof(ngx_rtmp_play_header)) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                     "play: could not read flv tag header");
        ngx_rtmp_send_user_stream_eof(s, 1);
        return;
    }

    /* parse header fields */
    ngx_memzero(&h, sizeof(h));
    h.msid = NGX_RTMP_LIVE_MSID;
    h.type = ngx_rtmp_play_header[0];
    size = 0;
    ngx_rtmp_rmemcpy(&size, ngx_rtmp_play_header + 1, 3);
    ngx_rtmp_rmemcpy(&h.timestamp, ngx_rtmp_play_header + 4, 3);
    ((u_char *) &h.timestamp)[3] = ngx_rtmp_play_header[7];

    ctx->offset += (sizeof(ngx_rtmp_play_header) + size + 4);

    last_timestamp = 0;

    switch (h.type) {
        case NGX_RTMP_MSG_AUDIO:
            h.csid = NGX_RTMP_LIVE_CSID_AUDIO;
            last_timestamp = ctx->last_audio;
            ctx->last_audio = h.timestamp;
            break;

        case NGX_RTMP_MSG_VIDEO:
            h.csid = NGX_RTMP_LIVE_CSID_VIDEO;
            last_timestamp = ctx->last_video;
            ctx->last_video = h.timestamp;
            break;

        default:
            goto skip;
    }

    ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                  "play: read tag type=%i size=%uD timestamp=%uD "
                  "last_timestamp=%uD", 
                  (ngx_int_t) h.type,size, h.timestamp, last_timestamp);

    lh = h;
    lh.timestamp = last_timestamp;

    if (size > sizeof(ngx_rtmp_play_buffer)) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                     "play: too big message: %D>%uz", size, 
                      sizeof(ngx_rtmp_play_buffer));
        goto next;
    }

    /* read tag body */
    n = ngx_read_file(&ctx->file, ngx_rtmp_play_buffer, size, 
                      ctx->offset - size - 4);
    if (n != (ssize_t) size) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                     "play: could not read flv tag");
        return;
    }

    /* prepare input chain */
    ngx_memzero(&in, sizeof(in));
    ngx_memzero(&in_buf, sizeof(in_buf));
    in.buf = &in_buf;
    in_buf.pos = ngx_rtmp_play_buffer;
    in_buf.last = ngx_rtmp_play_buffer + size;

    /* output chain */
    out = ngx_rtmp_append_shared_bufs(cscf, NULL, &in);
    ngx_rtmp_prepare_message(s, &h, ctx->msg_mask & (1 << h.type) ? 
                             &lh : NULL, out);
    ngx_rtmp_send_message(s, out, 0); /* TODO: priority */
    ngx_rtmp_free_shared_chain(cscf, out);

    ctx->msg_mask |= (1 << h.type);

next:
    if (ctx->start_timestamp == -1) {
        ctx->start_timestamp = h.timestamp;
        ctx->epoch = ngx_current_msec;
        ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                      "play: start_timestamp=%i", ctx->start_timestamp);
        goto skip;
    }

    buflen = (s->buflen ? s->buflen : NGX_RTMP_PLAY_DEFAULT_BUFLEN);
    end_timestamp = (ngx_current_msec - ctx->epoch) +
                     ctx->start_timestamp + buflen;

    ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
           "play: %s wait=%D timestamp=%D end_timestamp=%D bufen=%i",
            h.timestamp > end_timestamp ? "schedule" : "advance",
            h.timestamp > end_timestamp ? h.timestamp - end_timestamp : 0,
            h.timestamp, end_timestamp, (ngx_int_t) buflen);

    /* too much data sent; schedule timeout */
    if (h.timestamp > end_timestamp) {
        ngx_add_timer(e, h.timestamp - end_timestamp);
        return;
    }

skip:
    ngx_post_event(e, &ngx_posted_events);
}
Esempio n. 5
0
static ngx_int_t
ngx_rtmp_cmd_pause(ngx_rtmp_session_t *s, ngx_rtmp_pause_t *v)
{
    ngx_rtmp_header_t               h;

    static double                   trans;

    static ngx_rtmp_amf_elt_t       out_inf[] = {

        { NGX_RTMP_AMF_STRING,
          ngx_string("code"),
          "NetStream.Pause.Notify", 0 },

        { NGX_RTMP_AMF_STRING,
          ngx_string("level"),
          "status", 0 },

        { NGX_RTMP_AMF_STRING,
          ngx_string("description"),
          "Paused.", 0 },
    };

    static ngx_rtmp_amf_elt_t       out_elts[] = {

        { NGX_RTMP_AMF_STRING,
          ngx_null_string,
          "onStatus", 0 },

        { NGX_RTMP_AMF_NUMBER, 
          ngx_null_string,
          &trans, 0 },

        { NGX_RTMP_AMF_NULL, 
          ngx_null_string,
          NULL, 0 },

        { NGX_RTMP_AMF_OBJECT, 
          ngx_null_string,
          out_inf, sizeof(out_inf) },
    };

    /* send onStatus reply */
    ngx_memzero(&h, sizeof(h));
    h.type = NGX_RTMP_MSG_AMF_CMD;
    h.csid = NGX_RTMP_CMD_CSID_AMF;
    h.msid = NGX_RTMP_CMD_MSID;

    if (v->pause) {
        out_inf[0].data = "NetStream.Pause.Notify";
        out_inf[2].data = "Paused.";
        return ngx_rtmp_send_user_stream_eof(s, NGX_RTMP_CMD_MSID) != NGX_OK
            || ngx_rtmp_send_amf(s, &h, out_elts,
                    sizeof(out_elts) / sizeof(out_elts[0])) != NGX_OK
            ? NGX_ERROR
            : NGX_OK;
    }

    out_inf[0].data = "NetStream.Unpause.Notify";
    out_inf[2].data = "Unpaused.";
    return ngx_rtmp_send_user_stream_begin(s, NGX_RTMP_CMD_MSID) != NGX_OK
        || ngx_rtmp_send_amf(s, &h, out_elts,
                sizeof(out_elts) / sizeof(out_elts[0])) != NGX_OK
        ? NGX_ERROR
        : NGX_OK;
}