summaryrefslogtreecommitdiffstats
path: root/signal-composer/CMakeLists.txt
blob: f517d2795b59fb3f4e2e66b9f87595026739f363 (plain)
1
2
add_headers(signalcomposer.h)
add_sources(signalcomposer.cpp)
t .kp { color: #66d9ef } /* Keyword.Pseudo */ .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ .highlight .kt { color: #66d9ef } /* Keyword.Type */ .highlight .ld { color: #e6db74 } /* Literal.Date */ .highlight .m { color: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * Copyright (C) 2021,2022 Konsulko Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <QDebug>
#include <bluez-glib.h>
#include "bluetootheventhandler.h"
#include "bluetooth.h"
#include "bluetoothmodel.h"

#undef BLUETOOTH_EVENT_DEBUG


BluetoothEventHandler::BluetoothEventHandler(Bluetooth *parent, bool register_agent, bool handle_media) :
	m_parent(parent),
	m_agent(register_agent)
{
	bluez_add_adapter_event_callback(adapter_event_cb, this);
	bluez_add_device_event_callback(device_event_cb, this);

	if (register_agent)
		bluez_add_agent_event_callback(agent_event_cb, this);

	if (handle_media) {
		bluez_add_media_control_event_callback(media_control_event_cb, this);
		bluez_add_media_player_event_callback(media_player_event_cb, this);
	}
}

BluetoothEventHandler::~BluetoothEventHandler()
{
}

void BluetoothEventHandler::handle_init_event(gchar *adapter, gboolean status)
{
#ifdef BLUETOOTH_EVENT_DEBUG
	qDebug() << "BluetoothEventHandler::handle_init_event: enter, status = " << (int) status;
#endif

	if (status)
		m_parent->init_adapter_state(QString(adapter));
	else
		qCritical() << "BlueZ initialization failed";
}

void BluetoothEventHandler::handle_adapter_event(gchar *adapter,
						 bluez_event_t event,
						 GVariant *properties)
{
#ifdef BLUETOOTH_EVENT_DEBUG
	qDebug() << "BluetoothEventHandler::handle_adapter_event: enter";
	gchar *p = properties ? g_variant_print(properties, TRUE) : g_strdup("(null)");
	qDebug() << "BluetoothEventHandler::handle_adapter_event: adapter = "
		 << adapter << ", event = " << (int) event;
	qDebug() << "BluetoothEventHandler::handle_adapter_event: properties = " << p;
	g_free(p);
#endif

	if (!adapter || event != BLUEZ_EVENT_CHANGE)
		return;

	GVariantDict *props_dict = g_variant_dict_new(properties);
	if (!props_dict)
		return;

	gboolean powered = FALSE;
	if (!g_variant_dict_lookup(props_dict, "Powered", "b", &powered)) {
		g_variant_dict_unref(props_dict);
		return;
	}

	g_variant_dict_unref(props_dict);

	m_parent->update_adapter_power(powered);
}

void BluetoothEventHandler::handle_device_event(gchar *adapter,
						gchar *device,
						bluez_event_t event,
						GVariant *properties)
{
#ifdef BLUETOOTH_EVENT_DEBUG
	qDebug() << "BluetoothEventHandler::handle_device_event: enter";
	gchar *p = properties ? g_variant_print(properties, TRUE) : g_strdup("(null)");
	qDebug() << "BluetoothEventHandler::handle_device_event: adapter = "
		 << adapter << ", device = " << device << ", event = " << (int) event;
	qDebug() << "BluetoothEventHandler::handle_device_event: properties = " << p;
	g_free(p);
#endif

	if (!device)
		return;

	BluetoothDevice *model_device = m_parent->m_bluetooth->getDevice(QString(device));
	if (event == BLUEZ_EVENT_REMOVE) {
		if(model_device != nullptr)
			m_parent->m_bluetooth->removeDevice(model_device);

		return;
	}

	BluetoothDevice *new_device = m_parent->m_bluetooth->updateDeviceProperties(model_device, device, properties);
	if (new_device == nullptr) {
		qCritical() << "Failed to create device object with id: " << QString(device);
		return;
	}
	if (model_device == nullptr && event == BLUEZ_EVENT_ADD) {
		// device not previously in model
		m_parent->m_bluetooth->addDevice(new_device);
	}

	// Update parent's connected state
	// NOTE: Currently not worrying about multiple devices being connected
	GVariantDict *props_dict = g_variant_dict_new(properties);
	if (props_dict) {
		gboolean connected = FALSE;
		if (g_variant_dict_lookup(props_dict, "Connected", "b", &connected)) {
			m_parent->update_connected_state(QString(device), connected);
		}
		g_variant_dict_unref(props_dict);
	}
}

void BluetoothEventHandler::handle_media_control_event(gchar *adapter,
						       gchar *device,
						       bluez_event_t event,
						       GVariant *properties)
{
#ifdef BLUETOOTH_EVENT_DEBUG
	qDebug() << "BluetoothEventHandler::handle_media_control_event: enter";
	gchar *p = properties ? g_variant_print(properties, TRUE) : g_strdup("(null)");
	qDebug() << "BluetoothEventHandler::handle_media_control_event: adapter = "
		 << adapter << ", device = " << device << ", event = " << (int) event;
	qDebug() << "BluetoothEventHandler::handle_media_control_event: properties = " << p;
	g_free(p);
#endif

	if (event != BLUEZ_EVENT_CHANGE)
		return;

	// Update parent's media connected state
	// NOTE: Currently not worrying about multiple devices being connected
	GVariantDict *props_dict = g_variant_dict_new(properties);
	if (props_dict) {
		gboolean connected = FALSE;
		if (g_variant_dict_lookup(props_dict, "Connected", "b", &connected)) {
			m_parent->update_media_connected_state(connected);
		}
		g_variant_dict_unref(props_dict);
	}

}

void BluetoothEventHandler::handle_media_player_event(gchar *adapter,
						      gchar *device,
						      gchar *player,
						      bluez_event_t event,
						      GVariant *properties)
{
#ifdef BLUETOOTH_EVENT_DEBUG
	qDebug() << "BluetoothEventHandler::handle_media_player_event: enter";
	gchar *p = properties ? g_variant_print(properties, TRUE) : g_strdup("(null)");
	qDebug() << "BluetoothEventHandler::handle_media_player_event: adapter = "
		 << adapter << ", device = " << device << ", player = " << player
		 << ", event = " << (int) event;
	qDebug() << "BluetoothEventHandler::handle_media_player_event: properties = " << p;
	g_free(p);
#endif

	if (event != BLUEZ_EVENT_REMOVE) {
		QVariantMap tmp;
		parse_media_player_properties(properties, tmp);
		if (!tmp.empty()) {
			m_parent->update_media_properties(tmp);
		}
	}
}

void BluetoothEventHandler::handle_agent_event(gchar *device,
					       bluez_agent_event_t event,
					       GVariant *properties)
{
	const gchar *path = NULL;
	int pincode;

	if (event == BLUEZ_AGENT_EVENT_REQUEST_CONFIRMATION) {
		g_variant_get(properties, "(ou)", &path, &pincode);
		if (path)
			m_parent->request_confirmation(pincode);
	}
}

void BluetoothEventHandler::handle_connect_event(gchar *device, gboolean status)
{
	if (!status)
		qDebug() << "connect failed";
}

void BluetoothEventHandler::handle_pair_event(gchar *device, gboolean status)
{
	if (!status)
		qDebug() << "pairing failed";
}

void BluetoothEventHandler::parse_media_player_properties(GVariant *properties, QVariantMap &metadata)
{
	GVariantDict *props_dict = g_variant_dict_new(properties);
	if (!props_dict)
		return;

	GVariant *v = NULL;
	if (g_variant_dict_lookup(props_dict, "Track", "@a{sv}", &v)) {
		GVariantDict *track_dict = g_variant_dict_new(v);
		QVariantMap track;
		gchar *p = NULL;

		if (g_variant_dict_lookup(track_dict, "Title", "&s", &p))
			track.insert(QString("title"), QVariant(QString(p)));

		if (g_variant_dict_lookup(track_dict, "Artist", "&s", &p))
			track.insert(QString("artist"), QVariant(QString(p)));

		if (g_variant_dict_lookup(track_dict, "Album", "&s", &p))
			track.insert(QString("album"), QVariant(QString(p)));

		unsigned int duration = 0;
		if (g_variant_dict_lookup(track_dict, "Duration", "u", &duration))
			track.insert(QString("duration"), QVariant(duration));

		g_variant_dict_unref(track_dict);

		metadata.insert("track", track);
	}

	unsigned int position = 0;
	if (g_variant_dict_lookup(props_dict, "Position", "u", &position)) {
		metadata.insert("position", QVariant(position));
	}

	gchar *p = NULL;
	if (g_variant_dict_lookup(props_dict, "Status", "&s", &p))
		metadata.insert(QString("status"), QVariant(QString(p)));

	g_variant_dict_unref(props_dict);
}