Discman
Loading...
Searching...
No Matches
bluetooth_component.cc
Go to the documentation of this file.
1
6
8
9BluetoothComponent::BluetoothComponent(Glib::RefPtr<Gtk::Builder> builder)
10 : _adapter("hci0")
11 , _alsa_device(nullptr)
13 _bluetooth_button = builder->get_widget<Gtk::Button>("bluetoothButton");
14 _device_label = builder->get_widget<Gtk::Label>("deviceLabel");
15 _device_status_label = builder->get_widget<Gtk::Label>("deviceStatusLabel");
16 _devices_tree_view = builder->get_widget<Gtk::TreeView>("devicesTreeView");
17 _done_button = builder->get_widget<Gtk::Button>("bluetoothDoneButton");
18 _connect_button = builder->get_widget<Gtk::Button>("connectButton");
19
20 _devices_list_store = std::dynamic_pointer_cast<Gtk::ListStore>(builder->get_object("devicesListStore"));
21
23 _devices_tree_view->append_column("Devices", cols.name_column);
24
25 _bluetooth_button->signal_clicked().connect(sigc::mem_fun(*this, &BluetoothComponent::on_bluetooth_button));
26 _devices_tree_view->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &BluetoothComponent::on_devices_list_selection_changed));
27 _connect_button->signal_clicked().connect(sigc::mem_fun(*this, &BluetoothComponent::on_connect_button_clicked));
28 _done_button->signal_clicked().connect(sigc::mem_fun(*this, &BluetoothComponent::on_done_button_clicked));
29 _adapter.signal_device_added().connect(sigc::mem_fun(*this, &BluetoothComponent::on_device_added));
30 _adapter.signal_device_removed().connect(sigc::mem_fun(*this, &BluetoothComponent::on_device_removed));
31}
32
43
53
55 _adapter.stop_discovery();
56}
57
62
66
70
74
78
79void BluetoothComponent::on_device_added(const std::string& address) {
81
82 auto row = *(_devices_list_store->append());
83 row[cols.address_column] = address;
84 row[cols.name_column] = _adapter.alias(address);
85
86 _devices_tree_view->get_vadjustment()->set_value(_devices_tree_view->get_vadjustment()->get_upper());
87
88 if (!_alsa_device && _alsa_device_address == address) {
91 }
92}
93
94void BluetoothComponent::on_device_removed(const std::string& address) {
95 Gtk::TreeModel::iterator it = _devices_list_store->get_iter("0");
96
98
99 for (; it; it++) {
100 Gtk::TreeModel::Row row = *it;
101 if (row[cols.address_column] == address.data()) {
102 _devices_list_store->erase(it);
103 break;
104 }
105 }
106
107 if (_alsa_device && _alsa_device_address == address) {
108 delete _alsa_device;
109 _alsa_device = nullptr;
111 }
112}
113
115 std::string selectedAddress = _devices_tree_view->get_selection()->get_selected()->get_value(DevicesListColumnRecord().address_column);
116
117 const bool showDisconnect = (_alsa_device && _alsa_device->address() == selectedAddress && _alsa_device->connected());
118
119 _connect_button->set_sensitive(!_devices_tree_view->get_selection()->get_selected_rows().empty());
120 _connect_button->set_label(showDisconnect ? "Disconnect" : "Connect");
121}
122
123void BluetoothComponent::update_asoundrc(const std::string& address) {
124 std::ifstream asoundrc;
125 std::ofstream asoundrc_tmp;
126 std::string line;
127 const std::regex mac_pattern("([0-9A-F]{2}:){5}[0-9A-F]{2}");
128
129 asoundrc.open("/home/discman/.asoundrc");
130 asoundrc_tmp.open("/home/discman/.asoundrc.tmp");
131 if (asoundrc.good()) {
132 while (getline(asoundrc, line)) {
133 std::string outLine = std::regex_replace(line, mac_pattern, address);
134 asoundrc_tmp << outLine << std::endl;
135 }
136 }
137 asoundrc_tmp.close();
138 std::filesystem::rename("/home/discman/.asoundrc.tmp", "/home/discman/.asoundrc");
139}
140
142 const bool connect = _connect_button->get_label() == "Connect";
143 const std::string selectedAddress = _devices_tree_view->get_selection()->get_selected()->get_value(DevicesListColumnRecord().address_column);
144
145 if (connect) {
146 if (_alsa_device)
147 _alsa_device->disconnect();
149
150 update_asoundrc(selectedAddress);
154 assert(_alsa_device);
155 _alsa_device->connect();
156 } else {
157 assert(_alsa_device);
158 _alsa_device->disconnect();
159 }
160}
161
164
165 const std::string selectedAddress = _devices_tree_view->get_selection()->get_selected()->get_value(DevicesListColumnRecord().address_column);
166 const bool showDisconnect = (_alsa_device && _alsa_device->address() == selectedAddress && _alsa_device->connected());
167 _connect_button->set_label(showDisconnect ? "Disconnect" : "Connect");
168
169 if (_alsa_device->connected()) {
170 _signal_connected.emit();
171 }
172}
173
175 const std::vector<std::string> devices = _adapter.devices();
176
177 _devices_list_store->clear();
178
180
181 for (unsigned int i = 0; i < devices.size(); i++) {
182 auto row = *(_devices_list_store->append());
183 row[cols.address_column] = devices[i];
184 row[cols.name_column] = _adapter.alias(devices[i]);
185 }
186}
187
189 std::ifstream asoundrc;
190 std::string line;
191 const std::regex mac_pattern("([0-9A-F]{2}:){5}[0-9A-F]{2}");
192
193 asoundrc.open("/home/discman/.asoundrc");
194 if (asoundrc.good()) {
195 while (getline(asoundrc, line)) {
196 std::smatch match;
197
198 if (std::regex_search(line, match, mac_pattern)) {
199 _alsa_device_address = match[0];
200 return;
201 }
202 }
203 }
204}
205
207 try {
208 if (_alsa_device)
209 delete _alsa_device;
210
212 _alsa_device->signal_paired().connect(sigc::mem_fun(*this, &BluetoothComponent::on_device_status_change));
213 _alsa_device->signal_connected().connect(sigc::mem_fun(*this, &BluetoothComponent::on_device_status_change));
214 _alsa_device->signal_disconnected().connect(sigc::mem_fun(*this, &BluetoothComponent::on_device_status_change));
215 } catch (const Bluez::Adapter::DeviceNotFound& e) {
216 _alsa_device = nullptr;
217 }
218}
219
221 if (_alsa_device) {
222 _device_label->set_text(_alsa_device->alias());
223
224 if (_alsa_device->connected()) {
226 _device_status_label->set_text("Ready.");
228 _device_status_label->set_text("Initialization failed.");
229 } else {
230 _device_status_label->set_text("Connected.");
231 }
232 } else if (_alsa_device->paired()) {
233 _device_status_label->set_text("Paired.");
234 } else {
235 _device_status_label->set_text("Not connected.");
236 }
237 } else {
238 _device_label->set_text("Not Connected");
239 _device_status_label->set_text("Please select a device.");
240 }
241}
242
Gtk::TreeModelColumn< Glib::ustring > name_column
Device name column.
Gtk::TreeModelColumn< Glib::ustring > address_column
Device address column (hidden).
Gtk::Button * _connect_button
Connect/Disconnect button.
void on_show()
Called when the Bluetooth device selection screen is navigated to.
Gtk::Button * _bluetooth_button
Button that switches to the Bluetooth device selection screen.
Gtk::Button * _done_button
Done button.
void on_bluetooth_button()
Bluetooth button handler.
sig_conn _signal_connected
Emitted when the chosen device has been connected to.
void on_device_added(const std::string &address)
Called when _adapter discovers a new device.
Gtk::TreeView * _devices_tree_view
Device list.
void set_device_labels()
Updates _device_label and _device_status_label based on current state.
sig_done _signal_done
Emitted when the Done button is clicked.
void get_alsa_device_address()
Retrieves the device MAC address from the ALSA configuration file.
void on_device_initialization_complete(const bool initialized)
Called when the Bluetooth device initialization procedure has finished.
void update_asoundrc(const std::string &address)
Update the ALSA configuration file with the newly selected Bluetooth device.
sig_conn signal_connected()
Getter for _signal_connected.
Bluez::Device * _alsa_device
Bluetooth device retrieved from _adapter.
void on_connect_button_clicked()
Called when the Connect/Disconnect button is clicked.
~BluetoothComponent()
BluetoothComponent destructor.
Glib::RefPtr< Gtk::ListStore > _devices_list_store
Device list model.
BluetoothComponent(Glib::RefPtr< Gtk::Builder > builder)
BluetoothComponent constructor.
sigc::signal< void()> sig_conn
"Connected" signal type.
void build_devices_list()
Builds the initial list of preregistered Bluetooth devices.
void on_device_status_change()
Called when the chosen device pairs, connects or disconnects.
void on_device_removed(const std::string &address)
Called when _adapter reports a removed device.
Gtk::Label * _device_status_label
Label displaying chosen device connection status.
sig_button _signal_button
Emitted when the Bluetooth button is clicked.
std::string _alsa_device_address
MAC address of the chosen device.
sig_done signal_done()
Getter for _signal_done.
sigc::signal< void()> sig_done
"Done with screen" signal type.
DeviceInitialization
Bluetooth device initialization state.
Bluez::Adapter _adapter
Bluetooth adapter used for pairing and connection.
DeviceInitialization _alsa_device_init
Initialization status of the chosen device.
void on_hide()
Called when the Bluetooth device selection screen is navigated from.
Gtk::Label * _device_label
Label displaying the chosen device alias.
sig_button signal_button()
Getter for _signal_button.
void try_get_alsa_device()
Attempts to set _alsa_device based on _alsa_device_address.
void on_devices_list_selection_changed()
Called when a device is clicked in the device list.
void on_done_button_clicked()
Called when the Done button is clicked.