/* * 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 #include namespace Swift { IncomingScreenSharing::IncomingScreenSharing(boost::shared_ptr session, UDPSocketFactory* udpSocketFactory, ConnectivityManager* connectivityManager, TimerFactory* timerFactory, IQRouter* iqRouter, boost::shared_ptr content) : ScreenSharing(session, udpSocketFactory, connectivityManager), initialContent(content), parser(0), decoder(0), lastMouveMoveEvent(InputEventPayload::Event::MouseMove), inputEventPayload(boost::make_shared()), eventSendingTimer(timerFactory->createTimer(500)), iqRouter(iqRouter) { onStateChange(ScreenSharing::WaitingForAccept); eventSendingTimer->onTick.connect(boost::bind(&IncomingScreenSharing::handleEventSendingTimerTick, this)); } IncomingScreenSharing::~IncomingScreenSharing() { eventSendingTimer->onTick.disconnect(boost::bind(&IncomingScreenSharing::handleEventSendingTimerTick, this)); delete rtpSession; delete parser; delete decoder; } void IncomingScreenSharing::cancel() { jingleSession->sendTerminate(JinglePayload::Reason::Cancel); if (rtpSession) rtpSession->stop(); onStateChange(ScreenSharing::Canceled); } void IncomingScreenSharing::accept() { JingleRawUDPTransportPayload::ref transport = boost::make_shared(); if (!addBestCandidate(transport)) { SWIFT_LOG(error) << "Screen sharing: Unable to listening on any interface" << std::endl; jingleSession->sendTerminate(JinglePayload::Reason::FailedTransport); onStateChange(ScreenSharing::Failed); onFinished(); return; } JingleRTPDescription::ref desc = initialContent->getDescription(); if (!desc->getPayloadTypes().empty()) payloadTypeUsed = desc->getPayloadTypes().front(); // TODO: create a valid description instead of copying the initator's one jingleSession->sendAccept(getContentID(), desc, transport); JingleRawUDPTransportPayload::ref initialTransport = initialContent->getTransport(); clientSocket = udpSocketFactory->createUDPSocket(); clientSocket->connect(initialTransport->getCandidates().front().hostAddressPort); // Send a empty packet to let the server know about us SafeByteArray data(1, 0); clientSocket->send(data); rtpSession = new RTPSessionImpl(clientSocket, payloadTypeUsed); if (payloadTypeUsed.getID() == 98 && payloadTypeUsed.getName() == "VP8") { decoder = new VP8Decoder; parser = new VP8RTPParser(decoder); rtpSession->onIncomingPacket.connect(boost::bind(&VP8RTPParser::newPayloadReceived, parser, _1, _2, _3)); decoder->onNewRef.connect(boost::bind(&RTPSession::sendRPSIFeedback, rtpSession, _1)); decoder->onCorrupted.connect(boost::bind(&RTPSession::sendSLIFeedback, rtpSession, _1)); decoder->onNewImageAvailable.connect(boost::bind(&IncomingScreenSharing::handleNewImageAvailable, this, _1)); } onStateChange(ScreenSharing::Connecting); } const JID &IncomingScreenSharing::getSender() const { return jingleSession->getInitiator(); } void IncomingScreenSharing::sendInputEvent(const InputEventPayload::Event& event) { if (event.type == InputEventPayload::Event::Unknown) return; if (inputEventPayload->getEvents().empty()) { eventSendingTimer->start(); } if (event.type == InputEventPayload::Event::MouseMove) { lastMouveMoveEvent.realArg1 = event.realArg1; lastMouveMoveEvent.realArg2 = event.realArg2; } else { addLastMouseMoveIfDifferent(); inputEventPayload->addEvent(event); } } JingleContentID IncomingScreenSharing::getContentID() const { return JingleContentID(initialContent->getName(), initialContent->getCreator()); } void IncomingScreenSharing::handleNewImageAvailable(const Image& image) { onStateChange(ScreenSharing::Receiving); onNewImageReceived(image); } void IncomingScreenSharing::handleEventSendingTimerTick() { addLastMouseMoveIfDifferent(); boost::shared_ptr< GenericRequest > request = boost::make_shared< GenericRequest >(IQ::Set, getSender(), inputEventPayload, iqRouter); request->send(); // Prepare for a new payload inputEventPayload.reset(new InputEventPayload); } void IncomingScreenSharing::addLastMouseMoveIfDifferent() { const std::vector& events = inputEventPayload->getEvents(); std::vector::const_reverse_iterator last; std::vector::const_reverse_iterator it; for (it = events.rbegin(); it != events.rend(); ++it) { if (it->type == InputEventPayload::Event::MouseMove) { last = it; break; } } if (it == events.rend() || !approximatelyEqual(it->realArg1, lastMouveMoveEvent.realArg1) || !approximatelyEqual(it->realArg2, lastMouveMoveEvent.realArg2)) { inputEventPayload->addEvent(lastMouveMoveEvent); } } }