From: "Frédéric Danis" <frederic.danis@collabora.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v2 3/5] audio/hfp-hf: Add skeleton for HFP profile
Date: Thu, 11 Dec 2025 19:34:27 +0100 [thread overview]
Message-ID: <20251211183429.419619-3-frederic.danis@collabora.com> (raw)
In-Reply-To: <20251211183429.419619-1-frederic.danis@collabora.com>
This starts the Telephony interface for HFP HF, allowing to connect to
the remote HFP AG device.
---
v1->v2:
- Fix 'make distcheck' by adding missing profiles/audio/telephony.h to
builtin_sources
- Improve commit message
Makefile.plugins | 5 +
configure.ac | 7 ++
profiles/audio/hfp-hf.c | 220 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 232 insertions(+)
create mode 100644 profiles/audio/hfp-hf.c
diff --git a/Makefile.plugins b/Makefile.plugins
index 3572ee845..3a95b5fb5 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -160,3 +160,8 @@ if ASHA
builtin_modules += asha
builtin_sources += profiles/audio/asha.h profiles/audio/asha.c
endif
+
+if HFP
+builtin_modules += hfp
+builtin_sources += profiles/audio/telephony.h profiles/audio/telephony.c profiles/audio/hfp-hf.c
+endif
diff --git a/configure.ac b/configure.ac
index 16b81aca3..b6f6789be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -248,6 +248,13 @@ if test "${enable_asha}" != "no"; then
AC_DEFINE(HAVE_ASHA, 1, [Define to 1 if you have ASHA support.])
fi
+AC_ARG_ENABLE(hfp, AS_HELP_STRING([--disable-hfp],
+ [disable HFP support]), [enable_hfp=${enableval}])
+AM_CONDITIONAL(HFP, test "${enable_hfp}" != "no")
+if test "${enable_hfp}" != "no"; then
+ AC_DEFINE(HAVE_HFP, 1, [Define to 1 if you have HFP support.])
+fi
+
AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools],
[disable Bluetooth tools]), [enable_tools=${enableval}])
AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no")
diff --git a/profiles/audio/hfp-hf.c b/profiles/audio/hfp-hf.c
new file mode 100644
index 000000000..5375168cf
--- /dev/null
+++ b/profiles/audio/hfp-hf.c
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ * Copyright © 2025 Collabora Ltd.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <stdint.h>
+
+#include <glib.h>
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/sdp.h"
+#include "bluetooth/sdp_lib.h"
+#include "bluetooth/uuid.h"
+
+#include "gdbus/gdbus.h"
+
+#include "btio/btio.h"
+#include "src/adapter.h"
+#include "src/btd.h"
+#include "src/dbus-common.h"
+#include "src/device.h"
+#include "src/log.h"
+#include "src/plugin.h"
+#include "src/profile.h"
+#include "src/service.h"
+
+#include "telephony.h"
+
+#define URI "tel"
+#define URI_PREFIX URI ":"
+
+struct hfp_device {
+ struct telephony *telephony;
+ uint16_t version;
+ GIOChannel *io;
+};
+
+static void device_destroy(struct hfp_device *dev)
+{
+ DBG("%s", telephony_get_path(dev->telephony));
+
+ if (dev->io) {
+ g_io_channel_unref(dev->io);
+ dev->io = NULL;
+ }
+
+ telephony_unregister_interface(dev->telephony);
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+ struct hfp_device *dev = user_data;
+ struct btd_service *service = telephony_get_service(dev->telephony);
+
+ DBG("");
+
+ if (err) {
+ error("%s", err->message);
+ goto failed;
+ }
+
+ g_io_channel_set_close_on_unref(chan, FALSE);
+
+ btd_service_connecting_complete(service, 0);
+
+ return;
+
+failed:
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ device_destroy(dev);
+}
+
+struct telephony_callbacks hfp_callbacks = {
+};
+
+static int hfp_connect(struct btd_service *service)
+{
+ struct hfp_device *dev;
+ struct btd_profile *p;
+ const sdp_record_t *rec;
+ sdp_list_t *list, *protos;
+ sdp_profile_desc_t *desc;
+ int channel;
+ bdaddr_t src, dst;
+ GError *err = NULL;
+
+ DBG("");
+
+ dev = btd_service_get_user_data(service);
+
+ p = btd_service_get_profile(service);
+ rec = btd_device_get_record(telephony_get_device(dev->telephony),
+ p->remote_uuid);
+ if (!rec)
+ return -EIO;
+
+ if (sdp_get_profile_descs(rec, &list) == 0) {
+ desc = list->data;
+ dev->version = desc->version;
+ }
+ sdp_list_free(list, free);
+
+ if (sdp_get_access_protos(rec, &protos) < 0) {
+ error("unable to get access protocols from record");
+ return -EIO;
+ }
+
+ channel = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+ if (channel <= 0) {
+ error("unable to get RFCOMM channel from record");
+ return -EIO;
+ }
+
+ src = telephony_get_src(dev->telephony);
+ dst = telephony_get_dst(dev->telephony);
+ dev->io = bt_io_connect(connect_cb, dev,
+ NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_CHANNEL, channel,
+ BT_IO_OPT_INVALID);
+ if (dev->io == NULL) {
+ error("unable to start connection");
+ return -EIO;
+ }
+
+ return telephony_register_interface(dev->telephony);
+}
+
+static int hfp_disconnect(struct btd_service *service)
+{
+ DBG("");
+
+ btd_service_disconnecting_complete(service, 0);
+
+ return 0;
+}
+
+static int hfp_probe(struct btd_service *service)
+{
+ struct btd_device *device = btd_service_get_device(service);
+ const char *path = device_get_path(device);
+ struct hfp_device *dev;
+
+ DBG("%s", path);
+
+ dev = g_new0(struct hfp_device, 1);
+ if (!dev)
+ return -EINVAL;
+
+ dev->telephony = telephony_new(service, dev, &hfp_callbacks);
+ btd_service_set_user_data(service, dev);
+ telephony_add_uri_scheme(dev->telephony, URI);
+
+ return 0;
+}
+
+static void hfp_remove(struct btd_service *service)
+{
+ struct btd_device *device = btd_service_get_device(service);
+ const char *path = device_get_path(device);
+ struct hfp_device *dev;
+
+ DBG("%s", path);
+
+ dev = btd_service_get_user_data(service);
+
+ telephony_free(dev->telephony);
+ g_free(dev);
+}
+
+static struct btd_profile hfp_hf_profile = {
+ .name = "hfp",
+ .priority = BTD_PROFILE_PRIORITY_MEDIUM,
+
+ .remote_uuid = HFP_AG_UUID,
+ .device_probe = hfp_probe,
+ .device_remove = hfp_remove,
+
+ .auto_connect = true,
+ .connect = hfp_connect,
+ .disconnect = hfp_disconnect,
+
+ .experimental = true,
+};
+
+static int hfp_init(void)
+{
+ btd_profile_register(&hfp_hf_profile);
+
+ return 0;
+}
+
+static void hfp_exit(void)
+{
+ btd_profile_unregister(&hfp_hf_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(hfp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ hfp_init, hfp_exit)
--
2.43.0
next prev parent reply other threads:[~2025-12-11 18:34 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-11 18:34 [PATCH BlueZ v2 1/5] doc: Add new telephony related profiles interfaces Frédéric Danis
2025-12-11 18:34 ` [PATCH BlueZ v2 2/5] audio/telephony: Add shared interfaces implementation Frédéric Danis
2025-12-11 18:34 ` Frédéric Danis [this message]
2025-12-11 18:34 ` [PATCH BlueZ v2 4/5] audio/hfp-hf: Add HFP SLC connection and event support Frédéric Danis
2025-12-11 18:34 ` [PATCH BlueZ v2 5/5] client/telephony: Add new submenu Frédéric Danis
2025-12-11 19:37 ` [BlueZ,v2,1/5] doc: Add new telephony related profiles interfaces bluez.test.bot
2025-12-12 15:30 ` [PATCH BlueZ v2 1/5] " patchwork-bot+bluetooth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251211183429.419619-3-frederic.danis@collabora.com \
--to=frederic.danis@collabora.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.