1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19 
20 #include "mediastreamer2/mediastream.h"
21 #include "mediastreamer2/msrtt4103.h"
22 #include "mediastreamer2/msrtp.h"
23 #include "private.h"
24 
25 #include <sys/types.h>
26 
27 #ifndef _WIN32
28 	#include <sys/socket.h>
29 	#include <netdb.h>
30 #endif
31 
text_stream_free(TextStream * stream)32 static void text_stream_free(TextStream *stream) {
33 	media_stream_free(&stream->ms);
34 	if (stream->rttsource != NULL) ms_filter_destroy(stream->rttsource);
35 	if (stream->rttsink != NULL) ms_filter_destroy(stream->rttsink);
36 	ms_free(stream);
37 }
38 
text_stream_process_rtcp(MediaStream * media_stream,mblk_t * m)39 static void text_stream_process_rtcp(MediaStream *media_stream, mblk_t *m) {
40 }
41 
text_stream_new_with_sessions(MSFactory * factory,const MSMediaStreamSessions * sessions)42 TextStream *text_stream_new_with_sessions(MSFactory *factory, const MSMediaStreamSessions *sessions) {
43 	TextStream *stream = (TextStream *)ms_new0(TextStream, 1);
44 	stream->pt_red = 0;
45 	stream->pt_t140 = 0;
46 
47 	stream->ms.type = MSText;
48 	media_stream_init(&stream->ms, factory, sessions);
49 
50 	ms_factory_enable_statistics(factory, TRUE);
51 	ms_factory_reset_statistics(factory);
52 
53 	rtp_session_resync(stream->ms.sessions.rtp_session);
54 	/*some filters are created right now to allow configuration by the application before start() */
55 	stream->ms.rtpsend = ms_factory_create_filter(factory, MS_RTP_SEND_ID);
56 	stream->ms.ice_check_list = NULL;
57 	stream->ms.qi = ms_quality_indicator_new(stream->ms.sessions.rtp_session);
58 	ms_quality_indicator_set_label(stream->ms.qi, "text");
59 	stream->ms.process_rtcp = text_stream_process_rtcp;
60 
61 	return stream;
62 }
63 
text_stream_new(MSFactory * factory,int loc_rtp_port,int loc_rtcp_port,bool_t ipv6)64 TextStream *text_stream_new(MSFactory *factory, int loc_rtp_port, int loc_rtcp_port, bool_t ipv6) {
65 	return text_stream_new2(factory, ipv6 ? "::" : "0.0.0.0", loc_rtp_port, loc_rtcp_port);
66 }
67 
text_stream_new2(MSFactory * factory,const char * ip,int loc_rtp_port,int loc_rtcp_port)68 TextStream *text_stream_new2(MSFactory *factory, const char* ip, int loc_rtp_port, int loc_rtcp_port) {
69 	TextStream *stream;
70 	MSMediaStreamSessions sessions = {0};
71 	sessions.rtp_session = ms_create_duplex_rtp_session(ip, loc_rtp_port, loc_rtcp_port, ms_factory_get_mtu(factory));
72 	stream = text_stream_new_with_sessions(factory, &sessions);
73 	stream->ms.owns_sessions = TRUE;
74 	return stream;
75 }
76 
text_stream_start(TextStream * stream,RtpProfile * profile,const char * rem_rtp_addr,int rem_rtp_port,const char * rem_rtcp_addr,int rem_rtcp_port,int payload_type)77 TextStream* text_stream_start(TextStream *stream, RtpProfile *profile, const char *rem_rtp_addr, int rem_rtp_port, const char *rem_rtcp_addr, int rem_rtcp_port, int payload_type /* ignored */) {
78 	RtpSession *rtps = stream->ms.sessions.rtp_session;
79 	MSConnectionHelper h;
80 
81 	rtp_session_set_profile(rtps, profile);
82 	if (rem_rtp_port > 0) rtp_session_set_remote_addr_full(rtps, rem_rtp_addr, rem_rtp_port, rem_rtcp_addr, rem_rtcp_port);
83 	if (rem_rtcp_port > 0) {
84 		rtp_session_enable_rtcp(rtps, TRUE);
85 	} else {
86 		rtp_session_enable_rtcp(rtps, FALSE);
87 	}
88 
89 	stream->pt_t140 = rtp_profile_get_payload_number_from_mime_and_flag(profile, "t140", PAYLOAD_TYPE_FLAG_CAN_SEND);
90 	stream->pt_red = rtp_profile_get_payload_number_from_mime_and_flag(profile, "red", PAYLOAD_TYPE_FLAG_CAN_SEND);
91 	if (payload_type == stream->pt_t140) {
92 		ms_debug("Text payload type is T140");
93 	} else if (payload_type == stream->pt_red) {
94 		ms_debug("Text payload type is RED");
95 	} else {
96 		/* we dont know this kind of textstream... */
97 		ms_warning("Unknown type of textstream");
98 	}
99 	rtp_session_set_payload_type(rtps, payload_type);
100 
101 	if (rem_rtp_port > 0) ms_filter_call_method(stream->ms.rtpsend, MS_RTP_SEND_SET_SESSION, rtps);
102 	stream->ms.rtprecv = ms_factory_create_filter(stream->ms.factory, MS_RTP_RECV_ID);
103 	ms_filter_call_method(stream->ms.rtprecv, MS_RTP_RECV_SET_SESSION, rtps);
104 	stream->ms.sessions.rtp_session = rtps;
105 
106 	if (stream->ms.sessions.ticker == NULL) media_stream_start_ticker(&stream->ms);
107 
108 	stream->rttsource = ms_factory_create_filter(stream->ms.factory, MS_RTT_4103_SOURCE_ID);
109 	stream->rttsink = ms_factory_create_filter(stream->ms.factory, MS_RTT_4103_SINK_ID);
110 
111 	ms_filter_call_method(stream->rttsource, MS_RTT_4103_SOURCE_SET_T140_PAYLOAD_TYPE_NUMBER, &stream->pt_t140);
112 	ms_filter_call_method(stream->rttsink, MS_RTT_4103_SINK_SET_T140_PAYLOAD_TYPE_NUMBER, &stream->pt_t140);
113 	if (payload_type == stream->pt_red) {
114 		ms_filter_call_method(stream->rttsource, MS_RTT_4103_SOURCE_SET_RED_PAYLOAD_TYPE_NUMBER, &stream->pt_red);
115 		ms_filter_call_method(stream->rttsink, MS_RTT_4103_SINK_SET_RED_PAYLOAD_TYPE_NUMBER, &stream->pt_red);
116 	}
117 
118 	ms_connection_helper_start(&h);
119 	ms_connection_helper_link(&h, stream->rttsource, -1, 0);
120 	ms_connection_helper_link(&h, stream->ms.rtpsend, 0, -1);
121 	ms_connection_helper_start(&h);
122 	ms_connection_helper_link(&h, stream->ms.rtprecv, -1, 0);
123 	ms_connection_helper_link(&h, stream->rttsink, 0, -1);
124 
125 	ms_ticker_attach_multiple(stream->ms.sessions.ticker, stream->rttsource, stream->ms.rtprecv, NULL);
126 
127 	stream->ms.start_time = stream->ms.last_packet_time = ms_time(NULL);
128 	stream->ms.is_beginning = TRUE;
129 	stream->ms.state = MSStreamStarted;
130 	return stream;
131 }
132 
text_stream_stop(TextStream * stream)133 void text_stream_stop(TextStream *stream) {
134 	if (stream->ms.sessions.ticker) {
135 		if (stream->ms.state == MSStreamPreparing) {
136 			text_stream_unprepare_text(stream);
137 		} else if (stream->ms.state == MSStreamStarted) {
138 			MSConnectionHelper h;
139 			stream->ms.state = MSStreamStopped;
140 			ms_ticker_detach(stream->ms.sessions.ticker, stream->rttsource);
141 			ms_ticker_detach(stream->ms.sessions.ticker, stream->ms.rtprecv);
142 
143 			if (stream->ms.ice_check_list != NULL) {
144 				ice_check_list_print_route(stream->ms.ice_check_list, "Text session's route");
145 				stream->ms.ice_check_list = NULL;
146 			}
147 
148 			rtp_stats_display(rtp_session_get_stats(stream->ms.sessions.rtp_session),
149 					"             TEXT SESSION'S RTP STATISTICS                ");
150 
151 			ms_connection_helper_start(&h);
152 			ms_connection_helper_unlink(&h, stream->rttsource, -1, 0);
153 			ms_connection_helper_unlink(&h, stream->ms.rtpsend, 0, -1);
154 			ms_connection_helper_start(&h);
155 			ms_connection_helper_unlink(&h, stream->ms.rtprecv, -1, 0);
156 			ms_connection_helper_unlink(&h, stream->rttsink, 0, -1);
157 		}
158 	}
159 	ms_factory_log_statistics(stream->ms.factory);
160 	text_stream_free(stream);
161 
162 }
163 
text_stream_iterate(TextStream * stream)164 void text_stream_iterate(TextStream *stream) {
165 	media_stream_iterate(&stream->ms);
166 }
167 
text_stream_putchar32(TextStream * stream,uint32_t ic)168 void text_stream_putchar32(TextStream *stream, uint32_t ic) {
169 	if (stream->rttsource) {
170 		ms_filter_call_method(stream->rttsource, MS_RTT_4103_SOURCE_PUT_CHAR32, &ic);
171 	}
172 }
173 
text_stream_prepare_text(TextStream * stream)174 void text_stream_prepare_text(TextStream *stream){
175 	text_stream_unprepare_text(stream);
176 	stream->ms.rtprecv = ms_factory_create_filter(stream->ms.factory, MS_RTP_RECV_ID);
177 	rtp_session_set_payload_type(stream->ms.sessions.rtp_session, 0);
178 	rtp_session_enable_rtcp(stream->ms.sessions.rtp_session, FALSE);
179 	ms_filter_call_method(stream->ms.rtprecv, MS_RTP_RECV_SET_SESSION, stream->ms.sessions.rtp_session);
180 	stream->ms.voidsink = ms_factory_create_filter(stream->ms.factory, MS_VOID_SINK_ID);
181 	ms_filter_link(stream->ms.rtprecv, 0, stream->ms.voidsink, 0);
182 	media_stream_start_ticker(&stream->ms);
183 	ms_ticker_attach(stream->ms.sessions.ticker, stream->ms.rtprecv);
184 	stream->ms.state = MSStreamPreparing;
185 }
186 
stop_preload_graph(TextStream * stream)187 static void stop_preload_graph(TextStream *stream){
188 	ms_ticker_detach(stream->ms.sessions.ticker, stream->ms.rtprecv);
189 	ms_filter_unlink(stream->ms.rtprecv, 0, stream->ms.voidsink, 0);
190 	ms_filter_destroy(stream->ms.voidsink);
191 	ms_filter_destroy(stream->ms.rtprecv);
192 	stream->ms.voidsink = stream->ms.rtprecv = NULL;
193 }
194 
text_stream_unprepare_text(TextStream * stream)195 void text_stream_unprepare_text(TextStream *stream){
196 	if (stream->ms.state == MSStreamPreparing) {
197 		stop_preload_graph(stream);
198 		stream->ms.state = MSStreamInitialized;
199 	}
200 }