This source file includes following definitions.
- channel_is_valid
- RP_StopChannel
- RP_SessionActive
- RP_QueueCommand
- RP_Setup
- RP_SetupChannel
- RP_ProcessSetup
- RP_PreprocessDescribe
- RP_ProcessDescribe
- RP_Describe
- SkipCommandOnSession
- RP_PreprocessUserCom
- RP_ProcessUserCommand
- RP_FlushAndTearDown
- RP_UserCommand
- RP_ProcessTeardown
- RP_Teardown
#include "rtp_in.h"
#include <gpac/internal/ietf_dev.h>
#ifndef GPAC_DISABLE_STREAMING
#define GPAC_SATIP_PORT 1400
Bool channel_is_valid(RTPClient *rtp, RTPStream *ch)
{
u32 i=0;
RTPStream *st;
while ((st = (RTPStream *)gf_list_enum(rtp->channels, &i))) {
if (st == ch) return GF_TRUE;
}
return GF_FALSE;
}
void RP_StopChannel(RTPStream *ch)
{
if (!ch || !ch->rtsp) return;
ch->flags &= ~RTP_SKIP_NEXT_COM;
if (gf_rtp_is_interleaved(ch->rtp_ch)) {
gf_rtsp_unregister_interleave(ch->rtsp->session, gf_rtp_get_low_interleave_id(ch->rtp_ch));
}
}
Bool RP_SessionActive(RTPStream *ch)
{
RTPStream *ach;
u32 i, count;
i = count = 0;
while ((ach = (RTPStream *)gf_list_enum(ch->owner->channels, &i))) {
if (ach->rtsp != ch->rtsp) continue;
if (ach->status == RTP_Running) count++;
}
return count ? GF_TRUE : GF_FALSE;
}
static void RP_QueueCommand(RTSPSession *sess, RTPStream *ch, GF_RTSPCommand *com, Bool needs_sess_id)
{
if (needs_sess_id) {
com->Session = sess->session_id;
}
if (gf_mx_try_lock(sess->owner->mx)) {
gf_list_add(sess->rtsp_commands, com);
gf_mx_v(sess->owner->mx);
} else {
gf_list_add(sess->rtsp_commands, com);
}
}
void RP_Setup(RTPStream *ch)
{
u16 def_first_port;
const char *opt;
GF_RTSPCommand *com;
GF_RTSPTransport *trans;
com = gf_rtsp_command_new();
com->method = gf_strdup(GF_RTSP_SETUP);
def_first_port = 0;
opt = gf_modules_get_option((GF_BaseInterface *) gf_service_get_interface(ch->owner->service), "Streaming", "ForceFirstPort");
if (opt) def_first_port = atoi(opt);
opt = gf_modules_get_option((GF_BaseInterface *) gf_service_get_interface(ch->owner->service), "Streaming", "ForceMulticastIP");
if (gf_rtp_is_unicast(ch->rtp_ch) && (ch->owner->transport_mode != 1) && !gf_rtp_is_interleaved(ch->rtp_ch) ) {
gf_rtp_set_ports(ch->rtp_ch, def_first_port);
} else if (opt) {
gf_rtp_set_ports(ch->rtp_ch, def_first_port);
}
trans = gf_rtsp_transport_clone(gf_rtp_get_transport(ch->rtp_ch));
trans->port_first = trans->port_last = 0;
trans->SSRC = 0;
opt = gf_modules_get_option((GF_BaseInterface *) gf_service_get_interface(ch->owner->service), "Streaming", "ForceMulticastIP");
if (opt) {
trans->IsUnicast = GF_FALSE;
trans->destination = gf_strdup(opt);
opt = gf_modules_get_option((GF_BaseInterface *) gf_service_get_interface(ch->owner->service), "Streaming", "ForceMulticastTTL");
trans->TTL = opt ? atoi(opt) : 127;
if (trans->Profile) gf_free(trans->Profile);
trans->Profile = gf_strdup(GF_RTSP_PROFILE_RTP_AVP);
if (!(ch->rtsp->flags & RTSP_DSS_SERVER) ) {
trans->port_first = trans->client_port_first;
trans->port_last = trans->client_port_last;
}
gf_rtp_setup_transport(ch->rtp_ch, trans, NULL);
}
else if (ch->rtsp->flags & RTSP_FORCE_INTER) {
if (trans->Profile) gf_free(trans->Profile);
trans->Profile = gf_strdup(GF_RTSP_PROFILE_RTP_AVP_TCP);
trans->IsInterleaved = GF_TRUE;
trans->rtpID = gf_list_find(ch->owner->channels, ch);
trans->rtcpID = trans->rtpID+1;
gf_rtp_setup_transport(ch->rtp_ch, trans, NULL);
}
if (trans->source) {
gf_free(trans->source);
trans->source = NULL;
}
gf_list_add(com->Transports, trans);
if (strlen(ch->control)) com->ControlString = gf_strdup(ch->control);
com->user_data = ch;
ch->status = RTP_WaitingForAck;
RP_QueueCommand(ch->rtsp, ch, com, GF_TRUE);
}
GF_Err RP_SetupChannel(RTPStream *ch, ChannelDescribe *ch_desc)
{
GF_Err resp;
if (ch_desc && !ch->ES_ID && ch_desc->ES_ID) ch->ES_ID = ch_desc->ES_ID;
ch->status = RTP_Setup;
if (ch_desc && ch->channel) {
assert(ch->channel == ch_desc->channel);
} else if (!ch->channel && ch->rtsp && !ch->rtsp->satip) {
assert(ch_desc);
assert(ch_desc->channel);
ch->channel = ch_desc->channel;
}
if (!ch->rtsp) {
ch->flags |= RTP_CONNECTED;
resp = RP_InitStream(ch, GF_FALSE);
RP_ConfirmChannelConnect(ch, resp);
} else {
RP_Setup(ch);
}
return GF_OK;
}
void RP_ProcessSetup(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e)
{
RTPStream *ch;
u32 i;
GF_RTSPTransport *trans;
ch = (RTPStream *)com->user_data;
if (e) goto exit;
switch (sess->rtsp_rsp->ResponseCode) {
case NC_RTSP_OK:
break;
case NC_RTSP_Not_Found:
e = GF_STREAM_NOT_FOUND;
goto exit;
default:
e = GF_SERVICE_ERROR;
goto exit;
}
e = GF_SERVICE_ERROR;
if (!ch) goto exit;
if (!sess->rtsp_rsp->Session) {
e = GF_SERVICE_ERROR;
goto exit;
}
if (!sess->session_id) sess->session_id = gf_strdup(sess->rtsp_rsp->Session);
assert(!ch->session_id);
i=0;
while ((trans = (GF_RTSPTransport *)gf_list_enum(sess->rtsp_rsp->Transports, &i))) {
const char *opt = gf_modules_get_option((GF_BaseInterface *) gf_service_get_interface(ch->owner->service), "Streaming", "ForceClientPorts");
if (opt && !stricmp(opt, "yes"))
gf_rtp_get_ports(ch->rtp_ch, &trans->client_port_first, &trans->client_port_last);
if (gf_rtp_is_interleaved(ch->rtp_ch) && !trans->IsInterleaved) {
GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTSP] Requested interleaved RTP over RTSP but server did not setup interleave - cannot process command\n"));
e = GF_REMOTE_SERVICE_ERROR;
continue;
}
e = gf_rtp_setup_transport(ch->rtp_ch, trans, gf_rtsp_get_server_name(sess->session));
if (!e) break;
}
if (e) goto exit;
e = RP_InitStream(ch, GF_FALSE);
if (e) goto exit;
ch->status = RTP_Connected;
ch->flags &= ~RTP_INTERLEAVED;
if (gf_rtp_is_interleaved(ch->rtp_ch)) {
ch->flags |= RTP_INTERLEAVED;
gf_rtsp_set_interleave_callback(sess->session, RP_DataOnTCP);
}
if (sess->satip) {
ChannelControl *ch_ctrl = NULL;
GF_RTSPCommand *com = gf_rtsp_command_new();
com->method = gf_strdup(GF_RTSP_PLAY);
GF_SAFEALLOC(ch_ctrl, ChannelControl);
ch_ctrl->ch = ch;
com->user_data = ch_ctrl;
RP_QueueCommand(sess, ch, com, GF_TRUE);
}
exit:
if (ch && ! (ch->flags & RTP_CONNECTED) ) {
if (!e)
ch->flags |= RTP_CONNECTED;
RP_ConfirmChannelConnect(ch, e);
}
com->user_data = NULL;
}
Bool RP_PreprocessDescribe(RTSPSession *sess, GF_RTSPCommand *com)
{
RTPStream *ch;
ChannelDescribe *ch_desc;
if (!com->user_data) {
RP_SendMessage(sess->owner->service, GF_OK, "Connecting...");
return GF_TRUE;
}
ch_desc = (ChannelDescribe *)com->user_data;
ch = RP_FindChannel(sess->owner, NULL, ch_desc->ES_ID, ch_desc->esd_url, GF_FALSE);
if (!ch) return GF_TRUE;
RP_SetupChannel(ch, ch_desc);
if (ch_desc->esd_url) gf_free(ch_desc->esd_url);
gf_free(ch_desc);
return GF_FALSE;
}
GF_Err RP_ProcessDescribe(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e)
{
RTPStream *ch;
ChannelDescribe *ch_desc;
ch = NULL;
ch_desc = (ChannelDescribe *)com->user_data;
if (e) goto exit;
switch (sess->rtsp_rsp->ResponseCode) {
case NC_RTSP_Multiple_Choice:
e = ch_desc ? GF_STREAM_NOT_FOUND : GF_URL_ERROR;
goto exit;
case NC_RTSP_Not_Found:
e = GF_URL_ERROR;
goto exit;
case NC_RTSP_OK:
break;
default:
e = GF_SERVICE_ERROR;
goto exit;
}
ch = NULL;
if (ch_desc) {
ch = RP_FindChannel(sess->owner, ch_desc->channel, ch_desc->ES_ID, ch_desc->esd_url, GF_FALSE);
} else {
RP_SendMessage(sess->owner->service, GF_OK, "Connected");
}
RP_LoadSDP(sess->owner, sess->rtsp_rsp->body, sess->rtsp_rsp->Content_Length, ch);
if (!ch_desc) goto exit;
if (!ch) {
e = GF_STREAM_NOT_FOUND;
goto exit;
}
e = RP_SetupChannel(ch, ch_desc);
exit:
com->user_data = NULL;
if (e) {
if (!ch_desc) {
sess->connect_error = e;
return e;
} else if (ch) {
RP_ConfirmChannelConnect(ch, e);
} else {
gf_service_connect_ack(sess->owner->service, ch_desc->channel, e);
}
}
if (ch_desc) gf_free(ch_desc);
return GF_OK;
}
void RP_Describe(RTSPSession *sess, char *esd_url, LPNETCHANNEL channel)
{
const char *opt;
RTPStream *ch;
ChannelDescribe *ch_desc;
GF_RTSPCommand *com;
if (esd_url || channel) {
ch = RP_FindChannel(sess->owner, channel, 0, esd_url, GF_FALSE);
if (ch) {
if (!ch->channel) ch->channel = channel;
switch (ch->status) {
case RTP_Connected:
case RTP_Running:
RP_ConfirmChannelConnect(ch, GF_OK);
return;
default:
break;
}
ch_desc = (ChannelDescribe *)gf_malloc(sizeof(ChannelDescribe));
ch_desc->esd_url = esd_url ? gf_strdup(esd_url) : NULL;
ch_desc->channel = channel;
RP_SetupChannel(ch, ch_desc);
if (esd_url) gf_free(ch_desc->esd_url);
gf_free(ch_desc);
return;
}
}
com = gf_rtsp_command_new();
if (!sess->satip) {
com->method = gf_strdup(GF_RTSP_DESCRIBE);
} else {
GF_Err e;
GF_RTSPTransport *trans;
RTPStream *ch = NULL;
com->method = gf_strdup(GF_RTSP_SETUP);
GF_SAFEALLOC(trans, GF_RTSPTransport);
trans->IsUnicast = GF_TRUE;
trans->client_port_first = GPAC_SATIP_PORT;
trans->client_port_last = GPAC_SATIP_PORT+1;
trans->Profile = gf_strdup(GF_RTSP_PROFILE_RTP_AVP);
gf_list_add(com->Transports, trans);
ch = RP_NewSatipStream(sess->owner, sess->satip_server);
if (!ch) {
GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("SAT>IP: couldn't create the RTP stream.\n"));
return;
}
e = RP_AddStream(sess->owner, ch, "*");
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("SAT>IP: couldn't add the RTP stream.\n"));
return;
}
com->user_data = ch;
}
if (channel || esd_url) {
com->Accept = gf_strdup("application/sdp");
com->ControlString = esd_url ? gf_strdup(esd_url) : NULL;
ch_desc = (ChannelDescribe *)gf_malloc(sizeof(ChannelDescribe));
ch_desc->esd_url = esd_url ? gf_strdup(esd_url) : NULL;
ch_desc->channel = channel;
com->user_data = ch_desc;
} else {
com->Accept = gf_strdup("application/sdp, application/mpeg4-iod");
}
opt = (char *) gf_modules_get_option((GF_BaseInterface *) gf_service_get_interface(sess->owner->service), "Network", "Bandwidth");
if (opt && !stricmp(opt, "yes")) com->Bandwidth = atoi(opt);
RP_QueueCommand(sess, NULL, com, GF_FALSE);
}
static void SkipCommandOnSession(RTPStream *ch)
{
u32 i;
RTPStream *a_ch;
if (!ch || (ch->flags & RTP_SKIP_NEXT_COM) || !(ch->rtsp->flags & RTSP_AGG_CONTROL) ) return;
i=0;
while ((a_ch = (RTPStream *)gf_list_enum(ch->owner->channels, &i))) {
if ((ch == a_ch) || (a_ch->rtsp != ch->rtsp) ) continue;
if (a_ch->status>=RTP_Connected)
a_ch->flags |= RTP_SKIP_NEXT_COM;
}
}
Bool RP_PreprocessUserCom(RTSPSession *sess, GF_RTSPCommand *com)
{
ChannelControl *ch_ctrl;
RTPStream *ch;
GF_Err e;
Bool skip_it;
ch_ctrl = NULL;
if (strcmp(com->method, GF_RTSP_TEARDOWN)) ch_ctrl = (ChannelControl *)com->user_data;
if (!ch_ctrl || !ch_ctrl->ch) return GF_TRUE;
ch = ch_ctrl->ch;
if (!sess->satip) {
if (!ch->channel || !channel_is_valid(sess->owner, ch)) {
gf_free(ch_ctrl);
com->user_data = NULL;
return GF_FALSE;
}
assert(ch->rtsp == sess);
assert(ch->channel == ch_ctrl->com.base.on_channel);
}
skip_it = GF_FALSE;
if (!com->Session) {
if (!strcmp(com->method, GF_RTSP_PLAY) || !strcmp(com->method, GF_RTSP_PAUSE)) {
e = GF_SERVICE_ERROR;
goto err_exit;
}
skip_it = GF_TRUE;
} else {
SkipCommandOnSession(ch);
}
if (skip_it || ( (sess->flags & RTSP_AGG_CONTROL) && (ch->flags & RTP_SKIP_NEXT_COM) )) {
ch->flags &= ~RTP_SKIP_NEXT_COM;
gf_service_command(sess->owner->service, &ch_ctrl->com, GF_OK);
gf_free(ch_ctrl);
com->user_data = NULL;
return GF_FALSE;
}
return GF_TRUE;
err_exit:
gf_rtsp_reset_aggregation(ch->rtsp->session);
ch->status = RTP_Disconnected;
ch->check_rtp_time = RTP_SET_TIME_NONE;
gf_service_command(sess->owner->service, &ch_ctrl->com, e);
gf_free(ch_ctrl);
com->user_data = NULL;
return GF_FALSE;
}
void RP_ProcessUserCommand(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e)
{
ChannelControl *ch_ctrl;
RTPStream *ch, *agg_ch;
u32 i, count;
GF_RTPInfo *info;
ch_ctrl = (ChannelControl *)com->user_data;
ch = ch_ctrl->ch;
if (sess->satip) {
if (!strcmp(com->method, GF_RTSP_PLAY)) {
char url[64];
snprintf(url, 64, "mpegts-sk://%p", ch->rtp_ch->rtp);
e = ch->satip_m2ts_ifce->ConnectService(ch->satip_m2ts_ifce, sess->owner->service, url);
if (e) {
assert(0);
GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[SATIP] Couldn't connect the M2TS service.\n"));
return;
} else {
ch->satip_m2ts_service_connected = GF_TRUE;
}
} else if (!strcmp(com->method, GF_RTSP_PLAY)) {
if (ch->satip_m2ts_service_connected) {
ch->satip_m2ts_ifce->CloseService(ch->satip_m2ts_ifce);
ch->satip_m2ts_service_connected = GF_FALSE;
}
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[SATIP] Unhandled RTSP command: %s\n", com->method));
return;
}
return;
}
if (ch) {
if (!ch->channel || !channel_is_valid(sess->owner, ch)) {
gf_free(ch_ctrl);
com->user_data = NULL;
return;
}
assert(ch->channel==ch_ctrl->com.base.on_channel);
}
if (e) {
if (!strcmp(com->method, GF_RTSP_TEARDOWN)) {
goto process_reply;
} else {
if (sess->rtsp_rsp->ResponseCode == NC_RTSP_Only_Aggregate_Operation_Allowed) {
sess->flags |= RTSP_AGG_ONLY;
sess->rtsp_rsp->ResponseCode = NC_RTSP_OK;
} else {
goto err_exit;
}
}
}
switch (sess->rtsp_rsp->ResponseCode) {
case NC_RTSP_Method_Not_Allowed:
e = GF_NOT_SUPPORTED;
goto err_exit;
case NC_RTSP_OK:
break;
default:
e = GF_SERVICE_ERROR;
goto err_exit;
}
process_reply:
gf_service_command(sess->owner->service, &ch_ctrl->com, GF_OK);
if ( (ch_ctrl->com.command_type==GF_NET_CHAN_PLAY)
|| (ch_ctrl->com.command_type==GF_NET_CHAN_SET_SPEED)
|| (ch_ctrl->com.command_type==GF_NET_CHAN_RESUME) ) {
if (gf_list_count(sess->rtsp_rsp->RTP_Infos) > 1) {
sess->flags |= RTSP_AGG_CONTROL;
}
count = gf_list_count(sess->rtsp_rsp->RTP_Infos);
for (i=0; i<count; i++) {
info = (GF_RTPInfo*)gf_list_get(sess->rtsp_rsp->RTP_Infos, i);
agg_ch = RP_FindChannel(sess->owner, NULL, 0, info->url, GF_FALSE);
if (!agg_ch || (agg_ch->rtsp != sess) ) continue;
if (agg_ch->status == RTP_Running) {
gf_rtp_set_info_rtp(agg_ch->rtp_ch, info->seq, info->rtp_time, info->ssrc);
agg_ch->check_rtp_time = RTP_SET_TIME_RTP;
continue;
}
if (ch_ctrl->com.command_type != GF_NET_CHAN_RESUME) {
agg_ch->check_rtp_time = RTP_SET_TIME_RTP;
}
else {
agg_ch->check_rtp_time = RTP_SET_TIME_RTP_SEEK;
}
RP_InitStream(agg_ch, GF_TRUE);
gf_rtp_set_info_rtp(agg_ch->rtp_ch, info->seq, info->rtp_time, info->ssrc);
agg_ch->status = RTP_Running;
if ((ch != agg_ch) && ch && (ch->rtsp->flags & RTSP_AGG_CONTROL) ) agg_ch->flags |= RTP_SKIP_NEXT_COM;
if (gf_rtp_is_interleaved(agg_ch->rtp_ch)) {
gf_rtsp_register_interleave(sess->session,
agg_ch,
gf_rtp_get_low_interleave_id(agg_ch->rtp_ch),
gf_rtp_get_hight_interleave_id(agg_ch->rtp_ch));
}
}
if (ch && !i) {
ch->current_start = 0.0;
ch->check_rtp_time = RTP_SET_TIME_RTP;
RP_InitStream(ch, GF_TRUE);
ch->status = RTP_Running;
if (gf_rtp_is_interleaved(ch->rtp_ch)) {
gf_rtsp_register_interleave(sess->session,
ch, gf_rtp_get_low_interleave_id(ch->rtp_ch), gf_rtp_get_hight_interleave_id(ch->rtp_ch));
}
}
if (ch) ch->flags &= ~RTP_SKIP_NEXT_COM;
} else if (ch_ctrl->com.command_type == GF_NET_CHAN_PAUSE) {
if (ch) {
SkipCommandOnSession(ch);
ch->flags &= ~RTP_SKIP_NEXT_COM;
}
} else if (ch_ctrl->com.command_type == GF_NET_CHAN_STOP) {
}
gf_free(ch_ctrl);
com->user_data = NULL;
return;
err_exit:
gf_service_command(sess->owner->service, &ch_ctrl->com, e);
if (ch) {
ch->status = RTP_Disconnected;
gf_rtsp_reset_aggregation(ch->rtsp->session);
ch->check_rtp_time = RTP_SET_TIME_NONE;
}
gf_free(ch_ctrl);
com->user_data = NULL;
}
#if 0
static void RP_FlushAndTearDown(RTSPSession *sess)
{
GF_RTSPCommand *com;
gf_mx_p(sess->owner->mx);
while (gf_list_count(sess->rtsp_commands)) {
com = (GF_RTSPCommand *)gf_list_get(sess->rtsp_commands, 0);
gf_list_rem(sess->rtsp_commands, 0);
gf_rtsp_command_del(com);
}
if (sess->flags & RTSP_WAIT_REPLY) {
GF_Err e;
while (1) {
e = gf_rtsp_get_response(sess->session, sess->rtsp_rsp);
if (e!= GF_IP_NETWORK_EMPTY) break;
}
sess->flags &= ~RTSP_WAIT_REPLY;
}
gf_mx_v(sess->owner->mx);
com = gf_rtsp_command_new();
com->method = gf_strdup(GF_RTSP_TEARDOWN);
RP_QueueCommand(sess, NULL, com, 1);
}
#endif
void RP_UserCommand(RTSPSession *sess, RTPStream *ch, GF_NetworkCommand *command)
{
RTPStream *a_ch;
ChannelControl *ch_ctrl;
u32 i;
Bool needs_setup = GF_FALSE;
GF_RTSPCommand *com;
GF_RTSPRange *range;
switch (command->command_type) {
case GF_NET_CHAN_PLAY:
case GF_NET_CHAN_RESUME:
needs_setup = GF_TRUE;
break;
case GF_NET_CHAN_PAUSE:
case GF_NET_CHAN_STOP:
break;
default:
gf_service_command(sess->owner->service, command, GF_NOT_SUPPORTED);
return;
}
if (needs_setup) {
if (ch->status == RTP_Disconnected) {
if (sess->flags & RTSP_AGG_CONTROL) {
i=0;
while ((a_ch = (RTPStream *)gf_list_enum(sess->owner->channels, &i))) {
if (a_ch->rtsp != sess) continue;
if (a_ch->status == RTP_Disconnected)
RP_Setup(a_ch);
}
} else {
RP_Setup(ch);
}
}
}
com = gf_rtsp_command_new();
range = NULL;
if ( (command->command_type==GF_NET_CHAN_PLAY) || (command->command_type==GF_NET_CHAN_RESUME) ) {
range = gf_rtsp_range_new();
range->start = ch->range_start;
range->end = ch->range_end;
com->method = gf_strdup(GF_RTSP_PLAY);
ch->paused = GF_FALSE;
if (command->command_type==GF_NET_CHAN_RESUME) {
range->start = ch->current_start;
ch->stat_start_time -= ch->stat_stop_time;
ch->stat_start_time += gf_sys_clock();
ch->stat_stop_time = 0;
} else {
range->start = ch->range_start;
if (command->play.start_range>=0) range->start += command->play.start_range;
range->end = ch->range_start;
if (command->play.end_range >=0) {
range->end += command->play.end_range;
if (range->end > ch->range_end) range->end = ch->range_end;
}
ch->stat_start_time = gf_sys_clock();
ch->stat_stop_time = 0;
}
if (ch->flags & RTP_SKIP_NEXT_COM) {
ch->current_start = ch->rtsp->last_range;
} else {
ch->rtsp->last_range = range->start;
ch->current_start = range->start;
}
if (!(ch->flags & RTP_HAS_RANGE) && (command->command_type != GF_NET_CHAN_RESUME) ) {
gf_rtsp_range_del(range);
com->Range = NULL;
} else {
com->Range = range;
}
if (sess->flags & RTSP_AGG_CONTROL)
SkipCommandOnSession(ch);
else if (strlen(ch->control))
com->ControlString = gf_strdup(ch->control);
if (RP_SessionActive(ch)) {
if (!com->ControlString && ch->control) com->ControlString = gf_strdup(ch->control);
} else {
if (com->ControlString) {
gf_free(com->ControlString);
com->ControlString=NULL;
}
}
} else if (command->command_type==GF_NET_CHAN_PAUSE) {
com->method = gf_strdup(GF_RTSP_PAUSE);
if (ch) {
range = gf_rtsp_range_new();
ch->current_start += gf_rtp_get_current_time(ch->rtp_ch);
ch->stat_stop_time = gf_sys_clock();
range->start = ch->current_start;
range->end = -1.0;
com->Range = range;
if (sess->flags & RTSP_AGG_CONTROL)
SkipCommandOnSession(ch);
else if (strlen(ch->control))
com->ControlString = gf_strdup(ch->control);
ch->paused = GF_TRUE;
}
}
else if (command->command_type==GF_NET_CHAN_STOP) {
ch->current_start = 0;
ch->stat_stop_time = gf_sys_clock();
ch->status = RTP_Connected;
RP_InitStream(ch, GF_TRUE);
if (ch->rtsp->flags & RTSP_AGG_ONLY) {
RP_StopChannel(ch);
if (com) gf_rtsp_command_del(com);
if (!RP_SessionActive(ch))
RP_Teardown(sess, ch);
return;
}
else {
if (ch->paused) {
if (com) gf_rtsp_command_del(com);
return;
}
range = gf_rtsp_range_new();
range->start = 0;
range->end = -1;
com->method = gf_strdup(GF_RTSP_PAUSE);
com->Range = range;
if (ch->control) com->ControlString = gf_strdup(ch->control);
}
} else {
gf_service_command(sess->owner->service, command, GF_NOT_SUPPORTED);
gf_rtsp_command_del(com);
return;
}
ch_ctrl = (ChannelControl *)gf_malloc(sizeof(ChannelControl));
ch_ctrl->ch = ch;
memcpy(&ch_ctrl->com, command, sizeof(GF_NetworkCommand));
com->user_data = ch_ctrl;
RP_QueueCommand(sess, ch, com, GF_TRUE);
return;
}
void RP_ProcessTeardown(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e)
{
RTPStream *ch = (RTPStream *)com->user_data;
if (ch) {
if (ch->session_id) gf_free(ch->session_id);
ch->session_id = NULL;
} else {
if (sess->session_id) gf_free(sess->session_id);
sess->session_id = NULL;
}
}
void RP_Teardown(RTSPSession *sess, RTPStream *ch)
{
GF_RTSPCommand *com;
if (sess->owner->session_migration) return;
if (!sess->session_id) return;
if ((sess->flags & RTSP_AGG_CONTROL) && ch) return;
com = gf_rtsp_command_new();
com->method = gf_strdup(GF_RTSP_TEARDOWN);
if (ch && ch->control) {
com->ControlString = gf_strdup(ch->control);
com->user_data = ch;
}
RP_QueueCommand(sess, ch, com, GF_TRUE);
}
#endif