blob: 61f573a9a6aeb53e600f68544a3d98c765855375 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![recursion_limit = "1024"]
use {
anyhow::{format_err, Context, Error},
fidl_fuchsia_bluetooth_bredr as bredr, fuchsia_async as fasync,
fuchsia_component::server::ServiceFs,
fuchsia_inspect as inspect,
fuchsia_inspect_derive::Inspect,
futures::{channel::mpsc, stream::StreamExt, FutureExt},
log::{error, info, warn},
std::convert::TryInto,
};
mod packets;
mod peer;
mod peer_manager;
mod profile;
mod service;
mod types;
#[cfg(test)]
mod tests;
use crate::{
peer_manager::PeerManager,
profile::{protocol_to_channel_type, AvrcpService, ChannelType},
};
#[fasync::run_singlethreaded]
async fn main() -> Result<(), Error> {
fuchsia_syslog::init_with_tags(&["avrcp", "avctp"]).expect("Unable to initialize logger");
// Begin searching for AVRCP target/controller SDP records on newly connected remote peers
// and register our AVRCP service with the BrEdr profile service.
let (profile_proxy, mut connection_requests, mut search_result_requests) =
profile::connect_and_advertise().context("Unable to connect to BrEdr Profile Service")?;
// Create a channel that peer manager will receive requests for peer controllers from the FIDL
// service runner.
// TODO(fxbug.dev/44330) handle back pressure correctly and reduce mpsc::channel buffer sizes.
let (client_sender, mut service_request_receiver) = mpsc::channel(512);
let mut fs = ServiceFs::new();
let inspect = inspect::Inspector::new();
inspect.serve(&mut fs)?;
let mut peer_manager = PeerManager::new(profile_proxy);
if let Err(e) = peer_manager.iattach(inspect.root(), "peers") {
warn!("Failed to attach to inspect: {:?}", e);
}
let mut service_fut = service::run_services(fs, client_sender)
.expect("Unable to start AVRCP FIDL service")
.fuse();
loop {
futures::select! {
request = connection_requests.next() => {
let connected = match request {
None => return Err(format_err!("BR/EDR Profile Service closed connection target")),
Some(Err(e)) => return Err(format_err!("BR/EDR Profile connection target error: {}", e)),
Some(Ok(request)) => request,
};
let bredr::ConnectionReceiverRequest::Connected { peer_id, channel, protocol, .. } = connected;
let channel = match channel.try_into() {
Ok(chan) => chan,
Err(e) => {
info!("Couldn't convert channel: {:?}", e);
continue;
}
};
let peer_id = peer_id.into();
match protocol_to_channel_type(&protocol) {
Some(ChannelType::Control) => peer_manager.new_control_connection(&peer_id, channel),
Some(ChannelType::Browse) => peer_manager.new_browse_connection(&peer_id, channel),
None => {
info!("Received connection over non-AVRCP protocol: {:?}", protocol);
continue
}
}
}
result_request = search_result_requests.next() => {
let result = match result_request {
None => return Err(format_err!("BR/EDR Profile Service closed service search")),
Some(Err(e)) => return Err(format_err!("BR/EDR Profile service search error: {}", e)),
Some(Ok(request)) => request,
};
let bredr::SearchResultsRequest::ServiceFound { peer_id, protocol, attributes, responder } = result;
if let Some(service) = AvrcpService::from_attributes(attributes) {
info!("Service found on {:?}: {:?}", peer_id, service);
peer_manager.services_found(&peer_id.into(), vec![service]);
}
responder.send().context("FIDL response for search failed")?;
},
request = service_request_receiver.select_next_some() => {
peer_manager.handle_service_request(request);
},
service_result = service_fut => {
error!("Publishing Service finished unexpectedly: {:?}", service_result);
break;
},
complete => break,
}
}
Ok(())
}