From patchwork Tue Jan 21 14:44:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 859029 Received: from mail-lf1-f41.google.com (mail-lf1-f41.google.com [209.85.167.41]) (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 B87AF1F1508 for ; Tue, 21 Jan 2025 14:44:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470668; cv=none; b=LAOwNAvSiMzm956wpd2/Uf3Mlqep8xx7sVRvwU0eRCsMp2BiSTlLi4yUSb7sNZkffvpAOuI/iC0GXO0UtXfBW5dYbGXj1MjAdVqzuKIMF9RXO+O4edPndq6HuyPm7BCBbc5COnw5My707x2BFvtQmIxFnTGxlsTPUv5ntu7S0o0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470668; c=relaxed/simple; bh=sO+dboodXBdmqOHqDW2Ro0yGw2C8mpljwEwLlBSPMNU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=MiSDqJvdUicpZZmLH/b4OvUa6CAFMaPoHrkqtB0uQBx2VDBb87UzIT9/IPhjx9DgSfrJi2MAKJu+IC29sWHpOAdjMBrT6YL+TZbVwTRWAwktrpua+7AwMqZA9Wu7hcvLj2ES/i2UMp/I1FJzTZ4hqX2wSwCXNKsvmW8RPlKuTCQ= 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=IBAHoBm4; arc=none smtp.client-ip=209.85.167.41 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="IBAHoBm4" Received: by mail-lf1-f41.google.com with SMTP id 2adb3069b0e04-53df80eeeedso5702819e87.2 for ; Tue, 21 Jan 2025 06:44:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737470663; x=1738075463; 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=IBAHoBm4xuWlJVpHzXBfW7ZGLIlnnSGLet/+fU91F3CtiFMZNbZnbgAJgtE0WbYwZH bWZHcGpy+hs54VZK2JQsgpLdG21xqsAkf6MaDd8nXO1y/jcjSmTkR9HlAI0jltfmvP5j A/RFJBC4bUfbrsuL2TX3dmEc5E13mdhkb6vLw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737470663; x=1738075463; 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=aRrDFhJdb4w4dqMRHk4MaPdNyS1q9jGRUZe4t89NIqsvf7v+MhaB1hpJ6j4fpUUSCY 4E1d2HTJgDABczSXuNCRefk0JUPEf+MkxjkP0ZAb4mGxOVXKhbQ4I7+KBydfe2Qmqb7i OcZWRE6KeJ5KNuehCJ1jXEMunQt3vjmnxgubZfy8PzId1m1ZzlGbhPkITA5wMhIV0QRo 6Q0KYxSEWc224SRHd0YALaN4JOtIpTq7I8n/aCSvtHdjhSc2EOFr1bvVlnF5BeLAK/FS w5ZcXTpxxK6kuSOLFGZh3R7ZPWTDHzcUH+vWoEyqQgdKRmuhOJKDRIqBe3GV8EnRks4i B5hg== X-Gm-Message-State: AOJu0YyZLnjR2lvh9NfJAtDu7kHJoWjNryDViu2WkRKO7l33SzAmhZns +Jyefa8NhgPNoVjJh4jkdORqSL1eIHTHt/xIBV1ga6zY29aKme8NWRDrLJJOV0XC2zrtMzUzQmo = X-Gm-Gg: ASbGnctNEu+373cnxO6tHSmj3zaCGj26mvnZ1L6NzOawHuJxcPCovD76Qw+f3IuwpaV T7E1yWguozhhQIrvybB9oxefweKw16RbD8OkAFZ9RNJbkKwPDTLcx30laJ0pV9hlFXc6TLnR47+ ayBKH34mIwOjCCYM0KmcTbH+6QGS7gYdFMGf5lmCVIb7IK+uU2PHV6EKZvPWdtDktumn113Wwnb e4fFFqUq9oAZdCxTXZCLXToOCfbSAQNDUQywMxaj4DpDXXUM7NgiOvX5P/Ai9ke/R/0RGG2iheW TEyVh8AuQfl3OWiUPUwEJV13AO+vwByZBw3w4qLcmpNo X-Google-Smtp-Source: AGHT+IGixtvvYJTXX28Vaeb6aFbJ3zY3cFLSYujqyVjEImM/mVIm7j5mRXIF1rEgXZq9RJx9Wy53qw== X-Received: by 2002:ac2:5230:0:b0:541:1c48:8c0d with SMTP id 2adb3069b0e04-5439c285a31mr5438349e87.49.1737470663166; Tue, 21 Jan 2025 06:44:23 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5439af733fdsm1866237e87.174.2025.01.21.06.44.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 06:44:22 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v3 1/5] shared/vcp: add API to control volume on VCP client Date: Tue, 21 Jan 2025 15:44:00 +0100 Message-Id: <20250121144404.4087658-2-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121144404.4087658-1-michal.dzik@streamunlimited.com> References: <20250121144404.4087658-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 14:44:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 859863 Received: from mail-lf1-f48.google.com (mail-lf1-f48.google.com [209.85.167.48]) (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 878491F3D3B for ; Tue, 21 Jan 2025 14:44:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470669; cv=none; b=WCzfDXv0ip/2njgBO8kyrQtAEnSWz1jlykqjlQjpM7+8cBf9t8sV55RDOfDDl8Ky/jO1TjrPv6beNtonzCZOFGDUhXpApDaXrK6XSnaEowM+BoCVXsh3MIb3ADu1czucndGZ0KL7Te9NfcY24Aci7Hsx+StQxHh2+hepcf9nVgo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470669; c=relaxed/simple; bh=Z56dix/oiDp+VMSmG299Rw694eEi0cQPz+U0fe4Ixrk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=D1WAebIF43ZcKIO1Fl4LlLPKkZZJ2Xz9zmA1iiw7KCt4FqWKiX34zjwkZ6NeMaSWL6aGY6+8jvteOLfEyoNu7KvpoaL6wqKSdT9tamzDJ4nMbiwUEBLjbepDvQCXqr9c2eEYDtIlSThU1295+szyAVrjjJH7B9m0OMFe286J9EA= 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=UfC4v0zt; arc=none smtp.client-ip=209.85.167.48 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="UfC4v0zt" Received: by mail-lf1-f48.google.com with SMTP id 2adb3069b0e04-53e3778bffdso6014721e87.0 for ; Tue, 21 Jan 2025 06:44:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737470664; x=1738075464; 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=NyBSdaXHd09I3bbfigjja1hooXBxREedZ4We5DQhlcc=; b=UfC4v0ztfzSe7XoJrwUylX7691RNc3f1BKuq3MAKrRvkC8TuxUrVfDdUtOKbllhA2P k7FWkMEz8IjZakm0jfIbvYgOVU+nV6VUugNvqPT9ZlZ+uJ7ZzaKN+4rSk6itcVYbtO1e nIo16n4tmIow9eqgqQDf3jX61r8URv0lt+hTI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737470664; x=1738075464; 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=NyBSdaXHd09I3bbfigjja1hooXBxREedZ4We5DQhlcc=; b=Y6FP07ipc1DvNACUBSVNBgctTNcI/qjRKLOR8SKxxhWnD+FZWUTq+OXfsawbQSkOIj 5z7mvJXpwZkSTauUtcNTlvKYn04QgBkghtEIEWe+5O5wrZZxxqV0xUBgGHEjo5JKYnMa +2hoqX9hgugWH2eGzyx0BKYnG7sMse31Alin5KdF+hAR1mWct4JAl8sfpLqewkXGZ25T E1T2/G+rC+KnWVDGfmkaPLnzOGWDdbRmhRKvX7YgXRyckW4I8uVgymwDV9NEkHeACGkj eQjhHft8orazmOLSVkrrpTjXN4AsEYdvVp+wKLfdzOGbWasHd6sm+YN3KEY4MbyxGeej WZ5Q== X-Gm-Message-State: AOJu0YwoITpYHASJXGDgVAsEpie2tzcbJtyj1B2uv1Mcj8VpBJtNZq08 GWx0KIVq1V9hkcL+kAtl+luQfQp/fsjyiv3D2MkcdAuD+XWag6xq60qoOEfV4KOYUs5SaC8DciA = X-Gm-Gg: ASbGnctktrR9fV9OGHbQYeKPjeNMgXOc1LdbXeBo0Vk5Cedjfb0tYOqrxv9rj2s/4pG HFspgFU2LZMgwrx8KkCi6+GZ6eZ8Gw6LZn4lrK1cfC85N8pMtUkXdRveeWG/Mpc1t57xlcogK0o DCPuVpp0ghfKasa2QnAqquGCAbav8PQJrCG6CLyFZNBDaptUAPUQGCtyTIjgEsE9ct9piQio7yZ x++n1kWAtGDOcpWjzAOFt6qPVIAh5mdzQNoEFV0/EfkBHVPB2Jgo2rLkHbjrGUBPW1wMzV7C88R fDqnX/w9VxNoHBK++IMfGIyf6vvdbNSWFx2n0Jb0Jivt X-Google-Smtp-Source: AGHT+IEms4+idAwtagJdGPwGnvF2Ht0t+9FLI8EKz7XT9ERiW19mSuwonT0Zg4WAfa6X7XgrhmYeSA== X-Received: by 2002:a05:6512:1252:b0:542:2486:697b with SMTP id 2adb3069b0e04-5439c22a85bmr5990559e87.10.1737470664259; Tue, 21 Jan 2025 06:44:24 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5439af733fdsm1866237e87.174.2025.01.21.06.44.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 06:44:23 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v3 2/5] audio: connect VCP profile client to MediaTransport Date: Tue, 21 Jan 2025 15:44:01 +0100 Message-Id: <20250121144404.4087658-3-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121144404.4087658-1-michal.dzik@streamunlimited.com> References: <20250121144404.4087658-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..cc6f352c1 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; +} + +static int8_t scale_volume_vcp2transport(uint8_t volume) +{ + /* Transport has volume range 0-127, VCP has range 0-255 */ + return volume / 2; +} + +static 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 14:44:02 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 859028 Received: from mail-lf1-f52.google.com (mail-lf1-f52.google.com [209.85.167.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 6CCCB1F3FC0 for ; Tue, 21 Jan 2025 14:44:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470670; cv=none; b=uApWD8mP5lBUk8x/PfQUf7mc42P9jUuLWF3+PLYBsBCUV45R8IXjl9OtqGVUJThopJRHD6tY6GSOyAR1qDvGuq+79j+VubJECIQxDAx8DI0LuCSJYfNETlp9F8JxSnR2PU5V5xTPctmsBjdUqZa4XqCpHc9XDrsHvekmofaE1jQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470670; c=relaxed/simple; bh=TqiJSHNq+e3qqPdiBb4X9IRUX8pgul3fXpmo5HKqD8Q=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YAeKL+aym6hbBo2QF8gA2WJu5/CBCItwOLg+hMpTDW5g9wWZPRYasEpONafbMqNi5PYIvNYXBKLxW9b/t1zP9Q4hdCRLI9/1zUSmBS9Ztd83DU0sRondLG/u2Q3qThkE02EaDyFCSLcx5OtYT2rL/XRUMDDsG4KssRw+xZSU+jA= 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=mBwpX1K9; arc=none smtp.client-ip=209.85.167.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="mBwpX1K9" Received: by mail-lf1-f52.google.com with SMTP id 2adb3069b0e04-5401d3ea5a1so5404925e87.3 for ; Tue, 21 Jan 2025 06:44:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737470666; x=1738075466; 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=mBwpX1K98eEQx0RoNDqN3w2hEZQ82T4liHXmPtLBE9mgg+CpAFgD815Ryjfek2tSfd ya6Wz7DSeVLy+YQGO3yeWf0JSii9ON4Ee/N5yCH/wip5uUdCA/cjb0nTcKRvucac1d2B cub1Cb3wXu8+6LCrw1iGgCIpzJRKkKFIFSDTI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737470666; x=1738075466; 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=CzP/rIO3p66BTDrbZTpLX/k8AZ/5+LkAo+MqCZaFT63XsuqtQtUQsP+umEOT9bdVe5 bmIwrfH4bulpa4Md0k3bgfwtkD0QVH+svysJKeUCxTWWrnZQB6/9UmwNlmclfpxTme2e 9cD2RBsNwkJ9y9c7Y6CLsYzf2d4WEAY7WfZnYzvaE9YXZSDnQeITn3a/427duBksaocz m0UvIzrgukqrraa+top256IwGYN66gyFkVOYAygpSodkbNIB4a9upBG0oJz8dU2iN6hN zs2DjATBaLRW0gNTeFUelG4RX3LGwmSwnQvtUAEryKbtLyyYZf1tD7nQYinSp4RVZFgA bv6A== X-Gm-Message-State: AOJu0YwhVTcQZJAEE/3pU2VRYSy2sWFsDYHWGB7EQG0f1+Wy/9cz5EV5 nLNk6nUrQdchE4izCEdYByg6TYdgKb3M+/9HWiCVpxp1WLsyPBEkAV8tcjnMcfaF2ghRpW0LMCQ = X-Gm-Gg: ASbGncv5cmQ9Wx5fxUCgYZeNLwdgH08lO3j7mk+5xA981lQqx26CZ0Gkkq+sIHQstmO VUDWHN95Av09wmGfyREXkqe3FQOtOaNFRzLtSRIoDjpJS/APdwRRzM81VqVKpOe7uwHjjhTLakc qUj8n+igGpaTXXj/PUUgigDMxdGl76giNMZ76WY4ogFQptW/SS8c+k0EYXLcvdKNOMzEEZd4nFG M1NUrt/xjmOCn3nIrKTEaO3Eg4r3mwFJj3BiVO8+tPf9AtuMVl+rasi24vsHqUz3VutfhDYDJv4 wKMRACl20KBOsgCDy7F4kKiaXlT4JwnZ3SCZEFW6QAgj X-Google-Smtp-Source: AGHT+IEEoEamsXwXiU1DBhONwJqbjiWchhtMEv98s2evJVFatA6OHwuUSdbJ4lCZ8KCIewU3J09h1g== X-Received: by 2002:a05:6512:2255:b0:542:23a9:bd44 with SMTP id 2adb3069b0e04-5439c24116dmr6311510e87.17.1737470665599; Tue, 21 Jan 2025 06:44:25 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5439af733fdsm1866237e87.174.2025.01.21.06.44.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 06:44:25 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v3 3/5] shared/vcp: fix memory & connection management Date: Tue, 21 Jan 2025 15:44:02 +0100 Message-Id: <20250121144404.4087658-4-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121144404.4087658-1-michal.dzik@streamunlimited.com> References: <20250121144404.4087658-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 14:44:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 859862 Received: from mail-lf1-f51.google.com (mail-lf1-f51.google.com [209.85.167.51]) (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 00D9049641 for ; Tue, 21 Jan 2025 14:44:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470671; cv=none; b=BzX0/T0h0b6ShnNM/qEbU4fqDqo5hMHeiQ+YRNpjBeBAVrW9nV6muVV6h7Shz7Ai2ODkZFlLHp1CZpGm7dFmOHXV2WgFz5bKXbpSY00mo2cQDbzGta4QzdkiH5+QEf2eVZEIHMX25Cf8S20AV/jdoHuuzbe+5QBvjuCrKMJSBYs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470671; c=relaxed/simple; bh=BNkubpVSm10suv+o6ql/8MFhA4pk6I5o78eI9o+qmUw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=e4kzqKdqbyF4nNIJZv8DnYndV5JD468PY29yhyfsCNeaMyAyU3tI+YY0UW5Cnidpkr8MML9MsETWTeFOPpte4v6rBjHrGPtPAy5apvxnSpubg903vrC5RMfC89VOn8sdTb5BQ/75/qYZsP2R4+XsaIr1yAMYdFLALVDS4k0I8w8= 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=ssSfVEHW; arc=none smtp.client-ip=209.85.167.51 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="ssSfVEHW" Received: by mail-lf1-f51.google.com with SMTP id 2adb3069b0e04-540215984f0so6143970e87.1 for ; Tue, 21 Jan 2025 06:44:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737470667; x=1738075467; 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=erG11dIqQwlizbPs8opfHOp1y57ZM2gmol7QUTaAt48=; b=ssSfVEHW1gYWoDIbPKzW4qz54BkejDr5TUaDk3qnGFqXH6sFmZQd9EO8QVzQPcy31n R8fa9tAJGg+/6GHoQmxSO/TpwH9eQWlhUeGi29ynnCeNI9LVqhPb4eYVqGc4lEVYs++R q7tQl7Ea9KkMVSIljQcoTPM0oZMAmlJ74XV4Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737470667; x=1738075467; 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=erG11dIqQwlizbPs8opfHOp1y57ZM2gmol7QUTaAt48=; b=AImdvCZez/rFrsU0vn5eEOAhpqdTOmepm27jTrn3O8TPg3bwXjsX+nJDnIQHCCRB37 pCGUW0QmW2EBh64hpfmkdUV+nErgUrZi0q+DhhiiMAy/CPEvD6adynltcV1vyPpdHZst H7hkzz+mDmAE1XbOPLgL0Yf7/RT4txVGCCuttUgs6BqvIjuIEZrbbDf4rrPqOHoNGQWp DM+imYuLFFaQ7yRIYYkpyg3d0kqALPkzKIviz0bhiWRiwE1B/9FuRMPnOxb+waW3CszM gaA+sOWbFkIo5vtA7e9EES5aAVeJFz+rfja+KvkTUMCKzQgLfYzXaxm3/bHnO4pJYXj8 EopA== X-Gm-Message-State: AOJu0YxgkAPhCBE4OJwEV9l9swMrsjRq6VQKmnFPJ7Xiv02YO4QYlsYB 6esreL1uXPa/5QThPul0xPSvLyyJwrdoII+egCnIM5d8uRSlgfRFxJ5FxvZckrI6VXqjt/xy3LQ = X-Gm-Gg: ASbGncu6a0dmfYmNWXl3weMbOyft0RSW6YAbyUwlvWY+FOQwGZqzWMJb9Q6+C4B20zS qXH4uAyzORsnRLQE9W/2k65J2Ioy92Mi0KsKKkYncccdigOdyH+nAWpso0rDFDBR+6MTMQBM2nv 6wcoAgRj0Lz4K9oIe9gWY4qeYks9kgz74XyLvd9c7Wyz8i0evJYZFShK8Fr6uxYU4scsqGXkdS3 2XStUUTczm71guTfP8CLeMT3a2XWKhOAG/XqTQ/2if4XRRmFPSyEvkKdx62mgiF0Fo26MrlllLJ bU0PhgRBeZXMSLPlxZRD1WVy7YDclq61FH1Y8D5DJZzg X-Google-Smtp-Source: AGHT+IFhtpSAfIXZ+g6gdTp+54oM4L8oJbLAtE62uv//FT0/X757UXG7mu92gnTdRzBtvMWAI/3PGw== X-Received: by 2002:a05:6512:32ca:b0:540:2d64:4ef4 with SMTP id 2adb3069b0e04-5439c1c8879mr7487795e87.0.1737470666786; Tue, 21 Jan 2025 06:44:26 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5439af733fdsm1866237e87.174.2025.01.21.06.44.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 06:44:26 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v3 4/5] audio: fix VCP connection management Date: Tue, 21 Jan 2025 15:44:03 +0100 Message-Id: <20250121144404.4087658-5-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121144404.4087658-1-michal.dzik@streamunlimited.com> References: <20250121144404.4087658-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 cc6f352c1..d3723515a 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 14:44:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Dzik X-Patchwork-Id: 859027 Received: from mail-lf1-f42.google.com (mail-lf1-f42.google.com [209.85.167.42]) (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 429FC1F3D3B for ; Tue, 21 Jan 2025 14:44:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470672; cv=none; b=SJY/GWj642muCAc52t5z82AC3z9kqowi+33ZZSdOnf6gnhejdU0wbGKfrZbTPWD8UpjPtwRIcn8K8G4rS2I8W//lg8WsoycQepWKPpx2u8BV7QY4NG/Gh83CBBKt+LdPq+THxeweRrFMCr+dprbRxZKsvjw+NCue/yf8aJ55h7I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737470672; c=relaxed/simple; bh=wn1B9Gx/4YVsA26SoKfQOvl6b31fvWHtAVoKIIQCEWo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kZgmDexPfAYBhuYxknY9tv6WP9xwWvVg7EGvHvy3E1HQBdhRW+l0nJBGPFWzELnLoSTrJSI6mCZu2RpwBDA/oBW8nB8V4z7sgWM5MltGaR9ioqoPEfiOY2X5t7eQeKBue3E60nx0yb3C9EKDX/moFB08mdtJKVzf11tK7e1qRwA= 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=g0SkRuWo; arc=none smtp.client-ip=209.85.167.42 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="g0SkRuWo" Received: by mail-lf1-f42.google.com with SMTP id 2adb3069b0e04-5401c52000dso6062851e87.3 for ; Tue, 21 Jan 2025 06:44:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=streamunlimited.com; s=google; t=1737470668; x=1738075468; 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=cXwEOTqnAwGpLdBgRoFBLXm/lX+EzmxiYp2YjB18kHo=; b=g0SkRuWok9W0AHGWypZ9J1Rf7JjDZQHtgx5Gk7a7HlhHXKLqt9aQf4BXquICRBY6le tr/tVXPNS9Y414HgtB+QFR0eiJIqKra/Ulc/91RvaVvVCNtrUNPCzYK3zG1w3Glq8JHf JNe7KP697xkh68EBX6/qedoIWidpmJkYn/Mfs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737470668; x=1738075468; 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=cXwEOTqnAwGpLdBgRoFBLXm/lX+EzmxiYp2YjB18kHo=; b=nJPc78EVUqYGZ3KM832t3iDS3+NzARgzlsXxgQQEJNhn3mD7xlKUArpubRPfB49nt6 /9Qj1FbzWvVCmr4seZWucdBgyjTaoOtg3DGeEF5VczjXEbj6sL/x652KFIGNPS37yp2z jxDp+O23lnQ/F/gscPk4h0NsPPgDw2wW18WXxTMtFCBULINtRIWxOfT8TJ0FEK17e8yj Ep0wrbj8FbIbUXg9TNSlfeQQiI6vmz5E2L94vGT+qoTftQq/WcCCn7JOuMVrNyewF7e9 dFACfy88US9NnrxzVco3QGErRb8F6bgYyDbAyPKej+fJPaaq2ZKFssjvYAdk5xVotQMW VfZg== X-Gm-Message-State: AOJu0Yy1xbMkByoons5nKtSzIzsJ8HnvS5W/QEPr3yFM6pMqxgloemBY ieJgF0+FpQiLXzwtaSYtoaD6EN4ePQ8Rf4O/rcpcBMysCo0wEP8f7IA5D3kieKYSikQGFnp9eC4 = X-Gm-Gg: ASbGncvm1UtMgGX7JJaR0BDatytkBBcTyvHWhJu4oJa7AC/tAA+Y2uB9E1hsd0qiPzL t4udKkZLUl9GHnwiqqNOPo4c76KpOAJEKoU4qzzAQuI+OnQ6/EpeCf4/sOMviudPGW1a+0FWk+2 dizJp0eZnUdRb5dG7A0H7FZpYbe/hbyS2jT+K1HvDAJJCk0E1nw3wiKf/mh1qPaKg5ZLBjCecMU vcnxN4WFTuS0h0JPR0fBUvhUS/uQfsbc3lHH84FQlx/UiNm7HFKhdxpNiGMsv++KxfHaOYEtR3t 4zIfU6BtmgoE+ncMBLqWL5uFCn8OJR/wuTAg4K4vPOOL X-Google-Smtp-Source: AGHT+IGAig0CdqlDz2NwCGIVvajpDD1zM3X+IfSAU6P3qzb3QhUUUwrLjwDcArG+NzV7pSWS8YyVWQ== X-Received: by 2002:ac2:4294:0:b0:540:1f7d:8bc4 with SMTP id 2adb3069b0e04-5439c281105mr5956838e87.48.1737470668035; Tue, 21 Jan 2025 06:44:28 -0800 (PST) Received: from great-eastern.. (public-gprs172205.centertel.pl. [46.134.11.238]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5439af733fdsm1866237e87.174.2025.01.21.06.44.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jan 2025 06:44:27 -0800 (PST) From: Michal Dzik To: linux-bluetooth@vger.kernel.org Cc: Michal Dzik Subject: [PATCH BlueZ v3 5/5] shared/vcp: control volume when acting as a server Date: Tue, 21 Jan 2025 15:44:04 +0100 Message-Id: <20250121144404.4087658-6-michal.dzik@streamunlimited.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250121144404.4087658-1-michal.dzik@streamunlimited.com> References: <20250121144404.4087658-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..898303e05 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) +static bool 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; } +static bool 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 vcp_set_volume_client(vcp, volume); + else + return 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)