xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/fuchsia/host/fidl/iso_stream_server.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/iso_stream_server.h"
16 
17 #include <lib/fidl/cpp/wire/channel.h>
18 
19 #include <cinttypes>
20 
21 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/helpers.h"
22 
23 namespace bthost {
24 
IsoStreamServer(fidl::InterfaceRequest<fuchsia::bluetooth::le::IsochronousStream> request,fit::callback<void ()> on_closed_cb)25 IsoStreamServer::IsoStreamServer(
26     fidl::InterfaceRequest<fuchsia::bluetooth::le::IsochronousStream> request,
27     fit::callback<void()> on_closed_cb)
28     : ServerBase(this, std::move(request)),
29       on_closed_cb_(std::move(on_closed_cb)),
30       weak_self_(this) {
31   set_error_handler([this](zx_status_t) { OnClosed(); });
32 }
33 
OnStreamEstablished(bt::iso::IsoStream::WeakPtr stream_ptr,const bt::iso::CisEstablishedParameters & connection_params)34 void IsoStreamServer::OnStreamEstablished(
35     bt::iso::IsoStream::WeakPtr stream_ptr,
36     const bt::iso::CisEstablishedParameters& connection_params) {
37   bt_log(INFO, "fidl", "CIS established");
38   iso_stream_ = stream_ptr;
39   fuchsia::bluetooth::le::IsochronousStreamOnEstablishedRequest request;
40   request.set_result(ZX_OK);
41   fuchsia::bluetooth::le::CisEstablishedParameters params =
42       bthost::fidl_helpers::CisEstablishedParametersToFidl(connection_params);
43   request.set_established_params(std::move(params));
44   binding()->events().OnEstablished(std::move(request));
45 }
46 
OnStreamEstablishmentFailed(pw::bluetooth::emboss::StatusCode status)47 void IsoStreamServer::OnStreamEstablishmentFailed(
48     pw::bluetooth::emboss::StatusCode status) {
49   PW_CHECK(status != pw::bluetooth::emboss::StatusCode::SUCCESS);
50   bt_log(WARN,
51          "fidl",
52          "CIS failed to be established: %u",
53          static_cast<unsigned>(status));
54   fuchsia::bluetooth::le::IsochronousStreamOnEstablishedRequest request;
55   request.set_result(ZX_ERR_INTERNAL);
56   binding()->events().OnEstablished(std::move(request));
57 }
58 
SetupDataPath(fuchsia::bluetooth::le::IsochronousStreamSetupDataPathRequest parameters,SetupDataPathCallback fidl_cb)59 void IsoStreamServer::SetupDataPath(
60     fuchsia::bluetooth::le::IsochronousStreamSetupDataPathRequest parameters,
61     SetupDataPathCallback fidl_cb) {
62   pw::bluetooth::emboss::DataPathDirection direction =
63       fidl_helpers::DataPathDirectionFromFidl(parameters.data_direction());
64   const char* direction_as_str =
65       fidl_helpers::DataPathDirectionToString(direction);
66   bt_log(INFO,
67          "fidl",
68          "Request received to set up data path (direction: %s)",
69          direction_as_str);
70   if (direction != pw::bluetooth::emboss::DataPathDirection::OUTPUT) {
71     // We only support Controller => Host at the moment
72     bt_log(WARN,
73            "fidl",
74            "Attempt to set up data path with unsupported direction: %s",
75            direction_as_str);
76     fidl_cb(fpromise::error(ZX_ERR_NOT_SUPPORTED));
77     return;
78   }
79 
80   bt::StaticPacket<pw::bluetooth::emboss::CodecIdWriter> codec_id =
81       fidl_helpers::CodecIdFromFidl(parameters.codec_attributes().codec_id());
82   std::optional<std::vector<uint8_t>> codec_configuration;
83   if (parameters.codec_attributes().has_codec_configuration()) {
84     codec_configuration = parameters.codec_attributes().codec_configuration();
85   }
86 
87   zx::duration delay(parameters.controller_delay());
88   uint32_t delay_in_us = delay.to_usecs();
89   if (!iso_stream_.has_value()) {
90     bt_log(WARN, "fidl", "data path setup failed (CIS not established)");
91     fidl_cb(fpromise::error(ZX_ERR_BAD_STATE));
92     return;
93   }
94   if (!iso_stream_->is_alive()) {
95     bt_log(INFO, "fidl", "Attempt to set data path after CIS closed");
96     fidl_cb(fpromise::error(ZX_ERR_BAD_STATE));
97     return;
98   }
99 
100   auto on_setup_complete_cb =
101       [fidl_cb =
102            std::move(fidl_cb)](bt::iso::IsoStream::SetupDataPathError error) {
103         switch (error) {
104           case bt::iso::IsoStream::kSuccess:
105             bt_log(INFO, "fidl", "data path successfully setup");
106             fidl_cb(fpromise::ok());
107             break;
108           case bt::iso::IsoStream::kStreamAlreadyExists:
109             bt_log(
110                 WARN, "fidl", "data path setup failed (stream already setup)");
111             fidl_cb(fpromise::error(ZX_ERR_ALREADY_EXISTS));
112             break;
113           case bt::iso::IsoStream::kCisNotEstablished:
114             bt_log(
115                 WARN, "fidl", "data path setup failed (CIS not established)");
116             fidl_cb(fpromise::error(ZX_ERR_BAD_STATE));
117             break;
118           case bt::iso::IsoStream::kInvalidArgs:
119             bt_log(WARN, "fidl", "data path setup failed (invalid parameters)");
120             fidl_cb(fpromise::error(ZX_ERR_INVALID_ARGS));
121             break;
122           case bt::iso::IsoStream::kStreamClosed:
123             bt_log(WARN, "fidl", "data path setup failed (stream closed)");
124             fidl_cb(fpromise::error(ZX_ERR_BAD_STATE));
125             break;
126           default:
127             bt_log(ERROR,
128                    "fidl",
129                    "Unsupported case in SetupDataPathError: %u",
130                    static_cast<unsigned>(error));
131             fidl_cb(fpromise::error(ZX_ERR_INTERNAL));
132             break;
133         }
134       };
135   (*iso_stream_)
136       ->SetupDataPath(
137           direction,
138           codec_id,
139           codec_configuration,
140           delay_in_us,
141           std::move(on_setup_complete_cb),
142           fit::bind_member<&IsoStreamServer::OnIncomingDataAvailable>(this));
143 }
144 
OnIncomingDataAvailable(pw::span<const std::byte> packet)145 bool IsoStreamServer::OnIncomingDataAvailable(
146     pw::span<const std::byte> packet) {
147   // TODO(b/311639690): Currently, just acknowledges the read but does nothing
148   // with the data. This will keep data from backing up in the caller until a
149   // complete data path has been implemented.
150   return true;
151 }
152 
Read(ReadCallback callback)153 void IsoStreamServer::Read(ReadCallback callback) {}
154 
OnClosed()155 void IsoStreamServer::OnClosed() {
156   if (iso_stream_.has_value() && iso_stream_->is_alive()) {
157     (*iso_stream_)->Close();
158   }
159   // This may free our instance.
160   on_closed_cb_();
161 }
162 
Close(zx_status_t epitaph)163 void IsoStreamServer::Close(zx_status_t epitaph) {
164   binding()->Close(epitaph);
165   OnClosed();
166 }
167 
handle_unknown_method(uint64_t ordinal,bool has_response)168 void IsoStreamServer::handle_unknown_method(uint64_t ordinal,
169                                             bool has_response) {
170   bt_log(WARN,
171          "fidl",
172          "Received unknown fidl call %#" PRIx64 " (%s responses)",
173          ordinal,
174          has_response ? "with" : "without");
175 }
176 
177 }  // namespace bthost
178