mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-29 14:18:49 +03:00
Merge pull request #286 from trilene/voip
Adapt device monitoring for GStreamer 1.18
This commit is contained in:
commit
791a01487b
2 changed files with 121 additions and 24 deletions
|
@ -21,6 +21,7 @@ WebRTCSession::WebRTCSession()
|
||||||
{
|
{
|
||||||
qRegisterMetaType<WebRTCSession::State>();
|
qRegisterMetaType<WebRTCSession::State>();
|
||||||
connect(this, &WebRTCSession::stateChanged, this, &WebRTCSession::setState);
|
connect(this, &WebRTCSession::stateChanged, this, &WebRTCSession::setState);
|
||||||
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -78,7 +79,11 @@ WebRTCSession::init(std::string *errorMessage)
|
||||||
gst_object_unref(plugin);
|
gst_object_unref(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!initialised_) {
|
if (initialised_) {
|
||||||
|
#if GST_CHECK_VERSION(1, 18, 0)
|
||||||
|
startDeviceMonitor();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
nhlog::ui()->error(strError);
|
nhlog::ui()->error(strError);
|
||||||
if (errorMessage)
|
if (errorMessage)
|
||||||
*errorMessage = strError;
|
*errorMessage = strError;
|
||||||
|
@ -95,12 +100,65 @@ namespace {
|
||||||
bool isoffering_;
|
bool isoffering_;
|
||||||
std::string localsdp_;
|
std::string localsdp_;
|
||||||
std::vector<mtx::events::msg::CallCandidates::Candidate> localcandidates_;
|
std::vector<mtx::events::msg::CallCandidates::Candidate> localcandidates_;
|
||||||
|
std::vector<std::pair<std::string, GstDevice *>> audioSources_;
|
||||||
|
|
||||||
|
void
|
||||||
|
addDevice(GstDevice *device)
|
||||||
|
{
|
||||||
|
if (device) {
|
||||||
|
gchar *name = gst_device_get_display_name(device);
|
||||||
|
nhlog::ui()->debug("WebRTC: device added: {}", name);
|
||||||
|
audioSources_.push_back({name, device});
|
||||||
|
g_free(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GST_CHECK_VERSION(1, 18, 0)
|
||||||
|
void
|
||||||
|
removeDevice(GstDevice *device, bool changed)
|
||||||
|
{
|
||||||
|
if (device) {
|
||||||
|
if (auto it = std::find_if(audioSources_.begin(),
|
||||||
|
audioSources_.end(),
|
||||||
|
[device](const auto &s) { return s.second == device; });
|
||||||
|
it != audioSources_.end()) {
|
||||||
|
nhlog::ui()->debug(std::string("WebRTC: device ") +
|
||||||
|
(changed ? "changed: " : "removed: ") + "{}",
|
||||||
|
it->first);
|
||||||
|
gst_object_unref(device);
|
||||||
|
audioSources_.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
newBusMessage(GstBus *bus G_GNUC_UNUSED, GstMessage *msg, gpointer user_data)
|
newBusMessage(GstBus *bus G_GNUC_UNUSED, GstMessage *msg, gpointer user_data)
|
||||||
{
|
{
|
||||||
WebRTCSession *session = static_cast<WebRTCSession *>(user_data);
|
WebRTCSession *session = static_cast<WebRTCSession *>(user_data);
|
||||||
switch (GST_MESSAGE_TYPE(msg)) {
|
switch (GST_MESSAGE_TYPE(msg)) {
|
||||||
|
#if GST_CHECK_VERSION(1, 18, 0)
|
||||||
|
case GST_MESSAGE_DEVICE_ADDED: {
|
||||||
|
GstDevice *device;
|
||||||
|
gst_message_parse_device_added(msg, &device);
|
||||||
|
addDevice(device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_MESSAGE_DEVICE_REMOVED: {
|
||||||
|
GstDevice *device;
|
||||||
|
gst_message_parse_device_removed(msg, &device);
|
||||||
|
removeDevice(device, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_MESSAGE_DEVICE_CHANGED: {
|
||||||
|
GstDevice *device;
|
||||||
|
GstDevice *oldDevice;
|
||||||
|
gst_message_parse_device_changed(msg, &device, &oldDevice);
|
||||||
|
removeDevice(oldDevice, true);
|
||||||
|
addDevice(device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
case GST_MESSAGE_EOS:
|
case GST_MESSAGE_EOS:
|
||||||
nhlog::ui()->error("WebRTC: end of stream");
|
nhlog::ui()->error("WebRTC: end of stream");
|
||||||
session->end();
|
session->end();
|
||||||
|
@ -504,19 +562,18 @@ WebRTCSession::startPipeline(int opusPayloadType)
|
||||||
bool
|
bool
|
||||||
WebRTCSession::createPipeline(int opusPayloadType)
|
WebRTCSession::createPipeline(int opusPayloadType)
|
||||||
{
|
{
|
||||||
int nSources = audioSources_ ? g_list_length(audioSources_) : 0;
|
if (audioSources_.empty()) {
|
||||||
if (nSources == 0) {
|
|
||||||
nhlog::ui()->error("WebRTC: no audio sources");
|
nhlog::ui()->error("WebRTC: no audio sources");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioSourceIndex_ < 0 || audioSourceIndex_ >= nSources) {
|
if (audioSourceIndex_ < 0 || (size_t)audioSourceIndex_ >= audioSources_.size()) {
|
||||||
nhlog::ui()->error("WebRTC: invalid audio source index");
|
nhlog::ui()->error("WebRTC: invalid audio source index");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstElement *source = gst_device_create_element(
|
GstElement *source =
|
||||||
GST_DEVICE_CAST(g_list_nth_data(audioSources_, audioSourceIndex_)), nullptr);
|
gst_device_create_element(audioSources_[audioSourceIndex_].second, nullptr);
|
||||||
GstElement *volume = gst_element_factory_make("volume", "srclevel");
|
GstElement *volume = gst_element_factory_make("volume", "srclevel");
|
||||||
GstElement *convert = gst_element_factory_make("audioconvert", nullptr);
|
GstElement *convert = gst_element_factory_make("audioconvert", nullptr);
|
||||||
GstElement *resample = gst_element_factory_make("audioresample", nullptr);
|
GstElement *resample = gst_element_factory_make("audioresample", nullptr);
|
||||||
|
@ -609,6 +666,32 @@ WebRTCSession::end()
|
||||||
emit stateChanged(State::DISCONNECTED);
|
emit stateChanged(State::DISCONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if GST_CHECK_VERSION(1, 18, 0)
|
||||||
|
void
|
||||||
|
WebRTCSession::startDeviceMonitor()
|
||||||
|
{
|
||||||
|
if (!initialised_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static GstDeviceMonitor *monitor = nullptr;
|
||||||
|
if (!monitor) {
|
||||||
|
monitor = gst_device_monitor_new();
|
||||||
|
GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw");
|
||||||
|
gst_device_monitor_add_filter(monitor, "Audio/Source", caps);
|
||||||
|
gst_caps_unref(caps);
|
||||||
|
|
||||||
|
GstBus *bus = gst_device_monitor_get_bus(monitor);
|
||||||
|
gst_bus_add_watch(bus, newBusMessage, nullptr);
|
||||||
|
gst_object_unref(bus);
|
||||||
|
if (!gst_device_monitor_start(monitor)) {
|
||||||
|
nhlog::ui()->error("WebRTC: failed to start device monitor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
void
|
void
|
||||||
WebRTCSession::refreshDevices()
|
WebRTCSession::refreshDevices()
|
||||||
{
|
{
|
||||||
|
@ -622,31 +705,42 @@ WebRTCSession::refreshDevices()
|
||||||
gst_device_monitor_add_filter(monitor, "Audio/Source", caps);
|
gst_device_monitor_add_filter(monitor, "Audio/Source", caps);
|
||||||
gst_caps_unref(caps);
|
gst_caps_unref(caps);
|
||||||
}
|
}
|
||||||
g_list_free_full(audioSources_, g_object_unref);
|
|
||||||
audioSources_ = gst_device_monitor_get_devices(monitor);
|
std::for_each(audioSources_.begin(), audioSources_.end(), [](const auto &s) {
|
||||||
|
gst_object_unref(s.second);
|
||||||
|
});
|
||||||
|
audioSources_.clear();
|
||||||
|
GList *devices = gst_device_monitor_get_devices(monitor);
|
||||||
|
if (devices) {
|
||||||
|
audioSources_.reserve(g_list_length(devices));
|
||||||
|
for (GList *l = devices; l != nullptr; l = l->next)
|
||||||
|
addDevice(GST_DEVICE_CAST(l->data));
|
||||||
|
g_list_free(devices);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
WebRTCSession::getAudioSourceNames(const std::string &defaultDevice)
|
WebRTCSession::getAudioSourceNames(const std::string &defaultDevice)
|
||||||
{
|
{
|
||||||
if (!initialised_)
|
#if !GST_CHECK_VERSION(1, 18, 0)
|
||||||
return {};
|
|
||||||
|
|
||||||
refreshDevices();
|
refreshDevices();
|
||||||
|
#endif
|
||||||
|
// move default device to top of the list
|
||||||
|
if (auto it = std::find_if(audioSources_.begin(),
|
||||||
|
audioSources_.end(),
|
||||||
|
[&](const auto &s) { return s.first == defaultDevice; });
|
||||||
|
it != audioSources_.end())
|
||||||
|
std::swap(audioSources_.front(), *it);
|
||||||
|
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
ret.reserve(g_list_length(audioSources_));
|
ret.reserve(audioSources_.size());
|
||||||
for (GList *l = audioSources_; l != nullptr; l = l->next) {
|
std::for_each(audioSources_.cbegin(), audioSources_.cend(), [&](const auto &s) {
|
||||||
gchar *name = gst_device_get_display_name(GST_DEVICE_CAST(l->data));
|
ret.push_back(s.first);
|
||||||
ret.emplace_back(name);
|
});
|
||||||
g_free(name);
|
|
||||||
if (ret.back() == defaultDevice) {
|
|
||||||
// move default device to top of the list
|
|
||||||
std::swap(audioSources_->data, l->data);
|
|
||||||
std::swap(ret.front(), ret.back());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -697,6 +791,10 @@ void
|
||||||
WebRTCSession::refreshDevices()
|
WebRTCSession::refreshDevices()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
WebRTCSession::startDeviceMonitor()
|
||||||
|
{}
|
||||||
|
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
WebRTCSession::getAudioSourceNames(const std::string &)
|
WebRTCSession::getAudioSourceNames(const std::string &)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include "mtx/events/voip.hpp"
|
#include "mtx/events/voip.hpp"
|
||||||
|
|
||||||
typedef struct _GList GList;
|
|
||||||
typedef struct _GstElement GstElement;
|
typedef struct _GstElement GstElement;
|
||||||
|
|
||||||
class WebRTCSession : public QObject
|
class WebRTCSession : public QObject
|
||||||
|
@ -71,12 +70,12 @@ private:
|
||||||
unsigned int busWatchId_ = 0;
|
unsigned int busWatchId_ = 0;
|
||||||
std::string stunServer_;
|
std::string stunServer_;
|
||||||
std::vector<std::string> turnServers_;
|
std::vector<std::string> turnServers_;
|
||||||
GList *audioSources_ = nullptr;
|
|
||||||
int audioSourceIndex_ = -1;
|
int audioSourceIndex_ = -1;
|
||||||
|
|
||||||
bool startPipeline(int opusPayloadType);
|
bool startPipeline(int opusPayloadType);
|
||||||
bool createPipeline(int opusPayloadType);
|
bool createPipeline(int opusPayloadType);
|
||||||
void refreshDevices();
|
void refreshDevices();
|
||||||
|
void startDeviceMonitor();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WebRTCSession(WebRTCSession const &) = delete;
|
WebRTCSession(WebRTCSession const &) = delete;
|
||||||
|
|
Loading…
Reference in a new issue