1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "host/libs/audio_connector/server.h"
17 
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <strings.h>
21 #include <unistd.h>
22 
23 #include <utility>
24 #include <vector>
25 
26 #include <android-base/logging.h>
27 
28 #include "common/libs/fs/shared_select.h"
29 
30 namespace cuttlefish {
31 
32 namespace {
33 
AllocateShm(size_t size,const std::string & name,SharedFD * shm_fd)34 ScopedMMap AllocateShm(size_t size, const std::string& name, SharedFD* shm_fd) {
35   *shm_fd = SharedFD::MemfdCreate(name, 0);
36   if (!(*shm_fd)->IsOpen()) {
37     LOG(FATAL) << "Unable to allocate create file for " << name << ": "
38                << (*shm_fd)->StrError();
39     return ScopedMMap();
40   }
41 
42   auto truncate_ret = (*shm_fd)->Truncate(size);
43   if (truncate_ret != 0) {
44     LOG(FATAL) << "Unable to resize " << name << " to " << size
45                << " bytes: " << (*shm_fd)->StrError();
46     return ScopedMMap();
47   }
48 
49   auto mmap_res = (*shm_fd)->MMap(NULL /* addr */, size, PROT_READ | PROT_WRITE,
50                                   MAP_SHARED, 0 /*offset*/);
51   if (!mmap_res) {
52     LOG(FATAL) << "Unable to memory map " << name << ": "
53                << (*shm_fd)->StrError();
54   }
55   return mmap_res;
56 }
57 
BufferAt(ScopedMMap & shm,size_t offset,size_t len)58 volatile uint8_t* BufferAt(ScopedMMap& shm, size_t offset, size_t len) {
59   CHECK(shm.WithinBounds(offset, len))
60       << "Tx buffer bounds outside the buffer area: " << offset << " " << len;
61   void* ptr = shm.get();
62   return &reinterpret_cast<volatile uint8_t*>(ptr)[offset];
63 }
64 
CreateSocketPair(SharedFD * local,SharedFD * remote)65 bool CreateSocketPair(SharedFD* local, SharedFD* remote) {
66   auto ret = SharedFD::SocketPair(AF_UNIX, SOCK_SEQPACKET, 0, local, remote);
67   if (!ret) {
68     LOG(ERROR) << "Unable to create socket pair for audio IO signaling: "
69                << (*local)->StrError();
70   }
71   return ret;
72 }
73 
SendStatusCallback(uint32_t buffer_offset,SharedFD socket)74 std::function<void(AudioStatus, uint32_t, uint32_t)> SendStatusCallback(
75     uint32_t buffer_offset, SharedFD socket) {
76   // Consumption of an audio buffer is an asynchronous event, which could
77   // trigger after the client disconnected. A WeakFD ensures that the response
78   // will only be sent if there is still a client available.
79   auto weak_socket = WeakFD(socket);
80   return
81       [buffer_offset, weak_socket](AudioStatus status, uint32_t latency_bytes,
82                                    uint32_t consumed_length) {
83         auto socket = weak_socket.lock();
84         if (!socket->IsOpen()) {
85           return;
86         }
87         IoStatusMsg reply;
88         reply.status.status = Le32(static_cast<uint32_t>(status));
89         reply.status.latency_bytes = Le32(latency_bytes);
90         reply.buffer_offset = buffer_offset;
91         reply.consumed_length = consumed_length;
92         // Send the acknowledgment non-blockingly to avoid a slow client from
93         // blocking the server.
94         auto sent = socket->Send(&reply, sizeof(reply), MSG_DONTWAIT);
95         if (sent < sizeof(reply)) {
96           LOG(ERROR) << "Failed to send entire reply: " << socket->StrError();
97         }
98       };
99 }
100 
101 }  // namespace
102 
AcceptClient(uint32_t num_streams,uint32_t num_jacks,uint32_t num_chmaps,size_t tx_shm_len,size_t rx_shm_len)103 std::unique_ptr<AudioClientConnection> AudioServer::AcceptClient(
104     uint32_t num_streams, uint32_t num_jacks, uint32_t num_chmaps,
105     size_t tx_shm_len, size_t rx_shm_len) {
106   auto conn_fd = SharedFD::Accept(*server_socket_, nullptr, 0);
107   if (!conn_fd->IsOpen()) {
108     LOG(ERROR) << "Connection failed on audio server: " << conn_fd->StrError();
109     return nullptr;
110   }
111   return AudioClientConnection::Create(conn_fd, num_streams, num_jacks,
112                                        num_chmaps, tx_shm_len, rx_shm_len);
113 }
114 
115 /* static */
Create(SharedFD client_socket,uint32_t num_streams,uint32_t num_jacks,uint32_t num_chmaps,size_t tx_shm_len,size_t rx_shm_len)116 std::unique_ptr<AudioClientConnection> AudioClientConnection::Create(
117     SharedFD client_socket, uint32_t num_streams, uint32_t num_jacks,
118     uint32_t num_chmaps, size_t tx_shm_len, size_t rx_shm_len) {
119   SharedFD event_socket, event_pair;
120   SharedFD tx_socket, tx_pair;
121   SharedFD rx_socket, rx_pair;
122 
123   bool pairs_created = true;
124   pairs_created &= CreateSocketPair(&event_socket, &event_pair);
125   pairs_created &= CreateSocketPair(&tx_socket, &tx_pair);
126   pairs_created &= CreateSocketPair(&rx_socket, &rx_pair);
127   if (!pairs_created) {
128     return nullptr;
129   }
130 
131   SharedFD tx_shm_fd, rx_shm_fd;
132   auto tx_shm =
133       AllocateShm(tx_shm_len, "vios_audio_server_tx_queue", &tx_shm_fd);
134   if (!tx_shm) {
135     return nullptr;
136   }
137   auto rx_shm =
138       AllocateShm(rx_shm_len, "vios_audio_server_rx_queue", &rx_shm_fd);
139   if (!rx_shm) {
140     return nullptr;
141   }
142 
143   VioSConfig welcome_msg = {
144       .version = VIOS_VERSION,
145       .jacks = num_jacks,
146       .streams = num_streams,
147       .chmaps = num_chmaps,
148   };
149 
150   auto sent = client_socket->SendFileDescriptors(
151       &welcome_msg, sizeof(welcome_msg), event_pair, tx_pair, rx_pair,
152       tx_shm_fd, rx_shm_fd);
153   if (sent < 0) {
154     LOG(ERROR) << "Failed to send file descriptors to client: "
155                << client_socket->StrError();
156     return nullptr;
157   }
158 
159   return std::unique_ptr<AudioClientConnection>(new AudioClientConnection(
160       std::move(tx_shm), std::move(rx_shm), client_socket, event_socket,
161       tx_socket, rx_socket));
162 }
163 
ReceiveCommands(AudioServerExecutor & executor)164 bool AudioClientConnection::ReceiveCommands(AudioServerExecutor& executor) {
165   // The largest msg the client will send is 24 bytes long, using uint64_t
166   // guarantees it's aligned to 64 bits.
167   uint64_t recv_buffer[3];
168   auto recv_size =
169       ReceiveMsg(control_socket_, &recv_buffer, sizeof(recv_buffer));
170   if (recv_size <= 0) {
171     return false;
172   }
173   const auto cmd_hdr = reinterpret_cast<const virtio_snd_hdr*>(&recv_buffer[0]);
174   if (recv_size < sizeof(virtio_snd_hdr)) {
175     LOG(ERROR) << "Received control message is too small: " << recv_size;
176     return false;
177   }
178   switch (static_cast<AudioCommandType>(cmd_hdr->code.as_uint32_t())) {
179     case AudioCommandType::VIRTIO_SND_R_PCM_INFO: {
180       if (recv_size < sizeof(virtio_snd_query_info)) {
181         LOG(ERROR) << "Received QUERY_INFO message is too small: " << recv_size;
182         return false;
183       }
184       auto query_info = reinterpret_cast<const virtio_snd_query_info*>(cmd_hdr);
185       auto info_count = query_info->count.as_uint32_t();
186       auto start_id = query_info->start_id.as_uint32_t();
187       std::unique_ptr<virtio_snd_pcm_info[]> reply(
188           new virtio_snd_pcm_info[info_count]);
189       StreamInfoCommand cmd(start_id, info_count, reply.get());
190       LOG(DEBUG) << "VIRTIO_SND_PCM_INFO: start=" << start_id
191                  << ", count=" << info_count;
192 
193       executor.StreamsInfo(cmd);
194       return CmdReply(cmd.status(), reply.get(), info_count * sizeof(reply[0]));
195     }
196     case AudioCommandType::VIRTIO_SND_R_PCM_SET_PARAMS: {
197       LOG(DEBUG) << "IVRTIO_SND_R_PCM_SET_PARAM";
198       if (recv_size < sizeof(virtio_snd_pcm_set_params)) {
199         LOG(ERROR) << "Received SET_PARAMS message is too small: " << recv_size;
200         return false;
201       }
202       auto set_param_msg =
203           reinterpret_cast<const virtio_snd_pcm_set_params*>(cmd_hdr);
204       StreamSetParamsCommand cmd(set_param_msg->hdr.stream_id.as_uint32_t(),
205                                  set_param_msg->buffer_bytes.as_uint32_t(),
206                                  set_param_msg->period_bytes.as_uint32_t(),
207                                  set_param_msg->features.as_uint32_t(),
208                                  set_param_msg->channels, set_param_msg->format,
209                                  set_param_msg->rate);
210       executor.SetStreamParameters(cmd);
211       return CmdReply(cmd.status());
212     }
213     case AudioCommandType::VIRTIO_SND_R_PCM_PREPARE: {
214       if (recv_size < sizeof(virtio_snd_pcm_hdr)) {
215         LOG(ERROR) << "Received PREPARE message is too small: " << recv_size;
216         return false;
217       }
218       auto pcm_op_msg = reinterpret_cast<const virtio_snd_pcm_hdr*>(cmd_hdr);
219       StreamControlCommand cmd(AudioCommandType::VIRTIO_SND_R_PCM_PREPARE,
220                                pcm_op_msg->stream_id.as_uint32_t());
221       LOG(DEBUG) << "VRTIO_SND_R_PCM_PREPARE: stream_id="
222                  << pcm_op_msg->stream_id.as_uint32_t();
223       executor.PrepareStream(cmd);
224       return CmdReply(cmd.status());
225     }
226     case AudioCommandType::VIRTIO_SND_R_PCM_RELEASE: {
227       if (recv_size < sizeof(virtio_snd_pcm_hdr)) {
228         LOG(ERROR) << "Received RELEASE message is too small: " << recv_size;
229         return false;
230       }
231       auto pcm_op_msg = reinterpret_cast<const virtio_snd_pcm_hdr*>(cmd_hdr);
232       StreamControlCommand cmd(AudioCommandType::VIRTIO_SND_R_PCM_RELEASE,
233                                pcm_op_msg->stream_id.as_uint32_t());
234       LOG(DEBUG) << "VRTIO_SND_R_PCM_RELEASE: stream_id="
235                  << pcm_op_msg->stream_id.as_uint32_t();
236       executor.ReleaseStream(cmd);
237       return CmdReply(cmd.status());
238     }
239     case AudioCommandType::VIRTIO_SND_R_PCM_START: {
240       if (recv_size < sizeof(virtio_snd_pcm_hdr)) {
241         LOG(ERROR) << "Received START message is too small: " << recv_size;
242         return false;
243       }
244       auto pcm_op_msg = reinterpret_cast<const virtio_snd_pcm_hdr*>(cmd_hdr);
245       uint32_t stream_id = pcm_op_msg->stream_id.as_uint32_t();
246       StreamControlCommand cmd(AudioCommandType::VIRTIO_SND_R_PCM_START,
247                                stream_id);
248       LOG(DEBUG) << "VRTIO_SND_R_PCM_START: stream_id=" << stream_id;
249       frame_counters_[stream_id] = {0, 1};
250       executor.StartStream(cmd);
251       return CmdReply(cmd.status());
252     }
253     case AudioCommandType::VIRTIO_SND_R_PCM_STOP: {
254       if (recv_size < sizeof(virtio_snd_pcm_hdr)) {
255         LOG(ERROR) << "Received STOP message is too small: " << recv_size;
256         return false;
257       }
258       auto pcm_op_msg = reinterpret_cast<const virtio_snd_pcm_hdr*>(cmd_hdr);
259       StreamControlCommand cmd(AudioCommandType::VIRTIO_SND_R_PCM_STOP,
260                                pcm_op_msg->stream_id.as_uint32_t());
261       LOG(DEBUG) << "VRTIO_SND_R_PCM_STOP: stream_id="
262                  << pcm_op_msg->stream_id.as_uint32_t();
263       executor.StopStream(cmd);
264       return CmdReply(cmd.status());
265     }
266     case AudioCommandType::VIRTIO_SND_R_CHMAP_INFO: {
267       if (recv_size < sizeof(virtio_snd_query_info)) {
268         LOG(ERROR) << "Received QUERY_INFO message is too small: " << recv_size;
269         return false;
270       }
271       auto query_info = reinterpret_cast<const virtio_snd_query_info*>(cmd_hdr);
272       auto info_count = query_info->count.as_uint32_t();
273       auto start_id = query_info->start_id.as_uint32_t();
274       std::unique_ptr<virtio_snd_chmap_info[]> reply(
275           new virtio_snd_chmap_info[info_count]);
276       ChmapInfoCommand cmd(start_id, info_count, reply.get());
277       LOG(DEBUG) << "VRTIO_SND_R_CHMAP_INFO: start_id=" << start_id
278                  << ", count=" << info_count;
279 
280       executor.ChmapsInfo(cmd);
281       return CmdReply(cmd.status(), reply.get(), info_count * sizeof(reply[0]));
282     }
283     case AudioCommandType::VIRTIO_SND_R_JACK_INFO: {
284       if (recv_size < sizeof(virtio_snd_query_info)) {
285         LOG(ERROR) << "Received QUERY_INFO message is too small: " << recv_size;
286         return false;
287       }
288       auto query_info = reinterpret_cast<const virtio_snd_query_info*>(cmd_hdr);
289       auto info_count = query_info->count.as_uint32_t();
290       auto start_id = query_info->start_id.as_uint32_t();
291       std::unique_ptr<virtio_snd_jack_info[]> reply(
292           new virtio_snd_jack_info[info_count]);
293       JackInfoCommand cmd(start_id, info_count, reply.get());
294       LOG(DEBUG) << "VRTIO_SND_R_JACK_INFO: start_id=" << start_id
295                  << ", count=" << info_count;
296 
297       executor.JacksInfo(cmd);
298       return CmdReply(cmd.status(), reply.get(), info_count * sizeof(reply[0]));
299     }
300     case AudioCommandType::VIRTIO_SND_R_JACK_REMAP:
301       LOG(ERROR) << "Unsupported command type: " << cmd_hdr->code.as_uint32_t();
302       return CmdReply(AudioStatus::VIRTIO_SND_S_NOT_SUPP);
303     default:
304       LOG(ERROR) << "Unknown command type: " << cmd_hdr->code.as_uint32_t();
305       return CmdReply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
306   }
307   return true;
308 }
309 
ReceivePlayback(AudioServerExecutor & executor)310 bool AudioClientConnection::ReceivePlayback(AudioServerExecutor& executor) {
311   // The largest msg the client will send is 12 bytes long, using uint32_t
312   // guarantees it's aligned to 32 bits.
313   uint32_t recv_buffer[3];
314   auto recv_size = ReceiveMsg(tx_socket_, &recv_buffer, sizeof(recv_buffer));
315   if (recv_size <= 0) {
316     return false;
317   }
318   const auto msg_hdr = reinterpret_cast<const IoTransferMsg*>(&recv_buffer[0]);
319 
320   if (recv_size < sizeof(IoTransferMsg)) {
321     LOG(ERROR) << "Received PCM_XFER message is too small: " << recv_size;
322     return false;
323   }
324   const uint32_t stream_id = msg_hdr->io_xfer.stream_id.as_uint32_t();
325   auto& [frame_count, log_at] = frame_counters_[stream_id];
326   if (++frame_count >= log_at) {
327     LOG(DEBUG) << "Stream id=" << stream_id << ": " << frame_count << " frames";
328     log_at *= 16;
329   }
330   TxBuffer buffer(
331       msg_hdr->io_xfer,
332       BufferAt(tx_shm_, msg_hdr->buffer_offset, msg_hdr->buffer_len),
333       msg_hdr->buffer_len,
334       SendStatusCallback(msg_hdr->buffer_offset, tx_socket_));
335   executor.OnPlaybackBuffer(std::move(buffer));
336   return true;
337 }
338 
ReceiveCapture(AudioServerExecutor & executor)339 bool AudioClientConnection::ReceiveCapture(AudioServerExecutor& executor) {
340   uint32_t recv_buffer[3];
341   auto recv_size = ReceiveMsg(rx_socket_, &recv_buffer, sizeof(recv_buffer));
342   if (recv_size <= 0) {
343     return false;
344   }
345   const auto msg_hdr = reinterpret_cast<const IoTransferMsg*>(&recv_buffer[0]);
346   if (recv_size < sizeof(IoTransferMsg)) {
347     LOG(ERROR) << "Received PCM_XFER message is too small: " << recv_size;
348     return false;
349   }
350   const uint32_t stream_id = msg_hdr->io_xfer.stream_id.as_uint32_t();
351   auto& [frame_count, log_at] = frame_counters_[stream_id];
352   if (++frame_count >= log_at) {
353     LOG(DEBUG) << "Stream id=" << stream_id << ": " << frame_count << " frames";
354     log_at *= 16;
355   }
356   RxBuffer buffer(
357       msg_hdr->io_xfer,
358       BufferAt(rx_shm_, msg_hdr->buffer_offset, msg_hdr->buffer_len),
359       msg_hdr->buffer_len,
360       SendStatusCallback(msg_hdr->buffer_offset, rx_socket_));
361   executor.OnCaptureBuffer(std::move(buffer));
362   return true;
363 }
364 
CmdReply(AudioStatus status,const void * data,size_t size)365 bool AudioClientConnection::CmdReply(AudioStatus status, const void* data,
366                                      size_t size) {
367   virtio_snd_hdr vio_status = {
368       .code = Le32(static_cast<uint32_t>(status)),
369   };
370   std::vector<uint8_t> buffer(sizeof(vio_status) + size, 0);
371   std::memcpy(buffer.data(), &vio_status, sizeof(vio_status));
372   if (data) {
373     std::memcpy(buffer.data() + sizeof(vio_status), data, size);
374   }
375   auto status_sent = control_socket_->Send(buffer.data(), buffer.size(), 0);
376   if (status_sent < sizeof(vio_status) + size) {
377     LOG(ERROR) << "Failed to send entire command status: "
378                << control_socket_->StrError();
379     return false;
380   }
381   return true;
382 }
383 
SendEvent()384 bool AudioClientConnection::SendEvent(/*TODO*/) { return false; }
385 
ReceiveMsg(SharedFD socket,void * buffer,size_t size)386 ssize_t AudioClientConnection::ReceiveMsg(SharedFD socket, void* buffer,
387                                           size_t size) {
388   auto read = socket->Recv(buffer, size, MSG_TRUNC);
389   CHECK(read < 0 || read <= size)
390       << "Received a msg bigger than the buffer, msg was truncated: " << read
391       << " vs " << size;
392   if (read == 0) {
393     LOG(ERROR) << "Client closed the connection";
394   }
395   if (read < 0) {
396     LOG(ERROR) << "Error receiving messages from client: "
397                << socket->StrError();
398   }
399   return read;
400 }
401 
402 }  // namespace cuttlefish
403