static void
ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll, 
        ngx_rtmp_live_app_conf_t *lacf)
{
    ngx_rtmp_live_stream_t         *stream;
    ngx_rtmp_codec_ctx_t           *codec;
    ngx_rtmp_live_ctx_t            *ctx;
    ngx_rtmp_session_t             *s;
    ngx_int_t                       n;
    size_t                          nclients, total_nclients;
    u_char                          buf[NGX_OFF_T_LEN + 1];
    ngx_rtmp_stat_loc_conf_t       *slcf;
    u_char                         *cname;

    slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module);

    NGX_RTMP_STAT_L("<live>\r\n");

    total_nclients = 0;
    for (n = 0; n < lacf->nbuckets; ++n) {
        for (stream = lacf->streams[n]; stream; stream = stream->next) {
            NGX_RTMP_STAT_L("<stream>\r\n");

            NGX_RTMP_STAT_L("<name>");
            NGX_RTMP_STAT_ECS(stream->name);
            NGX_RTMP_STAT_L("</name>\r\n");

            NGX_RTMP_STAT_L("<time>");
            NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
                        "%M", ngx_current_msec - stream->epoch) - buf);
            NGX_RTMP_STAT_L("</time>");

            ngx_rtmp_stat_bw(r, lll, &stream->bw_in, &stream->bw_out);

            nclients = 0;
            codec = NULL;
            for (ctx = stream->ctx; ctx; ctx = ctx->next, ++nclients) {
                s = ctx->session;
                if (slcf->stat & NGX_RTMP_STAT_CLIENTS) {
                    NGX_RTMP_STAT_L("<client>");

#ifdef NGX_RTMP_POOL_DEBUG
                    ngx_rtmp_stat_dump_pool(r, lll, s->connection->pool);
#endif
                    NGX_RTMP_STAT_L("<id>");
                    NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui",
                                       (ngx_uint_t) s->connection->number)
                                       - buf);
                    NGX_RTMP_STAT_L("</id>");

                    NGX_RTMP_STAT_L("<address>");
                    NGX_RTMP_STAT_S(&s->connection->addr_text);
                    NGX_RTMP_STAT_L("</address>");

                    NGX_RTMP_STAT_L("<time>");
                    NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%M",
                                                    ngx_current_msec - s->epoch)
                                       - buf);
                    NGX_RTMP_STAT_L("</time>");

                    NGX_RTMP_STAT_L("<dropped>");
                    NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                                "%uD/%uD", ctx->cs[1].dropped,
                                           ctx->cs[0].dropped) - buf);
                    NGX_RTMP_STAT_L("</dropped>");

                    NGX_RTMP_STAT_L("<avsync>");
                    if (!lacf->interleave) {
                        NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                                      "%L", (int64_t) ctx->cs[1].timestamp -
                                            (int64_t) ctx->cs[0].timestamp)
                                           - buf);
                    }
                    NGX_RTMP_STAT_L("</avsync>");

                    if (s->flashver.len) {
                        NGX_RTMP_STAT_L("<flashver>");
                        NGX_RTMP_STAT_ES(&s->flashver);
                        NGX_RTMP_STAT_L("</flashver>");
                    }

                    if (s->page_url.len) {
                        NGX_RTMP_STAT_L("<pageurl>");
                        NGX_RTMP_STAT_ES(&s->page_url);
                        NGX_RTMP_STAT_L("</pageurl>");
                    }

                    if (s->swf_url.len) {
                        NGX_RTMP_STAT_L("<swfurl>");
                        NGX_RTMP_STAT_ES(&s->swf_url);
                        NGX_RTMP_STAT_L("</swfurl>");
                    }

                    if (ctx->publishing) {
                        NGX_RTMP_STAT_L("<publishing/>");
                    }

                    if (ctx->active) {
                        NGX_RTMP_STAT_L("<active/>");
                    }

                    NGX_RTMP_STAT_L("</client>\r\n");
                }
                if (ctx->publishing) {
                    codec = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
                }
            }
            total_nclients += nclients;

            if (codec) {
                NGX_RTMP_STAT_L("<meta><width>");
                NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                            "%ui", codec->width) - buf);
                NGX_RTMP_STAT_L("</width><height>");
                NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                            "%ui", codec->height) - buf);
                NGX_RTMP_STAT_L("</height><framerate>");
                NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                            "%ui", codec->frame_rate) - buf);
                NGX_RTMP_STAT_L("</framerate>");
                cname = ngx_rtmp_get_video_codec_name(codec->video_codec_id);
                if (*cname) {
                    NGX_RTMP_STAT_L("<video>");
                    NGX_RTMP_STAT_ECS(cname);
                    NGX_RTMP_STAT_L("</video>");
                }
                cname = ngx_rtmp_get_audio_codec_name(codec->audio_codec_id);
                if (*cname) {
                    NGX_RTMP_STAT_L("<audio>");
                    NGX_RTMP_STAT_ECS(cname);
                    NGX_RTMP_STAT_L("</audio>");
                }
                if (*codec->profile) {
                    NGX_RTMP_STAT_L("<profile>");
                    NGX_RTMP_STAT_ECS(codec->profile);
                    NGX_RTMP_STAT_L("</profile>");
                }
                if (*codec->level) {
                    NGX_RTMP_STAT_L("<level>");
                    NGX_RTMP_STAT_ECS(codec->level);
                    NGX_RTMP_STAT_L("</level>");
                }
                NGX_RTMP_STAT_L("</meta>\r\n");
            }

            NGX_RTMP_STAT_L("<nclients>");
            NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                        "%uz", nclients) - buf);
            NGX_RTMP_STAT_L("</nclients>\r\n");

            if (stream->publishing) {
                NGX_RTMP_STAT_L("<publishing/>\r\n");
            }

            if (stream->active) {
                NGX_RTMP_STAT_L("<active/>\r\n");
            }

            NGX_RTMP_STAT_L("</stream>\r\n");
        }
    }

    NGX_RTMP_STAT_L("<nclients>");
    NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                "%uz", total_nclients) - buf);
    NGX_RTMP_STAT_L("</nclients>\r\n");

    NGX_RTMP_STAT_L("</live>\r\n");
}
static ngx_int_t
ngx_rtmp_stat_handler(ngx_http_request_t *r)
{
    ngx_rtmp_stat_loc_conf_t       *slcf;
    ngx_rtmp_core_main_conf_t      *cmcf;
    ngx_rtmp_core_srv_conf_t      **cscf;
    ngx_chain_t                    *cl, *l, **ll, ***lll;
    size_t                          n;
    off_t                           len;
    static u_char                   tbuf[NGX_TIME_T_LEN + 1];
    static u_char                   nbuf[NGX_OFF_T_LEN + 1];

    slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module);
    if (slcf->stat == 0) {
        return NGX_DECLINED;
    }

    cmcf = ngx_rtmp_core_main_conf;
    if (cmcf == NULL) {
        goto error;
    }

    cl = NULL;
    ll = &cl;
    lll = &ll;

    NGX_RTMP_STAT_L("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n");
    if (slcf->stylesheet.len) {
        NGX_RTMP_STAT_L("<?xml-stylesheet type=\"text/xsl\" href=\"");
        NGX_RTMP_STAT_ES(&slcf->stylesheet);
        NGX_RTMP_STAT_L("\" ?>\r\n");
    }

    NGX_RTMP_STAT_L("<rtmp>\r\n");

