diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index dd4cd5470ff7837ba39be109d06682a580bfc896..51e404140560a234b2dd1e81bc5b878862f9aed1 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1144,6 +1144,8 @@ static void on_publish_response(SalOp *op) { const SalErrorInfo *ei = op->getErrorInfo(); if (lev == NULL) return; + LinphoneCore *lc = static_cast<LinphoneCore *>(op->getSal()->getUserPointer()); + if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) return; if (ei->reason == SalReasonNone) { if (linphone_event_get_publish_state(lev) != LinphonePublishTerminating) { SalPublishOp *publishOp = static_cast<SalPublishOp *>(op); diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp index 7dc17a40b6f708edc7341603d39530fa7b9dab6f..5b903424e8039540b068d6a8f22a7f4343e70b7b 100644 --- a/src/conference/participant-device.cpp +++ b/src/conference/participant-device.cpp @@ -220,7 +220,6 @@ bool ParticipantDevice::setThumbnailStreamSsrc(uint32_t newSsrc) { lInfo() << "Setting thumbnail stream ssrc of " << *this << " to " << newSsrc; } } - return changed; } @@ -606,8 +605,8 @@ std::set<LinphoneStreamType> ParticipantDevice::updateMediaCapabilities() { audioDir = getStreamDirectionFromSession(LinphoneStreamTypeAudio); videoDir = getStreamDirectionFromSession(LinphoneStreamTypeVideo); textDir = getStreamDirectionFromSession(LinphoneStreamTypeText); - thumbnailDir = - mMediaSession->getDirectionOfStream(MediaSessionPrivate::ThumbnailVideoContentAttribute); + thumbnailDir = mMediaSession->getDirectionOfStream( + MediaSessionPrivate::ThumbnailVideoContentAttribute, getThumbnailStreamLabel()); } updateSsrc = isInConference; @@ -649,7 +648,7 @@ std::set<LinphoneStreamType> ParticipantDevice::updateMediaCapabilities() { mediaCapabilityChanged.insert(LinphoneStreamTypeVideo); } - bool updateThumbnailSsrc = ((resultThumbnailDir != LinphoneMediaDirectionInactive) || (thumbnailSsrc == 0)); + bool updateThumbnailSsrc = (resultThumbnailDir != LinphoneMediaDirectionInactive); if (setThumbnailStreamSsrc(thumbnailSsrc) && updateThumbnailSsrc) { mediaCapabilityChanged.insert(LinphoneStreamTypeVideo); } diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 6c20061c6f73464990efa7fb3f026f508e609eb8..e0c7f8025c61237e1cb58b3e7ec1eb5c7a3dff63 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -1791,31 +1791,36 @@ void MediaSessionPrivate::fillConferenceParticipantStream(SalStreamDescription & } } } - if (dir == SalStreamInactive) { - lWarning() << *q << "Setting " << std::string(sal_stream_type_to_string(type)) - << " stream of participant device " << dev->getAddress() << " to inactive (label " << label - << " and content " << content - << ") because he or she doesn't have the send component in its stream capabilities"; + bool isInactive = (dir == SalStreamInactive); + if (isInactive) { + lWarning() << *q << ": Setting " << std::string(sal_stream_type_to_string(type)) << " stream of " + << *dev << " to inactive (label " << label << " and content " << content + << ") because the send component is disabled in its stream capabilities"; } cfg.dir = dir; if (isVideoStream) { validateVideoStreamDirection(cfg); } - if (getParams()->rtpBundleEnabled() && (dir != SalStreamInactive)) - addStreamToBundle(md, newStream, cfg, mid); + if (!isInactive) { + if (getParams()->rtpBundleEnabled()) { + addStreamToBundle(md, newStream, cfg, mid); + } + newStream.setSupportedEncryptions(encs); + } cfg.replacePayloads(l); newStream.addActualConfiguration(cfg); - newStream.setSupportedEncryptions(encs); fillRtpParameters(newStream); + lInfo() << "Add stream of type " << sal_stream_type_to_string(type) << " for " << *dev << " (label " + << label << " and content " << content << ") on local offer of " << *q; success = true; } PayloadTypeHandler::clearPayloadList(l); } if (!success) { - lInfo() << "Don't put video stream for device in conference with address " - << (dev ? dev->getAddress()->toString() : "sip:") << " on local offer for CallSession [" << q - << "] because no valid payload has been found or device is not valid (pointer " << dev << ")"; + lInfo() << "Don't put stream of type " << sal_stream_type_to_string(type) << " of device with address " + << (dev ? dev->getAddress()->toString() : "sip:") << " on local offer of " << *q + << " because no valid payload has been found or device is not valid (pointer " << dev << ")"; cfg.dir = SalStreamInactive; newStream.disable(); newStream.type = type; @@ -1872,7 +1877,12 @@ void MediaSessionPrivate::fillLocalStreamDescription(SalStreamDescription &strea cfg.frame_marking_extension_id = RTP_EXTENSION_FRAME_MARKING; } } - if (getParams()->rtpBundleEnabled()) addStreamToBundle(md, stream, cfg, mid); + bool isInactive = (dir == SalStreamInactive); + if (!isInactive) { + if (getParams()->rtpBundleEnabled()) { + addStreamToBundle(md, stream, cfg, mid); + } + } // Only used for testing if (q->getCore()->getCCore()->goog_remb_enabled) cfg.rtcp_fb.goog_remb_enabled = TRUE; @@ -1977,21 +1987,16 @@ SalStreamDescription &MediaSessionPrivate::addStreamToMd(std::shared_ptr<SalMedi } } - if (streamIdx < 0) { - if (freeSlot < 0) { - md->streams.resize(currentMdSize + 1); - return md->streams[currentMdSize]; - } else { - return md->streams[static_cast<size_t>(freeSlot)]; - } - } else { + // Stream position preference + if (streamIdx >= 0) { const auto &idx = static_cast<decltype(md->streams)::size_type>(streamIdx); try { auto stream = md->streams.at(idx); - // If a stream at the index requested in the the function argument has already been allocated and it is + // If a stream at the index requested in the function argument has already been allocated and it is // active, then it must be replaced. if ((stream.getDirection() != SalStreamInactive) && oldMd) { const auto ¤tStreamLabel = stream.getLabel(); + std::string oldStreamLabel; bool currentStreamLabelEmpty = currentStreamLabel.empty(); const auto oldMdSize = oldMd->streams.size(); int idxOldMd = -1; @@ -2001,7 +2006,7 @@ SalStreamDescription &MediaSessionPrivate::addStreamToMd(std::shared_ptr<SalMedi (std::find(protectedStreamNumbersOldMd.cbegin(), protectedStreamNumbersOldMd.cend(), mdStreamIdx) != protectedStreamNumbersOldMd.cend()); auto oldStream = oldMd->getStreamAtIdx(static_cast<unsigned int>(mdStreamIdx)); - const auto &oldStreamLabel = oldStream.getLabel(); + oldStreamLabel = oldStream.getLabel(); bool oldStreamLabelEmpty = oldStreamLabel.empty(); // Select index if either the labels match or the new and old stream have no labels and the index is // not the same. In fact it may happen that a faulty core sends an SDP with multiple streams without @@ -2024,30 +2029,35 @@ SalStreamDescription &MediaSessionPrivate::addStreamToMd(std::shared_ptr<SalMedi } } else { if (idxOldMd == streamIdx) { - lFatal() << "Unable to find available free stream description index:\n- Index in previous SDP: " - << idxOldMd << "\n- Guessed index: " << streamIdx; + lFatal() + << *q + << ": Unable to find available free stream description index:\n- Index in previous SDP: " + << idxOldMd << " - label: " << oldStreamLabel << "\n- Guessed index: " << streamIdx + << " - label: " << currentStreamLabel; } auto &streamToFill = addStreamToMd(md, idxOldMd, oldMd); streamToFill = stream; } } + lInfo() << *q << ": Add or replace stream at index " << idx; return md->streams.at(idx); } catch (std::out_of_range &) { - // If a stream at the index requested in the the function argument has not already been allocated, resize + // If a stream at the index requested in the function argument has not already been allocated, resize // the vector list - lWarning() << "The current media description has only " << currentMdSize + lWarning() << *q << ": The current media description has only " << currentMdSize << " streams and it has been requested to allocate a stream at index " << idx; md->streams.resize(idx + 1); if (oldMd) { const auto oldMdSize = oldMd->streams.size(); - lWarning() << "Keep the same type as in the previous media description for all newly allocate streams"; + lWarning() + << *q << ": Keep the same type as in the previous media description for all newly allocate streams"; for (decltype(md->streams)::size_type i = currentMdSize; i < idx; i++) { auto &c = md->streams[i]; if (i < oldMdSize) { const auto &s = oldMd->streams[i]; c.type = s.type; } - lWarning() << "Setting " << std::string(sal_stream_type_to_string(c.type)) + lWarning() << *q << ": Setting " << std::string(sal_stream_type_to_string(c.type)) << " stream inactive at index " << i << " because of std::out_of_range."; c.setDirection(SalStreamInactive); } @@ -2055,6 +2065,19 @@ SalStreamDescription &MediaSessionPrivate::addStreamToMd(std::shared_ptr<SalMedi return md->streams.at(idx); } } + + // Free slot + if (freeSlot >= 0) { + // No preferred stream position has been given but a free slot has been found + lInfo() << *q << ": Use free slot at index " << freeSlot; + return md->streams[static_cast<size_t>(freeSlot)]; + } + + // No preference has been given regarding the stream position and no free slots are available, therefore extend the + // media description by appending a stream at the end + md->streams.resize(currentMdSize + 1); + lInfo() << *q << ": Extend local media description to allocate stream at index " << currentMdSize; + return md->streams[currentMdSize]; } void MediaSessionPrivate::addConferenceLocalParticipantStreams(bool add, @@ -2107,15 +2130,9 @@ void MediaSessionPrivate::addConferenceLocalParticipantStreams(bool add, (deviceState == ParticipantDevice::State::OnHold)); if (addStream) { SalStreamDescription &newStream = addStreamToMd(md, foundStreamIdx, oldMd); - SalStreamConfiguration cfg; - newStream.type = type; - newStream.setContent(content); - - if (!deviceLabel.empty()) { - newStream.setLabel(deviceLabel); - } + SalStreamConfiguration cfg; cfg.proto = getParams()->getMediaProto(); bool bundle_enabled = getParams()->rtpBundleEnabled(); @@ -2127,7 +2144,6 @@ void MediaSessionPrivate::addConferenceLocalParticipantStreams(bool add, : emptyList), bundle_enabled); if (!l.empty()) { - cfg.replacePayloads(l); newStream.name = "Thumbnail " + std::string(sal_stream_type_to_string(type)) + " " + participantDevice->getAddress()->toString(); const auto mediaDirection = @@ -2153,15 +2169,24 @@ void MediaSessionPrivate::addConferenceLocalParticipantStreams(bool add, } } cfg.dir = dir; - if (type == SalVideo) { - validateVideoStreamDirection(cfg); - - if (!isInLocalConference) cfg.frame_marking_extension_id = RTP_EXTENSION_FRAME_MARKING; - } - if (bundle_enabled) { - const std::string bundleNamePrefix((type == SalVideo) ? "vs" : "as"); - const std::string bundleName(bundleNamePrefix + std::string("Me") + content); - addStreamToBundle(md, newStream, cfg, bundleName); + if (dir != SalStreamInactive) { + cfg.replacePayloads(l); + if (type == SalVideo) { + validateVideoStreamDirection(cfg); + if (!isInLocalConference) { + cfg.frame_marking_extension_id = RTP_EXTENSION_FRAME_MARKING; + } + } + newStream.setSupportedEncryptions(encs); + newStream.setContent(content); + if (!deviceLabel.empty()) { + newStream.setLabel(deviceLabel); + } + if (bundle_enabled) { + const std::string bundleNamePrefix((type == SalVideo) ? "vs" : "as"); + const std::string bundleName(bundleNamePrefix + std::string("Me") + content); + addStreamToBundle(md, newStream, cfg, bundleName); + } } } else { lInfo() << "Don't put " << std::string(sal_stream_type_to_string(type)) @@ -2171,7 +2196,6 @@ void MediaSessionPrivate::addConferenceLocalParticipantStreams(bool add, } PayloadTypeHandler::clearPayloadList(l); newStream.addActualConfiguration(cfg); - newStream.setSupportedEncryptions(encs); fillRtpParameters(newStream); } else { lWarning() << "Do not add thumbnail stream for the local participant " @@ -2248,8 +2272,7 @@ void MediaSessionPrivate::addConferenceParticipantStreams(std::shared_ptr<SalMed : dev->getStreamLabel(sal_stream_type_to_linphone(type)); // main stream has the same label as one of the thumbnail streams const auto &foundStreamIdx = - devLabel.empty() ? -1 - : oldMd->findIdxStreamWithContent(participantContent, devLabel); + devLabel.empty() ? -1 : oldMd->findIdxStreamWithLabel(type, devLabel); lInfo() << "MediaSession [" << q << "] (local address " << *q->getLocalAddress() << " remote address " << *q->getRemoteAddress() << "] in " << *conference << " is adding a stream of type " @@ -2339,9 +2362,8 @@ void MediaSessionPrivate::addConferenceParticipantStreams(std::shared_ptr<SalMed newStream.rtp_port = 0; newStream.rtcp_port = 0; newStream.addActualConfiguration(cfg); - lWarning() << *q - << ": New stream added as disabled and inactive because no device has been " - "found with label " + lWarning() << *q << ": New stream added at index " << idx + << " as disabled and inactive because no device has been found with label " << participantsAttrValue << " in " << *conference; } } @@ -2706,9 +2728,9 @@ void MediaSessionPrivate::makeLocalMediaDescription(bool localIsOfferer, videoStreamIdx = gridStreamIdxWithContent; } else if (activeSpeakerStreamIdxWithContent > -1) { videoStreamIdx = activeSpeakerStreamIdxWithContent; - } else { - videoStreamIdx = refMd->findIdxBestStream(SalVideo); } + // If no stream with content has been found, then let's append the stream. There is no way for the SDK + // to guess where the main stream should be } else { videoStreamIdx = refMd->findIdxBestStream(SalVideo); } @@ -2718,8 +2740,7 @@ void MediaSessionPrivate::makeLocalMediaDescription(bool localIsOfferer, fillLocalStreamDescription(videoStream, md, enableVideoStream, "Video", SalVideo, proto, videoDir, videoCodecs, "vs", getParams()->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeVideo)); - - if (conference) { + if (conference && videoStream.enabled()) { if (participantDevice && (isInLocalConference || (!isInLocalConference && remoteContactAddress && remoteContactAddress->hasParam(Conference::IsFocusParameter)))) { @@ -3667,7 +3688,7 @@ LinphoneStatus MediaSessionPrivate::pause() { q->updateContactAddressInOp(); if (conference) { - lInfo() << "Removing participant with session " << q << " (local addres " << *q->getLocalAddress() + lInfo() << "Removing participant with session " << q << " (local address " << *q->getLocalAddress() << " remote address " << *q->getRemoteAddress() << ") from conference " << *conference->getConferenceAddress(); // Do not preserve conference after removing the participant @@ -3949,32 +3970,47 @@ void MediaSessionPrivate::updateCurrentParams() const { getCurrentParams()->enableAudio(false); } - const auto streamIdx = q->getThumbnailStreamIdx(md); - const auto &videoStream = - (streamIdx == -1) ? md->findBestStream(SalVideo) : md->getStreamAtIdx(static_cast<unsigned int>(streamIdx)); - if (videoStream != Utils::getEmptyConstRefObject<SalStreamDescription>()) { - getCurrentParams()->getPrivate()->enableImplicitRtcpFb(videoStream.hasImplicitAvpf()); - - const auto videoDirection = getDirFromMd(md, SalVideo); - getCurrentParams()->setVideoDirection(videoDirection); + const auto mainStreamIdx = q->getMainVideoStreamIdx(md); + bool mainStreamEnabled = false; + if (mainStreamIdx != -1) { + const auto &mainVideoStream = md->getStreamAtIdx(static_cast<unsigned int>(mainStreamIdx)); + mainStreamEnabled = mainVideoStream.enabled(); + getCurrentParams()->getPrivate()->enableImplicitRtcpFb(mainVideoStream.hasImplicitAvpf()); if (getCurrentParams()->getVideoDirection() != LinphoneMediaDirectionInactive) { const std::string &rtpAddr = - (videoStream.getRtpAddress().empty() == false) ? videoStream.getRtpAddress() : md->addr; + (mainVideoStream.getRtpAddress().empty() == false) ? mainVideoStream.getRtpAddress() : md->addr; getCurrentParams()->enableVideoMulticast(!!ms_is_multicast(rtpAddr.c_str())); } else { getCurrentParams()->enableVideoMulticast(false); } - const auto enable = - (conference) ? (videoDirection != LinphoneMediaDirectionInactive) : videoStream.enabled(); - getCurrentParams()->enableVideo(enable); } else { getCurrentParams()->getPrivate()->enableImplicitRtcpFb(false); - getCurrentParams()->setVideoDirection(LinphoneMediaDirectionInactive); getCurrentParams()->enableVideoMulticast(false); - getCurrentParams()->enableVideo(false); } + const auto videoDirection = getDirFromMd(md, SalVideo); + getCurrentParams()->setVideoDirection(videoDirection); + getCurrentParams()->enableVideo((conference) ? (videoDirection != LinphoneMediaDirectionInactive) + : mainStreamEnabled); + + SalStreamDir thumbnailStreamDirection = SalStreamInactive; + if (conference) { + const auto thumbnailStreamIdx = q->getThumbnailStreamIdx(); + if (thumbnailStreamIdx != -1) { + const auto &thumbnailVideoStream = md->getStreamAtIdx(static_cast<unsigned int>(thumbnailStreamIdx)); + thumbnailStreamDirection = thumbnailVideoStream.getDirection(); + } + } else { + thumbnailStreamDirection = SalStreamSendRecv; + } + // The camera is enabled if: + // - the thumbnail stream is enabled + // - the thumbnail stream's direction is sendrecv or sendonly + getCurrentParams()->enableCamera( + ((thumbnailStreamDirection == SalStreamSendRecv) || (thumbnailStreamDirection == SalStreamSendOnly)) && + getCurrentParams()->videoEnabled()); + const SalStreamDescription &textStream = md->findBestStream(SalText); if (textStream != Utils::getEmptyConstRefObject<SalStreamDescription>()) { // Direction and multicast are not supported for real-time text. @@ -4029,7 +4065,7 @@ LinphoneStatus MediaSessionPrivate::startAccept() { if (isThisNotCurrentConference || isThisNotCurrentMediaSession) { if ((linphone_core_get_media_resource_mode(q->getCore()->getCCore()) == LinphoneExclusiveMediaResources) && linphone_core_preempt_sound_resources(q->getCore()->getCCore()) != 0) { - lInfo() << "Delaying call to " << __func__ << " for media session (local addres " << *q->getLocalAddress() + lInfo() << "Delaying call to " << __func__ << " for media session (local address " << *q->getLocalAddress() << " remote address " << *q->getRemoteAddress() << ") in state " << Utils::toString(state) << " because sound resources cannot be preempted"; q->addPendingAction([this] { @@ -4363,9 +4399,20 @@ ConferenceLayout MediaSession::computeConferenceLayout(const std::shared_ptr<Sal const auto ¶ms = (isInLocalConference) ? d->getRemoteParams() : d->getParams(); layout = params->getConferenceVideoLayout(); } else { - layout = ConferenceLayout::ActiveSpeaker; - lDebug() << "Unable to deduce layout from media description " << md - << " - Default it to: " << Utils::toString(layout); + const auto &content = MediaSessionPrivate::ThumbnailVideoContentAttribute; + const auto direction = (isInLocalConference) ? SalStreamSendOnly : SalStreamRecvOnly; + if ((md->nbActiveStreamsOfType(SalVideo) > 0) && (md->findIdxStreamWithContent(content, direction) == -1)) { + layout = ConferenceLayout::Grid; + lWarning() << "No stream with a main stream content attribute has been found; nonetheless the media " + "description has at least one stream active video stream and none with content " + << content << " and direction " << sal_stream_dir_to_string(direction) + << ". It means that the remote party is likely to be on a " << Utils::toString(layout) + << " layout and is not wishing to send its camera's video stream"; + } else { + layout = ConferenceLayout::ActiveSpeaker; + lDebug() << "Unable to deduce layout from media description " << md + << " - Default it to: " << Utils::toString(layout); + } } } return layout; @@ -5183,7 +5230,7 @@ bool MediaSession::cameraEnabled() const { if (iface) { auto vs = iface->getVideoStream(); if (vs && video_stream_local_screen_sharing_enabled(vs)) { - auto streamIdx = getLocalThumbnailStreamIdx(); + auto streamIdx = getThumbnailStreamIdx(); if (streamIdx >= 0) iface = dynamic_cast<MS2VideoControl *>(d->getStreamsGroup().getStream(streamIdx)); } } @@ -5200,7 +5247,7 @@ void MediaSession::enableCamera(BCTBX_UNUSED(bool value)) { if (iface) { auto vs = iface->getVideoStream(); if (vs && video_stream_local_screen_sharing_enabled(vs)) { - auto streamIdx = getLocalThumbnailStreamIdx(); + auto streamIdx = getThumbnailStreamIdx(); if (streamIdx >= 0) iface = dynamic_cast<MS2VideoControl *>(d->getStreamsGroup().getStream(streamIdx)); } } @@ -5426,7 +5473,7 @@ void MediaSession::setNativePreviewWindowId(BCTBX_UNUSED(void *id)) { if (iface) { auto vs = iface->getVideoStream(); if (vs && video_stream_local_screen_sharing_enabled(vs)) { - auto streamIdx = getLocalThumbnailStreamIdx(); + auto streamIdx = getThumbnailStreamIdx(); if (streamIdx < 0) return; auto videostream = dynamic_cast<VideoControlInterface *>(d->getStreamsGroup().getStream(streamIdx)); videostream->setNativePreviewWindowId(id); @@ -5442,7 +5489,7 @@ void *MediaSession::getNativePreviewVideoWindowId() const { if (iface) { auto vs = iface->getVideoStream(); if (vs && video_stream_local_screen_sharing_enabled(vs)) { - auto streamIdx = getLocalThumbnailStreamIdx(); + auto streamIdx = getThumbnailStreamIdx(); if (streamIdx < 0) return nullptr; auto videostream = dynamic_cast<VideoControlInterface *>(d->getStreamsGroup().getStream(streamIdx)); return videostream->getNativePreviewWindowId(); @@ -5459,7 +5506,7 @@ void *MediaSession::createNativePreviewVideoWindowId() const { if (iface) { auto vs = iface->getVideoStream(); if (vs && video_stream_local_screen_sharing_enabled(vs)) { - auto streamIdx = getLocalThumbnailStreamIdx(); + auto streamIdx = getThumbnailStreamIdx(); if (streamIdx < 0) return nullptr; auto videostream = dynamic_cast<MS2VideoControl *>(d->getStreamsGroup().getStream(streamIdx)); return videostream->createNativePreviewWindowId(); @@ -5533,29 +5580,41 @@ const MediaSessionParams *MediaSession::getRemoteParams() const { audioStream.custom_sdp_attributes); } else params->enableAudio(false); - const auto streamIdx = getThumbnailStreamIdx(md); - const auto &videoStream = (streamIdx == -1) ? md->findBestStream(SalVideo) - : md->getStreamAtIdx(static_cast<unsigned int>(streamIdx)); - if (videoStream != Utils::getEmptyConstRefObject<SalStreamDescription>()) { - const auto videoDir = d->getDirFromMd(md, SalVideo); - const auto &videoEnabled = videoStream.enabled(); - params->enableVideo(videoEnabled || (videoDir != LinphoneMediaDirectionInactive)); - params->setVideoDirection(videoDir); - params->setMediaEncryption(videoStream.hasSrtp() ? LinphoneMediaEncryptionSRTP - : LinphoneMediaEncryptionNone); + bool mainStreamEnabled = false; + const auto mainStreamIdx = getMainVideoStreamIdx(md); + SalStreamDir mainStreamDirection = SalStreamInactive; + if (mainStreamIdx != -1) { + const auto &mainVideoStream = md->getStreamAtIdx(static_cast<unsigned int>(mainStreamIdx)); + mainStreamEnabled = mainVideoStream.enabled(); + mainStreamDirection = mainVideoStream.getDirection(); + params->setMediaEncryption(mainVideoStream.hasSrtp() ? LinphoneMediaEncryptionSRTP + : LinphoneMediaEncryptionNone); params->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeVideo, - videoStream.custom_sdp_attributes); - // The camera is enabled if: - // - the thumbnail stream is enabled - // - the thumbnail stream's direction is sendrecv or sendonly - const auto &thumbnailDirection = videoStream.getDirection(); - params->enableCamera( - ((thumbnailDirection == SalStreamSendRecv) || (thumbnailDirection == SalStreamSendOnly)) && - videoEnabled); + mainVideoStream.custom_sdp_attributes); + } + + const auto videoDir = d->getDirFromMd(md, SalVideo); + params->setVideoDirection(videoDir); + params->enableVideo(mainStreamEnabled || (videoDir != LinphoneMediaDirectionInactive)); + + const auto conference = getCore()->findConference(getSharedFromThis(), false); + SalStreamDir thumbnailStreamDirection = SalStreamInactive; + if (conference) { + const auto thumbnailStreamIdx = getThumbnailStreamIdx(); + if (thumbnailStreamIdx != -1) { + const auto &thumbnailVideoStream = + md->getStreamAtIdx(static_cast<unsigned int>(thumbnailStreamIdx)); + thumbnailStreamDirection = thumbnailVideoStream.getDirection(); + } } else { - params->enableVideo(false); - params->enableCamera(false); + thumbnailStreamDirection = mainStreamDirection; } + // The camera is enabled if: + // - the thumbnail stream is enabled + // - the thumbnail stream's direction is sendrecv or sendonly + params->enableCamera( + ((thumbnailStreamDirection == SalStreamSendRecv) || (thumbnailStreamDirection == SalStreamSendOnly)) && + params->videoEnabled()); const SalStreamDescription &textStream = md->findBestStream(SalText); if (textStream != Utils::getEmptyConstRefObject<SalStreamDescription>()) { @@ -5938,92 +5997,68 @@ int MediaSession::getMainVideoStreamIdx(const std::shared_ptr<SalMediaDescriptio // client is more difficult as the NOTIFY message may have not come or been processed. The algorithm below searches // for the label in the main stream and then reuses the label to look for the desired thumbnail stream auto streamIdx = -1; - if (md) { - const auto conference = getCore()->findConference(getSharedFromThis(), false); - if (conference && d->op) { - const bool isInLocalConference = d->getParams()->getPrivate()->getInConference(); - const auto &confLayout = computeConferenceLayout(isInLocalConference ? d->op->getRemoteMediaDescription() - : d->op->getLocalMediaDescription()); - const auto isConferenceLayoutActiveSpeaker = (confLayout == ConferenceLayout::ActiveSpeaker); - const auto isConferenceLayoutGrid = (confLayout == ConferenceLayout::Grid); - const auto &participantDevice = (isInLocalConference) - ? conference->findParticipantDevice(getSharedFromThis()) - : conference->getMe()->findDevice(getSharedFromThis()); - - // Try to find a stream with the screen sharing content attribute as it will be for sure the main video - // stream. Indeed, screen sharing can be enabled regardless of the conference layout, it is needed to always - // make this try. - std::string mainStreamAttrValue = MediaSessionPrivate::ScreenSharingContentAttribute; - streamIdx = md->findIdxStreamWithContent(mainStreamAttrValue); - if (streamIdx == -1) { - // If no stream with the screen sharing content is found, then try with regular attributes for each of - // the different layouts - if (isConferenceLayoutActiveSpeaker) { - mainStreamAttrValue = MediaSessionPrivate::ActiveSpeakerVideoContentAttribute; - } else if (isConferenceLayoutGrid) { - mainStreamAttrValue = MediaSessionPrivate::GridVideoContentAttribute; - } else { - lError() << "Unable to determine attribute of main video stream of session " << this - << " (local addres " << *getLocalAddress() << " remote address " << *getRemoteAddress() - << ") in conference " << *conference->getConferenceAddress() << ":"; - lError() << " - grid layout: " << isConferenceLayoutGrid; - lError() << " - active speaker layout: " << isConferenceLayoutActiveSpeaker; - lError() << " - device is screen sharing: " - << (participantDevice && participantDevice->screenSharingEnabled()); - } - streamIdx = md->findIdxStreamWithContent(mainStreamAttrValue); - } - if (streamIdx == -1) { - // The stream index was not found despite all efforts - lDebug() << "Unable to find main video stream of session " << this << " (local addres " - << *getLocalAddress() << " remote address " << *getRemoteAddress() << "):"; - lDebug() << " - no stream with content \"" << MediaSessionPrivate::ScreenSharingContentAttribute - << "\" is found"; - lDebug() << " - grid layout: " << isConferenceLayoutGrid; - lDebug() << " - active speaker layout: " << isConferenceLayoutActiveSpeaker; - lDebug() << " - device is screen sharing: " + const auto conference = getCore()->findConference(getSharedFromThis(), false); + if (conference && d->op) { + const bool isInLocalConference = d->getParams()->getPrivate()->getInConference(); + const auto &refMd = + isInLocalConference ? d->op->getRemoteMediaDescription() : d->op->getLocalMediaDescription(); + const auto &confLayout = computeConferenceLayout(refMd); + const auto isConferenceLayoutActiveSpeaker = (confLayout == ConferenceLayout::ActiveSpeaker); + const auto isConferenceLayoutGrid = (confLayout == ConferenceLayout::Grid); + const auto &participantDevice = (isInLocalConference) ? conference->findParticipantDevice(getSharedFromThis()) + : conference->getMe()->findDevice(getSharedFromThis()); + + // Try to find a stream with the screen sharing content attribute as it will be for sure the main video + // stream. Indeed, screen sharing can be enabled regardless of the conference layout, it is needed to always + // make this try. + std::string mainStreamAttrValue = MediaSessionPrivate::ScreenSharingContentAttribute; + streamIdx = refMd->findIdxStreamWithContent(mainStreamAttrValue); + if (streamIdx == -1) { + // If no stream with the screen sharing content is found, then try with regular attributes for each of + // the different layouts + if (isConferenceLayoutActiveSpeaker) { + mainStreamAttrValue = MediaSessionPrivate::ActiveSpeakerVideoContentAttribute; + } else if (isConferenceLayoutGrid) { + mainStreamAttrValue = MediaSessionPrivate::GridVideoContentAttribute; + } else { + lError() << "Unable to determine attribute of main video stream of " << *this << " (local address " + << *getLocalAddress() << " remote address " << *getRemoteAddress() << ") in " << *conference + << ":"; + lError() << " - grid layout: " << isConferenceLayoutGrid; + lError() << " - active speaker layout: " << isConferenceLayoutActiveSpeaker; + lError() << " - device is screen sharing: " << (participantDevice && participantDevice->screenSharingEnabled()); } + streamIdx = refMd->findIdxStreamWithContent(mainStreamAttrValue); } if (streamIdx == -1) { - streamIdx = md->findIdxBestStream(SalVideo); - } + // The stream index was not found despite all efforts + lDebug() << "Unable to find main video stream of " << *this << " (local address " << *getLocalAddress() + << " remote address " << *getRemoteAddress() << ") in " << *conference << ":"; + lDebug() << " - no stream with content \"" << MediaSessionPrivate::ScreenSharingContentAttribute + << "\" is found"; + lDebug() << " - grid layout: " << isConferenceLayoutGrid; + lDebug() << " - active speaker layout: " << isConferenceLayoutActiveSpeaker; + lDebug() << " - device is screen sharing: " + << (participantDevice && participantDevice->screenSharingEnabled()); + } + } else if (md) { + streamIdx = md->findIdxBestStream(SalVideo); } - return streamIdx; } -int MediaSession::getLocalThumbnailStreamIdx() const { +int MediaSession::getThumbnailStreamIdx() const { L_D(); - return getThumbnailStreamIdx(d->op ? d->op->getLocalMediaDescription() : nullptr); -} - -int MediaSession::getThumbnailStreamIdx(const std::shared_ptr<SalMediaDescription> &md) const { - L_D(); - // In order to set properly the negotiated parameters, we must know if the client is sending video to the - // conference, i.e. look at the thumbnail stream direction. In order to do so, we must know the label of the - // searched thumbnail stream. The local case is quite straightforward because all labels are known, but for the - // client is more difficult as the NOTIFY message may have not come or been processed. The algorithm below searches - // for the label in the main stream and then reuses the label to look for the desired thumbnail stream auto streamIdx = -1; - if (md) { - const auto conference = getCore()->findConference(getSharedFromThis(), false); - if (conference) { - const auto content = MediaSessionPrivate::ThumbnailVideoContentAttribute; - const bool isInLocalConference = d->getParams()->getPrivate()->getInConference(); - std::string label; - if (isInLocalConference) { - auto device = conference->findParticipantDevice(getSharedFromThis()); - if (device) { - label = device->getThumbnailStreamLabel(); - } - } else { - auto device = conference->getMe()->findDevice(getSharedFromThis()); - if (device) { - label = device->getThumbnailStreamLabel(); - } - } - streamIdx = md->findIdxStreamWithContent(content, label); + const auto conference = getCore()->findConference(getSharedFromThis(), false); + if (conference) { + const bool isInLocalConference = d->getParams()->getPrivate()->getInConference(); + const auto &refMd = + isInLocalConference ? d->op->getRemoteMediaDescription() : d->op->getLocalMediaDescription(); + if (refMd) { + streamIdx = + refMd->findIdxStreamWithContent(MediaSessionPrivate::ThumbnailVideoContentAttribute, SalStreamSendOnly); } } return streamIdx; @@ -6033,20 +6068,19 @@ void MediaSession::setEkt(const MSEKTParametersSet *ekt_params) const { getStreamsGroup().setEkt(ekt_params); } -LinphoneMediaDirection MediaSession::getDirectionOfStream(BCTBX_UNUSED(const std::string content)) const { - auto direction = LinphoneMediaDirectionInactive; -#ifdef VIDEO_ENABLED +LinphoneMediaDirection MediaSession::getDirectionOfStream(const std::string &content, const std::string &label) const { L_D(); + auto direction = LinphoneMediaDirectionInactive; // If we are a conference server, we must look at the incoming INVITE as this SDP has the content attribute. // Look at the local description in all the other scenarions (remote conferece on a server or call) const auto &op = d->getOp(); if (op) { bool isServer = linphone_core_conference_server_enabled(getCore()->getCCore()); - std::shared_ptr<SalMediaDescription> offer = - (isServer) ? op->getRemoteMediaDescription() : op->getLocalMediaDescription(); + const auto &offer = (isServer) ? op->getLocalMediaDescription() : op->getRemoteMediaDescription(); if (offer) { // Look for the index of the stream containing the requested attribute in the offered SDP - const auto idx = offer->findIdxStreamWithContent(content); + const auto idx = label.empty() ? offer->findIdxStreamWithContent(content) + : offer->findIdxStreamWithContent(content, label); if (idx != -1) { std::shared_ptr<SalMediaDescription> &md = op->getFinalMediaDescription(); try { @@ -6066,7 +6100,6 @@ LinphoneMediaDirection MediaSession::getDirectionOfStream(BCTBX_UNUSED(const std } } } -#endif return direction; } diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 9573630291154a02d858e8acffbfd3b3bdc32abe..58b4ae4b559bb1ec72a7ea2e17989bcbdc94c807 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -187,8 +187,7 @@ public: uint32_t getSsrc(LinphoneStreamType type) const; uint32_t getSsrc(std::string content) const; - int getLocalThumbnailStreamIdx() const; - int getThumbnailStreamIdx(const std::shared_ptr<SalMediaDescription> &md) const; + int getThumbnailStreamIdx() const; int getMainVideoStreamIdx(const std::shared_ptr<SalMediaDescription> &md) const; /** @@ -199,7 +198,8 @@ public: void setEkt(const MSEKTParametersSet *ekt_params) const; bool dtmfSendingAllowed() const; - LinphoneMediaDirection getDirectionOfStream(const std::string content) const; + LinphoneMediaDirection getDirectionOfStream(const std::string &content, + const std::string &label = std::string()) const; bool isScreenSharingNegotiated() const; const std::shared_ptr<const VideoSourceDescriptor> getVideoSourceDescriptor() const; diff --git a/src/conference/session/video-stream.cpp b/src/conference/session/video-stream.cpp index 00299e1abc633656c52eb2949790d5b87104f82a..3dc136a6279b937620889224586b5f8e6329f5f0 100644 --- a/src/conference/session/video-stream.cpp +++ b/src/conference/session/video-stream.cpp @@ -398,7 +398,7 @@ void MS2VideoStream::render(const OfferAnswerContext &ctx, CallSession::State ta bool localScreenSharingChanged = false, displayModeChanged = false; auto participantDevice = getMediaSession().getParticipantDevice(LinphoneStreamTypeVideo, label); if (!participantDevice) { - if (conference) { + if (conference && conference->getMe()) { participantDevice = conference->getMe()->findDevice(LinphoneStreamTypeVideo, label, false); // is Me. Q : Me is always local? (multi account) isScreenSharing = (participantDevice && participantDevice->screenSharingEnabled()); @@ -418,7 +418,7 @@ void MS2VideoStream::render(const OfferAnswerContext &ctx, CallSession::State ta } } } else { // Get Thumbnail Stream. - int idx = getMediaSession().getLocalThumbnailStreamIdx(); + int idx = getMediaSession().getThumbnailStreamIdx(); if (idx >= 0) auxStream = dynamic_cast<MS2VideoStream *>(getGroup().getStream(idx)); localScreenSharingChanged = enableLocalScreenSharing(isScreenSharing); } @@ -747,7 +747,7 @@ void MS2VideoStream::render(const OfferAnswerContext &ctx, CallSession::State ta link_video_stream_with_itc_sink(mStream); // Current stream is Main, search for the thumbnail to connect with ITC. MS2VideoStream *vs = nullptr; - int idx = getMediaSession().getLocalThumbnailStreamIdx(); + int idx = getMediaSession().getThumbnailStreamIdx(); if (idx >= 0) vs = dynamic_cast<MS2VideoStream *>(getGroup().getStream(idx)); if (vs) { VideoStream *itcStream = vs->getVideoStream(); diff --git a/src/core/core.cpp b/src/core/core.cpp index 65e7351463c4a9dd61428d9aa22fb0fac4be71d0..aebb09694d749d233aa3d6b2e00aafbbd388c70e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -740,7 +740,7 @@ void CorePrivate::updateVideoDevice() { auto vs = i->getVideoStream(); if (vs && video_stream_local_screen_sharing_enabled(vs)) { auto &group = ms->getStreamsGroup(); - int idx = ms->getLocalThumbnailStreamIdx(); + int idx = ms->getThumbnailStreamIdx(); if (idx >= 0) i = dynamic_cast<MS2VideoControl *>(group.getStream(idx)); } if (i) i->parametersChanged(); diff --git a/src/event/event-publish.cpp b/src/event/event-publish.cpp index 89f54493d27c2b65e978511b742d08229bbb167b..641aaea843baa3d168d239d5f10f4b4fdc9204e1 100644 --- a/src/event/event-publish.cpp +++ b/src/event/event-publish.cpp @@ -224,7 +224,7 @@ void EventPublish::terminate() { } if (mPublishState != LinphonePublishNone) { - if (mPublishState == LinphonePublishOk && mExpires != -1) { + if (mOp && (mPublishState == LinphonePublishOk) && (mExpires != -1)) { auto op = dynamic_cast<SalPublishOp *>(mOp); op->unpublish(); } @@ -237,7 +237,7 @@ void EventPublish::terminate() { void EventPublish::startTimeoutHandling() { stopTimeoutHandling(); - if (mExpires > 0) + if (mExpires > 0) { mTimer = getCore()->createTimer( [this]() { lInfo() << "Publish event [" << this << "] has expired"; @@ -245,6 +245,7 @@ void EventPublish::startTimeoutHandling() { return true; }, static_cast<unsigned int>(mExpires) * 1000, "Publish timer"); + } } void EventPublish::stopTimeoutHandling() { diff --git a/src/event/event.cpp b/src/event/event.cpp index 08a85e38fa56bfa0c0253e07078f30daf221cafb..47638a56e8b4d3754df2daad5788f9720868e16a 100644 --- a/src/event/event.cpp +++ b/src/event/event.cpp @@ -151,7 +151,9 @@ std::shared_ptr<Address> Event::getRemoteContact() const { if (!mRemoteContactAddress) { mRemoteContactAddress = Address::create(); } - mRemoteContactAddress->setImpl(mOp->getRemoteContactAddress()); + if (mOp) { + mRemoteContactAddress->setImpl(mOp->getRemoteContactAddress()); + } return mRemoteContactAddress; } @@ -159,7 +161,9 @@ std::shared_ptr<Address> Event::cacheFrom() const { if (!mFromAddress) { mFromAddress = Address::create(); } - mFromAddress->setImpl(mOp->getFromAddress()); + if (mOp) { + mFromAddress->setImpl(mOp->getFromAddress()); + } return mFromAddress; } @@ -167,7 +171,9 @@ std::shared_ptr<Address> Event::cacheTo() const { if (!mToAddress) { mToAddress = Address::create(); } - mToAddress->setImpl(mOp->getToAddress()); + if (mOp) { + mToAddress->setImpl(mOp->getToAddress()); + } return mToAddress; } @@ -175,7 +181,9 @@ std::shared_ptr<Address> Event::cacheRequestAddress() const { if (!mRequestAddress) { mRequestAddress = Address::create(); } - mRequestAddress->setImpl(mOp->getRequestAddress()); + if (mOp) { + mRequestAddress->setImpl(mOp->getRequestAddress()); + } return mRequestAddress; } diff --git a/src/sal/sal_stream_description.cpp b/src/sal/sal_stream_description.cpp index 9f4ee3b500a5155cc8ac0a690d7a9584436b1a9c..586dd67dc474de40432cc50c444904258bffb301 100644 --- a/src/sal/sal_stream_description.cpp +++ b/src/sal/sal_stream_description.cpp @@ -524,7 +524,6 @@ SalStreamDescription::addAcapsToConfiguration(const SalStreamConfiguration &base cfgList.push_back(cfg); cfg = baseCfg; } - } else if (enc == LinphoneMediaEncryptionZRTP) { for (const auto &attr : attrs) { const auto &capNameValue = attr.second; @@ -1217,7 +1216,7 @@ SalStreamDescription::toSdpMediaDescription(const SalMediaDescription *salMediaD bctbx_free(value); } - if (actualCfg.conference_ssrc) { + if ((actualCfg.conference_ssrc != 0) && !actualCfg.rtcp_cname.empty()) { char *ssrc_attribute = ms_strdup_printf("%u cname:%s", actualCfg.conference_ssrc, actualCfg.rtcp_cname.c_str()); belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc", ssrc_attribute)); ms_free(ssrc_attribute); diff --git a/tester/local-conference-tester-functions.cpp b/tester/local-conference-tester-functions.cpp index 39785a865ebdbe069dc0ab2f01f87caad9dd3195..91bd36c29e70e9abddf57f4302f0351b1a6a5f26 100644 --- a/tester/local-conference-tester-functions.cpp +++ b/tester/local-conference-tester-functions.cpp @@ -181,6 +181,50 @@ void check_conference_me(LinphoneConference *conference, bool_t is_admin) { } } +void check_delete_focus_conference_info(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs, + std::list<LinphoneCoreManager *> conferenceMgrs, + LinphoneCoreManager *focus, + LinphoneAddress *confAddr, + time_t end_time) { + if (end_time > 0) { + long focus_cleanup_window = linphone_core_get_conference_cleanup_period(focus->lc); + time_t now = ms_time(NULL); + time_t time_left = end_time - now; + if (focus_cleanup_window > 0) { + time_left += focus_cleanup_window; + // The conference information is only deleted by the cleanup timer. Hence even if the end time went by, the + // conference information might not be deleted + CoreManagerAssert(coreMgrs).waitUntil(chrono::seconds(focus_cleanup_window), [] { return false; }); + } + + for (const auto &mgr : conferenceMgrs) { + LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); + if ((mgr == focus) && (time_left <= 0) && (focus_cleanup_window > 0)) { + BC_ASSERT_PTR_NULL(info); + } else { + BC_ASSERT_PTR_NOT_NULL(info); + } + if (info) { + linphone_conference_info_unref(info); + } + } + + if (time_left > 0) { + // wait for the conference to end + CoreManagerAssert(coreMgrs).waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); + LinphoneConferenceInfo *focus_info = + linphone_core_find_conference_information_from_uri(focus->lc, confAddr); + if (focus_cleanup_window > 0) { + BC_ASSERT_PTR_NULL(focus_info); + } else { + if (BC_ASSERT_PTR_NOT_NULL(focus_info)) { + linphone_conference_info_unref(focus_info); + } + } + } + } +} + LinphoneAddress * create_conference_on_server(Focus &focus, ClientConference &organizer, @@ -257,7 +301,7 @@ create_conference_on_server(Focus &focus, BC_ASSERT_PTR_NOT_NULL(conference); if (conference) { bctbx_list_t *participant_addresses = NULL; - for (auto &mgr : participants) { + for (const auto &mgr : participants) { participant_addresses = bctbx_list_append(participant_addresses, mgr->identity); } LinphoneCallParams *call_params = linphone_core_create_call_params(organizer.getLc(), NULL); @@ -303,7 +347,7 @@ create_conference_on_server(Focus &focus, int call_ok_cnt = 0; // Conference server dials out participants - for (auto &mgr : participants) { + for (const auto &mgr : participants) { auto old_stats = participant_stats[idx]; if (have_common_audio_payload(mgr, focus.getCMgr()) && !previous_calls[mgr]) { BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallIncomingReceived, @@ -337,7 +381,7 @@ create_conference_on_server(Focus &focus, duration = static_cast<int>((end_time - start_time) / 60); // duration is expected to be set in minutes } - for (auto &mgr : participants) { + for (const auto &mgr : participants) { previous_calls[mgr] = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity); } @@ -443,7 +487,7 @@ create_conference_on_server(Focus &focus, } idx = 0; - for (auto &mgr : participants) { + for (const auto &mgr : participants) { if (!is_dialout || !previous_calls[mgr]) { auto old_stats = participant_stats[idx]; if (will_send_ics) { @@ -745,24 +789,34 @@ void does_all_participants_have_matching_ekt(LinphoneCoreManager *focus, if (security_level == LinphoneConferenceSecurityLevelEndToEnd) { auto firstClientConf = dynamic_cast<const LinphonePrivate::ClientConference *>( Conference::toCpp(linphone_core_search_conference_2(members.begin()->first->lc, confAddr))); - shared_ptr<ClientEktManager::EktContext> firstClientEktCtx; BC_ASSERT_PTR_NOT_NULL(firstClientConf); if (firstClientConf) { - firstClientEktCtx = firstClientConf->getClientEktManager()->getEktCtx(); - BC_ASSERT_PTR_NOT_NULL(firstClientEktCtx); - for (auto member : members) { - auto conf = linphone_core_search_conference_2(member.first->lc, confAddr); - BC_ASSERT_PTR_NOT_NULL(conf); - if (conf) { - auto rcConf = - dynamic_cast<const LinphonePrivate::ClientConference *>(Conference::toCpp(conf)); - BC_ASSERT_PTR_NOT_NULL(rcConf); - if (rcConf) { - auto rcEktCtx = rcConf->getClientEktManager()->getEktCtx(); - BC_ASSERT_PTR_NOT_NULL(rcEktCtx); - BC_ASSERT_EQUAL(firstClientEktCtx->getSSpi(), rcEktCtx->getSSpi(), uint16_t, "%d"); - BC_ASSERT_TRUE(firstClientEktCtx->getCSpi() == rcEktCtx->getCSpi()); - BC_ASSERT_TRUE(firstClientEktCtx->getEkt() == rcEktCtx->getEkt()); + const auto &firstClientEktManager = firstClientConf->getClientEktManager(); + BC_ASSERT_PTR_NOT_NULL(firstClientEktManager); + if (firstClientEktManager) { + const auto &firstClientEktCtx = firstClientEktManager->getEktCtx(); + BC_ASSERT_PTR_NOT_NULL(firstClientEktCtx); + for (auto member : members) { + auto conf = linphone_core_search_conference_2(member.first->lc, confAddr); + BC_ASSERT_PTR_NOT_NULL(conf); + if (conf) { + auto rcConf = + dynamic_cast<const LinphonePrivate::ClientConference *>(Conference::toCpp(conf)); + BC_ASSERT_PTR_NOT_NULL(rcConf); + if (rcConf) { + const auto &clientEktManager = rcConf->getClientEktManager(); + BC_ASSERT_PTR_NOT_NULL(clientEktManager); + if (clientEktManager) { + const auto &rcEktCtx = clientEktManager->getEktCtx(); + BC_ASSERT_PTR_NOT_NULL(rcEktCtx); + if (rcEktCtx && firstClientEktCtx) { + BC_ASSERT_EQUAL(firstClientEktCtx->getSSpi(), rcEktCtx->getSSpi(), uint16_t, + "%d"); + BC_ASSERT_TRUE(firstClientEktCtx->getCSpi() == rcEktCtx->getCSpi()); + BC_ASSERT_TRUE(firstClientEktCtx->getEkt() == rcEktCtx->getEkt()); + } + } + } } } } @@ -4087,25 +4141,8 @@ void create_conference_base(time_t start_time, liblinphone_tester_sip_timeout)); } - if (end_time > 0) { - time_t now = ms_time(NULL); - time_t time_left = end_time - now + linphone_core_get_conference_cleanup_period(focus.getLc()); - if (time_left < 0) { - time_left = 0; - } - for (auto mgr : allConferenceMgrs) { - LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); - if (BC_ASSERT_PTR_NOT_NULL(info)) { - linphone_conference_info_unref(info); - } - } - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}) - .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); - LinphoneConferenceInfo *focus_info = - linphone_core_find_conference_information_from_uri(focus.getLc(), confAddr); - BC_ASSERT_PTR_NULL(focus_info); - } + check_delete_focus_conference_info({focus, marie, pauline, laure, michelle, berthe}, allConferenceMgrs, + focus.getCMgr(), confAddr, end_time); std::list<LinphoneCoreManager *> allMembers{marie.getCMgr(), pauline.getCMgr()}; if (!version_mismatch) allMembers.push_back(laure.getCMgr()); @@ -4682,7 +4719,6 @@ void create_conference_with_screen_sharing_base(time_t start_time, BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning, focus_stat.number_of_LinphoneCallStreamsRunning + 1, liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE(check_screen_sharing_sdp(focus.getCMgr(), laure.getCMgr(), FALSE)); } BC_ASSERT_FALSE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_screen_sharing_enabled, @@ -6129,19 +6165,8 @@ void create_conference_with_screen_sharing_chat_base(time_t start_time, BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1, liblinphone_tester_sip_timeout)); - long focus_cleanup_window = linphone_core_get_conference_cleanup_period(focus.getLc()); - if (end_time > 0) { - time_t now = ms_time(NULL); - time_t time_left = end_time - now; - if (focus_cleanup_window > 0) { - time_left += focus_cleanup_window; - } - if (time_left > 0) { - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline, michelle, laure, berthe}) - .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); - } - } + check_delete_focus_conference_info({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, + focus.getCMgr(), confAddr, end_time); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1, liblinphone_tester_sip_timeout)); @@ -8099,35 +8124,8 @@ void create_conference_with_chat_base(LinphoneConferenceSecurityLevel security_l BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1, liblinphone_tester_sip_timeout)); - long focus_cleanup_window = linphone_core_get_conference_cleanup_period(focus.getLc()); - if (end_time > 0) { - time_t now = ms_time(NULL); - time_t time_left = end_time - now; - if (focus_cleanup_window > 0) { - time_left += focus_cleanup_window; - } - if (time_left > 0) { - for (auto mgr : conferenceMgrs) { - LinphoneConferenceInfo *info = - linphone_core_find_conference_information_from_uri(mgr->lc, confAddr); - if (BC_ASSERT_PTR_NOT_NULL(info)) { - linphone_conference_info_unref(info); - } - } - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline, michelle, laure, berthe}) - .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); - LinphoneConferenceInfo *focus_info = - linphone_core_find_conference_information_from_uri(focus.getLc(), confAddr); - if (focus_cleanup_window > 0) { - BC_ASSERT_PTR_NULL(focus_info); - } else { - if (BC_ASSERT_PTR_NOT_NULL(focus_info)) { - linphone_conference_info_unref(focus_info); - } - } - } - } + check_delete_focus_conference_info({focus, marie, pauline, michelle, laure, berthe}, conferenceMgrs, + focus.getCMgr(), confAddr, end_time); if (!!server_restart) { focus_stat = focus.getStats(); @@ -8304,6 +8302,7 @@ void create_conference_with_chat_base(LinphoneConferenceSecurityLevel security_l const LinphoneErrorInfo *error_info = linphone_call_log_get_error_info(call_log); BC_ASSERT_PTR_NOT_NULL(error_info); if (error_info) { + long focus_cleanup_window = linphone_core_get_conference_cleanup_period(focus.getLc()); LinphoneReason reason = (focus_cleanup_window <= 0) ? LinphoneReasonForbidden : LinphoneReasonNotFound; BC_ASSERT_EQUAL(linphone_error_info_get_reason(error_info), reason, int, "%d"); @@ -8824,26 +8823,8 @@ void conference_joined_multiple_times(LinphoneConferenceSecurityLevel security_l }); } - if ((focus_cleanup_window > 0) && (end_time > 0)) { - time_t now = ms_time(NULL); - time_t time_left = end_time - now + focus_cleanup_window; - if (time_left < 0) { - time_left = 0; - } - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline, michelle, laure, berthe}) - .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); - } - - LinphoneConferenceInfo *focus_info = - linphone_core_find_conference_information_from_uri(focus.getLc(), confAddr); - if (focus_cleanup_window > 0) { - BC_ASSERT_PTR_NULL(focus_info); - } else { - if (BC_ASSERT_PTR_NOT_NULL(focus_info)) { - linphone_conference_info_unref(focus_info); - } - } + check_delete_focus_conference_info({focus, marie, pauline, michelle, laure, berthe}, conferenceMgrs, + focus.getCMgr(), confAddr, end_time); ms_free(conference_address_str); bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref); @@ -13211,15 +13192,8 @@ void create_conference_with_audio_only_participants_base(LinphoneConferenceSecur BC_ASSERT_TRUE( wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased, total_focus_calls, 40000)); - if (end_time > 0) { - time_t now = ms_time(NULL); - time_t time_left = end_time - now + linphone_core_get_conference_cleanup_period(focus.getLc()); - if (time_left > 0) { - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline, laure, berthe}) - .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); - } - } + check_delete_focus_conference_info({focus, marie, pauline, laure, berthe}, conferenceMgrs, focus.getCMgr(), + confAddr, end_time); for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), berthe.getCMgr()}) { @@ -13676,10 +13650,6 @@ void create_simple_conference_dial_out_with_some_calls_declined_base(LinphoneRea LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd); bool video_available = !!linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo); - // if (linphone_conference_is_me(conference, - // linphone_participant_device_get_address(d))) { - // BC_ASSERT_TRUE(video_available == - // video_enabled); } else { LinphoneMediaDirection video_direction = linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo); BC_ASSERT_TRUE(video_available == (((video_direction == LinphoneMediaDirectionSendOnly) || diff --git a/tester/local-conference-tester-functions.h b/tester/local-conference-tester-functions.h index aeae4f68bb0a0ca3271361246f198a6c029eb223..123f1e0937094a446c8eb93ac78ae554de198ea8 100644 --- a/tester/local-conference-tester-functions.h +++ b/tester/local-conference-tester-functions.h @@ -409,6 +409,11 @@ void create_one_participant_conference_toggle_video_base(LinphoneConferenceLayou void create_conference_with_active_call_base(bool_t is_dialout); void check_conference_me(LinphoneConference *conference, bool_t is_me); +void check_delete_focus_conference_info(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs, + std::list<LinphoneCoreManager *> conferenceMgrs, + LinphoneCoreManager *focus, + LinphoneAddress *confAddr, + time_t end_time); LinphoneAddress * create_conference_on_server(Focus &focus, diff --git a/tester/local-scheduled-conference-tester.cpp b/tester/local-scheduled-conference-tester.cpp index a18edb287cb8534d13d6565efc45abc0267986fe..ad60bb627b181fef0a3659f0771c3089fbe09bcf 100644 --- a/tester/local-scheduled-conference-tester.cpp +++ b/tester/local-scheduled-conference-tester.cpp @@ -666,19 +666,8 @@ static void alone_in_conference_with_chat_exits_enter(void) { BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1, liblinphone_tester_sip_timeout)); - long focus_cleanup_window = linphone_core_get_conference_cleanup_period(focus.getLc()); - if (end_time > 0) { - time_t now = ms_time(NULL); - time_t time_left = end_time - now; - if (focus_cleanup_window > 0) { - time_left += focus_cleanup_window; - } - if (time_left > 0) { - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline, michelle, laure, berthe}) - .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); - } - } + check_delete_focus_conference_info({focus, marie, pauline, michelle, laure, berthe}, conferenceMgrs, + focus.getCMgr(), confAddr, end_time); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1, liblinphone_tester_sip_timeout)); @@ -1049,19 +1038,8 @@ static void conference_with_participants_late_except_one(void) { BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1, liblinphone_tester_sip_timeout)); - long focus_cleanup_window = linphone_core_get_conference_cleanup_period(focus.getLc()); - if (end_time > 0) { - time_t now = ms_time(NULL); - time_t time_left = end_time - now; - if (focus_cleanup_window > 0) { - time_left += focus_cleanup_window; - } - if (time_left > 0) { - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline, michelle, laure, berthe}) - .waitUntil(chrono::seconds((time_left + 1)), [] { return false; }); - } - } + check_delete_focus_conference_info({focus, marie, pauline, michelle, laure, berthe}, conferenceMgrs, + focus.getCMgr(), confAddr, end_time); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1, liblinphone_tester_sip_timeout)); @@ -6068,28 +6046,8 @@ static void create_simple_conference_in_sfu_payload_mode(void) { } } - if (end_time > 0) { - LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(focus.getLc(), confAddr); - BC_ASSERT_PTR_NOT_NULL(info); - if (info) { - linphone_conference_info_unref(info); - info = NULL; - } - time_t now = ms_time(NULL); - time_t time_left = end_time - now + linphone_core_get_conference_cleanup_period(focus.getLc()); - if (time_left > 0) { - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds((time_left + 1)), [] { - return false; - }); - } - info = linphone_core_find_conference_information_from_uri(focus.getLc(), confAddr); - BC_ASSERT_PTR_NULL(info); - if (info) { - linphone_conference_info_unref(info); - info = NULL; - } - } + check_delete_focus_conference_info({focus, marie, pauline}, conferenceMgrs, focus.getCMgr(), confAddr, + end_time); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending, 1, liblinphone_tester_sip_timeout)); diff --git a/tester/local-transferred-conference-tester.cpp b/tester/local-transferred-conference-tester.cpp index 28779a0abae83651cd0ad2614b9149426647ff05..521123dc5aaac92cb91ac003e24b0f2b5088cb29 100644 --- a/tester/local-transferred-conference-tester.cpp +++ b/tester/local-transferred-conference-tester.cpp @@ -427,16 +427,8 @@ void create_transfer_conference_base(time_t start_time, } } - if (end_time > 0) { - time_t now = ms_time(NULL); - time_t time_left = end_time - now + linphone_core_get_conference_cleanup_period(focus.getLc()); - if (time_left > 0) { - // wait for the conference to end - CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds((time_left + 1)), [] { - return false; - }); - } - } + check_delete_focus_conference_info({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), confAddr, + end_time); BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending, 1, liblinphone_tester_sip_timeout)); diff --git a/tester/shared_tester_functions.cpp b/tester/shared_tester_functions.cpp index 610fad1f23042ca09d0b79bf25d2e45e5e147984..9a9fd1bc281c8a84788f00855a20e62c86c0da8a 100644 --- a/tester/shared_tester_functions.cpp +++ b/tester/shared_tester_functions.cpp @@ -956,12 +956,13 @@ bool check_conference_ssrc(LinphoneConference *local_conference, LinphoneConfere // The thumbnail video stream can only be sendonly (or recvonly from the server // standpoint) or inactive. Henceherefore a client that can only receive video, will // have to set it to inactive + uint32_t stream_ssrc = linphone_participant_device_get_ssrc(device, type); if (media_direction == LinphoneMediaDirectionInactive) { - if (linphone_participant_device_get_ssrc(device, type) != 0) { + if (stream_ssrc != 0) { ret = false; } } else { - if (linphone_participant_device_get_ssrc(device, type) == 0) { + if (stream_ssrc == 0) { ret = false; } } @@ -972,17 +973,14 @@ bool check_conference_ssrc(LinphoneConference *local_conference, LinphoneConfere if (!stream_available) { continue; } - uint32_t video_ssrc = linphone_participant_device_get_ssrc(device, type); - auto cppDevice = ParticipantDevice::toCpp(device)->getSharedFromThis(); bool thumbnail_available = cppDevice->getThumbnailStreamAvailability(); uint32_t thumbnail_ssrc = cppDevice->getThumbnailStreamSsrc(); - if (thumbnail_available) { if (thumbnail_ssrc == 0) { ret = false; } - if (thumbnail_ssrc == video_ssrc) { + if (thumbnail_ssrc == stream_ssrc) { ret = false; } }