diff --git a/src/accountcreationwizard.cpp b/src/accountcreationwizard.cpp index db1bda4f130f84432af77436564204f97395edb9..e1d1e7bffec7ca381d4fa816d142334b6f48d6fd 100644 --- a/src/accountcreationwizard.cpp +++ b/src/accountcreationwizard.cpp @@ -102,6 +102,8 @@ struct _AccountCreationWizardPrivate GtkWidget *error_view; GtkWidget *button_error_view_ok; + lrc::api::AVModel* avModel_; + }; G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_TYPE_SCROLLED_WINDOW); @@ -591,10 +593,13 @@ build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_but } GtkWidget * -account_creation_wizard_new(bool show_cancel_button) +account_creation_wizard_new(bool show_cancel_button, lrc::api::AVModel& avModel) { gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + priv->avModel_ = &avModel; + build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button); return (GtkWidget *)view; } @@ -615,7 +620,7 @@ account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_p each time the profile is made visible / hidden. While not the most elegant solution, this allows us to run the preview if and only if it is displayed, and always stop it when hidden. */ if (show_preview && !priv->avatar_manipulation) { - priv->avatar_manipulation = avatar_manipulation_new_from_wizard(); + priv->avatar_manipulation = avatar_manipulation_new_from_wizard(priv->avModel_); gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0); gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation); } else if (priv->avatar_manipulation) { diff --git a/src/accountcreationwizard.h b/src/accountcreationwizard.h index 5d424ffbf58210ab2f971eb96058a10f75537c5e..fdba92cc186fd5e3403c78c2d4a732e7411f4b89 100644 --- a/src/accountcreationwizard.h +++ b/src/accountcreationwizard.h @@ -27,6 +27,14 @@ #include "accountinfopointer.h" +namespace lrc +{ +namespace api +{ + class AVModel; +} +} + G_BEGIN_DECLS #define ACCOUNT_CREATION_WIZARD_TYPE (account_creation_wizard_get_type ()) @@ -39,7 +47,7 @@ typedef struct _AccountCreationWizard AccountCreationWizard; typedef struct _AccountCreationWizardClass AccountCreationWizardClass; GType account_creation_wizard_get_type (void) G_GNUC_CONST; -GtkWidget *account_creation_wizard_new (bool cancel_button); +GtkWidget *account_creation_wizard_new (bool cancel_button, lrc::api::AVModel& avModel); void account_creation_wizard_show_preview (AccountCreationWizard *win, gboolean show_preview = TRUE); void account_creation_wizard_cancel (AccountCreationWizard *win); diff --git a/src/avatarmanipulation.cpp b/src/avatarmanipulation.cpp index 776bfd73f02264032fa5d16b3fe95d328df57706..99301bc74e5ccdcdd7f05c129c146c11a042504f 100644 --- a/src/avatarmanipulation.cpp +++ b/src/avatarmanipulation.cpp @@ -22,12 +22,10 @@ /* LRC */ #include <api/newaccountmodel.h> +#include <api/avmodel.h> #include <globalinstances.h> #include <person.h> #include <profile.h> -#include <video/configurationproxy.h> -#include <video/previewmanager.h> -#include <video/devicemodel.h> /* client */ #include "native/pixbufmanipulator.h" @@ -94,6 +92,8 @@ struct _AvatarManipulationPrivate gboolean video_started_by_avatar_manipulation; GtkWidget *crop_area; + + lrc::api::AVModel* avModel_; }; G_DEFINE_TYPE_WITH_PRIVATE(AvatarManipulation, avatar_manipulation, GTK_TYPE_BOX); @@ -118,7 +118,7 @@ avatar_manipulation_dispose(GObject *object) /* make sure we stop the preview and the video widget */ if (priv->video_started_by_avatar_manipulation) - Video::PreviewManager::instance().stopPreview(); + priv->avModel_->stopPreview(); if (priv->video_widget) { gtk_container_remove(GTK_CONTAINER(priv->frame_video), priv->video_widget); priv->video_widget = NULL; @@ -134,13 +134,14 @@ avatar_manipulation_finalize(GObject *object) } GtkWidget* -avatar_manipulation_new(AccountInfoPointer const & accountInfo) +avatar_manipulation_new(AccountInfoPointer const & accountInfo, lrc::api::AVModel* avModel) { // a profile must exist gpointer view = g_object_new(AVATAR_MANIPULATION_TYPE, NULL); auto* priv = AVATAR_MANIPULATION_GET_PRIVATE(view); priv->accountInfo_ = &accountInfo; + priv->avModel_ = avModel; set_state(AVATAR_MANIPULATION(view), AVATAR_MANIPULATION_STATE_CURRENT); @@ -148,13 +149,14 @@ avatar_manipulation_new(AccountInfoPointer const & accountInfo) } GtkWidget* -avatar_manipulation_new_from_wizard(void) +avatar_manipulation_new_from_wizard(lrc::api::AVModel* avModel) { // a profile must exist gpointer view = g_object_new(AVATAR_MANIPULATION_TYPE, NULL); auto* priv = AVATAR_MANIPULATION_GET_PRIVATE(view); priv->accountInfo_ = nullptr; + priv->avModel_ = avModel; set_state(AVATAR_MANIPULATION(view), AVATAR_MANIPULATION_STATE_CURRENT); @@ -247,7 +249,7 @@ set_state(AvatarManipulation *self, AvatarManipulationState state) gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_views), "page_avatar"); /* available actions: start camera (if available) or choose image */ - if (Video::DeviceModel::instance().rowCount() > 0) { + if (priv->avModel_->getDevices().size() > 0) { // TODO: update if a video device gets inserted while in this state gtk_widget_set_visible(priv->button_start_camera, true); } @@ -257,7 +259,7 @@ set_state(AvatarManipulation *self, AvatarManipulationState state) /* make sure video widget and camera is not running */ if (priv->video_started_by_avatar_manipulation) - Video::PreviewManager::instance().stopPreview(); + priv->avModel_->stopPreview(); if (priv->video_widget) { gtk_container_remove(GTK_CONTAINER(priv->frame_video), priv->video_widget); priv->video_widget = NULL; @@ -276,16 +278,23 @@ set_state(AvatarManipulation *self, AvatarManipulationState state) gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_views), "page_photobooth"); - /* local renderer, but set as "remote" so that it takes up the whole screen */ - video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget), - Video::PreviewManager::instance().previewRenderer(), - VIDEO_RENDERER_REMOTE); - - if (!Video::PreviewManager::instance().isPreviewing()) { - priv->video_started_by_avatar_manipulation = TRUE; - Video::PreviewManager::instance().startPreview(); - } else { - priv->video_started_by_avatar_manipulation = FALSE; + // local renderer, but set as "remote" so that it takes up the whole screen + try { + const lrc::api::video::Renderer* previewRenderer = + &priv->avModel_->getRenderer( + lrc::api::video::PREVIEW_RENDERER_ID); + video_widget_add_new_renderer(VIDEO_WIDGET(priv->video_widget), + priv->avModel_, + previewRenderer, VIDEO_RENDERER_REMOTE); + + if (!previewRenderer->isRendering()) { + priv->video_started_by_avatar_manipulation = TRUE; + priv->avModel_->startPreview(); + } else { + priv->video_started_by_avatar_manipulation = FALSE; + } + } catch (const std::out_of_range& e) { + g_warning(e.what()); } /* available actions: take snapshot, return*/ @@ -298,7 +307,7 @@ set_state(AvatarManipulation *self, AvatarManipulationState state) { /* make sure video widget and camera is not running */ if (priv->video_started_by_avatar_manipulation) - Video::PreviewManager::instance().stopPreview(); + priv->avModel_->stopPreview(); if (priv->video_widget) { gtk_container_remove(GTK_CONTAINER(priv->frame_video), priv->video_widget); priv->video_widget = NULL; diff --git a/src/avatarmanipulation.h b/src/avatarmanipulation.h index 10a11d66972e87400fd95e16f73ba867cac6d850..83a66f8f0c111f2dba152ccd320710fe4facdafd 100644 --- a/src/avatarmanipulation.h +++ b/src/avatarmanipulation.h @@ -26,6 +26,14 @@ #include "accountinfopointer.h" +namespace lrc +{ +namespace api +{ + class AVModel; +} +} + G_BEGIN_DECLS #define AVATAR_MANIPULATION_TYPE (avatar_manipulation_get_type ()) @@ -58,10 +66,10 @@ typedef enum GType avatar_manipulation_get_type (void) G_GNUC_CONST; -GtkWidget *avatar_manipulation_new (AccountInfoPointer const & accountInfo); +GtkWidget *avatar_manipulation_new (AccountInfoPointer const & accountInfo, lrc::api::AVModel* avModel); /* used from the account creation wizard */ -GtkWidget *avatar_manipulation_new_from_wizard(void); +GtkWidget *avatar_manipulation_new_from_wizard(lrc::api::AVModel* avModel); void avatar_manipulation_wizard_completed(AvatarManipulation *); gchar* avatar_manipulation_get_temporary (AvatarManipulation *view); diff --git a/src/currentcallview.cpp b/src/currentcallview.cpp index 9b17f623cee89e4931a3f2f0416054a2b8080ff4..dfdbc01092aa0c8dc1750f8651f87f873e45b4cf 100644 --- a/src/currentcallview.cpp +++ b/src/currentcallview.cpp @@ -25,6 +25,7 @@ #include <glib/gi18n.h> // Lrc +#include <api/avmodel.h> #include <api/conversationmodel.h> #include <api/contact.h> #include <api/contactmodel.h> @@ -198,7 +199,8 @@ public: void init(); void setup(WebKitChatContainer* chat_widget, AccountInfoPointer const & account_info, - lrc::api::conversation::Info* conversation); + lrc::api::conversation::Info* conversation, + lrc::api::AVModel& avModel); void add_transfer_contact(const std::string& uri); void insertControls(); @@ -209,10 +211,10 @@ public: lrc::api::conversation::Info* conversation = nullptr; AccountInfoPointer const *accountInfo = nullptr; + lrc::api::AVModel* avModel_; QMetaObject::Connection state_change_connection; - QMetaObject::Connection local_renderer_connection; - QMetaObject::Connection remote_renderer_connection; + QMetaObject::Connection renderer_connection; QMetaObject::Connection new_message_connection; QMetaObject::Connection smartinfo_refresh_connection; @@ -671,8 +673,7 @@ CppImpl::CppImpl(CurrentCallView& widget) CppImpl::~CppImpl() { QObject::disconnect(state_change_connection); - QObject::disconnect(local_renderer_connection); - QObject::disconnect(remote_renderer_connection); + QObject::disconnect(renderer_connection); QObject::disconnect(smartinfo_refresh_connection); QObject::disconnect(new_message_connection); g_clear_object(&widgets->settings); @@ -719,11 +720,13 @@ CppImpl::init() void CppImpl::setup(WebKitChatContainer* chat_widget, AccountInfoPointer const & account_info, - lrc::api::conversation::Info* conv_info) + lrc::api::conversation::Info* conv_info, + lrc::api::AVModel& avModel) { widgets->webkit_chat_container = GTK_WIDGET(chat_widget); conversation = conv_info; accountInfo = &account_info; + avModel_ = &avModel; setCallInfo(); if ((*accountInfo)->profileInfo.type == lrc::api::profile::Type::RING) @@ -764,7 +767,6 @@ CppImpl::setCallInfo() updateState(); updateDetails(); - // NOTE/TODO we need to rewrite the video_widget file to use the new LRC. g_signal_connect(widgets->video_widget, "button-press-event", G_CALLBACK(video_widget_on_button_press_in_screen_event), nullptr); @@ -772,26 +774,58 @@ CppImpl::setCallInfo() auto callToRender = conversation->callId; if (!conversation->confId.empty()) callToRender = conversation->confId; - video_widget_push_new_renderer(VIDEO_WIDGET(widgets->video_widget), - (*accountInfo)->callModel->getRenderer(callToRender), - VIDEO_RENDERER_REMOTE); - // local renderer - if (Video::PreviewManager::instance().isPreviewing()) - video_widget_push_new_renderer(VIDEO_WIDGET(widgets->video_widget), - Video::PreviewManager::instance().previewRenderer(), - VIDEO_RENDERER_LOCAL); + try { + // local renderer + const lrc::api::video::Renderer* previewRenderer = + &avModel_->getRenderer( + lrc::api::video::PREVIEW_RENDERER_ID); + if (previewRenderer->isRendering()) + video_widget_add_new_renderer(VIDEO_WIDGET(widgets->video_widget), + avModel_, previewRenderer, VIDEO_RENDERER_LOCAL); + + const lrc::api::video::Renderer* vRenderer = + &avModel_->getRenderer( + callToRender); + + video_widget_add_new_renderer(VIDEO_WIDGET(widgets->video_widget), + avModel_, vRenderer, VIDEO_RENDERER_REMOTE); + + } catch (...) { + // The renderer doesn't exist for now. Ignore + } + + // callback for local renderer - local_renderer_connection = QObject::connect( - &Video::PreviewManager::instance(), - &Video::PreviewManager::previewStarted, - [this] (Video::Renderer* renderer) { - video_widget_push_new_renderer(VIDEO_WIDGET(widgets->video_widget), - renderer, - VIDEO_RENDERER_LOCAL); - } - ); + renderer_connection = QObject::connect( + &*avModel_, + &lrc::api::AVModel::rendererStarted, + [=](const std::string& id) { + if (id == lrc::api::video::PREVIEW_RENDERER_ID) { + try { + // local renderer + const lrc::api::video::Renderer* previewRenderer = + &avModel_->getRenderer(lrc::api::video::PREVIEW_RENDERER_ID); + if (previewRenderer->isRendering()) { + video_widget_add_new_renderer(VIDEO_WIDGET(widgets->video_widget), + avModel_, previewRenderer, VIDEO_RENDERER_LOCAL); + } + } catch (...) { + g_warning("Preview renderer is not accessible! This should not happen"); + } + } else if (id == conversation->callId) { + try { + const lrc::api::video::Renderer* vRenderer = + &avModel_->getRenderer( + callToRender); + video_widget_add_new_renderer(VIDEO_WIDGET(widgets->video_widget), + avModel_, vRenderer, VIDEO_RENDERER_REMOTE); + } catch (...) { + g_warning("Remote renderer is not accessible! This should not happen"); + } + } + }); smartinfo_refresh_connection = QObject::connect( &SmartInfoHub::instance(), @@ -799,17 +833,6 @@ CppImpl::setCallInfo() [this] { updateSmartInfo(); } ); - remote_renderer_connection = QObject::connect( - &*(*accountInfo)->callModel, - &lrc::api::NewCallModel::remotePreviewStarted, - [this] (const std::string& callId, Video::Renderer* renderer) { - if (conversation->callId == callId) { - video_widget_push_new_renderer(VIDEO_WIDGET(widgets->video_widget), - renderer, - VIDEO_RENDERER_REMOTE); - } - }); - state_change_connection = QObject::connect( &*(*accountInfo)->callModel, &lrc::api::NewCallModel::callStatusChanged, @@ -1235,11 +1258,12 @@ current_call_view_class_init(CurrentCallViewClass *klass) GtkWidget * current_call_view_new(WebKitChatContainer* chat_widget, AccountInfoPointer const & accountInfo, - lrc::api::conversation::Info* conversation) + lrc::api::conversation::Info* conversation, + lrc::api::AVModel& avModel) { auto* self = g_object_new(CURRENT_CALL_VIEW_TYPE, NULL); auto* priv = CURRENT_CALL_VIEW_GET_PRIVATE(self); - priv->cpp->setup(chat_widget, accountInfo, conversation); + priv->cpp->setup(chat_widget, accountInfo, conversation, avModel); return GTK_WIDGET(self); } diff --git a/src/currentcallview.h b/src/currentcallview.h index 85637de07e3e54509aacaa1c15d119f68499952d..563b7e25bbc1ef55b3cb9d69b53e96401678057f 100644 --- a/src/currentcallview.h +++ b/src/currentcallview.h @@ -30,6 +30,7 @@ namespace lrc { namespace api { + class AVModel; namespace conversation { struct Info; @@ -52,7 +53,8 @@ typedef struct _CurrentCallViewClass CurrentCallViewClass; GType current_call_view_get_type (void) G_GNUC_CONST; GtkWidget *current_call_view_new (WebKitChatContainer* view, AccountInfoPointer const & accountInfo, - lrc::api::conversation::Info* conversation); + lrc::api::conversation::Info* conversation, + lrc::api::AVModel& avModel); lrc::api::conversation::Info current_call_view_get_conversation(CurrentCallView*); GtkWidget *current_call_view_get_chat_view(CurrentCallView*); diff --git a/src/mediasettingsview.cpp b/src/mediasettingsview.cpp index 10730ecbe6d5db00879242713fddd926bb110965..f35abd107302d36f4a8c2b31460a3ebd445e5d6f 100644 --- a/src/mediasettingsview.cpp +++ b/src/mediasettingsview.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2015-2018 Savoir-faire Linux Inc. * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com> + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +21,20 @@ #include "mediasettingsview.h" #include <gtk/gtk.h> -#include "models/gtkqtreemodel.h" +#include <string> + +// LRC +#include <api/avmodel.h> +#include <api/newvideo.h> + #include "video/video_widget.h" #include <video/previewmanager.h> #include <video/configurationproxy.h> -#include <QtCore/QItemSelectionModel> -#include <audio/settings.h> -#include <audio/managermodel.h> -#include <audio/alsapluginmodel.h> -#include <audio/outputdevicemodel.h> -#include <audio/inputdevicemodel.h> -#include <audio/ringtonedevicemodel.h> + +namespace { namespace details +{ +class CppImpl; +}} struct _MediaSettingsView { @@ -54,11 +58,6 @@ struct _MediaSettingsViewPrivate GtkWidget *combobox_output; GtkWidget *combobox_input; - QMetaObject::Connection manager_selection; - QMetaObject::Connection ringtone_selection; - QMetaObject::Connection output_selection; - QMetaObject::Connection input_selection; - /* camera settings */ GtkWidget *combobox_device; GtkWidget *combobox_channel; @@ -73,19 +72,201 @@ struct _MediaSettingsViewPrivate gboolean video_started_by_settings; QMetaObject::Connection local_renderer_connection; - QMetaObject::Connection device_selection; - QMetaObject::Connection channel_selection; - QMetaObject::Connection resolution_selection; - QMetaObject::Connection rate_selection; /* hardware accel settings */ GtkWidget *checkbutton_hardware_decoding; + + details::CppImpl* cpp; ///< Non-UI and C++ only code }; G_DEFINE_TYPE_WITH_PRIVATE(MediaSettingsView, media_settings_view, GTK_TYPE_SCROLLED_WINDOW); #define MEDIA_SETTINGS_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MEDIA_SETTINGS_VIEW_TYPE, MediaSettingsViewPrivate)) +namespace { namespace details +{ + +class CppImpl +{ +public: + explicit CppImpl(MediaSettingsView& widget, lrc::api::AVModel& avModel); + + void drawAudioDevices(); + void drawFramerates(); + void drawResolutions(); + void drawChannels(); + void drawVideoDevices(); + + lrc::api::AVModel* avModel_ = nullptr; + MediaSettingsView* self = nullptr; // The GTK widget itself + MediaSettingsViewPrivate* widgets = nullptr; +}; + +CppImpl::CppImpl(MediaSettingsView& widget, lrc::api::AVModel& avModel) +: self {&widget} +, widgets {MEDIA_SETTINGS_VIEW_GET_PRIVATE(&widget)} +, avModel_(&avModel) +{ + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(widgets->checkbutton_hardware_decoding), + avModel_->getDecodingAccelerated()); + + auto activeIdx = 0; + auto currentManager = avModel_->getAudioManager(); + auto i = 0; + for (const auto& manager : avModel_->getSupportedAudioManagers()) { + if (manager == currentManager) { + activeIdx = i; + } + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widgets->combobox_manager), nullptr, manager.c_str()); + i++; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_manager), activeIdx); + drawAudioDevices(); + drawVideoDevices(); +} + +void +CppImpl::drawAudioDevices() +{ + if (!avModel_) { + g_warning("AVModel not initialized yet"); + return; + } + auto activeOutput = 0, activeRingtone = 0; + auto currentOutput = avModel_->getOutputDevice(); + auto currentRingtone = avModel_->getRingtoneDevice(); + auto i = 0; + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(widgets->combobox_ringtone)); + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(widgets->combobox_output)); + for (const auto& output : avModel_->getAudioOutputDevices()) { + if (output == currentOutput) { + activeOutput = i; + } + if (output == currentRingtone) { + activeRingtone = i; + } + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widgets->combobox_ringtone), nullptr, output.c_str()); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widgets->combobox_output), nullptr, output.c_str()); + i++; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_ringtone), activeRingtone); + gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_output), activeOutput); + + auto activeInput = 0; + auto currentInput = avModel_->getInputDevice(); + i = 0; + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(widgets->combobox_input)); + for (const auto& input : avModel_->getAudioInputDevices()) { + if (input == currentInput) { + activeInput = i; + } + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widgets->combobox_input), nullptr, input.c_str()); + i++; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_input), activeInput); +} + +void +CppImpl::drawFramerates() +{ + if (!avModel_) { + g_warning("AVModel not initialized yet"); + return; + } + auto active = 0; + auto currentDevice = avModel_->getDefaultDeviceName(); + auto currentChannel = avModel_->getDeviceSettings(currentDevice).channel; + auto currentRes = avModel_->getDeviceSettings(currentDevice).size; + auto currentRate = std::to_string(avModel_->getDeviceSettings(currentDevice).rate); + auto rates = avModel_->getDeviceCapabilities(currentDevice).at(currentChannel).at(currentRes); + auto i = 0; + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(widgets->combobox_framerate)); + for (const auto& rate : rates) { + auto rateStr = std::to_string(rate); + if (rateStr == currentRate) { + active = i; + } + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widgets->combobox_framerate), nullptr, rateStr.c_str()); + i++; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_framerate), active); +} + +void +CppImpl::drawResolutions() +{ + if (!avModel_) { + g_warning("AVModel not initialized yet"); + return; + } + auto active = 0; + auto currentDevice = avModel_->getDefaultDeviceName(); + auto currentChannel = avModel_->getDeviceSettings(currentDevice).channel; + auto currentRes = avModel_->getDeviceSettings(currentDevice).size; + auto resToRates = avModel_->getDeviceCapabilities(currentDevice).at(currentChannel); + auto i = 0; + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(widgets->combobox_resolution)); + for (const auto& item : resToRates) { + if (item.first == currentRes) { + active = i; + } + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widgets->combobox_resolution), nullptr, item.first.c_str()); + i++; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_resolution), active); + drawFramerates(); +} + +void +CppImpl::drawChannels() +{ + if (!avModel_) { + g_warning("AVModel not initialized yet"); + return; + } + auto active = 0; + auto currentDevice = avModel_->getDefaultDeviceName(); + auto currentChannel = avModel_->getDeviceSettings(currentDevice).channel; + auto i = 0; + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(widgets->combobox_channel)); + for (const auto& capabilites : avModel_->getDeviceCapabilities(currentDevice)) { + if (capabilites.first == currentChannel) { + active = i; + } + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widgets->combobox_channel), nullptr, capabilites.first.c_str()); + i++; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_channel), active); + drawResolutions(); +} + +void +CppImpl::drawVideoDevices() +{ + if (!avModel_) { + g_warning("AVModel not initialized yet"); + return; + } + auto active = 0; + auto current = avModel_->getDefaultDeviceName(); + auto i = 0; + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(widgets->combobox_device)); + for (const auto& device : avModel_->getDevices()) { + if (device == current) { + active = i; + } + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widgets->combobox_device), nullptr, device.c_str()); + i++; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_device), active); + drawChannels(); +} + +}} // namespace details + + + static void media_settings_view_dispose(GObject *object) { @@ -94,153 +275,133 @@ media_settings_view_dispose(GObject *object) /* make sure to stop the preview if this view is getting destroyed */ if (priv->video_started_by_settings) { - Video::PreviewManager::instance().stopPreview(); + priv->cpp->avModel_->stopPreview(); priv->video_started_by_settings = FALSE; } - QObject::disconnect(priv->manager_selection); - QObject::disconnect(priv->ringtone_selection); - QObject::disconnect(priv->output_selection); - QObject::disconnect(priv->input_selection); - QObject::disconnect(priv->local_renderer_connection); - QObject::disconnect(priv->device_selection); - QObject::disconnect(priv->channel_selection); - QObject::disconnect(priv->resolution_selection); - QObject::disconnect(priv->rate_selection); G_OBJECT_CLASS(media_settings_view_parent_class)->dispose(object); } -static QModelIndex -get_index_from_combobox(GtkComboBox *box) +static void +hardware_decoding_toggled(GtkToggleButton *toggle_button, MediaSettingsView *self) { - GtkTreeIter iter; - GtkTreeModel *model = gtk_combo_box_get_model(box); - if (gtk_combo_box_get_active_iter(box, &iter)) { - return gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter); - } else { - return QModelIndex(); + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + gboolean hardware_decoding = gtk_toggle_button_get_active(toggle_button); + priv->cpp->avModel_->setDecodingAccelerated(hardware_decoding); +} + +static void +set_audio_manager(MediaSettingsView* self) +{ + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + auto* audio_manager = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(priv->combobox_manager)); + if (audio_manager) { + priv->cpp->avModel_->setAudioManager(audio_manager); + priv->cpp->drawAudioDevices(); } } static void -update_selection(GtkComboBox *box, QItemSelectionModel *selection_model) +set_ringtone_device(MediaSettingsView* self) { - QModelIndex idx = get_index_from_combobox(box); - if (idx.isValid()) - selection_model->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + auto* ringtone_device = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(priv->combobox_ringtone)); + if (ringtone_device) { + priv->cpp->avModel_->setRingtoneDevice(ringtone_device); + } } -static QMetaObject::Connection -connect_combo_box_qmodel(GtkComboBox *box, QAbstractItemModel *qmodel, QItemSelectionModel *selection_model) +static void +set_output_device(MediaSettingsView* self) { - QMetaObject::Connection connection; - GtkCellRenderer *renderer; - GtkQTreeModel *model = gtk_q_tree_model_new(qmodel, - 1, - 0, Qt::DisplayRole, G_TYPE_STRING); - - gtk_combo_box_set_model(box, GTK_TREE_MODEL(model)); - renderer = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box), renderer, FALSE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(box), renderer, - "text", 0, NULL); - g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL); - - /* connect signals to and from the selection model */ - connection = QObject::connect( - selection_model, - &QItemSelectionModel::currentChanged, - [=](const QModelIndex & current, G_GNUC_UNUSED const QModelIndex & previous) { - /* select the current */ - if (current.isValid()) { - GtkTreeIter new_iter; - GtkTreeModel *model = gtk_combo_box_get_model(box); - g_return_if_fail(model); - if (gtk_q_tree_model_source_index_to_iter(GTK_Q_TREE_MODEL(model), current, &new_iter)) { - gtk_combo_box_set_active_iter(box, &new_iter); - } else { - g_warning("SelectionModel changed to invalid QModelIndex?"); - } - } - } - ); - g_signal_connect(box, - "changed", - G_CALLBACK(update_selection), - selection_model); - - /* sync the initial selection */ - QModelIndex idx = selection_model->currentIndex(); - if (idx.isValid()) { - GtkTreeIter iter; - if (gtk_q_tree_model_source_index_to_iter(model, idx, &iter)) - gtk_combo_box_set_active_iter(box, &iter); + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + auto* output_device = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(priv->combobox_output)); + if (output_device) { + priv->cpp->avModel_->setOutputDevice(output_device); } +} - return connection; +static void +set_input_device(MediaSettingsView* self) +{ + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + auto* input_device = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(priv->combobox_input)); + if (input_device) { + priv->cpp->avModel_->setInputDevice(input_device); + } } static void -hardware_decoding_toggled(GtkToggleButton *toggle_button, G_GNUC_UNUSED MediaSettingsView *self) +set_video_device(MediaSettingsView* self) { - gboolean hardware_decoding = gtk_toggle_button_get_active(toggle_button); - Video::ConfigurationProxy::setDecodingAccelerated(hardware_decoding); + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + auto* video_device = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(priv->combobox_device)); + if (video_device) { + priv->cpp->avModel_->setDefaultDevice(video_device); + priv->cpp->drawChannels(); + } } static void -media_settings_view_init(MediaSettingsView *view) +set_channel(MediaSettingsView* self) { - gtk_widget_init_template(GTK_WIDGET(view)); + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + auto* video_channel = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(priv->combobox_channel)); + if (video_channel) { + auto currentDevice = priv->cpp->avModel_->getDefaultDeviceName(); + auto settings = priv->cpp->avModel_->getDeviceSettings(currentDevice); + settings.channel = video_channel; + priv->cpp->avModel_->setDeviceSettings(settings); + priv->cpp->drawChannels(); + } +} - MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(view); +static void +set_resolution(MediaSettingsView* self) +{ + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + auto* video_resolution = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(priv->combobox_resolution)); + if (video_resolution) { + auto currentDevice = priv->cpp->avModel_->getDefaultDeviceName(); + auto settings = priv->cpp->avModel_->getDeviceSettings(currentDevice); + settings.size = video_resolution; + priv->cpp->avModel_->setDeviceSettings(settings); + priv->cpp->drawFramerates(); + } +} - /* video settings */ - /* TODO: this is a workaround for a possible LRC issue - * make sure all the models are instantiated before making a selection - */ - Video::ConfigurationProxy::rateModel(); - Video::ConfigurationProxy::resolutionModel(); - Video::ConfigurationProxy::channelModel(); - Video::ConfigurationProxy::deviceModel(); - - priv->device_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_device), - &Video::ConfigurationProxy::deviceModel(), - &Video::ConfigurationProxy::deviceSelectionModel()); - priv->channel_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_channel), - &Video::ConfigurationProxy::channelModel(), - &Video::ConfigurationProxy::channelSelectionModel()); - priv->resolution_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_resolution), - &Video::ConfigurationProxy::resolutionModel(), - &Video::ConfigurationProxy::resolutionSelectionModel()); - priv->rate_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_framerate), - &Video::ConfigurationProxy::rateModel(), - &Video::ConfigurationProxy::rateSelectionModel()); +static void +set_framerate(MediaSettingsView* self) +{ + g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self)); + MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + auto* video_framerate = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(priv->combobox_framerate)); + if (video_framerate) { + auto currentDevice = priv->cpp->avModel_->getDefaultDeviceName(); + auto settings = priv->cpp->avModel_->getDeviceSettings(currentDevice); + try { + settings.rate = std::stoi(video_framerate); + } catch (...) { + g_debug("Cannot convert framerate."); + } + priv->cpp->avModel_->setDeviceSettings(settings); + } +} - /* audio settings */ - /* TODO: this is a workaround for a possible LRC issue - * make sure all the models are instantiated before making a selection - */ - Audio::Settings::instance().alsaPluginModel(); - Audio::Settings::instance().ringtoneDeviceModel(); - Audio::Settings::instance().inputDeviceModel(); - Audio::Settings::instance().outputDeviceModel(); - priv->manager_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_manager), - Audio::Settings::instance().managerModel(), - Audio::Settings::instance().managerModel()->selectionModel()); - priv->ringtone_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_ringtone), - Audio::Settings::instance().ringtoneDeviceModel(), - Audio::Settings::instance().ringtoneDeviceModel()->selectionModel()); - priv->input_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_input), - Audio::Settings::instance().inputDeviceModel(), - Audio::Settings::instance().inputDeviceModel()->selectionModel()); - priv->output_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_output), - Audio::Settings::instance().outputDeviceModel(), - Audio::Settings::instance().outputDeviceModel()->selectionModel()); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkbutton_hardware_decoding), Video::ConfigurationProxy::getDecodingAccelerated()); - g_signal_connect(priv->checkbutton_hardware_decoding, "toggled", G_CALLBACK(hardware_decoding_toggled), view); +static void +media_settings_view_init(MediaSettingsView *view) +{ + gtk_widget_init_template(GTK_WIDGET(view)); } static void @@ -264,11 +425,34 @@ media_settings_view_class_init(MediaSettingsViewClass *klass) } GtkWidget * -media_settings_view_new() +media_settings_view_new(lrc::api::AVModel& avModel) { - gpointer view = g_object_new(MEDIA_SETTINGS_VIEW_TYPE, NULL); + auto self = g_object_new(MEDIA_SETTINGS_VIEW_TYPE, NULL); + auto* priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self); + priv->cpp = new details::CppImpl( + *(reinterpret_cast<MediaSettingsView*>(self)), avModel + ); - return (GtkWidget *)view; + // CppImpl ctor + g_signal_connect(priv->checkbutton_hardware_decoding, "toggled", + G_CALLBACK(hardware_decoding_toggled), self); + g_signal_connect_swapped(priv->combobox_manager, "changed", + G_CALLBACK(set_audio_manager), self); + g_signal_connect_swapped(priv->combobox_ringtone, "changed", + G_CALLBACK(set_ringtone_device), self); + g_signal_connect_swapped(priv->combobox_output, "changed", + G_CALLBACK(set_output_device), self); + g_signal_connect_swapped(priv->combobox_input, "changed", + G_CALLBACK(set_input_device), self); + g_signal_connect_swapped(priv->combobox_device, "changed", + G_CALLBACK(set_video_device), self); + g_signal_connect_swapped(priv->combobox_channel, "changed", + G_CALLBACK(set_channel), self); + g_signal_connect_swapped(priv->combobox_resolution, "changed", + G_CALLBACK(set_resolution), self); + g_signal_connect_swapped(priv->combobox_framerate, "changed", + G_CALLBACK(set_framerate), self); + return (GtkWidget *)self; } void @@ -291,29 +475,35 @@ media_settings_view_show_preview(MediaSettingsView *self, gboolean show_preview) // set minimum size for video so it doesn't shrink too much gtk_widget_set_size_request(priv->video_widget, 400, -1); - if (Video::PreviewManager::instance().isPreviewing()) { - priv->video_started_by_settings = FALSE; - - /* local renderer, but set as "remote" so that it takes up the whole screen */ - video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget), - Video::PreviewManager::instance().previewRenderer(), - VIDEO_RENDERER_REMOTE); - } else { - priv->video_started_by_settings = TRUE; - priv->local_renderer_connection = QObject::connect( - &Video::PreviewManager::instance(), - &Video::PreviewManager::previewStarted, - [=](Video::Renderer *renderer) { - video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget), - renderer, - VIDEO_RENDERER_REMOTE); - } - ); - Video::PreviewManager::instance().startPreview(); + try { + const lrc::api::video::Renderer* previewRenderer = + &priv->cpp->avModel_->getRenderer( + lrc::api::video::PREVIEW_RENDERER_ID); + priv->video_started_by_settings = previewRenderer->isRendering(); + if (priv->video_started_by_settings) { + video_widget_add_new_renderer(VIDEO_WIDGET(priv->video_widget), + priv->cpp->avModel_, previewRenderer, VIDEO_RENDERER_REMOTE); + } else { + priv->video_started_by_settings = true; + priv->local_renderer_connection = QObject::connect( + &*priv->cpp->avModel_, + &lrc::api::AVModel::rendererStarted, + [=](const std::string& id) { + if (id != lrc::api::video::PREVIEW_RENDERER_ID) + return; + video_widget_add_new_renderer( + VIDEO_WIDGET(priv->video_widget), + priv->cpp->avModel_, + previewRenderer, VIDEO_RENDERER_REMOTE); + }); + priv->cpp->avModel_->startPreview(); + } + } catch (const std::out_of_range& e) { + g_warning(e.what()); } } else { if (priv->video_started_by_settings) { - Video::PreviewManager::instance().stopPreview(); + priv->cpp->avModel_->stopPreview(); QObject::disconnect(priv->local_renderer_connection); priv->video_started_by_settings = FALSE; } diff --git a/src/mediasettingsview.h b/src/mediasettingsview.h index cd7ce7d695f81509c32545fd22a84362fd8effcd..563f7e41cc208ae92d54cc591e6763bec94f62ed 100644 --- a/src/mediasettingsview.h +++ b/src/mediasettingsview.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2015-2018 Savoir-faire Linux Inc. * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com> + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +23,14 @@ #include <gtk/gtk.h> +namespace lrc +{ +namespace api +{ + class AVModel; +} +} + G_BEGIN_DECLS #define MEDIA_SETTINGS_VIEW_TYPE (media_settings_view_get_type ()) @@ -34,7 +43,7 @@ typedef struct _MediaSettingsView MediaSettingsView; typedef struct _MediaSettingsViewClass MediaSettingsViewClass; GType media_settings_view_get_type (void) G_GNUC_CONST; -GtkWidget *media_settings_view_new (void); +GtkWidget *media_settings_view_new (lrc::api::AVModel& avModel); void media_settings_view_show_preview (MediaSettingsView *self, gboolean show_preview); G_END_DECLS diff --git a/src/newaccountsettingsview.cpp b/src/newaccountsettingsview.cpp index 96ae1daabbd96ded622e5eb721bdab3e2c4a5d09..aeda49381dcd888c336219d2993b515fef7f71cd 100644 --- a/src/newaccountsettingsview.cpp +++ b/src/newaccountsettingsview.cpp @@ -200,6 +200,8 @@ struct _NewAccountSettingsViewPrivate QMetaObject::Connection device_removed_connection; QMetaObject::Connection banned_status_changed_connection; QMetaObject::Connection export_on_ring_ended; + + lrc::api::AVModel* avModel_; }; G_DEFINE_TYPE_WITH_PRIVATE(NewAccountSettingsView, new_account_settings_view, GTK_TYPE_SCROLLED_WINDOW); @@ -2195,7 +2197,7 @@ new_account_settings_view_save_account(NewAccountSettingsView *view) } GtkWidget* -new_account_settings_view_new(AccountInfoPointer const & accountInfo) +new_account_settings_view_new(AccountInfoPointer const & accountInfo, lrc::api::AVModel& avModel) { gpointer view = g_object_new(NEW_ACCOUNT_SETTINGS_VIEW_TYPE, NULL); auto* priv = NEW_ACCOUNT_SETTINGS_VIEW_GET_PRIVATE(view); @@ -2203,6 +2205,7 @@ new_account_settings_view_new(AccountInfoPointer const & accountInfo) if (*priv->accountInfo_) { build_settings_view(NEW_ACCOUNT_SETTINGS_VIEW(view)); } + priv->avModel_ = &avModel; return reinterpret_cast<GtkWidget*>(view); } @@ -2219,7 +2222,7 @@ new_account_settings_view_show(NewAccountSettingsView *self, gboolean show_profi } if (show_profile) { /* avatar manipulation widget */ - priv->avatarmanipulation = avatar_manipulation_new(*priv->accountInfo_); + priv->avatarmanipulation = avatar_manipulation_new(*priv->accountInfo_, priv->avModel_); gtk_widget_set_halign(priv->avatar_box, GtkAlign::GTK_ALIGN_CENTER); gtk_box_pack_start(GTK_BOX(priv->avatar_box), priv->avatarmanipulation, true, true, 0); gtk_widget_set_visible(priv->avatarmanipulation, true); diff --git a/src/newaccountsettingsview.h b/src/newaccountsettingsview.h index 830d3eba03631c7c5bce230e34627125fe18500b..cd007520d778da17ff7f63d080702d19f4d66a05 100644 --- a/src/newaccountsettingsview.h +++ b/src/newaccountsettingsview.h @@ -27,6 +27,14 @@ #include "accountinfopointer.h" +namespace lrc +{ +namespace api +{ + class AVModel; +} +} + G_BEGIN_DECLS #define NEW_ACCOUNT_SETTINGS_VIEW_TYPE (new_account_settings_view_get_type ()) @@ -39,7 +47,7 @@ typedef struct _NewAccountSettingsView NewAccountSettingsView; typedef struct _NewAccountSettingsViewClass NewAccountSettingsViewClass; GType new_account_settings_view_get_type (void) G_GNUC_CONST; -GtkWidget *new_account_settings_view_new (AccountInfoPointer const & accountInfo); +GtkWidget *new_account_settings_view_new (AccountInfoPointer const & accountInfo, lrc::api::AVModel& avModel); void new_account_settings_view_show (NewAccountSettingsView *view, gboolean show_profile); void new_account_settings_view_update (NewAccountSettingsView *view, gboolean reset_view = true); void new_account_settings_view_save_account (NewAccountSettingsView *view); diff --git a/src/ringmainwindow.cpp b/src/ringmainwindow.cpp index 5bf1e756ae8fa32687b1e73b2869877facef328f..d1a134b4484f245bfff2bc2d67324a5c7db6ae63 100644 --- a/src/ringmainwindow.cpp +++ b/src/ringmainwindow.cpp @@ -29,6 +29,7 @@ // LRC #include <accountmodel.h> // Old lrc but still used #include <api/account.h> +#include <api/avmodel.h> #include <api/contact.h> #include <api/profile.h> #include <api/contactmodel.h> @@ -895,6 +896,7 @@ update_download_folder(RingMainWindow* self) void CppImpl::init() { + lrc_->getAVModel().deactivateOldVideoModels(); // Remember the tabs page number for easier selection later smartviewPageNum = gtk_notebook_page_num(GTK_NOTEBOOK(widgets->notebook_contacts), widgets->scrolled_window_smartview); @@ -997,12 +999,12 @@ CppImpl::init() gtk_stack_add_named(GTK_STACK(widgets->stack_main_view), widgets->vbox_call_view, CALL_VIEW_NAME); - widgets->media_settings_view = media_settings_view_new(); + widgets->media_settings_view = media_settings_view_new(lrc_->getAVModel()); gtk_stack_add_named(GTK_STACK(widgets->stack_main_view), widgets->media_settings_view, MEDIA_SETTINGS_VIEW_NAME); if (not accountIds.empty()) { - widgets->new_account_settings_view = new_account_settings_view_new(accountInfo_); + widgets->new_account_settings_view = new_account_settings_view_new(accountInfo_, lrc_->getAVModel()); gtk_stack_add_named(GTK_STACK(widgets->stack_main_view), widgets->new_account_settings_view, NEW_ACCOUNT_SETTINGS_VIEW_NAME); } @@ -1200,7 +1202,9 @@ CppImpl::displayCurrentCallView(lrc::api::conversation::Info conversation) { chatViewConversation_.reset(new lrc::api::conversation::Info(conversation)); auto* new_view = current_call_view_new(webkitChatContainer(), - accountInfo_, chatViewConversation_.get()); + accountInfo_, + chatViewConversation_.get(), + lrc_->getAVModel()); try { auto contactUri = chatViewConversation_->participants.front(); @@ -1388,7 +1392,7 @@ void CppImpl::enterAccountCreationWizard(bool showControls) { if (!widgets->account_creation_wizard) { - widgets->account_creation_wizard = account_creation_wizard_new(false); + widgets->account_creation_wizard = account_creation_wizard_new(false, lrc_->getAVModel()); g_object_add_weak_pointer(G_OBJECT(widgets->account_creation_wizard), reinterpret_cast<gpointer*>(&widgets->account_creation_wizard)); g_signal_connect_swapped(widgets->account_creation_wizard, "account-creation-completed", @@ -1689,7 +1693,7 @@ CppImpl::slotAccountAddedFromLrc(const std::string& id) if (!accountInfo_) { updateLrc(id); if (!gtk_stack_get_child_by_name(GTK_STACK(widgets->stack_main_view), NEW_ACCOUNT_SETTINGS_VIEW_NAME)) { - widgets->new_account_settings_view = new_account_settings_view_new(accountInfo_); + widgets->new_account_settings_view = new_account_settings_view_new(accountInfo_, lrc_->getAVModel()); gtk_stack_add_named(GTK_STACK(widgets->stack_main_view), widgets->new_account_settings_view, NEW_ACCOUNT_SETTINGS_VIEW_NAME); } diff --git a/src/video/video_widget.cpp b/src/video/video_widget.cpp index 0d7c087e541db4c2b63dceec1e00ecbf0889c394..4e9d71d948316ed783dabe7df50973262768b793 100644 --- a/src/video/video_widget.cpp +++ b/src/video/video_widget.cpp @@ -19,22 +19,23 @@ #include "video_widget.h" -#include <callmodel.h> -#include <glib/gi18n.h> +// std +#include <atomic> +#include <mutex> +#include <string> + +// gtk #include <clutter/clutter.h> #include <clutter-gtk/clutter-gtk.h> -#include <video/renderer.h> -#include <video/sourcemodel.h> -#include <media/video.h> -#include <video/devicemodel.h> -#include <QtCore/QUrl> +#include <glib/gi18n.h> + +// LRC +#include <api/avmodel.h> +#include <smartinfohub.h> + +// gnome client #include "../defines.h" -#include <stdlib.h> -#include <atomic> -#include <mutex> -#include <call.h> #include "xrectsel.h" -#include <smartinfohub.h> static constexpr int VIDEO_LOCAL_SIZE = 150; static constexpr int VIDEO_LOCAL_OPACITY_DEFAULT = 255; /* out of 255 */ @@ -83,13 +84,15 @@ struct _VideoWidgetPrivate { GAsyncQueue *new_renderer_queue; GtkWidget *popup_menu; + + lrc::api::AVModel* avModel_; }; struct _VideoWidgetRenderer { VideoRendererType type; ClutterActor *actor; ClutterAction *drag_action; - Video::Renderer *renderer; + const lrc::api::video::Renderer* v_renderer; GdkPixbuf *snapshot; std::mutex run_mutex; bool running; @@ -391,42 +394,29 @@ void video_widget_on_drag_data_received(G_GNUC_UNUSED GtkWidget *self, auto* priv = VIDEO_WIDGET_GET_PRIVATE(self); g_return_if_fail(priv); gchar **uris = gtk_selection_data_get_uris(selection_data); - - Call *call = nullptr; - for (const auto& activeCall: CallModel::instance().getActiveCalls()) { - if (activeCall->videoRenderer() == priv->remote->renderer) { - call = activeCall; - break; - } - } - - if (!call) { - g_strfreev(uris); - return; + if (uris && *uris && priv->avModel_) { + priv->avModel_->setInputFile(*uris); } - - if (uris && *uris){ - if (auto out_media = call->firstMedia<media::Video>(media::Media::Direction::OUT)) - out_media->sourceModel()->setFile(QUrl(*uris)); - } - g_strfreev(uris); } static void -switch_video_input(GtkWidget *widget, Video::Device *device) +switch_video_input(GtkWidget *widget, GtkWidget *parent) { - gpointer data = g_object_get_data(G_OBJECT(widget), JOIN_CALL_KEY); - g_return_if_fail(data); - Call *call = (Call*)data; + auto* priv = VIDEO_WIDGET_GET_PRIVATE(parent); + g_return_if_fail(priv); - if (auto out_media = call->firstMedia<media::Video>(media::Media::Direction::OUT)) - out_media->sourceModel()->switchTo(device); + auto* label = gtk_menu_item_get_label(GTK_MENU_ITEM(widget)); + g_return_if_fail(label); + + if (priv->avModel_) + priv->avModel_->switchInputTo(label); } static void -switch_video_input_screen_area(G_GNUC_UNUSED GtkWidget *item, Call* call) +switch_video_input_screen_area(G_GNUC_UNUSED GtkWidget *item, GtkWidget *parent) { + auto* priv = VIDEO_WIDGET_GET_PRIVATE(parent); unsigned x, y; unsigned width, height; @@ -453,13 +443,14 @@ switch_video_input_screen_area(G_GNUC_UNUSED GtkWidget *item, Call* call) height = gdk_screen_height(); } - if (auto out_media = call->firstMedia<media::Video>(media::Media::Direction::OUT)) - out_media->sourceModel()->setDisplay(display, QRect(x,y,width,height)); + if (priv->avModel_) + priv->avModel_->setDisplay(display, x, y, width, height); } static void -switch_video_input_monitor(G_GNUC_UNUSED GtkWidget *item, Call* call) +switch_video_input_monitor(G_GNUC_UNUSED GtkWidget *item, GtkWidget *parent) { + auto* priv = VIDEO_WIDGET_GET_PRIVATE(parent); unsigned x, y; unsigned width, height; @@ -480,17 +471,17 @@ switch_video_input_monitor(G_GNUC_UNUSED GtkWidget *item, Call* call) width = gdk_screen_width(); height = gdk_screen_height(); - if (auto out_media = call->firstMedia<media::Video>(media::Media::Direction::OUT)) - out_media->sourceModel()->setDisplay(display, QRect(x,y,width,height)); + if (priv->avModel_) + priv->avModel_->setDisplay(display, x, y, width, height); } static void -switch_video_input_file(GtkWidget *item, GtkWidget *parent) +switch_video_input_file(G_GNUC_UNUSED GtkWidget *item, GtkWidget *parent) { auto* priv = VIDEO_WIDGET_GET_PRIVATE(parent); if (parent && GTK_IS_WIDGET(parent)) { - /* get parent window */ + // get parent window parent = gtk_widget_get_toplevel(GTK_WIDGET(parent)); } @@ -503,24 +494,10 @@ switch_video_input_file(GtkWidget *item, GtkWidget *parent) NULL); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - Call *call = nullptr; - for (const auto& activeCall: CallModel::instance().getActiveCalls()) { - if (activeCall->videoRenderer() == priv->remote->renderer) { - call = activeCall; - break; - } - } - - if (!call) { - gtk_widget_destroy(dialog); - return; - } - gchar *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); - if (uri) { - if (auto out_media = call->firstMedia<media::Video>(media::Media::Direction::OUT)) - out_media->sourceModel()->setFile(QUrl(uri)); + if (uri && priv->avModel_) { + priv->avModel_->setInputFile(uri); g_free(uri); } } @@ -534,97 +511,74 @@ switch_video_input_file(GtkWidget *item, GtkWidget *parent) * Handle button event in the video screen. */ gboolean -video_widget_on_button_press_in_screen_event(VideoWidget *self, GdkEventButton *event, Call* call) +video_widget_on_button_press_in_screen_event(VideoWidget *self, GdkEventButton *event, G_GNUC_UNUSED gpointer) { - /* check for right click */ + // check for right click if (event->button != BUTTON_RIGHT_CLICK || event->type != GDK_BUTTON_PRESS) return FALSE; - /* update menu with available video sources */ + // update menu with available video sources auto priv = VIDEO_WIDGET_GET_PRIVATE(self); + g_return_val_if_fail(priv->remote->v_renderer, false); auto menu = priv->popup_menu; - gtk_container_forall(GTK_CONTAINER(menu), (GtkCallback)gtk_widget_destroy, nullptr); + gtk_container_forall(GTK_CONTAINER(menu), (GtkCallback)gtk_widget_destroy, + nullptr); - Video::SourceModel *sourcemodel = nullptr; - int active = -1; - /* if sourcemodel is null then we have no outgoing video */ - for (const auto& activeCall: CallModel::instance().getActiveCalls()) - if (activeCall->videoRenderer() == priv->remote->renderer) - call = activeCall; - - if (call) { - if (auto out_media = call->firstMedia<media::Video>(media::Media::Direction::OUT)) { - sourcemodel = out_media->sourceModel(); - active = sourcemodel->activeIndex(); - } - } + // list available devices and check off the active device + auto device_list = priv->avModel_->getDevices(); + auto active_device = priv->avModel_->getCurrentRenderedDevice( + priv->remote->v_renderer->getId()); - /* list available devices and check off the active device */ - auto device_list = Video::DeviceModel::instance().devices(); - - for( auto device: device_list) { - GtkWidget *item = gtk_check_menu_item_new_with_mnemonic(device->name().toLocal8Bit().constData()); + for (auto device : device_list) { + GtkWidget *item = gtk_check_menu_item_new_with_mnemonic(device.c_str()); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - if (sourcemodel) { - auto device_idx = sourcemodel->getDeviceIndex(device); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), device_idx == active); - g_object_set_data(G_OBJECT(item), JOIN_CALL_KEY, call); - g_signal_connect(item, "activate", G_CALLBACK(switch_video_input), device); - } else { - gtk_widget_set_sensitive(item, FALSE); - } + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), + device == active_device.name + && active_device.type == lrc::api::video::DeviceType::CAMERA); + g_signal_connect(item, "activate", G_CALLBACK(switch_video_input), + self); } /* add separator */ gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); - /* add screen area as an input */ + // add screen area as an input GtkWidget *item = gtk_check_menu_item_new_with_mnemonic(_("Share _screen area")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - if (sourcemodel) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), Video::SourceModel::ExtendedDeviceList::SCREEN == active); - g_object_set_data(G_OBJECT(item), JOIN_CALL_KEY, call); - g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_screen_area), call); - } else { - gtk_widget_set_sensitive(item, FALSE); - } + // TODO(sblin) only set active if fullscreen + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), + active_device.type == lrc::api::video::DeviceType::DISPLAY); + g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_screen_area), self); - /* add screen area as an input */ + // add screen area as an input item = gtk_check_menu_item_new_with_mnemonic(_("Share _monitor")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - if (sourcemodel) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), Video::SourceModel::ExtendedDeviceList::SCREEN == active); - g_object_set_data(G_OBJECT(item), JOIN_CALL_KEY, call); - g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_monitor), call); - } else { - gtk_widget_set_sensitive(item, FALSE); - } + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), + active_device.type == lrc::api::video::DeviceType::DISPLAY); + g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_monitor), self); - /* add file as an input */ + // add file as an input item = gtk_check_menu_item_new_with_mnemonic(_("Stream _file")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - if (sourcemodel) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), Video::SourceModel::ExtendedDeviceList::FILE == active); - g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_file), self); - } else { - gtk_widget_set_sensitive(item, FALSE); - } + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), + active_device.type == lrc::api::video::DeviceType::FILE); + g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_file), self); - /* add separator */ + // add separator gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); - /* add SmartInfo */ + // add SmartInfo item = gtk_check_menu_item_new_with_mnemonic(_("Show advanced information")); gtk_actionable_set_action_name(GTK_ACTIONABLE(item), "app.display-smartinfo"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_insert_action_group(menu, "app", G_ACTION_GROUP(g_application_get_default())); - /* show menu */ + // show menu gtk_widget_show_all(menu); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); - return TRUE; /* event has been fully handled */ + return TRUE; // event has been fully handled } static void @@ -696,19 +650,20 @@ clutter_render_image(VideoWidgetRenderer* wg_renderer) if (!wg_renderer->running) return; - auto renderer = wg_renderer->renderer; - if (renderer == nullptr) + if (!wg_renderer->v_renderer) return; - auto frame_ptr = renderer->currentFrame(); - auto frame_data = frame_ptr.ptr; + auto v_renderer = wg_renderer->v_renderer; + if (!v_renderer) + return; + auto frame_data = v_renderer->currentFrame().ptr; if (!frame_data) return; image_new = clutter_image_new(); g_return_if_fail(image_new); - const auto& res = renderer->size(); + const auto& res = v_renderer->size(); gint BPP = 4; /* BGRA */ gint ROW_STRIDE = BPP * res.width(); @@ -820,7 +775,7 @@ video_widget_add_renderer(VideoWidget *self, VideoWidgetRenderer *new_video_rend { g_return_if_fail(IS_VIDEO_WIDGET(self)); g_return_if_fail(new_video_renderer); - g_return_if_fail(new_video_renderer->renderer); + g_return_if_fail(new_video_renderer->v_renderer); VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self); @@ -880,43 +835,37 @@ video_widget_new(void) return self; } -/** - * video_widget_push_new_renderer() - * - * This function is used add a new Video::Renderer to the VideoWidget in a - * thread-safe manner. - */ void -video_widget_push_new_renderer(VideoWidget *self, Video::Renderer *renderer, VideoRendererType type) +video_widget_add_new_renderer(VideoWidget* self, lrc::api::AVModel* avModel, + const lrc::api::video::Renderer* renderer, VideoRendererType type) { g_return_if_fail(IS_VIDEO_WIDGET(self)); VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self); + priv->avModel_ = avModel; /* if the renderer is nullptr, there is nothing to be done */ if (!renderer) return; VideoWidgetRenderer *new_video_renderer = g_new0(VideoWidgetRenderer, 1); - new_video_renderer->renderer = renderer; + new_video_renderer->v_renderer = renderer; new_video_renderer->type = type; - if (new_video_renderer->renderer->isRendering()) + if (renderer->isRendering()) renderer_start(new_video_renderer); new_video_renderer->render_stop = QObject::connect( - new_video_renderer->renderer, - &Video::Renderer::stopped, - [=]() { + &*avModel, + &lrc::api::AVModel::rendererStopped, + [=](const std::string&) { renderer_stop(new_video_renderer); - } - ); + }); new_video_renderer->render_start = QObject::connect( - new_video_renderer->renderer, - &Video::Renderer::started, - [=]() { + &*avModel, + &lrc::api::AVModel::rendererStarted, + [=](const std::string&) { renderer_start(new_video_renderer); - } - ); + }); g_async_queue_push(priv->new_renderer_queue, new_video_renderer); } diff --git a/src/video/video_widget.h b/src/video/video_widget.h index a7f6b77357122e95ae524d4e6f74c4f8ada74867..57d5c0cc3b476db340d8fcf56dded86f1a486066 100644 --- a/src/video/video_widget.h +++ b/src/video/video_widget.h @@ -22,8 +22,15 @@ #include <gtk/gtk.h> #include <video/renderer.h> +#include <api/newvideo.h> -class Call; +namespace lrc +{ +namespace api +{ + class AVModel; +} +} G_BEGIN_DECLS @@ -45,7 +52,7 @@ typedef enum { /* Public interface */ GType video_widget_get_type (void) G_GNUC_CONST; GtkWidget* video_widget_new (void); -void video_widget_push_new_renderer (VideoWidget *, Video::Renderer *, VideoRendererType); +void video_widget_add_new_renderer (VideoWidget*, lrc::api::AVModel* avModel, const lrc::api::video::Renderer*, VideoRendererType); void video_widget_pause_rendering (VideoWidget *self, gboolean pause); void video_widget_on_drag_data_received (GtkWidget *self, GdkDragContext *context, @@ -57,7 +64,7 @@ void video_widget_on_drag_data_received (GtkWidget *self, gpointer data); gboolean video_widget_on_button_press_in_screen_event (VideoWidget *self, GdkEventButton *event, - Call* call); + G_GNUC_UNUSED gpointer); void video_widget_take_snapshot (VideoWidget *self); GdkPixbuf* video_widget_get_snapshot (VideoWidget *self); diff --git a/ui/mediasettingsview.ui b/ui/mediasettingsview.ui index 4878d1addd51addcb722761b665a995d3bd81a41..38014db58c306ed633fadb3ab4cfb20b20c5cc47 100644 --- a/ui/mediasettingsview.ui +++ b/ui/mediasettingsview.ui @@ -82,7 +82,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="combobox_manager"> + <object class="GtkComboBoxText" id="combobox_manager"> <property name="visible">True</property> <property name="popup-fixed-width">False</property> <property name="margin_left">10</property> @@ -93,7 +93,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="combobox_ringtone"> + <object class="GtkComboBoxText" id="combobox_ringtone"> <property name="visible">True</property> <property name="popup-fixed-width">False</property> <property name="margin_left">10</property> @@ -104,7 +104,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="combobox_output"> + <object class="GtkComboBoxText" id="combobox_output"> <property name="visible">True</property> <property name="popup-fixed-width">False</property> <property name="margin_left">10</property> @@ -115,7 +115,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="combobox_input"> + <object class="GtkComboBoxText" id="combobox_input"> <property name="visible">True</property> <property name="popup-fixed-width">False</property> <property name="margin_left">10</property> @@ -192,7 +192,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="combobox_device"> + <object class="GtkComboBoxText" id="combobox_device"> <property name="visible">True</property> <property name="popup-fixed-width">False</property> <property name="margin_left">10</property> @@ -203,7 +203,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="combobox_channel"> + <object class="GtkComboBoxText" id="combobox_channel"> <property name="visible">True</property> <property name="popup-fixed-width">False</property> <property name="margin_left">10</property> @@ -214,7 +214,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="combobox_resolution"> + <object class="GtkComboBoxText" id="combobox_resolution"> <property name="visible">True</property> <property name="popup-fixed-width">False</property> <property name="margin_left">10</property> @@ -225,7 +225,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="combobox_framerate"> + <object class="GtkComboBoxText" id="combobox_framerate"> <property name="visible">True</property> <property name="popup-fixed-width">False</property> <property name="margin_left">10</property>