#ifdef NGINX_VERSION
    NGX_RTMP_STAT_L("<version>" NGINX_VERSION "</version>\r\n");
#endif

#ifdef NGX_COMPILER
    NGX_RTMP_STAT_L("<compiler>" NGX_COMPILER "</compiler>\r\n");
#endif
    NGX_RTMP_STAT_L("<built>" __DATE__ " " __TIME__ "</built>\r\n");

    NGX_RTMP_STAT_L("<pid>");
    NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf),
                  "%ui", (ngx_uint_t) ngx_getpid()) - nbuf);
    NGX_RTMP_STAT_L("</pid>\r\n");

    NGX_RTMP_STAT_L("<uptime>");
    NGX_RTMP_STAT(tbuf, ngx_snprintf(tbuf, sizeof(tbuf),
                "%T", ngx_cached_time->sec - start_time) - tbuf);
    NGX_RTMP_STAT_L("</uptime>\r\n");

    NGX_RTMP_STAT_L("<naccepted>");
    NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf),
                  "%ui", ngx_rtmp_naccepted) - nbuf);
    NGX_RTMP_STAT_L("</naccepted>\r\n");

    ngx_rtmp_stat_bw(r, lll, &ngx_rtmp_bw_in, &ngx_rtmp_bw_out);

    cscf = cmcf->servers.elts;
    for (n = 0; n < cmcf->servers.nelts; ++n, ++cscf) {
        ngx_rtmp_stat_server(r, lll, *cscf);
    }

    NGX_RTMP_STAT_L("</rtmp>\r\n");

    len = 0;
    for (l = cl; l; l = l->next) {
        len += (l->buf->last - l->buf->pos);
    }
    ngx_str_set(&r->headers_out.content_type, "text/xml");
    r->headers_out.content_length_n = len;
    r->headers_out.status = NGX_HTTP_OK;
    ngx_http_send_header(r);
    (*ll)->buf->last_buf = 1;
    return ngx_http_output_filter(r, cl);

