/* * Copyright (c) 2012 Yoann Blein * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Swift { OutgoingScreenSharing::OutgoingScreenSharing(boost::shared_ptr session, UDPSocketFactory* udpSocketFactory, TimerFactory* timerFactory, const JID &toJID) : ScreenSharing(session, udpSocketFactory), timerFactory(timerFactory), recipient(toJID), contentID(JingleContentID(idGenerator.generateID(), JingleContentPayload::InitiatorCreator)), canceled(false), sessionAccepted(false), socketConnected(false), encoder(0), packetizer(0) { jingleSession->onSessionAcceptReceived.connect(boost::bind(&OutgoingScreenSharing::handleSessionAcceptReceived, this, _1, _2, _3)); } OutgoingScreenSharing::~OutgoingScreenSharing() { jingleSession->onSessionAcceptReceived.disconnect(boost::bind(&OutgoingScreenSharing::handleSessionAcceptReceived, this, _1, _2, _3)); delete rtpSession; delete encoder; delete packetizer; } void OutgoingScreenSharing::cancel() { canceled = true; jingleSession->sendTerminate(JinglePayload::Reason::Cancel); onStateChange(ScreenSharing::Canceled); } void OutgoingScreenSharing::start(unsigned int width, unsigned int height) { //onStateChange(ScreenSharing::WaitingForStart); this->width = width; this->height = height; JingleRTPDescription::ref desc = boost::make_shared(JingleRTPDescription::Video); payloadTypeUsed = RTPPayloadType(98, "VP8", 90000); desc->addPayloadType(payloadTypeUsed); JingleRawUDPTransportPayload::ref transport = boost::make_shared(); if (addBestCandidate(transport)) { SWIFT_LOG(debug) << "Screen sharing: start" << std::endl; jingleSession->sendInitiate(contentID, desc, transport); serverSocket->onConnected.connect(boost::bind(&OutgoingScreenSharing::handleSocketConnected, this)); serverSocket->connectToFirstIncoming(); onStateChange(ScreenSharing::WaitingForAccept); } else { SWIFT_LOG(error) << "Screen sharing: Unable to listening on any interface" << std::endl; onStateChange(ScreenSharing::Failed); onFinished(); } } void OutgoingScreenSharing::addImage(const Image &image) { encoder->encodeImage(image); } const JID& OutgoingScreenSharing::getRecipient() const { return recipient; } void OutgoingScreenSharing::handleSocketConnected() { if (canceled) return; SWIFT_LOG(debug) << "Screen sharing: UDP socket connected" << std::endl; serverSocket->onConnected.disconnect(boost::bind(&OutgoingScreenSharing::handleSocketConnected, this)); socketConnected = true; if (sessionAccepted) startRTPSession(); } void OutgoingScreenSharing::handleSessionAcceptReceived(const JingleContentID& /*id*/, boost::shared_ptr /*desc*/, boost::shared_ptr /*transport*/) { if (canceled) return; SWIFT_LOG(debug) << "Screen sharing: accepted" << std::endl; // TODO: check desc and transport sessionAccepted = true; if (socketConnected) { startRTPSession(); } else { connectionTimer = timerFactory->createTimer(1000); connectionTimer->onTick.connect(boost::bind(&OutgoingScreenSharing::handleConnectionFailed, this)); connectionTimer->start(); onStateChange(ScreenSharing::Connecting); } } void OutgoingScreenSharing::handleConnectionFailed() { SWIFT_LOG(debug) << "Screen sharing: unable to connect" << std::endl; connectionTimer->onTick.disconnect(boost::bind(&OutgoingScreenSharing::handleConnectionFailed, this)); jingleSession->sendTerminate(JinglePayload::Reason::ConnectivityError); canceled = true; onStateChange(ScreenSharing::Failed); } void OutgoingScreenSharing::startRTPSession() { SWIFT_LOG(debug) << "Screen sharing: accepted and connected, start sharing" << std::endl; // Session accepted and socket connected, we can start the rtp session rtpSession = new RTPSessionImpl(serverSocket, payloadTypeUsed); if (payloadTypeUsed.getID() == 98 && payloadTypeUsed.getName() == "VP8") { packetizer = new VP8RTPPacketizer; encoder = new VP8Encoder(packetizer, width, height); packetizer->onNewPayloadReady.connect(boost::bind(&OutgoingScreenSharing::handleNewPayloadReady, this, _1, _2)); rtpSession->onRPSIFeedback.connect(boost::bind(&VP8Encoder::handleRPSIFeedback, static_cast(encoder), _1)); onReady(); onStateChange(ScreenSharing::BroadCasting); } } void OutgoingScreenSharing::handleNewPayloadReady(const std::vector& data, bool marker) { SafeByteArray sba(data.begin(), data.end()); rtpSession->sendPacket(sba, 500, marker); } }