From: "Frédéric Danis" <frederic.danis@collabora.com>
To: linux-bluetooth@vger.kernel.org
Subject: [RFC BlueZ 03/10] audio/telephony: Add skeleton for HFP profile
Date: Wed, 28 May 2025 10:59:23 +0200 [thread overview]
Message-ID: <20250528085930.227816-4-frederic.danis@collabora.com> (raw)
In-Reply-To: <20250528085930.227816-1-frederic.danis@collabora.com>
---
Makefile.plugins | 5 +
configure.ac | 7 ++
profiles/audio/hfp-hf.c | 218 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+)
create mode 100644 profiles/audio/hfp-hf.c
diff --git a/Makefile.plugins b/Makefile.plugins
index bae4363d0..66e8033e4 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -150,3 +150,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.c profiles/audio/hfp-hf.c
+endif
diff --git a/configure.ac b/configure.ac
index 1e089aaa7..b3dc40626 100644
--- a/configure.ac
+++ b/configure.ac
@@ -238,6 +238,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..aa74cd515
--- /dev/null
+++ b/profiles/audio/hfp-hf.c
@@ -0,0 +1,218 @@
+/* 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 "lib/bluetooth.h"
+#include "bluetooth/sdp.h"
+#include "bluetooth/sdp_lib.h"
+#include "lib/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"
+
+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 get 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);
+
+ 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);
+
+ btd_service_unref(service);
+}
+
+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-05-28 8:59 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-28 8:59 [RFC BlueZ 00/10] New Telephony interface for HSP, HFP and CCP Frédéric Danis
2025-05-28 8:59 ` [RFC BlueZ 01/10] doc: Add new telephony related profiles interfaces Frédéric Danis
2025-05-28 10:33 ` New Telephony interface for HSP, HFP and CCP bluez.test.bot
2025-05-28 8:59 ` [RFC BlueZ 02/10] audio/telephony: Add shared interfaces implementation Frédéric Danis
2025-05-28 8:59 ` Frédéric Danis [this message]
2025-05-28 8:59 ` [RFC BlueZ 04/10] audio/hfp-hf: Add HFP SLC connection and event support Frédéric Danis
2025-05-28 8:59 ` [RFC BlueZ 05/10] audio/hfp-hf: Add dial support Frédéric Danis
2025-05-28 8:59 ` [RFC BlueZ 06/10] audio/hfp-hf: Add hangup all calls support Frédéric Danis
2025-05-28 8:59 ` [RFC BlueZ 07/10] audio/hfp-hf: Add answer a specific call support Frédéric Danis
2025-05-28 8:59 ` [RFC BlueZ 08/10] client/telephony: Add new submenu Frédéric Danis
2025-05-28 8:59 ` [RFC BlueZ 09/10] audio/hfp-hf: Remove call interface during profile disconnection Frédéric Danis
2025-05-28 8:59 ` [RFC BlueZ 10/10] audio/hfp-hf: Create existing call during SLC phase Frédéric Danis
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=20250528085930.227816-4-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox