1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 use std::os::unix::io::{AsRawFd, RawFd}; 5 use std::{io, mem}; 6 7 use cras_sys::gen::{cras_disconnect_stream_message, cras_server_message, CRAS_SERVER_MESSAGE_ID}; 8 use sys_util::{net::UnixSeqpacket, ScmSocket}; 9 10 use data_model::DataInit; 11 12 /// Server socket type to connect. 13 pub enum CrasSocketType { 14 /// A server socket type supports only playback function. 15 Legacy, 16 /// A server socket type supports both playback and capture functions. 17 Unified, 18 } 19 20 impl CrasSocketType { sock_path(&self) -> &str21 fn sock_path(&self) -> &str { 22 match self { 23 Self::Legacy => "/run/cras/.cras_socket", 24 Self::Unified => "/run/cras/.cras_unified", 25 } 26 } 27 } 28 29 /// A socket connecting to the CRAS audio server. 30 pub struct CrasServerSocket { 31 socket: UnixSeqpacket, 32 } 33 34 impl CrasServerSocket { new() -> io::Result<CrasServerSocket>35 pub fn new() -> io::Result<CrasServerSocket> { 36 Self::with_type(CrasSocketType::Legacy) 37 } 38 39 /// Creates a `CrasServerSocket` with given `CrasSocketType`. 40 /// 41 /// # Errors 42 /// 43 /// Returns the `io::Error` generated when connecting to the socket on failure. with_type(socket_type: CrasSocketType) -> io::Result<CrasServerSocket>44 pub fn with_type(socket_type: CrasSocketType) -> io::Result<CrasServerSocket> { 45 Ok(CrasServerSocket { 46 socket: UnixSeqpacket::connect(socket_type.sock_path())?, 47 }) 48 } 49 50 /// Sends a sized and packed server messge to the server socket. The message 51 /// must implement `Sized` and `DataInit`. 52 /// # Arguments 53 /// * `message` - A sized and packed message. 54 /// * `fds` - A slice of fds to send. 55 /// 56 /// # Returns 57 /// * Length of written bytes in `usize`. 58 /// 59 /// # Errors 60 /// Return error if the socket fails to write message to server. send_server_message_with_fds<M: Sized + DataInit>( &self, message: &M, fds: &[RawFd], ) -> io::Result<usize>61 pub fn send_server_message_with_fds<M: Sized + DataInit>( 62 &self, 63 message: &M, 64 fds: &[RawFd], 65 ) -> io::Result<usize> { 66 match fds.len() { 67 0 => self.socket.send(message.as_slice()), 68 _ => { 69 let ioslice = io::IoSlice::new(message.as_slice()); 70 match self.send_with_fds(&[ioslice], fds) { 71 Ok(len) => Ok(len), 72 Err(err) => Err(io::Error::new(io::ErrorKind::Other, format!("{}", err))), 73 } 74 } 75 } 76 } 77 78 /// Creates a clone of the underlying socket. The returned clone can also be 79 /// used to communicate with the cras server. try_clone(&self) -> io::Result<CrasServerSocket>80 pub fn try_clone(&self) -> io::Result<CrasServerSocket> { 81 let new_sock = self.socket.try_clone()?; 82 Ok(CrasServerSocket { socket: new_sock }) 83 } 84 85 /// Send a message to request disconnection of the given stream. 86 /// 87 /// Builds a `cras_disconnect_stream_message` containing `stream_id` and 88 /// sends it to the server. 89 /// No response is expected. 90 /// 91 /// # Arguments 92 /// 93 /// * `stream_id` - The id of the stream that should be disconnected. 94 /// 95 /// # Errors 96 /// 97 /// * If the message was not written to the server socket successfully. disconnect_stream(&self, stream_id: u32) -> io::Result<()>98 pub fn disconnect_stream(&self, stream_id: u32) -> io::Result<()> { 99 let msg_header = cras_server_message { 100 length: mem::size_of::<cras_disconnect_stream_message>() as u32, 101 id: CRAS_SERVER_MESSAGE_ID::CRAS_SERVER_DISCONNECT_STREAM, 102 }; 103 let server_cmsg = cras_disconnect_stream_message { 104 header: msg_header, 105 stream_id, 106 }; 107 self.send_server_message_with_fds(&server_cmsg, &[]) 108 .map(|_| ()) 109 } 110 } 111 112 // For using `recv_with_fds` and `send_with_fds`. 113 impl ScmSocket for CrasServerSocket { socket_fd(&self) -> RawFd114 fn socket_fd(&self) -> RawFd { 115 self.socket.as_raw_fd() 116 } 117 } 118 119 // For using `PollContex`. 120 impl AsRawFd for CrasServerSocket { as_raw_fd(&self) -> RawFd121 fn as_raw_fd(&self) -> RawFd { 122 self.socket.as_raw_fd() 123 } 124 } 125