reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
GstRtpSession.cxx
Go to the documentation of this file.
1#include "GstRtpSession.hxx"
2
3#include <regex>
4
5#include "GStreamerUtils.hxx"
6
7#ifdef USE_GSTREAMER
8
9using namespace resipgst;
10using namespace resip;
11using namespace Glib;
12using namespace Gst;
13using namespace std;
14
15#define RESIPROCATE_SUBSYSTEM resip::GstSubsystem::GSTREAMER
16
17
18GstRtpSession::GstRtpSession(GstRtpManager& rTPManager, bool webRTC)
21{
22 mMediaBin = Bin::create();
23}
24
25GstRtpSession::~GstRtpSession()
26{
27
28}
29
30const Data&
31GstRtpSession::getLocalAddress() const
32{
33 return mRTPManager.getLocalAddress();
34}
35
36unsigned int
37GstRtpSession::allocatePort()
38{
39 // FIXME - must free the port when finished
40 return mRTPManager.getPortManager().allocateRTPPort();
41}
42
43std::shared_ptr<SdpContents>
44GstRtpSession::buildOffer(bool audio, bool video)
45{
46 std::shared_ptr<SdpContents> offer;
47
48 unsigned int audioPort = allocatePort();
49 unsigned int videoPort = allocatePort();
50
52 const CodecConfigMap& codecConfigs = mRTPManager.getCodecConfigMap();
53 // FIXME - add more codecs
54 const CodecConfig& cAudio = *codecConfigs.at("PCMA");
55 unsigned int ptAudio = 8;
56 const CodecConfig& cVideo = *codecConfigs.at("H264");
57 unsigned int ptVideo = 97;
58 // FIXME - free txt, IPv6, timestamps, other static stuff...
59 Data* txt = new Data("v=0\r\n"
60 "o=- 3838180699 3838180699 IN IP4 " + localAddress + "\r\n"
61 "s=" + mRTPManager.getApplicationName() + "\r\n"
62 "c=IN IP4 " + localAddress + "\r\n"
63 "t=0 0\r\n"
64 "a=ice-pwd:da9801364d7cd7d3a87f7f2f\r\n"
65 "a=ice-ufrag:91f7ed7e\r\n"
66 "a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n"
67 "m=audio " + Data(audioPort) + " RTP/AVP " + Data(ptAudio) + "\r\n"
68 "a=sendrecv\r\n"
69 "a=rtcp:" + Data(audioPort+1) + "\r\n"
70 "a=rtpmap:" + Data(ptAudio) + " " + cAudio.mName + "/" + Data(cAudio.mRate) + "\r\n"
71 //"a=ssrc:2337389544 cname:user269660271@host-9999cdcf\r\n"
72 "m=video " + Data(videoPort) + " RTP/AVP " + Data(ptVideo) + "\r\n"
73 "a=sendrecv\r\n"
74 "a=rtcp:" + Data(videoPort+1) + "\r\n"
75 "a=rtpmap:" + Data(ptVideo) + " " + cVideo.mName + "/" + Data(cVideo.mRate) + "\r\n"
76 "a=fmtp:" + Data(ptVideo) + " " + cVideo.mFmtp + "\r\n"
77 //"a=ssrc:2005192486 cname:user269660271@host-9999cdcf\r\n"
78 );
79
80 HeaderFieldValue *hfv = new HeaderFieldValue(txt->data(), (unsigned int)txt->size());
81 Mime type("application", "sdp");
82 mLocal = std::make_shared<SdpContents>(SdpContents(*hfv, type));
83
85
87
88 return mLocal;
89}
90
91// disable the stream by setting port to 0 as per RFC 3264 s6
92// FIXME: move this logic to SdpContents
93void
95{
96 o << "m=" << m.name() << " 0 " << m.protocol() << " ";
97 if(!m.getFormats().empty())
98 {
99 o << m.getFormats().front();
100 }
101 else if(!m.codecs().empty())
102 {
103 o << m.codecs().front().payloadType();
104 }
105 else
106 {
107 o << "*";
108 // o << "0"; // an alternative
109 }
110 o << "\r\n";
111}
112
113std::shared_ptr<SdpContents>
114GstRtpSession::buildAnswer(std::shared_ptr<resip::SdpContents> remoteOffer)
115{
116 Data* txt = new Data();
117 DataStream stream(*txt);
118
120 // FIXME - free txt, IPv6, timestamps
121 stream << "v=0\r\n"
122 "o=- 3838180699 3838180699 IN IP4 " + localAddress + "\r\n"
123 "s=" + mRTPManager.getApplicationName() + "\r\n"
124 "c=IN IP4 " + localAddress + "\r\n"
125 "t=0 0\r\n"
126 "a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n";
127
128 const CodecConfigMap& codecConfigs = mRTPManager.getCodecConfigMap();
129
131 unsigned int entry = 0;
132 for(auto& m : remoteOffer->session().media())
133 {
135 if(caps)
136 {
137 Glib::ustring codecName;
138 caps->get_structure(0).get_field("encoding-name", codecName);
140 caps->get_structure(0).get_field<gint>("clock-rate", clockRate);
141 gint pt;
142 caps->get_structure(0).get_field<gint>("payload", pt);
144 _codecName.uppercase();
145 CodecConfigMap::const_iterator it = codecConfigs.find(_codecName);
146 // FIXME - check all codec properties are compatible
147 if(it != codecConfigs.end())
148 {
149 const CodecConfig& cc = *it->second;
150 unsigned int localPort = allocatePort();
151 stream << "m=" << m.name() << " " << localPort << " RTP/AVP " << pt << "\r\n"
152 << "a=sendrecv\r\n";
153 stream << "a=rtpmap:" << pt << " " << cc.mName << "/" << cc.mRate << "\r\n";
154 if(m.name() == "video")
155 {
156 stream << "a=fmtp:" << pt << " " << cc.mFmtp << "\r\n";
157 }
158 }
159 else
160 {
161 DebugLog(<<"didn't find supported codec");
162 rejectStream(stream, m);
163 }
164 }
165 else
166 {
167 DebugLog(<<"unsupported media type");
168 rejectStream(stream, m);
169 }
170 entry++;
171 }
172
173 stream.flush();
174 HeaderFieldValue *hfv = new HeaderFieldValue(txt->data(), (unsigned int)txt->size());
175 Mime type("application", "sdp");
176 mLocal = std::make_shared<SdpContents>(SdpContents(*hfv, type));
177
178 //initRtpPorts(); // configure ports to match the answer
180
181 return mLocal;
182}
183
184void
185GstRtpSession::processAnswer(std::shared_ptr<resip::SdpContents> remoteAnswer)
186{
187 const CodecConfigMap& codecConfigs = mRTPManager.getCodecConfigMap();
188
190
191 // FIXME - intersect properly against the local SDP
192 // and then iterate over the intersected SDP instead
193
194 unsigned int entry = 0;
195 for(auto& m : remoteAnswer->session().media())
196 {
198 if(caps)
199 {
200 Glib::ustring codecName;
201 caps->get_structure(0).get_field("encoding-name", codecName);
203 caps->get_structure(0).get_field<gint>("clock-rate", clockRate);
204 gint pt;
205 caps->get_structure(0).get_field<gint>("payload", pt);
207 _codecName.uppercase();
208 CodecConfigMap::const_iterator it = codecConfigs.find(_codecName);
209 // FIXME - check all codec properties are compatible
210 if(it != codecConfigs.end())
211 {
212 const CodecConfig& cc = *it->second;
213 //unsigned int localPort = allocatePort();
214
215
216 // FIXME - we are simply assuming that everything matches here
217
218 }
219 else
220 {
221 DebugLog(<<"didn't find supported codec");
222 //rejectStream(stream, m);
223 }
224 }
225 else
226 {
227 DebugLog(<<"unsupported media type");
228 //rejectStream(stream, m);
229 }
230 entry++;
231 }
232
235
236 // doOfferAnswerIntersect
237
238 initRtpRxPorts(); // ensure RX ports really ready
239 initRtpTxPorts(); // configure ports to match the offer
240
241 DebugLog(<<"going to STATE_PLAYING");
242 StateChangeReturn ret = mMediaBin->set_state(STATE_PLAYING);
244 {
245 ErrLog(<<"pipeline fail");
246 }
247}
248
249Glib::RefPtr<Gst::Caps>
250GstRtpSession::getCaps(SdpContents::Session::Medium& m)
251{
252 SdpContents::Session::Codec& c = m.codecs().front();
253 /*Data caps = "application/x-rtp,media=" + m.name()
254 + ",encoding-name=" + c.getName()
255 + ",clock-rate=" + Data(c.getRate())
256 + ",payload=" + Data(c.payloadType());*/
257 /*Data caps = "application/x-rtp,media=(string)" + m.name()
258 + ",encoding-name=(string)" + c.getName()
259 + ",clock-rate=(int)" + Data(c.getRate())
260 + ",payload=(int)" + Data(c.payloadType());
261 return Gst::Caps::create_from_string(caps.c_str());*/
262 return Gst::Caps::create_simple("application/x-rtp",
263 "media", m.name().c_str(),
264 "encoding-name", c.getName().c_str(),
265 "clock-rate", c.getRate(),
266 "payload", c.payloadType());
267}
268
269Glib::RefPtr<Gst::Caps>
270GstRtpSession::getCaps(const resip::Data& mediumName)
271{
272 std::list<std::reference_wrapper<SdpContents::Session::Medium>> media =
273 mLocal->session().getMediaByType(mediumName);
274 if(media.size() == 0)
275 {
276 WarningLog(<<"no medium found: " << mediumName);
277 return RefPtr<Gst::Caps>();
278 }
279 SdpContents::Session::Medium& m = media.front().get();
280 return getCaps(m);
281}
282
284GstRtpSession::createOutgoingPipeline(const RefPtr<Caps> caps)
285{
286 DebugLog(<<"creating outgoing bin for caps: " << caps->to_string());
287 RefPtr<Bin> encodeBin = Bin::create();
288
289 RefPtr<Queue> queueIn = Queue::create();
290 encodeBin->add(queueIn);
291
292 RefPtr<Pad> queueInSrc = queueIn->get_static_pad("src");
293
294 string mediaType = caps->get_structure(0).get_name();
295 StackLog(<<"mediaType: " << mediaType);
296 string mediaName;
297 if(caps->get_structure(0).has_field("media"))
298 {
299 caps->get_structure(0).get_field("media", mediaName);
300 }
301 StackLog(<<"mediaName: " << mediaName);
302 string encodingName;
303 if(caps->get_structure(0).has_field("encoding-name"))
304 {
305 caps->get_structure(0).get_field("encoding-name", encodingName);
306 }
307 StackLog(<<"encodingName: " << encodingName);
311 Glib::RefPtr<Gst::Caps> v_caps;
312 if(regex_search(mediaType, regex("^video")) || mediaName == "video")
313 {
314 //GstCaps* __caps = gst_caps_from_string("video/x-raw");
315 // profile stuff is only for Gst::EncodeBin
316 //encodeBin->property_profile() =
317 //GstEncodingVideoProfile* videoProfile =
318 // gst_encoding_video_profile_new(__caps, NULL, NULL, 1);
319 //g_object_set(encodeBin->gobj(), "profile", videoProfile, NULL);
320 if(encodingName == "VP8")
321 {
322 // https://gstreamer.freedesktop.org/documentation/vpx/vp8enc.html?gi-language=c
323 // https://www.webmproject.org/docs/encoder-parameters/
324 // The parameters have slightly different names in gstreamer:
325 // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good/html/gst-plugins-good-plugins-vp8enc.html
326 enc = Gst::ElementFactory::create_element("vp8enc");
327 v_caps = Gst::Caps::create_simple("video/x-vp8",
328 "profile", "0");
329 enc->property<gint64>("deadline", 0);
330 //enc->property<bool>("rt", true);
331 //enc->property<guint>("threads", 24); // FIXME magic number
332 //enc->property<GstVP8EncTokenPartitions>("token-partitions", 3); // FIXME magic number - requires 8 cores/threads
333 enc->property<gint>("token-partitions", 3); // FIXME magic number - requires 8 cores/threads
334 enc->property<gint>("keyframe-max-dist", 2000);
335 // FIXME properties on vp8enc
336 payloader = Gst::ElementFactory::create_element("rtpvp8pay");
337 payloader->set_property<gint32>("pt", 120); // FIXME magic number
338 }
339 else if(encodingName == "H264")
340 {
341 // https://gstreamer.freedesktop.org/documentation/openh264/openh264enc.html?gi-language=c
342 enc = Gst::ElementFactory::create_element("openh264enc");
343 v_caps = Gst::Caps::create_simple("video/x-h264",
344 "profile", "baseline");
345 enc->property<guint>("bitrate", 90000); // low // FIXME magic number
346 enc->property<gint64>("complexity", 0); // low
347 enc->property<gint64>("rate-control", 1); // bitrate // FIXME magic number
348
349 // https://gstreamer.freedesktop.org/documentation/vaapi/vaapih264enc.html?gi-language=c
350 /*enc = Gst::ElementFactory::create_element("vaapih264enc");
351 v_caps = Gst::Caps::create_simple("video/x-h264",
352 "profile", "constrained-baseline");
353 enc->property<guint>("bitrate", 90); // low // FIXME magic number
354 //enc->property<guint>("quality-factor", 26); // ICQ/QVBR bitrate control mode quality
355 enc->property<guint>("quality-level", 10); // faster encode, lower quality
356 enc->property<gint64>("rate-control", 2); // bitrate // FIXME magic number */
357
358 // https://gstreamer.freedesktop.org/documentation/x264/index.html?gi-language=c
359 /*enc = Gst::ElementFactory::create_element("x264enc");
360 v_caps = Gst::Caps::create_simple("video/x-h264",
361 "profile", "constrained-baseline");
362 enc->property<guint>("bitrate", 90); // low // FIXME magic number
363 enc->property<gint64>("pass", 0); // CBR // FIXME magic number
364 enc->property<gint64>("tune", 4); // zero latency // FIXME magic number */
365
366 // FIXME properties on enc
367 payloader = Gst::ElementFactory::create_element("rtph264pay");
368 payloader->set_property<gint32>("pt", 97); // FIXME magic number
369 }
370 else
371 {
372 ErrLog(<<"unsupported encoding: " << encodingName);
373 resip_assert(0);
374 }
375 }
376 else if(regex_search(mediaType, regex("^audio")) || mediaName == "audio")
377 {
378 //GstCaps* __caps = gst_caps_from_string("audio/x-raw");
379 // profile stuff is only for Gst::EncodeBin
380 //encodeBin->property_profile() =
381 //GstEncodingAudioProfile* audioProfile =
382 // gst_encoding_audio_profile_new(__caps, NULL, NULL, 1);
383 //g_object_set(encodeBin->gobj(), "profile", audioProfile, NULL);
384 if(encodingName == "OPUS")
385 {
386 // https://gstreamer.freedesktop.org/documentation/opus/opusenc.html?gi-language=c
387 enc = Gst::ElementFactory::create_element("opusenc");
388 uint32_t pt = 109; // FIXME magic number
389 v_caps = Gst::Caps::create_simple("audio/x-opus",
390 "payload", pt,
391 "encoding-name", "OPUS",
392 "rate", 48000, // FIXME magic number
393 "channels", 2); // FIXME magic number
394 enc->property<gint>("bitrate", 48000);
395 payloader = Gst::ElementFactory::create_element("rtpopuspay");
396 payloader->set_property<gint32>("pt", pt);
397 }
398 else if(encodingName == "PCMA")
399 {
400 // https://gstreamer.freedesktop.org/documentation/alaw/alawenc.html?gi-language=c
401 enc = Gst::ElementFactory::create_element("alawenc");
402 v_caps = Gst::Caps::create_simple("audio/x-alaw",
403 "rate", 8000, // FIXME magic number
404 "channels", 1); // FIXME magic number
405 payloader = Gst::ElementFactory::create_element("rtppcmapay");
406 payloader->set_property<gint32>("pt", 8); // FIXME magic number
407 }
408 else
409 {
410 CritLog(<<"unsupported encoding: " << encodingName);
411 resip_assert(0);
412 }
413 }
414 else
415 {
416 ErrLog(<<"unhandled mediaType");
417 resip_assert(0);
418 }
419
420 encodeBin->add(enc);
421 encodeBin->add(payloader);
422 RefPtr<Gst::Queue> queue = Gst::Queue::create("queueOut");
423 encodeBin->add(queue);
424
425 queueInSrc->link(enc->get_static_pad("sink"));
426
427 if(!v_caps)
428 {
429 enc->link(payloader);
430 }
431 else
432 {
433 enc->link(payloader, v_caps);
434 }
435 payloader->link(queue, caps);
436 RefPtr<Pad> queueSrc = queue->get_static_pad("src");
437
438 RefPtr<Pad> sink = GhostPad::create(queueIn->get_static_pad("sink"), "sink");
439 encodeBin->add_pad(sink);
440 RefPtr<Pad> src = GhostPad::create(queueSrc, "src");
441 encodeBin->add_pad(src);
442
443 return encodeBin;
444}
445
446std::string
447makePadName(const std::string& prefix, unsigned int streamId)
448{
449 ostringstream padName;
450 padName << prefix << streamId;
451 return padName.str();
452}
453
455GstRtpSession::createMediaSink(RefPtr<Caps> caps, unsigned int streamId)
456{
458
459 mMediaBin->add(encodeBin);
460
461 RefPtr<Pad> src = encodeBin->get_static_pad("src");
462
463 RefPtr<Caps> padCaps = Caps::create_from_string("application/x-rtp");
464 RefPtr<Gst::PadTemplate> tmpl = PadTemplate::create("send_rtp_sink_%u", PAD_SINK, PAD_REQUEST, padCaps);
465 ostringstream padName;
466 padName << "sink_" << streamId;
467 DebugLog(<< "linking to " << padName.str());
468 //RefPtr<Pad> binSink = mRtpTransportBin->create_compatible_pad(queueSrc, caps);
469 //RefPtr<Pad> binSink = mRtpTransportBin->get_request_pad(padName.str());
470 //RefPtr<Caps> padCaps2 = Caps::create_from_string("application/x-rtp");
471 //RefPtr<Pad> binSink = mRtpTransportBin->request_pad(tmpl, padName.str(), padCaps2);
472 // is a ghost pad, should have been created already
473
475 if(mWebRTC)
476 {
477 // it is a request pad on the webrtcbin
478 binSink = mRtpTransportBin->create_compatible_pad(src, caps);
479 }
480 else
481 {
482 // it is static_pad on the rtpbin wrapper
483 // FIXME - reimplement this as a request pad like webrtcbin
484 binSink = mRtpTransportBin->get_static_pad(padName.str());
485 }
486 if(!binSink)
487 {
488 CritLog(<<"failed to get request pad " << padName.str());
489 resip_assert(0);
490 }
491
492 if(binSink->is_linked())
493 {
494 RefPtr<Pad> peer = binSink->get_peer();
495 binSink->unlink(peer);
496 }
497
498 src->link(binSink);
499
500 string sinkName = makePadName("sink_", streamId);
501 RefPtr<GhostPad> ghostSink = RefPtr<GhostPad>::cast_dynamic(mMediaBin->get_static_pad(sinkName));
502 if(ghostSink)
503 {
504 ghostSink->set_target(encodeBin->get_static_pad("sink"));
505 }
506 else
507 {
508 StackLog(<<"adding new sink: " << sinkName);
509
510 ghostSink = GhostPad::create(encodeBin->get_static_pad("sink"), sinkName);
511 mMediaBin->add_pad(ghostSink);
512 }
513
514 return ghostSink;
515}
516
517Glib::RefPtr<Gst::Bin>
518GstRtpSession::createDecodeBin(const Data& streamKey, const Glib::ustring& srcPadName, bool isWebRTC)
519{
520 /*RefPtr<Gst::DecodeBin> decodeBin = Gst::DecodeBin::create();*/
521
522 RefPtr<Bin> decodeBin = Gst::Bin::create();
523 RefPtr<Element> queue = Gst::Queue::create();
524 decodeBin->add(queue);
526 if(streamKey == "video")
527 {
529 RefPtr<Element> parse;
530 if(isWebRTC)
531 {
532 depay = Gst::ElementFactory::create_element("rtpvp8depay");
533 parse = Gst::ElementFactory::create_element("vp8parse");
534 dec = Gst::ElementFactory::create_element("vp8dec");
535 //dec->property<guint>("threads", 24); // FIXME magic number
536 }
537 else
538 {
539 depay = Gst::ElementFactory::create_element("rtph264depay");
540 parse = Gst::ElementFactory::create_element("h264parse");
541 dec = Gst::ElementFactory::create_element("openh264dec");
542 }
543 decodeBin->add(depay);
544 decodeBin->add(parse);
545 decodeBin->add(dec);
546 queue->link(depay);
547 depay->link(parse);
548 parse->link(dec);
549 }
550 else if(streamKey == "audio")
551 {
553 if(isWebRTC)
554 {
555 depay = Gst::ElementFactory::create_element("rtpopusdepay");
556 dec = Gst::ElementFactory::create_element("opusdec");
557 }
558 else
559 {
560 depay = Gst::ElementFactory::create_element("rtppcmadepay");
561 dec = Gst::ElementFactory::create_element("alawdec");
562 }
563 decodeBin->add(depay);
564 decodeBin->add(dec);
565 queue->link(depay);
566 depay->link(dec);
567 }
568 else
569 {
570 CritLog(<<"unrecognized streamKey: " << streamKey);
571 resip_assert(0);
572 }
573
574 RefPtr<Pad> sink = GhostPad::create(queue->get_static_pad("sink"), "sink");
575 decodeBin->add_pad(sink);
576
577 sink->signal_linked().connect([this, decodeBin, srcPadName, dec](const RefPtr<Pad>& pad){
578 StackLog(<<"linked: " << pad->get_name());
579 Iterator<Element> it = decodeBin->iterate_sources();
580 it.begin();
581 if(it.is_end())
582 {
583 StackLog(<<"adding src pad");
584 // this is where the signal on-pad-added is triggered
585 // for any signal handlers created elsewhere
586 //RefPtr<Pad> src = GhostPad::create(dec->get_static_pad("src"), "src");
587 RefPtr<Pad> src = GhostPad::create(dec->get_static_pad("src"), srcPadName);
588 decodeBin->add_pad(src);
589 }
590 else
591 {
592 StackLog(<<"src pad already added");
593 }
594 });
595
596 sink->signal_unlinked().connect([this, decodeBin, dec](const RefPtr<Pad>& pad){
597 StackLog(<<"linked: " << pad->get_name());
598 Iterator<Element> it = decodeBin->iterate_sources();
599 it.begin();
600 while(!it.is_end())
601 {
602 RefPtr<GhostPad> g = RefPtr<GhostPad>::cast_dynamic(*it);
603 if(g)
604 {
605 decodeBin->remove_pad(g);
606 g->set_target(RefPtr<Pad>());
607 g.clear();
608 }
609 it.next();
610 }
611 });
612
613 return decodeBin;
614}
615
616#define P_CLIENTS(a,p) (a + ":" + Data(p)) // FIXME - eliminate macros
617
618void
619GstRtpSession::initRtpRxPorts()
620{
621 RefPtr<Caps> rtcp_caps = Gst::Caps::create_simple("application/x-rtcp");
622
624 {
625 DebugLog(<<"mRtpTransportBin not ready yet");
626 return;
627 }
628
629 RefPtr<Bin> rtpBin = RefPtr<Bin>::cast_dynamic(mRtpTransportBin->get_child("rtpbin0"));
630 if(!rtpBin)
631 {
632 DebugLog(<<"rtpBin not ready yet");
633 return;
634 }
635
636 if(mRtpTransportBin->get_child("udpsrc0"))
637 {
638 DebugLog(<<"udpsrc0 already present");
639 return;
640 }
641
642 if(!mLocal)
643 {
644 DebugLog(<<"mLocal not ready");
645 return;
646 }
647
648 // Iterators
649 SdpContents::Session::MediumContainer::iterator local = mLocal->session().media().begin(); // FIXME - migrate to const_iterator
650 //SdpContents::Session::MediumContainer::const_iterator remote = mRemote->session().media().cbegin();
651 //std::vector<Glib::RefPtr<Gst::Bin>>::const_iterator enc = mEncBin.cbegin();
652
653 unsigned int streamCount = 0;
654 for(; local != mLocal->session().media().end() /* &&
655 remote != mRemote->session().media().cend() */ /*&&
656 enc != mEncBin.cend()*/ ; )
657 {
658 if(local->name() == "audio" || local->name() == "video")
659 {
660 string localAddress = local->getConnections().front().getAddress().c_str(); // FIXME - more than one Connection?
661 //Data peerAddress = remote->getConnections().front().getAddress(); // FIXME - more than one Connection?
662
663 // https://gstreamer.freedesktop.org/documentation/udp/udpsrc.html?gi-language=c
664 Glib::RefPtr<Gst::Element> udpSource = Gst::ElementFactory::create_element("udpsrc");
665 udpSource->set_property<Glib::ustring>("address", localAddress);
666 udpSource->set_property<gint32>("port", local->port());
667
668 Glib::RefPtr<Gst::Element> udpSourceRtcp = Gst::ElementFactory::create_element("udpsrc");
669 udpSourceRtcp->set_property<Glib::ustring>("address", localAddress);
670 udpSourceRtcp->set_property<gint32>("port", local->firstRtcpPort()); // FIXME - more than one Connection / RTCP?
671
672 // https://gstreamer.freedesktop.org/documentation/udp/multiudpsink.html?gi-language=c#properties
673 //Glib::RefPtr<Gst::Element> udpSink = Gst::ElementFactory::create_element("multiudpsink");
674 //Data peerClient = P_CLIENTS(peerAddress, remote->port());
675 //DebugLog(<<"peerClient = " << peerClient);
676
677 //udpSink->set_property<Glib::ustring>("clients", peerClient.c_str());
678 // FIXME - specifying the bind-address and bind-port is a very good idea for NAT
679 // traversal (symmetric RTP RFC 4961)
680 // https://www.rfc-editor.org/rfc/rfc4961
681 // - however, when I tried to use these settings, I found that the streams were not
682 // activated at all or sometimes the pad-added event was only received for one
683 // stream (audio or video) and not both
684 // - there is also an option to obtain the GSocket pointer from the udpsrc and give it to
685 // the udpsink so they share the same socket (properties: socket, socket-v6)
686 //udpSink->set_property<Glib::ustring>("bind-address", localAddress); // FIXME share socket with udpsrc?
687 //udpSink->set_property<gint32>("bind-port", local->port());
688 //udpSink->set_property("sync", false);
689 //udpSink->set_property("async", false);
690 //udpSink->set_property("qos-dscp", ); // FIXME
691 //udpSink->set_property("socket", ); // FIXME
692 //udpSink->set_property("socket-v6", ); // FIXME
693
694 //Glib::RefPtr<Gst::Element> udpSinkRtcp = Gst::ElementFactory::create_element("multiudpsink");
695 //Data peerClientRtcp = P_CLIENTS(peerAddress, remote->firstRtcpPort());
696 //DebugLog(<<"peerClientRtcp = " << peerClientRtcp);
697
698 //udpSinkRtcp->set_property<Glib::ustring>("clients", peerClientRtcp.c_str());
699 // FIXME - see comments above about bind-address and bind-port with udpSink element
700 //udpSinkRtcp->set_property<Glib::ustring>("bind-address", localAddress); // FIXME share socket with udpsrc?
701 //udpSinkRtcp->set_property<gint32>("bind-port", local->firstRtcpPort()); // FIXME - more than one Connection / RTCP?
702 //udpSinkRtcp->set_property("sync", false);
703 //udpSinkRtcp->set_property("async", false);
704 //udpSinkRtcp->set_property("qos-dscp", ); // FIXME
705 //udpSinkRtcp->set_property("socket", ); // FIXME
706 //udpSinkRtcp->set_property("socket-v6", ); // FIXME
707
710 //mRtpTransportBin->add(udpSink);
711 //mRtpTransportBin->add(udpSinkRtcp);
712
713 // incoming RTP / RTCP
714 Glib::RefPtr<Gst::Caps> incomingCaps = getCaps(*local);
715 udpSource->link_pads("src", rtpBin, makePadName("recv_rtp_sink_", streamCount), incomingCaps);
716 udpSourceRtcp->link_pads("src", rtpBin, makePadName("recv_rtcp_sink_", streamCount), rtcp_caps);
717
718 // outgoing RTP - linked by on-pad-added signal handler
719 //rtpBin->link_pads(makePadName("send_rtp_src_", mStreamCount), udpSink, "sink");
720 // outgoing RTCP - linked manually
721 //rtpBin->link_pads(makePadName("send_rtcp_src_", mStreamCount), udpSinkRtcp, "sink", rtcp_caps);
722 //mSendSinks[mStreamCount] = udpSink;
723 //mSendRtcpSinks[mStreamCount] = udpSinkRtcp;
724
725 // FIXME - create the outgoing ghost pads on request only
726 // outgoing media
727 /*RefPtr<Gst::Bin> _enc = *enc;
728 _enc->link_pads("src", rtpBin, s.str());*/
729 //RefPtr<Pad> mediaSink = rtpBin->create_compatible_pad(pad, caps);
730 // needs to be consistent with webrtcbin naming convention
731 // rather than rtcbin naming conventions
732 //string rtcBinPadName = makePadName("send_rtp_sink_", streamCount);
733 string webrtcBinPadName = makePadName("sink_", streamCount);
734 //RefPtr<Pad> mediaSink = rtpBin->get_request_pad(rtcBinPadName);
735 //RefPtr<Pad> ghostSink = GhostPad::create(mediaSink, webrtcBinPadName);
736 RefPtr<GhostPad> ghostSink = RefPtr<GhostPad>::cast_dynamic(mRtpTransportBin->get_static_pad(webrtcBinPadName));
737 if(!ghostSink)
738 {
739 DebugLog(<<"creating GhostPad " << webrtcBinPadName);
740 ghostSink = GhostPad::create(PAD_SINK, webrtcBinPadName);
741 mRtpTransportBin->add_pad(ghostSink);
742 }
743 }
744
745 local++;
746 //remote++;
747 //enc++;
748 streamCount++;
749 }
751}
752
753void
754GstRtpSession::initRtpTxPorts()
755{
756 RefPtr<Caps> rtcp_caps = Gst::Caps::create_simple("application/x-rtcp");
757
759 {
760 DebugLog(<<"mRtpTransportBin not ready yet");
761 return;
762 }
763
764 RefPtr<Bin> rtpBin = RefPtr<Bin>::cast_dynamic(mRtpTransportBin->get_child("rtpbin0"));
765 if(!rtpBin)
766 {
767 DebugLog(<<"rtpBin not ready yet");
768 return;
769 }
770
771 if(mRtpTransportBin->get_child("multiudpsink0"))
772 {
773 DebugLog(<<"multiudpsink0 already present");
774 return;
775 }
776
777 if(!mLocal)
778 {
779 DebugLog(<<"mLocal not ready");
780 return;
781 }
782
783 if(!mRemote)
784 {
785 DebugLog(<<"mRemote not ready");
786 return;
787 }
788
789 // Iterators
790 SdpContents::Session::MediumContainer::iterator local = mLocal->session().media().begin(); // FIXME - migrate to const_iterator
791 SdpContents::Session::MediumContainer::const_iterator remote = mRemote->session().media().cbegin();
792 //std::vector<Glib::RefPtr<Gst::Bin>>::const_iterator enc = mEncBin.cbegin();
793
794 unsigned int streamCount = 0;
795 for(; local != mLocal->session().media().end() &&
796 remote != mRemote->session().media().cend() /*&&
797 enc != mEncBin.cend()*/ ; )
798 {
799 if(local->name() == "audio" || local->name() == "video")
800 {
801 string localAddress = local->getConnections().front().getAddress().c_str(); // FIXME - more than one Connection?
802 Data peerAddress = remote->getConnections().front().getAddress(); // FIXME - more than one Connection?
803
804 // https://gstreamer.freedesktop.org/documentation/udp/udpsrc.html?gi-language=c
805 /*Glib::RefPtr<Gst::Element> udpSource = Gst::ElementFactory::create_element("udpsrc");
806 udpSource->set_property<Glib::ustring>("address", localAddress);
807 udpSource->set_property<gint32>("port", local->port());*/
808
809 //Glib::RefPtr<Gst::Element> udpSourceRtcp = Gst::ElementFactory::create_element("udpsrc");
810 //udpSourceRtcp->set_property<Glib::ustring>("address", localAddress);
811 //udpSourceRtcp->set_property<gint32>("port", local->firstRtcpPort()); // FIXME - more than one Connection / RTCP?
812
813 // https://gstreamer.freedesktop.org/documentation/udp/multiudpsink.html?gi-language=c#properties
814 Glib::RefPtr<Gst::Element> udpSink = Gst::ElementFactory::create_element("multiudpsink");
816 DebugLog(<<"peerClient = " << peerClient);
817
818 udpSink->set_property<Glib::ustring>("clients", peerClient.c_str());
819 // FIXME - specifying the bind-address and bind-port is a very good idea for NAT
820 // traversal (symmetric RTP RFC 4961)
821 // https://www.rfc-editor.org/rfc/rfc4961
822 // - however, when I tried to use these settings, I found that the streams were not
823 // activated at all or sometimes the pad-added event was only received for one
824 // stream (audio or video) and not both
825 // - there is also an option to obtain the GSocket pointer from the udpsrc and give it to
826 // the udpsink so they share the same socket (properties: socket, socket-v6)
827 //udpSink->set_property<Glib::ustring>("bind-address", localAddress); // FIXME share socket with udpsrc?
828 //udpSink->set_property<gint32>("bind-port", local->port());
829 udpSink->set_property("sync", false);
830 udpSink->set_property("async", false);
831 //udpSink->set_property("qos-dscp", ); // FIXME
832 //udpSink->set_property("socket", ); // FIXME
833 //udpSink->set_property("socket-v6", ); // FIXME
834
835 Glib::RefPtr<Gst::Element> udpSinkRtcp = Gst::ElementFactory::create_element("multiudpsink");
836 Data peerClientRtcp = P_CLIENTS(peerAddress, remote->firstRtcpPort());
837 DebugLog(<<"peerClientRtcp = " << peerClientRtcp);
838
839 udpSinkRtcp->set_property<Glib::ustring>("clients", peerClientRtcp.c_str());
840 // FIXME - see comments above about bind-address and bind-port with udpSink element
841 //udpSinkRtcp->set_property<Glib::ustring>("bind-address", localAddress); // FIXME share socket with udpsrc?
842 //udpSinkRtcp->set_property<gint32>("bind-port", local->firstRtcpPort()); // FIXME - more than one Connection / RTCP?
843 udpSinkRtcp->set_property("sync", false);
844 udpSinkRtcp->set_property("async", false);
845 //udpSinkRtcp->set_property("qos-dscp", ); // FIXME
846 //udpSinkRtcp->set_property("socket", ); // FIXME
847 //udpSinkRtcp->set_property("socket-v6", ); // FIXME
848
849 //mRtpTransportBin->add(udpSource);
850 //mRtpTransportBin->add(udpSourceRtcp);
853
854 // incoming RTP / RTCP
855 /*Glib::RefPtr<Gst::Caps> incomingCaps = getCaps(*local);
856 udpSource->link_pads("src", rtpBin, makePadName("recv_rtp_sink_", mStreamCount), incomingCaps);
857 udpSourceRtcp->link_pads("src", rtpBin, makePadName("recv_rtcp_sink_", mStreamCount), rtcp_caps);*/
858
859 // outgoing RTP - linked by on-pad-added signal handler
860 //rtpBin->link_pads(makePadName("send_rtp_src_", mStreamCount), udpSink, "sink");
861 // outgoing RTCP - linked manually
862 rtpBin->link_pads(makePadName("send_rtcp_src_", streamCount), udpSinkRtcp, "sink", rtcp_caps);
865
866 // FIXME - create the outgoing ghost pads on request only
867 // outgoing media
868 /*RefPtr<Gst::Bin> _enc = *enc;
869 _enc->link_pads("src", rtpBin, s.str());*/
870 //RefPtr<Pad> mediaSink = rtpBin->create_compatible_pad(pad, caps);
871 // needs to be consistent with webrtcbin naming convention
872 // rather than rtcbin naming conventions
873 string rtcBinPadName = makePadName("send_rtp_sink_", streamCount);
874 string webrtcBinPadName = makePadName("sink_", streamCount);
875 RefPtr<Pad> mediaSink = rtpBin->get_request_pad(rtcBinPadName);
876 //RefPtr<Pad> ghostSink = GhostPad::create(mediaSink, webrtcBinPadName);
877 //mRtpTransportBin->add_pad(ghostSink);
878 RefPtr<GhostPad> ghostSink = RefPtr<GhostPad>::cast_dynamic(mRtpTransportBin->get_static_pad(webrtcBinPadName));
879 if(ghostSink)
880 {
881 DebugLog(<<"using existing GhostPad " << webrtcBinPadName);
882 ghostSink->set_target(mediaSink);
883 }
884 else
885 {
886 DebugLog(<<"creating GhostPad " << webrtcBinPadName);
887 ghostSink = GhostPad::create(mediaSink, webrtcBinPadName);
888 mRtpTransportBin->add_pad(ghostSink);
889 }
890 }
891
892 local++;
893 remote++;
894 //enc++;
895 streamCount++;
896 }
898}
899
900void
901GstRtpSession::createRtpTransportBin()
902{
904 {
905 WarningLog(<<"mRtpTransportBin already initialized");
906 }
907
908 if(mWebRTC)
909 {
910 mRtpTransportBin = RefPtr<Bin>::cast_dynamic(ElementFactory::create_element("webrtcbin"));
911 }
912 else
913 {
914 mRtpTransportBin = Bin::create();
915
916 // FIXME - find better way to test whether it is already initialized
917 /*if(mRtpTransportBin->get_num_children() > 0)
918 {
919 DebugLog(<<"mRtpTransportBin already initialized, num_children = " << mRtpTransportBin->get_num_children());
920 return mRtpTransportBin;
921 }*/
922
923 Glib::RefPtr<Gst::Element> rtpBin = Gst::ElementFactory::create_element("rtpbin");
925
926 //rtpBin->signal_pad_added().connect(sigc::mem_fun(*this, &GstThread::on_demux_pad_added));
927 rtpBin->signal_pad_added().connect([this, rtpBin](const RefPtr<Pad>& newPad){
928 Glib::ustring padName = newPad->get_name();
929 DebugLog(<<"Dynamic pad created. Linking demuxer/decoder " << padName);
930
931 if(newPad->get_direction() != PAD_SRC)
932 {
933 DebugLog(<<"not a src pad: " << padName);
934 return;
935 }
936
937 // extract ID
938 std::regex r("recv_rtp_src_(\\d+)_(\\d+)_(\\d+)");
939 std::smatch match;
940 const std::string& s = padName.raw();
941 if(std::regex_search(s.begin(), s.end(), match, r))
942 {
943 DebugLog(<<"found a stream " << padName);
944 RefPtr<Pad> ghostSource = GhostPad::create(newPad, padName);
946 //mSourcePads.push_back(ghostSource);
947 return;
948 }
949
950 r = "send_rtp_src_(\\d+)";
951 if(std::regex_search(s.begin(), s.end(), match, r))
952 {
953 unsigned int streamId = atoi(match[1].str().c_str());
954 DebugLog(<<"linking for stream " << streamId);
956 rtpBin->link_pads(padName, udpSink, "sink");
957
958 Glib::RefPtr<Gst::Caps> rtcp_caps = Gst::Caps::create_simple(
959 "application/x-rtcp");
960 ostringstream _padNameRtcp;
961 _padNameRtcp << "send_rtcp_src_" << streamId;
962 Glib::ustring padNameRtcp = _padNameRtcp.str();
963 DebugLog(<<"RTCP pad: " << padNameRtcp);
965 //rtpBin->link_pads(padNameRtcp, udpRtcpSink, "sink", rtcp_caps);
966
967 return;
968 }
969
970 /*r = "send_rtcp_src_(\\d+)";
971 if(std::regex_search(s.begin(), s.end(), match, r))
972 {
973 unsigned int streamId = atoi(match[1].str().c_str());
974 DebugLog(<<"linking for stream " << streamId);
975 RefPtr<Element> udpRtcpSink = mSendRtcpSinks[streamId];
976 rtpBin->link_pads(padName, udpRtcpSink, "sink");
977 return;
978 }*/
979
980 DebugLog(<<"ignoring pad: " << padName);
981 return;
982
984
985 // extract ID
986 //std::regex r("recv_rtp_src_(\\d+)_(\\d+)_(\\d+)");
987 //std::smatch match;
988 //const std::string& s = padName.raw();
989 if (std::regex_search(s.begin(), s.end(), match, r))
990 {
991 unsigned int streamId = atoi(match[1].str().c_str());
992 auto& ssrc = match[2];
993 StackLog(<<"streamId: " << streamId << " SSRC: " << ssrc);
994 RefPtr<Gst::Bin> dec; // = mDecBin.at(streamId);
995 sinkPad = dec->get_static_pad("sink");
996
997 // FIXME - setup HOMER if all pads connected
998 //
999 // Now all audio and video pads, incoming and outgoing,
1000 // are present. We can enable the RTCP signals. If we
1001 // ask for these signals before the pads are ready then
1002 // it looks like we don't receive any signals at all.
1003 //addGstreamerRtcpMonitoringPads(rtpbin, mHepAgent, mPeerSpecs, mCorrelationId);
1004
1006
1008 {
1009 DebugLog(<< "Linking of pads " << padName << " and "
1010 << sinkPad->get_name() << " failed.");
1011 }
1012 DebugLog(<<"linking done");
1013
1014 /*GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(pipeline->gobj()),
1015 GST_DEBUG_GRAPH_SHOW_ALL,
1016 "test-pipeline");*/
1017 /*GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline->gobj()),
1018 GST_DEBUG_GRAPH_SHOW_ALL,
1019 "test-pipeline");*/
1020 }
1021 else
1022 {
1023 DebugLog(<<"pad not handled: " << padName);
1024 return;
1025 }
1026 });
1027
1028 // we used to call this here, now
1029 // it is broken up and called as the offer/answer exchange
1030 // progresses
1031 //initRtpPorts();
1034 }
1035
1036 mRtpTransportBin->signal_pad_added().connect([this](const RefPtr<Pad>& pad){
1037 const Glib::ustring padName = pad->get_name();
1038 if(pad->get_direction() == PAD_SRC)
1039 {
1040 StackLog(<<"trying to extract pt from pad name: " << padName);
1041 std::regex r1("recv_rtp_src_(\\d+)_(\\d+)_(\\d+)");
1042 std::regex r2("src_(\\d+)");
1043 std::smatch match;
1044 const std::string& s = padName.raw();
1045 // from rtpbin
1046 if (std::regex_search(s.begin(), s.end(), match, r1))
1047 {
1048 unsigned int streamId = atoi(match[1].str().c_str());
1049 unsigned long ssrc = atoi(match[2].str().c_str());
1050 unsigned int pt = atoi(match[3].str().c_str());
1051 StackLog(<< "found stream " << streamId
1052 << " SSRC: " << ssrc
1053 << " payload type: " << pt);
1054
1055 createDecodeBinForStream(pad, streamId, pt);
1056 }
1057 else if (std::regex_search(s.begin(), s.end(), match, r2))
1058 {
1059 unsigned int streamId = atoi(match[1].str().c_str());
1060 StackLog(<< "found stream " << streamId);
1061 createDecodeBinForStream(pad, streamId, -1);
1062 }
1063 else
1064 {
1065 ErrLog(<<"unrecognized src pad: " << padName);
1066 return;
1067 }
1068 }
1069 else
1070 {
1071 StackLog(<<"not a src pad: " << padName);
1072 }
1073 });
1074
1075 mMediaBin->add(mRtpTransportBin);
1076}
1077
1079GstRtpSession::getRtpTransportBin()
1080{
1081 if(!mRtpTransportBin)
1082 {
1084 }
1085
1086 return mRtpTransportBin;
1087}
1088
1089void
1090GstRtpSession::createDecodeBinForStream(const RefPtr<Pad>& pad, unsigned int streamId, int pt)
1091{
1092 // FIXME - some of this logic can move to SdpContents
1093
1094 Glib::ustring srcPadName = pad->get_name();
1095
1096 // use streamId to find Medium
1097 if(!mLocal)
1098 {
1099 ErrLog(<<"no local SDP, new pad is not expected and can't be handled");
1100 return;
1101 }
1102 unsigned int mediaCount = mLocal->session().media().size();
1103 if(streamId >= mediaCount)
1104 {
1105 ErrLog(<<"media.size() == " << mediaCount << ", streamId too high: " << streamId);
1106 return;
1107 }
1108 auto mediaIt = mLocal->session().media().cbegin();
1109 for(unsigned int i = 0; i < streamId;)
1110 {
1111 i++;
1112 mediaIt++;
1113 }
1115
1116 // use pt to find the format in the Medium
1117 auto codecIt = m.codecs().cbegin();
1118 if(pt >= 0)
1119 {
1120 while(codecIt != m.codecs().cend() && codecIt->payloadType() != pt)
1121 {
1122 if(++codecIt == m.codecs().cend())
1123 {
1124 ErrLog(<<"no payload format matches pt: " << pt);
1125 return;
1126 }
1127 }
1128 }
1129 else
1130 {
1131 RefPtr<Caps> caps = pad->get_current_caps();
1132 if(!caps->get_structure(0).has_field("encoding-name"))
1133 {
1134 CritLog(<<"can't find encoding-name");
1135 resip_assert(0);
1136 }
1137 string capsEncodingName;
1138 caps->get_structure(0).get_field("encoding-name", capsEncodingName);
1140 _capsEncodingName.uppercase();
1141 while(codecIt != m.codecs().cend() && codecIt->getName() != _capsEncodingName)
1142 {
1143 if(++codecIt == m.codecs().cend())
1144 {
1145 ErrLog(<<"no codec name matches: " << _capsEncodingName);
1146 return;
1147 }
1148 }
1149 }
1150 const auto& codec = *codecIt;
1151 StackLog(<<"matched Codec: " << codec);
1152
1153 // create the decode Bin
1154 const CodecConfigMap& codecConfigs = mRTPManager.getCodecConfigMap();
1155 Data codecName = codec.getName();
1156 codecName.uppercase(); // FIXME - use a type for case-insensitive codec names
1157 CodecConfigMap::const_iterator codecRegIt = codecConfigs.find(codecName);
1158 if(codecRegIt == codecConfigs.end())
1159 {
1160 ErrLog(<<"codec " << codecName << " not found in local registry");
1161 return;
1162 }
1163 std::shared_ptr<CodecConfig> cc = codecRegIt->second;
1164 // FIXME - check all codec properties are compatible
1165
1166 // create decoder
1167 RefPtr<Bin> decodeBin = Bin::create();
1168 RefPtr<Queue> decQueue = Queue::create();
1169 decodeBin->add(decQueue);
1170 RefPtr<Element> decPay = ElementFactory::create_element(cc->mDepay.c_str());
1171 decodeBin->add(decPay);
1172 decQueue->link(decPay);
1173
1174 RefPtr<Element> dec = ElementFactory::create_element(cc->mDecoder.c_str());
1175 decodeBin->add(dec);
1176
1177 if(!cc->mParse.empty())
1178 {
1179 RefPtr<Element> decParse = Gst::ElementFactory::create_element(cc->mParse.c_str());
1180 decodeBin->add(decParse);
1181 decPay->link(decParse);
1182 decParse->link(dec);
1183 }
1184 else
1185 {
1186 decPay->link(dec);
1187 }
1188
1189 bool isVideo = false; // FIXME - add property to CodecConfig
1190 if(codecName == "VP8" || codecName == "H264")
1191 {
1192 isVideo = true;
1193 }
1194
1195 // Setup the keyframe request probe
1196 if(isVideo)
1197 {
1199 }
1200
1201 // link the src pad to the decode Bin
1202 RefPtr<Pad> ghostSink = GhostPad::create(decQueue->get_static_pad("sink"), "sink");
1203 decodeBin->add_pad(ghostSink);
1204
1205 RefPtr<Pad> ghostSrc = GhostPad::create(dec->get_static_pad("src"), srcPadName);
1206 decodeBin->add_pad(ghostSrc);
1207
1208 // FIXME store it in a map?
1209 mMediaBin->add(decodeBin);
1210
1211 // link the src pad from the RtpBin to the DecodeBin
1212 pad->link(ghostSink);
1213
1214 // notify the application about the new decode Bin
1215 // - application receives signal on new src pad here:
1216 RefPtr<Pad> outerSrc = GhostPad::create(ghostSrc, srcPadName);
1217 mMediaBin->add_pad(outerSrc);
1218
1219 if(++mDecodes == getStreamCount())
1220 {
1221 DebugLog(<<"all incoming streams connected to decoders");
1222 if(mHepAgent)
1223 {
1224 DebugLog(<<"all pads ready, trying to setup HOMER HEP RTCP");
1225 //resip::addGstreamerRtcpMonitoringPads(RefPtr<Bin>::cast_dynamic(mRtpTransportElement));
1226 // Now all audio and video pads, incoming and outgoing,
1227 // are present. We can enable the RTCP signals. If we
1228 // ask for these signals before the pads are ready then
1229 // it looks like we don't receive any signals at all.
1230 RtcpPeerSpecVector peerSpecs = resip::createRtcpPeerSpecs(*getLocalSdp(), *getRemoteSdp());
1231 addGstreamerRtcpMonitoringPads(RefPtr<Bin>::cast_dynamic(mRtpTransportBin),
1232 mHepAgent, peerSpecs, mCorrelationId);
1233 }
1234 }
1235
1236 DebugLog(<<"successfully created incoming decode bin for " << srcPadName);
1237}
1238
1239void
1240GstRtpSession::onPlaying()
1241{
1242 DebugLog(<<"onPlaying");
1243 for(auto& pad : mSourcePads)
1244 {
1245 DebugLog(<<"onPlaying: adding pad " << pad->get_name());
1246 //mRtpTransportBin->add_pad(pad);
1247 }
1248}
1249
1250void
1251GstRtpSession::initCaps(std::shared_ptr<SdpContents> sdp, std::vector<Glib::RefPtr<Caps>>& sessionCaps)
1252{
1253 if(!sdp)
1254 {
1255 ErrLog(<<"initCaps: we don't have valid SDP");
1256 return;
1257 }
1258
1259 const CodecConfigMap& codecConfigs = mRTPManager.getCodecConfigMap();
1260
1261 sessionCaps.clear();
1262 sessionCaps.resize(sdp->session().media().size());
1263
1264 unsigned int entry = 0;
1265 for(const auto& m : sdp->session().media())
1266 {
1267 RefPtr<Caps>& caps = sessionCaps[entry];
1268 Data mediumName = m.name();
1270 if(mediumName == "audio" || mediumName == "video")
1271 {
1272 StackLog(<<"parsing a medium entry for caps, name = " << mediumName);
1273 std::list<Data> formats = m.getFormats(); // must have a copy here because it is emptied by m.codecs()
1274 std::map<int, SdpContents::Session::Codec> codecMap;
1275 for(const auto& c : m.codecs())
1276 {
1277 codecMap[c.payloadType()] = c;
1278 }
1279 StackLog(<<"found " << codecMap.size() << " codec(s) and " << formats.size() << " format(s) in the SDP offer");
1280 resip_assert(formats.size() > 0); // FIXME
1281 for(const auto& f : formats)
1282 {
1283 StackLog(<<"checking format " << f);
1284 if(!caps && f != "webrtc-datachannel" && f != "*")
1285 {
1286 int pt = f.convertInt();
1287 if(codecMap.find(pt) != codecMap.end())
1288 {
1289 const Codec& c = codecMap.at(pt);
1290 Data codecName = c.getName();
1292
1293 CodecConfigMap::const_iterator it = codecConfigs.find(codecName);
1294 // FIXME - check all codec properties are compatible
1295
1296 if(it != codecConfigs.cend())
1297 {
1298 const shared_ptr<CodecConfig> cc = it->second;
1299 DebugLog(<<"found supported codec: " << codecName);
1300
1301 caps = Gst::Caps::create_simple("application/x-rtp",
1302 "media", mediumName.c_str(),
1303 "encoding-name", codecName.c_str(),
1304 "clock-rate", c.getRate(),
1305 "payload", c.payloadType());
1306 }
1307 else
1308 {
1309 DebugLog(<<"ignoring unsupported codec: " << codecName);
1310 }
1311 }
1312 else
1313 {
1314 WarningLog(<<"format " << pt << " not found in codecMap");
1315 }
1316 }
1317 }
1318 }
1319 else
1320 {
1321 WarningLog(<<"medium name " << mediumName << " not supported");
1322 }
1323 entry++;
1324 }
1325}
1326
1327void
1328GstRtpSession::initOutgoingBins()
1329{
1332
1333 mOutgoingPads.clear();
1334 mOutgoingPads.resize(getOutgoingCaps().size());
1335 unsigned int streamId = 0;
1336 for(auto& caps : getOutgoingCaps())
1337 {
1338 if(caps)
1339 {
1341 }
1342 streamId++;
1343 }
1344}
1345
1346void
1347GstRtpSession::addStream(Glib::RefPtr<Gst::Caps> caps)
1348{
1349 unsigned int streamId = mOutgoingCaps.size();
1350 mOutgoingCaps.push_back(caps);
1351 mOutgoingPads.push_back(GhostPad::create(PAD_SINK, makePadName("sink_", streamId)));
1352}
1353
1354void
1355GstRtpSession::setRemoteSdp(std::shared_ptr<resip::SdpContents> remote)
1356{
1357 mRemote = remote;
1359
1362}
1363
1364unsigned int
1365GstRtpSession::getStreamCount()
1366{
1367 if(mWebRTC)
1368 {
1369 unsigned int result = 0;
1370 Iterator<Pad> it = mRtpTransportBin->iterate_sink_pads();
1371 it.begin();
1372 while(it.next() == ITERATOR_OK)
1373 {
1374 result++;
1375 }
1376 return result;
1377 }
1378 else
1379 {
1380 return mStreamCount;
1381 }
1382}
1383
1384void
1385GstRtpSession::initHomer(const resip::Data& correlationId, std::shared_ptr<resip::HepAgent> hepAgent)
1386{
1388 mHepAgent = hepAgent;
1389}
1390
1391#endif
1392
1393/* ====================================================================
1394 *
1395 * Copyright (c) 2022, Software Freedom Institute https://softwarefreedom.institute
1396 * Copyright (c) 2022, Daniel Pocock https://danielpocock.com
1397 *
1398 * Redistribution and use in source and binary forms, with or without
1399 * modification, are permitted provided that the following conditions
1400 * are met:
1401 *
1402 * 1. Redistributions of source code must retain the above copyright
1403 * notice, this list of conditions and the following disclaimer.
1404 *
1405 * 2. Redistributions in binary form must reproduce the above copyright
1406 * notice, this list of conditions and the following disclaimer in
1407 * the documentation and/or other materials provided with the
1408 * distribution.
1409 *
1410 * 3. Neither the name of the author(s) nor the names of any contributors
1411 * may be used to endorse or promote products derived from this software
1412 * without specific prior written permission.
1413 *
1414 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
1415 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1416 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1417 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
1418 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1419 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1420 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1421 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1422 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1423 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1424 * SUCH DAMAGE.
1425 *
1426 * ====================================================================
1427 *
1428 *
1429 */
static const Data pad("\0\0\0\0\0\0\0", 7)
#define DebugLog(args_)
Definition Logger.hxx:128
#define StackLog(args_)
Definition Logger.hxx:125
#define CritLog(args_)
Definition Logger.hxx:140
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
Data & uppercase()
Converts this Data to uppercase.
Definition Data.cxx:1648
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
Data & lowercase()
Converts this Data to lowercase.
Definition Data.cxx:1635
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
Definition Data.cxx:1947
Represents the "media-type" element in the RFC 3261 grammar.
Definition Mime.hxx:20
parameters for a specific codec are stored in this class.
process m= (media announcement) blocks
const std::list< Data > & getFormats() const
return a list of codec formats
const CodecContainer & codecs() const
preferred codec/format interface
const Data & protocol() const
return the transport protocol
const Data & name() const
return the media type
Provides an interface to process and generate SDP bodies (MIME content-type application/sdp).
dcm! – add UnusedChecking(_enum) below;
unsigned int uint32_t
Definition stdint.h:85
void list()
Definition userAdmin.cxx:66