From patchwork Tue Jan 21 12:47:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 13946244 Received: from mail-ed1-f46.google.com (mail-ed1-f46.google.com [209.85.208.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF5011DF96A for ; Tue, 21 Jan 2025 12:47:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463659; cv=none; b=PobcwyMm18YcQP3a0a772hLoQ+qeQfor89tR6a4qqDZdtZ6J5NbYkCxbdmm0LMvWs3VkOZiFd5ILpzcoz75eJXUR/5iFnRifJeFiqOLl1/MCOZjRtE07xYOx2fI/qhiauvFC/r40oKcT9Bnb+YIWxFIBrLxyssp+yos0qiuExjM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463659; c=relaxed/simple; bh=sO+dboodXBdmqOHqDW2Ro0yGw2C8mpljwEwLlBSPMNU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=M6Wj5fvpkRlAbxd3sly90XWi2EcrDJWCkMbaOA2X9QKQauBNZzUjneTbK3K1nTDh817yHaHEZEfNaAvxv24XYGguO3ndNs3ipFfiowlWk4jAzrfzvS7u0rvAXTHcEH3/wkv9KnTQJb8o3CgJLuHKio4U3pLfnrENDI9IA/AKd4s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com; spf=pass smtp.mailfrom=streamunlimited.com; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b=pxwPwlja; arc=none smtp.client-ip=209.85.208.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b="pxwPwlja" Received: by mail-ed1-f46.google.com with SMTP id 4fb4d7f45d1cf-5d3d0205bd5so8987031a12.3 for ; Tue, 21 Jan 2025 04:47:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737463655; x=1738068455; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BRLQplTHJGkAWlkArhYviFfIPTshswlkLWRCkvQRO/g=; b=pxwPwljaj+HtEspxFM/vP7LzTPbhZwInscJ7DydmpxwzSrkzu2UBThOjylYVkhaqyg TyLRcPWORb1pk0+ju8HIYSeWZWfcPoiBH4mQIHg6L9RXI4+6NnCGBC37Db9RpqgypZtm Al6JZi+2o5gAx4SHfxHPuns6pQMJ3cga2IN4s= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737463655; x=1738068455; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BRLQplTHJGkAWlkArhYviFfIPTshswlkLWRCkvQRO/g=; b=XBDO7uVZJ4QewNemBl13CZx9F48G0YUowhqd3XZqiyL6PkczuEA3uPtraBAavNJmru on4BrsSoL17onwGmZRu/nfpSXgfYax5Js6vN6V/3l8/w8VsKTg0FEFnYrIICGPMorccq 0oNaiq4SV/F+Z6qlg1g68V/lDaly3Odm6omgsIVWHDU6ChSIxVB1zLjo3darZlbOnqsE TP+MqY8QpcRkvhrWYsx75W76+36gP5IL5Pc+XyYWnn9N0/BKyZfMbL4pkVW8vpC+kRB3 XoEF6ZPE1KuUalJoE7fNHxzH4YVDOEdwX9whETRYAAliqB7lRmiGETkqKJJ36CtqVWg3 RR9g== X-Gm-Message-State: AOJu0Yx0Qs51B7w4ItXMEJM7A9vBzxYvHi5qRcY/kvXpVjs7NjMsRei8 11mkWSBeWWQiRc3SIGgIQCqpPt9NbesGG4f1umJqmf1HIL8Vea8uDb2tCWkrXWTHFCcTOYT4YQw = X-Gm-Gg: ASbGncuGoKq2KIrk4CypGoxDxAxDN+ajcqrP54ClA33hbJVI2KYKBxfSmiKgDs/7y2P npDII+iY8QgdLi/PiZ0vYR3ztZKMN8ytNuv3eREbmcOu9Ui+Xi9CpQm2BjjbB6UsPZMNff49JLa jWisA3UpFzEaccOx6Hgay1cZMdQ9omwS91BViDlFFDtJMu+VGvmAJaZ4BQIrueHpuCpT1jJfEcB lAdol9YolR3h0e11fSCupQxaayw+Zc3rqjUXR+uJqHm3QsTHFl6tXmwtyKSS6Hw30h711587QeT rh+S2P1refgKmTWvKnY3z/rJVhC9SYlNngEyH9v/V6AS X-Google-Smtp-Source: AGHT+IEIofdoUTZNJ/DKIOGpK8JqSZkfg3cGhiKPHCv3Mq8AKY1oYEvv2LUQk1HjRWGWLDesBy+eQw== X-Received: by 2002:a05:6402:524b:b0:5da:ba6:3a3e with SMTP id 4fb4d7f45d1cf-5db7d2e2824mr16403429a12.7.1737463654824; Tue, 21 Jan 2025 04:47:34 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5db73670cf8sm7153591a12.19.2025.01.21.04.47.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 04:47:34 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v2 1/5] shared/vcp: add API to control volume on VCP client Date: Tue, 21 Jan 2025 13:47:14 +0100 Message-Id: <20250121124718.3995904-2-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> References: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 --- src/shared/vcp.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++- src/shared/vcp.h | 7 ++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/shared/vcp.c b/src/shared/vcp.c index cfc426624..abc5a35a3 100644 --- a/src/shared/vcp.c +++ b/src/shared/vcp.c @@ -147,6 +147,12 @@ struct bt_vcs_ab_vol { uint8_t vol_set; } __packed; +struct bt_vcs_client_ab_vol { + uint8_t op; + uint8_t change_counter; + uint8_t vol_set; +} __packed; + struct bt_vocs_set_vol_off { uint8_t change_counter; int16_t set_vol_offset; @@ -192,6 +198,11 @@ struct bt_vcp { bt_vcp_debug_func_t debug_func; bt_vcp_destroy_func_t debug_destroy; + bt_vcp_volume_func_t volume_changed; + + uint8_t volume; + uint8_t volume_counter; + void *debug_data; void *user_data; }; @@ -1874,6 +1885,15 @@ bool bt_vcp_set_debug(struct bt_vcp *vcp, bt_vcp_debug_func_t func, return true; } +bool bt_vcp_set_volume_callback(struct bt_vcp *vcp, + bt_vcp_volume_func_t volume_changed) +{ + if (!vcp) + return false; + + vcp->volume_changed = volume_changed; + return true; +} unsigned int bt_vcp_register(bt_vcp_func_t attached, bt_vcp_func_t detached, void *user_data) { @@ -1959,6 +1979,65 @@ static void vcp_vstate_notify(struct bt_vcp *vcp, uint16_t value_handle, DBG(vcp, "Vol Settings 0x%x", vstate.vol_set); DBG(vcp, "Mute Status 0x%x", vstate.mute); DBG(vcp, "Vol Counter 0x%x", vstate.counter); + + vcp->volume = vstate.vol_set; + vcp->volume_counter = vstate.counter; + + if (vcp->volume_changed) + vcp->volume_changed(vcp, vcp->volume); +} + +static void vcp_volume_cp_sent(bool success, uint8_t err, void *user_data) +{ + struct bt_vcp *vcp = user_data; + + if (!success) { + if (err == BT_ATT_ERROR_INVALID_CHANGE_COUNTER) + DBG(vcp, "setting volume failed: invalid counter"); + else + DBG(vcp, "setting volume failed: error 0x%x", err); + } +} + +uint8_t bt_vcp_get_volume(struct bt_vcp *vcp) +{ + return vcp->volume; +} + +bool bt_vcp_set_volume(struct bt_vcp *vcp, uint8_t volume) +{ + struct bt_vcs_client_ab_vol req; + uint16_t value_handle; + struct bt_vcs *vcs = vcp_get_vcs(vcp); + + if (!vcs) { + DBG(vcp, "error: vcs not available"); + return false; + } + + if (!vcs->vol_cp) { + DBG(vcp, "error: vol_cp characteristics not available"); + return false; + } + + if (!gatt_db_attribute_get_char_data(vcs->vol_cp, NULL, &value_handle, + NULL, NULL, NULL)) { + DBG(vcp, "error: vol_cp characteristics not available"); + return false; + } + + vcp->volume = volume; + req.op = BT_VCS_SET_ABSOLUTE_VOL; + req.vol_set = vcp->volume; + req.change_counter = vcp->volume_counter; + + if (!bt_gatt_client_write_value(vcp->client, value_handle, (void *) &req, + sizeof(struct bt_vcs_client_ab_vol), vcp_volume_cp_sent, vcp, + NULL)) { + DBG(vcp, "error writing volume"); + return false; + } + return true; } static void vcp_voffset_state_notify(struct bt_vcp *vcp, uint16_t value_handle, @@ -2061,6 +2140,9 @@ static void read_vol_state(struct bt_vcp *vcp, bool success, uint8_t att_ecode, DBG(vcp, "Vol Set:%x", vs->vol_set); DBG(vcp, "Vol Mute:%x", vs->mute); DBG(vcp, "Vol Counter:%x", vs->counter); + + vcp->volume = vs->vol_set; + vcp->volume_counter = vs->counter; } static void read_vol_offset_state(struct bt_vcp *vcp, bool success, @@ -2757,4 +2839,3 @@ bool bt_vcp_attach(struct bt_vcp *vcp, struct bt_gatt_client *client) return true; } - diff --git a/src/shared/vcp.h b/src/shared/vcp.h index 26db5732d..705b6f301 100644 --- a/src/shared/vcp.h +++ b/src/shared/vcp.h @@ -36,6 +36,7 @@ struct bt_vcp; typedef void (*bt_vcp_destroy_func_t)(void *user_data); typedef void (*bt_vcp_debug_func_t)(const char *str, void *user_data); typedef void (*bt_vcp_func_t)(struct bt_vcp *vcp, void *user_data); +typedef void (*bt_vcp_volume_func_t)(struct bt_vcp *vcp, uint8_t volume); struct bt_vcp *bt_vcp_ref(struct bt_vcp *vcp); void bt_vcp_unref(struct bt_vcp *vcp); @@ -45,9 +46,15 @@ void bt_vcp_add_db(struct gatt_db *db); bool bt_vcp_attach(struct bt_vcp *vcp, struct bt_gatt_client *client); void bt_vcp_detach(struct bt_vcp *vcp); +uint8_t bt_vcp_get_volume(struct bt_vcp *vcp); +bool bt_vcp_set_volume(struct bt_vcp *vcp, uint8_t volume); + bool bt_vcp_set_debug(struct bt_vcp *vcp, bt_vcp_debug_func_t cb, void *user_data, bt_vcp_destroy_func_t destroy); +bool bt_vcp_set_volume_callback(struct bt_vcp *vcp, + bt_vcp_volume_func_t volume_changed); + struct bt_att *bt_vcp_get_att(struct bt_vcp *vcp); bool bt_vcp_set_user_data(struct bt_vcp *vcp, void *user_data); From patchwork Tue Jan 21 12:47:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 13946245 Received: from mail-ed1-f46.google.com (mail-ed1-f46.google.com [209.85.208.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D58B21F131F for ; Tue, 21 Jan 2025 12:47:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463662; cv=none; b=sqNqw8nIHTPUQp8jxb9W/Y9ISdPTXpg4TY1KDM7BB6P5sEDZg0FonAWiekJHpB9zB5R3mNfGOhm5lsdlaNvLfKQFDjxGxcHSzbc5h0BqSDOUegM3I6ZuGWSUtbh3CtmfJ/yWhEy1AFIe167bbIHZCCMbcZk8neLOET3gDCOquj0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463662; c=relaxed/simple; bh=+84sE4wyL9QsOPDP1IIvr17HEhN5mw8t86BOC5IHme0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=qqnd9j7fTjS0M7+KAXS8HgD2elCEwv9BvSdHuEiRrrcTcxyYxoCepPkZGcoaxY9diNgRqHWT4BFSPlB+/RaM4F4tc9MH6IyErdKzTGVZyripGClwO8P6qpE5y9IlWxbRf6ARjeqe5HCOCrvSUFekD1jravWZqWFHyMH9At4LYsI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com; spf=pass smtp.mailfrom=streamunlimited.com; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b=uydYKQTI; arc=none smtp.client-ip=209.85.208.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b="uydYKQTI" Received: by mail-ed1-f46.google.com with SMTP id 4fb4d7f45d1cf-5d3e6274015so2062641a12.0 for ; Tue, 21 Jan 2025 04:47:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737463658; x=1738068458; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=p23enX7TgUP8WMEv3OmFEAa5B2iMNVSFLiXOKOknp7Y=; b=uydYKQTIwDvXVYbPGzk2GSsMsekyMhynVo6dOsix2QIxZpuTptsIMMTyCwIMFGvUR6 6rc8CKfgXQzKXeOxk7R8lJtuduRtpgKe9T6x663XAq/F1dKkIRfta80AnLhaSQ3XVAu1 ywveIC65PTVXftHjRMIErGo/Z9Vs6S5iSW/es= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737463658; x=1738068458; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=p23enX7TgUP8WMEv3OmFEAa5B2iMNVSFLiXOKOknp7Y=; b=UKRAF+xH3jYQl9KepyN9VLI0fXh9gqvAH005wmEs3Eeyoo+N1hGseoFk+pghZuunX/ 1Bvd//JhCmAEd3fZ60owVXjIEEO00/i/5ibko7L8GPofSuuyS5sAx5bLKdF5pC/Rv3Zg mAHfJpMKkeHSywFQdQ12p8WYhgGT1Ki0zZMdlWyPPMWxMYEk4qyxfQOTx7ifbIMgSfW8 QHTcQvntlu8xYA6Pq5tovOdTLFabcT7MAS5umzGkujcZcVbK9esnRwQ/mVlqeZENYj4n 6TeV8QIT5TmArGJg102r76O/OPBHIWmXRgT7apywgrVIDIt8uHZoXK7TjKOctqjfCR6P Z5TQ== X-Gm-Message-State: AOJu0YzWWRuWgNHi9oqfx2yVdBWVEJoUzvqKAZ1MTjtgLDU1+QcDd3iS qeROFtW7sXhYbo36mI7WowDkWgCV3HPO5qMenr6ZwngmAKXofncDRWvfuCf44FtWCLP7d9ocHZk = X-Gm-Gg: ASbGnctR11K8LThsYk4dUVoqp9wSFoarj5iR2gv+NdAVW5Afem5tRftcBgSe1nSiiG1 R0aCrTnZ9QKNaMW/fZMrPUVKYdFwOYBzSuQTrEySuATJaXRQ/2PopTa6/EYZuR8iGFbwLxlB2ks 3E7XI2CNr5mOX3Roua+KFabNUqDh4MxdagY8pXQO06T0In0sPugffvKzB5By1cPffyHnHyoUxSA VbLu8Gj3Hrh2HeWLlYFkfUN+erQJfAzzNJ6+m3/jF7H3vF+eOmprQiOWeGg3sLmwWb+3Do/Bd5z gtAhz41uBQrPx4nduMgHcjTJ74UpuzUm84h+LblRSkbm X-Google-Smtp-Source: AGHT+IGwPB1GFSjRoBmS3GQpFszcsrN4KJc0O9NPPgZ8/Y4ltluK3hfy/zuz8QPq8j5aMj3h0YLSTA== X-Received: by 2002:a05:6402:84f:b0:5d9:f1f8:e752 with SMTP id 4fb4d7f45d1cf-5db7d319633mr15938342a12.19.1737463657802; Tue, 21 Jan 2025 04:47:37 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5db73670cf8sm7153591a12.19.2025.01.21.04.47.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 04:47:37 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v2 2/5] audio: connect VCP profile client to MediaTransport Date: Tue, 21 Jan 2025 13:47:15 +0100 Message-Id: <20250121124718.3995904-3-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> References: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 It is now possible to control absolute volume of remote volume renderer device via dbus and also get notifications if the volume changes. --- Makefile.plugins | 2 +- profiles/audio/transport.c | 37 +++++++++++++++++++------ profiles/audio/vcp.c | 57 ++++++++++++++++++++++++++++++++++++-- profiles/audio/vcp.h | 12 ++++++++ 4 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 profiles/audio/vcp.h diff --git a/Makefile.plugins b/Makefile.plugins index 97335d643..81cf3155a 100644 --- a/Makefile.plugins +++ b/Makefile.plugins @@ -128,7 +128,7 @@ endif if VCP builtin_modules += vcp -builtin_sources += profiles/audio/vcp.c +builtin_sources += profiles/audio/vcp.h profiles/audio/vcp.c endif if MICP diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c index a4198d23a..eff95a7c2 100644 --- a/profiles/audio/transport.c +++ b/profiles/audio/transport.c @@ -55,6 +55,7 @@ #include "media.h" #include "transport.h" #include "bass.h" +#include "vcp.h" #define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1" @@ -1420,6 +1421,7 @@ static const GDBusPropertyTable transport_bap_uc_properties[] = { { "Location", "u", get_location }, { "Metadata", "ay", get_metadata }, { "Links", "ao", get_links, NULL, links_exists }, + { "Volume", "q", get_volume, set_volume, volume_exists }, { } }; @@ -2188,6 +2190,17 @@ static void bap_connecting(struct bt_bap_stream *stream, bool state, int fd, bap_update_links(transport); } +static int8_t transport_bap_get_volume(struct media_transport *transport) +{ + return bt_audio_vcp_get_volume(transport->device); +} + +static int transport_bap_set_volume(struct media_transport *transport, + int8_t volume) +{ + return bt_audio_vcp_set_volume(transport->device, volume) ? 0 : -EIO; +} + static void transport_bap_destroy(void *data) { struct bap_transport *bap = data; @@ -2411,7 +2424,8 @@ static void *transport_asha_init(struct media_transport *transport, void *data) transport_bap_init, \ transport_bap_resume, transport_bap_suspend, \ transport_bap_cancel, _set_state, \ - transport_bap_get_stream, NULL, NULL, NULL, \ + transport_bap_get_stream, transport_bap_get_volume, \ + transport_bap_set_volume, NULL, \ _update_links, transport_bap_destroy) #define BAP_UC_OPS(_uuid) \ @@ -2573,17 +2587,18 @@ struct btd_device *media_transport_get_dev(struct media_transport *transport) void media_transport_update_volume(struct media_transport *transport, int8_t volume) { - struct a2dp_transport *a2dp = transport->data; - if (volume < 0) return; - /* Check if volume really changed */ - if (a2dp->volume == volume) - return; + if (media_endpoint_get_sep(transport->endpoint)) { + struct a2dp_transport *a2dp = transport->data; - a2dp->volume = volume; + /* Check if volume really changed */ + if (a2dp->volume == volume) + return; + a2dp->volume = volume; + } g_dbus_emit_property_changed(btd_get_dbus_connection(), transport->path, MEDIA_TRANSPORT_INTERFACE, "Volume"); @@ -2628,11 +2643,15 @@ void media_transport_update_device_volume(struct btd_device *dev, /* Attempt to locate the transport to set its volume */ for (l = transports; l; l = l->next) { struct media_transport *transport = l->data; + const char *uuid = media_endpoint_get_uuid(transport->endpoint); if (transport->device != dev) continue; - /* Volume is A2DP only */ - if (media_endpoint_get_sep(transport->endpoint)) { + /* Volume is A2DP and BAP only */ + if (media_endpoint_get_sep(transport->endpoint) || + strcasecmp(uuid, PAC_SINK_UUID) || + strcasecmp(uuid, PAC_SOURCE_UUID) || + strcasecmp(uuid, BAA_SERVICE_UUID)) { media_transport_update_volume(transport, volume); break; } diff --git a/profiles/audio/vcp.c b/profiles/audio/vcp.c index 175275f2e..a0c77d45f 100644 --- a/profiles/audio/vcp.c +++ b/profiles/audio/vcp.c @@ -51,6 +51,9 @@ #include "src/log.h" #include "src/error.h" +#include "vcp.h" +#include "transport.h" + #define VCS_UUID_STR "00001844-0000-1000-8000-00805f9b34fb" #define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1" @@ -83,6 +86,33 @@ static struct vcp_data *vcp_data_new(struct btd_device *device) return data; } +static bool match_data(const void *data, const void *match_data) +{ + const struct vcp_data *vdata = data; + const struct bt_vcp *vcp = match_data; + + return vdata->vcp == vcp; +} + +int8_t scale_volume_vcp2transport(uint8_t volume) +{ + /* Transport has volume range 0-127, VCP has range 0-255 */ + return volume / 2; +} + +uint8_t scale_volume_transport2vcp(int8_t volume) +{ + return volume * 2; +} + +static void vcp_volume_changed(struct bt_vcp *vcp, uint8_t volume) +{ + struct vcp_data *data = queue_find(sessions, match_data, vcp); + + if (data) + media_transport_update_device_volume(data->device, scale_volume_vcp2transport(volume)); +} + static void vcp_data_add(struct vcp_data *data) { DBG("data %p", data); @@ -93,6 +123,7 @@ static void vcp_data_add(struct vcp_data *data) } bt_vcp_set_debug(data->vcp, vcp_debug, NULL, NULL); + bt_vcp_set_volume_callback(data->vcp, vcp_volume_changed); if (!sessions) sessions = queue_new(); @@ -103,12 +134,12 @@ static void vcp_data_add(struct vcp_data *data) btd_service_set_user_data(data->service, data); } -static bool match_data(const void *data, const void *match_data) +static bool match_device(const void *data, const void *match_data) { const struct vcp_data *vdata = data; - const struct bt_vcp *vcp = match_data; + const struct btd_device *device = match_data; - return vdata->vcp == vcp; + return vdata->device == device; } static void vcp_data_free(struct vcp_data *data) @@ -137,6 +168,26 @@ static void vcp_data_remove(struct vcp_data *data) } } +int8_t bt_audio_vcp_get_volume(struct btd_device *device) +{ + struct vcp_data *data = queue_find(sessions, match_device, device); + + if (data) + return scale_volume_vcp2transport(bt_vcp_get_volume(data->vcp)); + + return 0; +} + +bool bt_audio_vcp_set_volume(struct btd_device *device, int8_t volume) +{ + struct vcp_data *data = queue_find(sessions, match_device, device); + + if (data) + return bt_vcp_set_volume(data->vcp, scale_volume_transport2vcp(volume)); + + return FALSE; +} + static void vcp_detached(struct bt_vcp *vcp, void *user_data) { struct vcp_data *data; diff --git a/profiles/audio/vcp.h b/profiles/audio/vcp.h new file mode 100644 index 000000000..f313cd96a --- /dev/null +++ b/profiles/audio/vcp.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2024 StreamUnlimited Engineering GmbH + * + * + */ + +int8_t bt_audio_vcp_get_volume(struct btd_device *device); +bool bt_audio_vcp_set_volume(struct btd_device *device, int8_t volume); From patchwork Tue Jan 21 12:47:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 13946246 Received: from mail-ed1-f49.google.com (mail-ed1-f49.google.com [209.85.208.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A96D1F2376 for ; Tue, 21 Jan 2025 12:47:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463664; cv=none; b=GqGdcJDIlDsIW/zuwED0bkT3fwGoMPMlZddu/tZCtmkSyJ38vbywSfZVZKnJNvjZjsly2RueR/apB184/K5apy0C7Eep3OEbxG/fZI4kAGenHWfLRNW3NKmMiLBqs2oIMUaeM/FyMXAzEwicw5UHRUvBESl9viFNq7i6BSf4lzM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463664; c=relaxed/simple; bh=TqiJSHNq+e3qqPdiBb4X9IRUX8pgul3fXpmo5HKqD8Q=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=BL2pK6xa4Ng1J6xwEekczcInGbo7AnSaq3pYuBLSpj2Ua1D72Psrmb7SopHluLn4e6kz3umuP8b2MqPR+j7LNmIyr/ZQ0No9AcJm013K6hY3fE6T8dT9vtAAcfJiSpL6GeVlir/9dbvmax9rGQ/41QjnePbRvBYtuQ+NsICZ5Wo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com; spf=pass smtp.mailfrom=streamunlimited.com; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b=t56KfbwX; arc=none smtp.client-ip=209.85.208.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b="t56KfbwX" Received: by mail-ed1-f49.google.com with SMTP id 4fb4d7f45d1cf-5da12190e75so11436478a12.1 for ; Tue, 21 Jan 2025 04:47:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737463659; x=1738068459; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=2I3MtPMq1q/q7OhoezyHC+aX2aZ5CTAnHXUsCORbDLU=; b=t56KfbwXMXXFE5nDrqW/mbq/sXmUuoxKJFjY11qQmYKs3B8h+f0tb8wWgpvSjgDh6c S7i8cwNVY9ePDqkhhguzPQdYld5muccqGHGBCJdVhl6pvsAkLZS1bi55WXVNtBCMlsso N2EoBWHRMI+RnNgBuIHlrJRUom5HdNiv8CAbM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737463659; x=1738068459; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2I3MtPMq1q/q7OhoezyHC+aX2aZ5CTAnHXUsCORbDLU=; b=UG+CsocMgbrhcTvAvAr17BXSzZRSwyxJosmkIfzl8RTei5wh0vk7z+EHnOnvUuYbiz bkCCCLJ/Ax1IcrLUgOr3zKb1n6NwWBtuCXoTMYHCOzbGxSWUsmoWtQHiQkVpsFCO6wy7 5aJ7OYio4y7c68GGZpsDgtFz96TyodWIN0hWgrrGVkOcS6D1/Vap3ddqNlX0OY+XGls/ 7JRJ3XiRnyn898tYdxJahKQSYejkDy+i91DjZdZ8Y5ipq1yZyddHL3jdV4MGTU4MCQS/ f+AVfn0fn+8Ll/csmZKhxSKG0yz/NqHr76K+LhuSsd6+ur9sUVRR71qGHsd/iUWpJCMl OaSA== X-Gm-Message-State: AOJu0YySWidAAMFqi10fvQ2x/w3RW6P676wjsjvQ/tAgyvKQ15nLaIfL 2C4ACH2WHwUUHdRKQyfvBjDlx3T5uwbKUucc+vG3EShBiqVUITXRzuXDuaXxQa83beGQ1JC0/4c = X-Gm-Gg: ASbGnct58nB0eNvDSCguYFJBSquHKGHK4fE5ZuKcMVhHo6J6Fl05KNaNjacq3isSorV mez+2BsmggTOpnNE5aNxUo5Hqrw0Hs2O+3jpjEvmT3rD0TJJUPxFqPKJLAQRtLVQ9XVEwY2O4uv hVsqQn6BA+hzgm/2QAj8bQfQLcrIxtR0nnOzmuSOoAfj8t8FdSlErxOIoRMcNxs2q6tfZg85pM4 ZE7UiJqbV/fS5KhN/s2876DabNDHkGVAsCJ5m6Yd/iT1ZEvsPPnFd7R4vnZCDvNfOlKprhjgvDG ODfS6x6Y228Dyuv1K8bU4tgPMT1+R6NS8diO2AgpLuTJ X-Google-Smtp-Source: AGHT+IGOmbDMgp0gM4hHjjXFBth+m2UszKCk8BkNW1F1J3nwmIB9n3MIuWtvtcF7WB9eQa/KdTKGxQ== X-Received: by 2002:a05:6402:3510:b0:5d9:84ee:fef1 with SMTP id 4fb4d7f45d1cf-5db7d2e7efemr13730993a12.4.1737463659267; Tue, 21 Jan 2025 04:47:39 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5db73670cf8sm7153591a12.19.2025.01.21.04.47.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 04:47:39 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v2 3/5] shared/vcp: fix memory & connection management Date: Tue, 21 Jan 2025 13:47:16 +0100 Message-Id: <20250121124718.3995904-4-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> References: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Those changes are mandatory to be able to connect to the same VCP renderer more than once without need to restart bluez - don't call vcp_detached on all cbs, as it would clean up too many (all) device-related objects - vcs members can be already set when connecting for the second time --- src/shared/vcp.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/shared/vcp.c b/src/shared/vcp.c index abc5a35a3..683650f31 100644 --- a/src/shared/vcp.c +++ b/src/shared/vcp.c @@ -392,10 +392,10 @@ void bt_vcp_detach(struct bt_vcp *vcp) if (!queue_remove(sessions, vcp)) return; - bt_gatt_client_unref(vcp->client); - vcp->client = NULL; - - queue_foreach(vcp_cbs, vcp_detached, vcp); + if (vcp->client) { + bt_gatt_client_unref(vcp->client); + vcp->client = NULL; + } } static void vcp_db_free(void *data) @@ -489,6 +489,7 @@ static void vcp_debug(struct bt_vcp *vcp, const char *format, ...) static void vcp_disconnected(int err, void *user_data) { + /* called only when this device is acting a a server */ struct bt_vcp *vcp = user_data; DBG(vcp, "vcp %p disconnected err %d", vcp, err); @@ -508,12 +509,15 @@ static struct bt_vcp *vcp_get_session(struct bt_att *att, struct gatt_db *db) return vcp; } + /* called only when this device is acting a a server */ vcp = bt_vcp_new(db, NULL); vcp->att = att; bt_att_register_disconnect(att, vcp_disconnected, vcp, NULL); - bt_vcp_attach(vcp, NULL); + if (!sessions) + sessions = queue_new(); + queue_push_tail(sessions, vcp); return vcp; @@ -2344,7 +2348,7 @@ static void foreach_vcs_char(struct gatt_db_attribute *attr, void *user_data) DBG(vcp, "VCS Vol state found: handle 0x%04x", value_handle); vcs = vcp_get_vcs(vcp); - if (!vcs || vcs->vs) + if (!vcs) return; vcs->vs = attr; @@ -2361,7 +2365,7 @@ static void foreach_vcs_char(struct gatt_db_attribute *attr, void *user_data) DBG(vcp, "VCS Volume CP found: handle 0x%04x", value_handle); vcs = vcp_get_vcs(vcp); - if (!vcs || vcs->vol_cp) + if (!vcs) return; vcs->vol_cp = attr; @@ -2373,7 +2377,7 @@ static void foreach_vcs_char(struct gatt_db_attribute *attr, void *user_data) DBG(vcp, "VCS Vol Flag found: handle 0x%04x", value_handle); vcs = vcp_get_vcs(vcp); - if (!vcs || vcs->vf) + if (!vcs) return; vcs->vf = attr; From patchwork Tue Jan 21 12:47:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 13946247 Received: from mail-ed1-f52.google.com (mail-ed1-f52.google.com [209.85.208.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E08B31F03C3 for ; Tue, 21 Jan 2025 12:47:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463664; cv=none; b=HULD63adwjd7UVmXTCPo7uuCQTk6Dijm2EFlS3fGFmfykaD5IwPCMyhMlYFbYTkRiEXUyOhaW/tO122klJbvu8zZ4pw3yVKODxgpD9GyJk6ASvcY7pVXqBwP2MEUpVkjqvFXZghuUD+RguuxlqdBuzj4qF6PIYaC6/Ua+M4qDMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463664; c=relaxed/simple; bh=Ht2bEvcviyDOnuUoUna0SildHQ02MGAV1ztnDIlhDAw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=abeeR9jDPWnmn5Ix1a61VARsHaYle1DPMIAGKenxnEMi4+7LtVhEpsLWmfUX5X57n17b7tKBI/Wyufa6+XGFPOmSFgh9m1syJ2xujPb9MOW5XdL9M43LqRtoMu9shw3b3DwuzrWD4X7fB6xSC21cpgvlDDl2PC1ai4qYI3rYAWI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com; spf=pass smtp.mailfrom=streamunlimited.com; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b=F7ugaUEU; arc=none smtp.client-ip=209.85.208.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b="F7ugaUEU" Received: by mail-ed1-f52.google.com with SMTP id 4fb4d7f45d1cf-5d0d32cd31aso8388277a12.0 for ; Tue, 21 Jan 2025 04:47:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737463661; x=1738068461; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+/Rk6pDXs8zGzcrI1wCYal82gpP98EkNSIPLnCPhbco=; b=F7ugaUEURh4FjI7aKjhOmggyAf9vM5uEoWurkKdSBX5uCGTO6Le4KwoJcsefyxB3DE oTqPttayC3CRbzNyomWIuJ5x85Q/xBU9rYFyl54C02/G9nXii9L7kttFcjDKhcm3McbN EAbmL4s9AHqZpr/uJ9dhoYcErYCAbGRzqOEKA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737463661; x=1738068461; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+/Rk6pDXs8zGzcrI1wCYal82gpP98EkNSIPLnCPhbco=; b=Ztg+DNAarmLA/KetQTdHSZh9H9+cNeYRgzUhwR/Q4dG1zg3IPcCM/g4P9oyl7EchnM uTxoTS4FsV0+DEJm30OlL0eWujgKceRWEJ4vbCUvq2wB1wczb4iIy0KlR7f5sGCWOYre M0sYkGPk66MP+4Oqo2dkxQYuzk079KocMYDNd0N01ce7t+VfbPqSHoBqq89x3Z3rzc6e 3yZKLmHRS/27RH9eDUmgyFD6LM2SyV5j4+JLJahDPS76oMy2SYm1ay5fn6+H9NthPE7w LJE5QEpwm93KEZCfLJ0iJATZPfc9e0ZJndcjcCx+TjC1nneQQr48pDZ5nLLnQROKnFlx KgAg== X-Gm-Message-State: AOJu0YwieTiUCJ17P4oLHZmxS4bfwS2v0Eha8e9HhXM0UJAPeBV9qTPa GrmfY7BFGtg4CWTdH7v4tPhPp4TJXnwdWlEbkD/vlYqD0gY5T1M44sg1ysPPWRHimiG+VVWKlVU = X-Gm-Gg: ASbGncuRaDwxdYC2RDbeI7tf/g0j2JiQCGeWpGToIZkaRAj9C9Z3KRx42MHbziyJv+V TDZv910x6JoLL63Zexe7cnJsl4CnVhwKQNg68tjwZxV/4IiunK3rpjJU7tV/dnJr0gzoLKR3XhB rTRSXvEHwR/hON5I6cux47IJGrRkYaRwJTuFxv6GTNndOQ8TsuFHFxxqqgo+QU6m8WmQk+y+XNY E8CDfli6FD1XiQVUiBGPt1Qx3sFShMOHbUEytIY2VOhmcc4FC7U+wZ+r/UnvftG4SpncHllYy50 gvQSnoIu6Yrgp+mzxzJk4BQk2v3FBe5HZ6mQ+IxAIfxb X-Google-Smtp-Source: AGHT+IGZ+cPtfWjV65USxxCd36UuFPVAG3i6SE4uH3HWAWL5+SaSrn3T3roxqPMTrm22bc+538QpKQ== X-Received: by 2002:a05:6402:2791:b0:5d0:abb8:7a3 with SMTP id 4fb4d7f45d1cf-5db7d2dc6bcmr46275959a12.6.1737463660756; Tue, 21 Jan 2025 04:47:40 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5db73670cf8sm7153591a12.19.2025.01.21.04.47.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 04:47:40 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v2 4/5] audio: fix VCP connection management Date: Tue, 21 Jan 2025 13:47:17 +0100 Message-Id: <20250121124718.3995904-5-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> References: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Those changes are mandatory to be able to connect to the same VCP renderer more than once without need to restart bluez. - use vcp_disconnect() to close client connection and reset vcs members - call bt_vcp_detach() the same way as bt_vcp_attach - from btd_profile callback --- profiles/audio/vcp.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/profiles/audio/vcp.c b/profiles/audio/vcp.c index a0c77d45f..dc21771f1 100644 --- a/profiles/audio/vcp.c +++ b/profiles/audio/vcp.c @@ -72,7 +72,16 @@ static void vcp_debug(const char *str, void *user_data) static int vcp_disconnect(struct btd_service *service) { + struct vcp_data *data = btd_service_get_user_data(service); DBG(""); + + if (!data) { + error("VCP service not handled by profile"); + return -EINVAL; + } + bt_vcp_detach(data->vcp); + + btd_service_disconnecting_complete(service, 0); return 0; } @@ -188,7 +197,7 @@ bool bt_audio_vcp_set_volume(struct btd_device *device, int8_t volume) return FALSE; } -static void vcp_detached(struct bt_vcp *vcp, void *user_data) +static void vcp_remote_client_detached(struct bt_vcp *vcp, void *user_data) { struct vcp_data *data; @@ -203,7 +212,7 @@ static void vcp_detached(struct bt_vcp *vcp, void *user_data) vcp_data_remove(data); } -static void vcp_attached(struct bt_vcp *vcp, void *user_data) +static void vcp_remote_client_attached(struct bt_vcp *vcp, void *user_data) { struct vcp_data *data; struct bt_att *att; @@ -354,7 +363,8 @@ static int vcp_init(void) if (err) return err; - vcp_id = bt_vcp_register(vcp_attached, vcp_detached, NULL); + vcp_id = bt_vcp_register(vcp_remote_client_attached, + vcp_remote_client_detached, NULL); return 0; } From patchwork Tue Jan 21 12:47:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 13946248 Received: from mail-ed1-f53.google.com (mail-ed1-f53.google.com [209.85.208.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8628B1EF0AF for ; Tue, 21 Jan 2025 12:47:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463666; cv=none; b=Ox03wcoR8KSx/m2C+08QBtyuxK161ETDqUgFjzD9idgSgajUAWFGfxAj5C4g+dgLXqRYK6NMNW//Bry8Qpq7WV1GO8NRYbLXo6T2r1RXLgl3ooD5v/fuAewmO06h4sTgaNbD/qQiLdeZ5Yjq0dcWf9KEmTNjye4HPRChkYGeD5E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737463666; c=relaxed/simple; bh=us7BX9z3JbNUm1iwU4gbVF2qCYXv2kzA2cq2Zi/POMM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nZd6tStGfaw4bdEIwWJ0uF2eLcYu8ESlnGove8tC1/ywBooOwv39bIqDhrpaNyO2f51uaduOiRQGhPv4oXx5vNFz8D0tqx1Dv5SBQEmPDjpgVXA1nYJ0C+fIP2feTC8mkaxxlIGfAipmNbKAfwApK7uzKAPIwEAxL+Ez1X6OFL0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com; spf=pass smtp.mailfrom=streamunlimited.com; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b=Rmw83k0c; arc=none smtp.client-ip=209.85.208.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=streamunlimited.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=streamunlimited.com header.i=@streamunlimited.com header.b="Rmw83k0c" Received: by mail-ed1-f53.google.com with SMTP id 4fb4d7f45d1cf-5d3d0205bd5so8987240a12.3 for ; Tue, 21 Jan 2025 04:47:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737463662; x=1738068462; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0EBgcxkfUJPQfZObbMHq5EhfZB/o0AHpwA81k4Z0yUo=; b=Rmw83k0cI81/yruSQjPxShv83MQLJmZCOciLyRkZYPrMb4dnWaa+bp7EcyIvNfGR7Z AaOi85Wt0HbAaM2u46yjjdWFEuAQJguZozsIXXjwRkiP4XclPFd+9vbOoqnIYm5oN2dH sdE7U6XCw5DjPrGUgrQLz/Qdm5tOmEMYkUg/g= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737463662; x=1738068462; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0EBgcxkfUJPQfZObbMHq5EhfZB/o0AHpwA81k4Z0yUo=; b=nupJaYEhpm8wkYHBMpm0wqzTdjHHFyyfzs3tLcvkjXGSqXVDyIgdxHJMD+kUt1iXcH dmpuEvokH13W+pzBSVQsO/LH3aLtPjLgc32WWFuqRWc0WnrmijwBGpdPz+F2CxazOdzf PPvKbHz6WEt/W/oMNyUlgYi46PypPt4Z/kPrbuEYo3+geRgLwJdRB5a+aQzTkahJf3ef cbn1HbuPij5U9wffiVymPC1SIlGJ/6YeOalJI5YNX9lAthgrRHUC9CwAi354FyYg77Jm OcGH5bINC6xl1iXh4fwn8lEgrDizDK+dvu+4BfomORmaoxt/HFj1y/SBjDzZ7q+GZyke FElQ== X-Gm-Message-State: AOJu0YyoS2JqC63FAOVS0bZSB+U7mSzYa5HVkSvn4Ls7WYwrbVQD+MM2 +MHseyxwm6v3cnJSW7aj6o2giBrl6u9mwT0dgPscn83yih/7tURw5YFHbDjuhFgDLZftNGasZYg = X-Gm-Gg: ASbGncv6Ku7UVSQy1CMXAuN2hNcoJGMT8hgIQ2GaMh/r7/0zPMCHPKVWCIF8ikS+dOX p9pj6fU/smFN+jwdPHvhc3bJC0/31yvURY7tFlrm9oZttLjS/vnjb8dnn2iTObXLmeaYkeDoG+d 6mKauXQHO5YfRjG7xbSfe2OeyfjLNuvg6kgCCxIp2r2azfXKml84QgmYJpq6Ch1ACN3W9Y2Pu8K qaO6PDODFLiFPQvbIV89C3UK3AjZeA7ON+VsLyWMcPscHCVLULYctAI2Qzsj0AN4kLMlbl/Zwof t5il7C5JztzKftVDW9YHR80/1OXUxQ5D26TPZM0H3niJ X-Google-Smtp-Source: AGHT+IG8wPa2N92av6SDmNSCWM6TqStZMdnUEcO9sWp2HuU7/ym25JUm88P51r+Wc8egDUTbE3EvAw== X-Received: by 2002:a05:6402:278f:b0:5d2:7346:3ecb with SMTP id 4fb4d7f45d1cf-5db7d2f8066mr16803487a12.12.1737463662150; Tue, 21 Jan 2025 04:47:42 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5db73670cf8sm7153591a12.19.2025.01.21.04.47.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 04:47:41 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v2 5/5] shared/vcp: control volume when acting as a server Date: Tue, 21 Jan 2025 13:47:18 +0100 Message-Id: <20250121124718.3995904-6-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> References: <20250121124718.3995904-1-michal.dzik@streamunlimited.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Local VCP chatacteristics are now connected to transport properties. --- src/shared/vcp.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/shared/vcp.c b/src/shared/vcp.c index 683650f31..7ce6d576a 100644 --- a/src/shared/vcp.c +++ b/src/shared/vcp.c @@ -379,7 +379,15 @@ static struct bt_aics *vcp_get_aics(struct bt_vcp *vcp) return vcp->rdb->aics; } -static void vcp_detached(void *data, void *user_data) +static void vcp_remote_client_attached(void *data, void *user_data) +{ + struct bt_vcp_cb *cb = data; + struct bt_vcp *vcp = user_data; + + cb->attached(vcp, cb->user_data); +} + +static void vcp_remote_client_detached(void *data, void *user_data) { struct bt_vcp_cb *cb = data; struct bt_vcp *vcp = user_data; @@ -495,6 +503,7 @@ static void vcp_disconnected(int err, void *user_data) DBG(vcp, "vcp %p disconnected err %d", vcp, err); bt_vcp_detach(vcp); + queue_foreach(vcp_cbs, vcp_remote_client_detached, vcp); } static struct bt_vcp *vcp_get_session(struct bt_att *att, struct gatt_db *db) @@ -513,6 +522,8 @@ static struct bt_vcp *vcp_get_session(struct bt_att *att, struct gatt_db *db) vcp = bt_vcp_new(db, NULL); vcp->att = att; + queue_foreach(vcp_cbs, vcp_remote_client_attached, vcp); + bt_att_register_disconnect(att, vcp_disconnected, vcp, NULL); if (!sessions) @@ -555,6 +566,10 @@ static uint8_t vcs_rel_vol_down(struct bt_vcs *vcs, struct bt_vcp *vcp, vstate->vol_set = MAX((vstate->vol_set - VCP_STEP_SIZE), 0); vstate->counter = -~vstate->counter; /*Increment Change Counter*/ + vcp->volume = vstate->vol_set; + + if (vcp->volume_changed) + vcp->volume_changed(vcp, vcp->volume); gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate, sizeof(struct vol_state), @@ -594,6 +609,10 @@ static uint8_t vcs_rel_vol_up(struct bt_vcs *vcs, struct bt_vcp *vcp, vstate->vol_set = MIN((vstate->vol_set + VCP_STEP_SIZE), 255); vstate->counter = -~vstate->counter; /*Increment Change Counter*/ + vcp->volume = vstate->vol_set; + + if (vcp->volume_changed) + vcp->volume_changed(vcp, vcp->volume); gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate, sizeof(struct vol_state), @@ -634,6 +653,10 @@ static uint8_t vcs_unmute_rel_vol_down(struct bt_vcs *vcs, struct bt_vcp *vcp, vstate->mute = 0x00; vstate->vol_set = MAX((vstate->vol_set - VCP_STEP_SIZE), 0); vstate->counter = -~vstate->counter; /*Increment Change Counter*/ + vcp->volume = vstate->vol_set; + + if (vcp->volume_changed) + vcp->volume_changed(vcp, vcp->volume); gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate, sizeof(struct vol_state), @@ -674,6 +697,10 @@ static uint8_t vcs_unmute_rel_vol_up(struct bt_vcs *vcs, struct bt_vcp *vcp, vstate->mute = 0x00; vstate->vol_set = MIN((vstate->vol_set + VCP_STEP_SIZE), 255); vstate->counter = -~vstate->counter; /*Increment Change Counter*/ + vcp->volume = vstate->vol_set; + + if (vcp->volume_changed) + vcp->volume_changed(vcp, vcp->volume); gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate, sizeof(struct vol_state), @@ -713,6 +740,10 @@ static uint8_t vcs_set_absolute_vol(struct bt_vcs *vcs, struct bt_vcp *vcp, vstate->vol_set = req->vol_set; vstate->counter = -~vstate->counter; /*Increment Change Counter*/ + vcp->volume = vstate->vol_set; + + if (vcp->volume_changed) + vcp->volume_changed(vcp, vcp->volume); gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate, sizeof(struct vol_state), @@ -2008,7 +2039,7 @@ uint8_t bt_vcp_get_volume(struct bt_vcp *vcp) return vcp->volume; } -bool bt_vcp_set_volume(struct bt_vcp *vcp, uint8_t volume) +bool bt_vcp_set_volume_client(struct bt_vcp *vcp, uint8_t volume) { struct bt_vcs_client_ab_vol req; uint16_t value_handle; @@ -2044,6 +2075,39 @@ bool bt_vcp_set_volume(struct bt_vcp *vcp, uint8_t volume) return true; } +bool bt_vcp_set_volume_server(struct bt_vcp *vcp, uint8_t volume) +{ + struct bt_vcp_db *vdb = vcp_get_vdb(vcp); + struct vol_state *vstate; + + vcp->volume = volume; + + if (!vdb) { + DBG(vcp, "error: VDB not available"); + return false; + } + + vstate = vdb_get_vstate(vdb); + if (!vstate) { + DBG(vcp, "error: VSTATE not available"); + return false; + } + + vstate->vol_set = vcp->volume; + vstate->counter = -~vstate->counter; /*Increment Change Counter*/ + gatt_db_attribute_notify(vdb->vcs->vs, (void *) vstate, + sizeof(struct vol_state), bt_vcp_get_att(vcp)); + return true; +} + +bool bt_vcp_set_volume(struct bt_vcp *vcp, uint8_t volume) +{ + if (vcp->client) + return bt_vcp_set_volume_client(vcp, volume); + else + return bt_vcp_set_volume_server(vcp, volume); +} + static void vcp_voffset_state_notify(struct bt_vcp *vcp, uint16_t value_handle, const uint8_t *value, uint16_t length, void *user_data)