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 }