error:
    r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
    r->headers_out.content_length_n = 0;
    return ngx_http_send_header(r);
}
static void
ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll, 
        ngx_rtmp_live_app_conf_t *lacf)
{
    ngx_rtmp_live_stream_t         *stream;
    ngx_rtmp_codec_ctx_t           *codec;
    ngx_rtmp_live_ctx_t            *ctx;
    ngx_rtmp_session_t             *s;
    ngx_int_t                       n;
    ngx_uint_t                      nclients, total_nclients;
    u_char                          buf[NGX_INT_T_LEN];
    u_char                          bbuf[NGX_INT32_LEN];
    ngx_rtmp_stat_loc_conf_t       *slcf;
    u_char                         *cname;

    if (!lacf->live) {
        return;
    }

    slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module);

    NGX_RTMP_STAT_L("<live>\r\n");

    total_nclients = 0;
    for (n = 0; n < lacf->nbuckets; ++n) {
        for (stream = lacf->streams[n]; stream; stream = stream->next) {
            NGX_RTMP_STAT_L("<stream>\r\n");

            NGX_RTMP_STAT_L("<name>");
            NGX_RTMP_STAT_ECS(stream->name);
            NGX_RTMP_STAT_L("</name>\r\n");

            NGX_RTMP_STAT_L("<time>");
            NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%i",
                          (ngx_int_t) (ngx_current_msec - stream->epoch))
                          - buf);
            NGX_RTMP_STAT_L("</time>");

            ngx_rtmp_stat_bw(r, lll, &stream->bw_in, &stream->bw_out);

            nclients = 0;
            codec = NULL;
            for (ctx = stream->ctx; ctx; ctx = ctx->next, ++nclients) {
                s = ctx->session;
                if (slcf->stat & NGX_RTMP_STAT_CLIENTS) {
                    NGX_RTMP_STAT_L("<client>");

                    ngx_rtmp_stat_client(r, lll, s);

                    NGX_RTMP_STAT_L("<dropped>");
                    NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                                  "%ui", ctx->ndropped) - buf);
                    NGX_RTMP_STAT_L("</dropped>");

                    NGX_RTMP_STAT_L("<avsync>");
                    if (!lacf->interleave) {
                        NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), 
                                      "%D", ctx->cs[1].timestamp -
                                      ctx->cs[0].timestamp) - bbuf);
                    }
                    NGX_RTMP_STAT_L("</avsync>");

                    if (ctx->publishing) {
                        NGX_RTMP_STAT_L("<publishing/>");
                    }

                    if (ctx->active) {
                        NGX_RTMP_STAT_L("<active/>");
                    }

                    NGX_RTMP_STAT_L("</client>\r\n");
                }
                if (ctx->publishing) {
                    codec = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
                }
            }
            total_nclients += nclients;

            if (codec) {
                NGX_RTMP_STAT_L("<meta><width>");
                NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                              "%ui", codec->width) - buf);
                NGX_RTMP_STAT_L("</width><height>");
                NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                              "%ui", codec->height) - buf);
                NGX_RTMP_STAT_L("</height><framerate>");
                NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                              "%ui", codec->frame_rate) - buf);
                NGX_RTMP_STAT_L("</framerate>");
                cname = ngx_rtmp_get_video_codec_name(codec->video_codec_id);
                if (*cname) {
                    NGX_RTMP_STAT_L("<video>");
                    NGX_RTMP_STAT_ECS(cname);
                    NGX_RTMP_STAT_L("</video>");
                }
                cname = ngx_rtmp_get_audio_codec_name(codec->audio_codec_id);
                if (*cname) {
                    NGX_RTMP_STAT_L("<audio>");
                    NGX_RTMP_STAT_ECS(cname);
                    NGX_RTMP_STAT_L("</audio>");
                }
                if (*codec->profile) {
                    NGX_RTMP_STAT_L("<profile>");
                    NGX_RTMP_STAT_ECS(codec->profile);
                    NGX_RTMP_STAT_L("</profile>");
                }
                if (*codec->level) {
                    NGX_RTMP_STAT_L("<level>");
                    NGX_RTMP_STAT_ECS(codec->level);
                    NGX_RTMP_STAT_L("</level>");
                }
                NGX_RTMP_STAT_L("</meta>\r\n");
            }

            NGX_RTMP_STAT_L("<nclients>");
            NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                          "%ui", nclients) - buf);
            NGX_RTMP_STAT_L("</nclients>\r\n");

            if (stream->publishing) {
                NGX_RTMP_STAT_L("<publishing/>\r\n");
            }

            if (stream->active) {
                NGX_RTMP_STAT_L("<active/>\r\n");
            }

            NGX_RTMP_STAT_L("</stream>\r\n");
        }
    }

    NGX_RTMP_STAT_L("<nclients>");
    NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), 
                  "%ui", total_nclients) - buf);
    NGX_RTMP_STAT_L("</nclients>\r\n");

    NGX_RTMP_STAT_L("</live>\r\n");
}