diff --git a/src/call/callmanager.cpp b/src/call/callmanager.cpp index dcf3d2248..fdb3da7ad 100644 --- a/src/call/callmanager.cpp +++ b/src/call/callmanager.cpp @@ -203,8 +203,9 @@ void CallManager::handleNegotiate(NeoChatRoom *room, const Quotient::CallNegotia qCDebug(voip) << "Ignoring negotiate for unknown user id" << event->senderId() << ". Remote user id is" << m_remoteUser->id(); return; } + // TODO DUPLICATES FFS m_session->setMetadata(event->contentJson()["org.matrix.msc3077.sdp_stream_metadata"].toObject()); - m_session->renegotiateOffer(event->sdp(), m_remoteUser->id()); + m_session->renegotiateOffer(event->sdp(), m_remoteUser->id(), event->contentJson()["description"]["type"] == QStringLiteral("answer")); } void CallManager::ring(int lifetime) @@ -406,7 +407,7 @@ void CallManager::startCall(NeoChatRoom *room) m_room->postJson("m.call.candidates", c); }); - connect(m_session, &CallSession::renegotiate, this, [this](const QString &sdp) { + connect(m_session, &CallSession::renegotiate, this, [this](const QString &sdp, const QString &type) { QVector> msidToPurpose; const auto &[uuids, _sdp] = mangleSdp(sdp); for (const auto &uuid : uuids) { @@ -415,7 +416,7 @@ void CallManager::startCall(NeoChatRoom *room) QJsonObject json{ {QStringLiteral("lifetime"), 60000}, {QStringLiteral("version"), 1}, - {QStringLiteral("description"), QJsonObject{{QStringLiteral("type"), QStringLiteral("answer")}, {QStringLiteral("sdp"), _sdp}}}, + {QStringLiteral("description"), QJsonObject{{QStringLiteral("type"), type}, {QStringLiteral("sdp"), _sdp}}}, // AAAAA {QStringLiteral("party_id"), m_partyId}, {QStringLiteral("call_id"), m_callId}, }; @@ -425,6 +426,7 @@ void CallManager::startCall(NeoChatRoom *room) metadata[stream] = purpose; } json["org.matrix.msc3077.sdp_stream_metadata"] = metadata; + qWarning() << json; m_room->postJson("m.call.negotiate", json); }); } diff --git a/src/call/callsession.cpp b/src/call/callsession.cpp index 139b3395e..56f680f13 100644 --- a/src/call/callsession.cpp +++ b/src/call/callsession.cpp @@ -84,6 +84,7 @@ void setLocalDescription(GstPromise *promise, gpointer user_data) { INSTANCE qCDebug(voip) << "Setting local description"; + qWarning() << "SETTING LOCAL DESCRIPTION"; const GstStructure *reply = gst_promise_get_reply(promise); gboolean isAnswer = gst_structure_id_has_field(reply, g_quark_from_string("answer")); GstWebRTCSessionDescription *gstsdp = nullptr; @@ -95,7 +96,8 @@ void setLocalDescription(GstPromise *promise, gpointer user_data) gchar *sdp = gst_sdp_message_as_text(gstsdp->sdp); if (!instance->m_localSdp.isEmpty()) { // This is a renegotiation - Q_EMIT instance->renegotiate(QString(sdp)); + qWarning() << "emitting renegotiate"; + Q_EMIT instance->renegotiate(QString(sdp), isAnswer ? QStringLiteral("answer") : QStringLiteral("offer")); } instance->m_localSdp = QString(sdp); g_free(sdp); @@ -195,9 +197,10 @@ void iceConnectionStateChanged(GstElement *webrtc, GParamSpec *pspec, gpointer u case GST_WEBRTC_ICE_CONNECTION_STATE_FAILED: instance->setState(CallSession::ICEFAILED); break; + case GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED: + instance->setState(CallSession::CONNECTED); case GST_WEBRTC_ICE_CONNECTION_STATE_COMPLETED: case GST_WEBRTC_ICE_CONNECTION_STATE_DISCONNECTED: - case GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED: case GST_WEBRTC_ICE_CONNECTION_STATE_CLOSED: default: break; @@ -263,6 +266,8 @@ gboolean testPacketLoss(gpointer) GstElement *newVideoSinkChain(GstElement *pipe, QQuickItem *quickItem) { + Q_ASSERT(pipe); + Q_ASSERT(quickItem); qCWarning(voip) << "Creating Video Sink Chain"; auto queue = createElement("queue", pipe); auto compositor = createElement("compositor", pipe); @@ -496,17 +501,20 @@ void CallSession::setRemoteDescription(GstWebRTCSessionDescription *remote, cons g_signal_emit_by_name(webrtcbin, "set-remote-description", remote, promise); } -void CallSession::renegotiateOffer(const QString &_offer, const QString &userId) +void CallSession::renegotiateOffer(const QString &_offer, const QString &userId, bool answer) { - GstWebRTCSessionDescription *offer = parseSDP(_offer, GST_WEBRTC_SDP_TYPE_OFFER); - if (!offer) { + GstWebRTCSessionDescription *sdp = parseSDP(_offer, answer ? GST_WEBRTC_SDP_TYPE_ANSWER : GST_WEBRTC_SDP_TYPE_OFFER); + if (!sdp) { Q_ASSERT(false); } GstElement *webrtcbin = binGetByName(m_pipe, "webrtcbin"); - setRemoteDescription(offer, userId); - GstPromise *promise = gst_promise_new_with_change_func(setLocalDescription, this, nullptr); - g_signal_emit_by_name(webrtcbin, "create-answer", nullptr, promise); + setRemoteDescription(sdp, userId); + qWarning() << "answer:" << answer; + if (!answer) { + GstPromise *promise = gst_promise_new_with_change_func(setLocalDescription, this, nullptr); + g_signal_emit_by_name(webrtcbin, "create-answer", nullptr, promise); + } } void CallSession::acceptOffer(const QString &sdp, const QVector remoteCandidates, const QString &userId) @@ -676,18 +684,16 @@ void CallSession::createPipeline() // TODO propagate errors up and end call return; } - - // if (sendVideo) { - // TODO where? addVideoPipeline(); - // } } void CallSession::toggleCamera() { - g_object_set(m_inputSelector, "active-pad", m_inactivePad, nullptr); - auto _tmp = m_inactivePad; - m_inactivePad = m_activePad; - m_activePad = _tmp; + // TODO do this only once + static bool inited = false; + if (!inited) { + addVideoPipeline(); + inited = true; + } } bool CallSession::addVideoPipeline() @@ -712,19 +718,7 @@ bool CallSession::addVideoPipeline() g_object_set(camerafilter, "caps", caps, nullptr); gst_caps_unref(caps); - auto videotestsrc = createElement("videotestsrc", m_pipe); - m_inputSelector = createElement("input-selector", m_pipe); - g_object_set(m_inputSelector, "sync-mode", 1, nullptr); - - m_inactivePad = gst_element_request_pad_simple(m_inputSelector, "sink_%u"); - gst_pad_link(gst_element_get_static_pad(videotestsrc, "src"), m_inactivePad); - - auto selectorSrc = gst_element_get_static_pad(m_inputSelector, "src"); - gst_pad_link(selectorSrc, gst_element_get_static_pad(videoconvert, "sink")); - - m_activePad = gst_element_request_pad_simple(m_inputSelector, "sink_%u"); - gst_pad_link(gst_element_get_static_pad(camera, "src"), m_activePad); - g_object_set(m_inputSelector, "active-pad", m_activePad, nullptr); + gst_element_link(camera, videoconvert); if (!gst_element_link_many(videoconvert, camerafilter, nullptr)) { qCWarning(voip) << "Failed to link camera elements"; @@ -765,6 +759,8 @@ bool CallSession::addVideoPipeline() gst_object_unref(webrtcbin); return false; } + auto promise = gst_promise_new_with_change_func(setLocalDescription, this, nullptr); + g_signal_emit_by_name(webrtcbin, "create-offer", nullptr, promise); gst_object_unref(webrtcbin); @@ -790,6 +786,7 @@ bool CallSession::addVideoPipeline() connectSingleShot(participant, &CallParticipant::initialized, this, [=](QQuickItem *item) { gst_pad_unlink(newpad, fakepad); + Q_ASSERT(item); auto queue = newVideoSinkChain(m_pipe, item); Q_ASSERT(queue); @@ -801,6 +798,7 @@ bool CallSession::addVideoPipeline() Q_ASSERT(ok); g_object_set(selector, "active-pad", selectorSrc, nullptr); gst_object_unref(queuepad); + GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(m_pipe), GST_DEBUG_GRAPH_SHOW_ALL, "foo"); }); return true; } diff --git a/src/call/callsession.h b/src/call/callsession.h index b407fe534..4dba89103 100644 --- a/src/call/callsession.h +++ b/src/call/callsession.h @@ -62,7 +62,7 @@ public: void end(); - void renegotiateOffer(const QString &offer, const QString &userId); + void renegotiateOffer(const QString &offer, const QString &userId, bool answer); void setTurnServers(QStringList servers); static QStringList missingPlugins(); @@ -85,7 +85,7 @@ Q_SIGNALS: void mutedChanged(); void newVideoStream(VideoStream *stream); - void renegotiate(QString sdp); + void renegotiate(QString sdp, const QString &type); private: CallSession(QObject *parent = nullptr); diff --git a/src/qml/Component/Call/VideoStreamDelegate.qml b/src/qml/Component/Call/VideoStreamDelegate.qml index aa99c4376..c59393736 100644 --- a/src/qml/Component/Call/VideoStreamDelegate.qml +++ b/src/qml/Component/Call/VideoStreamDelegate.qml @@ -34,7 +34,11 @@ Rectangle { Layout.preferredHeight: parent.height Layout.preferredWidth: parent.width Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - onActiveChanged: if (active) model.object.initCamera(camera) + onActiveChanged: { + if (active) { + model.object.initCamera(camera) + } + } Component.onCompleted: if (active) model.object.initCamera(camera) GstGLVideoItem { id: camera @@ -55,7 +59,7 @@ Rectangle { height: parent.height Component.onCompleted: { - //model.object.initCamera(this) + model.object.initCamera(this) } } } diff --git a/src/qml/Page/CallPage.qml b/src/qml/Page/CallPage.qml index 1ba4ab63f..1e1ec9c5f 100644 --- a/src/qml/Page/CallPage.qml +++ b/src/qml/Page/CallPage.qml @@ -84,8 +84,8 @@ Kirigami.Page { } } CallPageButton { - text: checked ? i18n("Enable Camera") : i18n("Disable Camera") - icon.name: checked ? "camera-off" : "camera-on" + text: checked ? i18n("Disable Camera") : i18n("Enable Camera") + icon.name: checked ? "camera-on" : "camera-off" checkable: true onToggled: CallManager.toggleCamera() }