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