Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efd6b6e2 authored by Hsin-chen Chuang's avatar Hsin-chen Chuang Committed by Automerger Merge Worker
Browse files

Merge changes from topic "qual-mps-av-suspend" am: 0002ef51

parents d13df434 0002ef51
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -173,6 +173,21 @@ bool StopRequest() {
  return true;
}

bool SuspendRequest() {
  if (a2dp_pending_cmd_ != A2DP_CTRL_CMD_NONE) {
    LOG_WARN("%s: busy in pending_cmd=%u", __func__, a2dp_pending_cmd_);
    return false;
  }
  if (!btif_av_stream_started_ready()) {
    LOG_WARN("%s: AV stream is not started", __func__);
    return false;
  }
  LOG_INFO("%s: handling", __func__);
  a2dp_pending_cmd_ = A2DP_CTRL_CMD_SUSPEND;
  btif_av_stream_suspend();
  return true;
}

// Invoked by audio server to check audio presentation position periodically.
PresentationPosition GetPresentationPosition() {
  PresentationPosition presentation_position{
+3 −0
Original line number Diff line number Diff line
@@ -44,6 +44,9 @@ bool StartRequest();
// Invoked by audio server when audio streaming is done.
bool StopRequest();

// Invoked by audio server when audio streaming is suspended.
bool SuspendRequest();

struct PresentationPosition {
  uint64_t remote_delay_report_ns;
  uint64_t total_bytes_read;
+111 −21
Original line number Diff line number Diff line
@@ -243,6 +243,7 @@ pub struct BluetoothMedia {
    avrcp_direction: BtConnectionDirection,
    a2dp_states: HashMap<RawAddress, BtavConnectionState>,
    a2dp_audio_state: HashMap<RawAddress, BtavAudioState>,
    a2dp_has_interrupted_stream: bool, // Only used for qualification.
    hfp: Option<Hfp>,
    hfp_states: HashMap<RawAddress, BthfConnectionState>,
    hfp_audio_state: HashMap<RawAddress, BthfAudioState>,
@@ -288,6 +289,7 @@ impl BluetoothMedia {
            avrcp_direction: BtConnectionDirection::Unknown,
            a2dp_states: HashMap::new(),
            a2dp_audio_state: HashMap::new(),
            a2dp_has_interrupted_stream: false,
            hfp: None,
            hfp_states: HashMap::new(),
            hfp_audio_state: HashMap::new(),
@@ -573,6 +575,15 @@ impl BluetoothMedia {
                    Ok(()) => (),
                    Err(e) => warn!("{}", e),
                }

                const AVRCP_ID_PAUSE: u8 = 0x46;
                const AVRCP_STATE_PRESS: u8 = 0;

                // Per MPS v1.0, on receiving a pause key through AVRCP,
                // central should pause the A2DP stream with an AVDTP suspend command.
                if self.phone_ops_enabled && key == AVRCP_ID_PAUSE && value == AVRCP_STATE_PRESS {
                    self.suspend_audio_request_impl();
                }
            }
            AvrcpCallbacks::AvrcpSetActiveDevice(addr) => {
                self.uinput.set_active_device(addr.to_string());
@@ -690,6 +701,9 @@ impl BluetoothMedia {
                            self.call_list = vec![];
                            self.phone_state_change("".into());
                        }

                        // Resume the A2DP stream when a phone call ended (per MPS v1.0).
                        self.try_a2dp_resume();
                    }
                    BthfAudioState::Connecting => {
                        info!("[{}]: hfp audio connecting.", DisplayAddress(&addr));
@@ -785,6 +799,12 @@ impl BluetoothMedia {
                    return;
                }
                self.phone_state_change("".into());

                // Try resume the A2DP stream (per MPS v1.0) on rejecting an incoming call or an
                // outgoing call is rejected.
                // It may fail if a SCO connection is still active (terminate call case), in that
                // case we will retry on SCO disconnected.
                self.try_a2dp_resume();
            }
            HfpCallbacks::DialCall(number, addr) => {
                let number = if number == "" {
@@ -800,12 +820,16 @@ impl BluetoothMedia {
                // Respond OK/ERROR to the HF which sent the command.
                // This should be called before calling phone_state_change.
                self.simple_at_response(success, addr.clone());
                if success {
                    // Success means the call state has changed. Inform the LibBluetooth stack.
                    self.phone_state_change("".into());
                } else {
                if !success {
                    warn!("[{}]: Unexpected dialing command from HF", DisplayAddress(&addr));
                    return;
                }
                // Inform libbluetooth that the state has changed to dialing.
                self.phone_state_change("".into());
                self.try_a2dp_suspend();
                // Change to alerting state and inform libbluetooth.
                self.dialing_to_alerting();
                self.phone_state_change("".into());
            }
            HfpCallbacks::CallHold(command, addr) => {
                let success = match command {
@@ -820,7 +844,7 @@ impl BluetoothMedia {
                // This should be called before calling phone_state_change.
                self.simple_at_response(success, addr.clone());
                if success {
                    // Success means the call state has changed. Inform the LibBluetooth stack.
                    // Success means the call state has changed. Inform libbluetooth.
                    self.phone_state_change("".into());
                } else {
                    warn!(
@@ -1213,6 +1237,50 @@ impl BluetoothMedia {
            .collect()
    }

    fn start_audio_request_impl(&mut self) -> bool {
        // TODO(b/254808917): revert to debug log once fixed
        info!("Start audio request");

        match self.a2dp.as_mut() {
            Some(a2dp) => a2dp.start_audio_request(),
            None => {
                warn!("Uninitialized A2DP to start audio request");
                false
            }
        }
    }

    fn suspend_audio_request_impl(&mut self) {
        match self.a2dp.as_mut() {
            Some(a2dp) => a2dp.suspend_audio_request(),
            None => warn!("Uninitialized A2DP to suspend audio request"),
        };
    }

    fn try_a2dp_resume(&mut self) {
        if !self.phone_ops_enabled {
            return;
        }
        // Make sure there is no any SCO connection and then resume the A2DP stream.
        if self.a2dp_has_interrupted_stream
            && !self.hfp_audio_state.values().any(|state| *state == BthfAudioState::Connected)
        {
            self.a2dp_has_interrupted_stream = false;
            self.start_audio_request_impl();
        }
    }

    fn try_a2dp_suspend(&mut self) {
        if !self.phone_ops_enabled {
            return;
        }
        // Suspend the A2DP stream if there is any.
        if self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) {
            self.a2dp_has_interrupted_stream = true;
            self.suspend_audio_request_impl();
        }
    }

    fn start_sco_call_impl(
        &mut self,
        address: String,
@@ -1332,10 +1400,13 @@ impl BluetoothMedia {
        }
        // There must be exactly one incoming/dialing call in the list.
        for c in self.call_list.iter_mut() {
            if c.state == CallState::Incoming || c.state == CallState::Dialing {
            match c.state {
                CallState::Incoming | CallState::Dialing | CallState::Alerting => {
                    c.state = CallState::Active;
                    break;
                }
                _ => {}
            }
        }
        self.phone_state.state = CallState::Idle;
        self.phone_state.num_active += 1;
@@ -1350,16 +1421,19 @@ impl BluetoothMedia {
            CallState::Idle if self.phone_state.num_active > 0 => {
                self.phone_state.num_active -= 1;
            }
            CallState::Incoming | CallState::Dialing => {
            CallState::Incoming | CallState::Dialing | CallState::Alerting => {
                self.phone_state.state = CallState::Idle;
            }
            _ => {
                return false;
            }
        }
        // At this point, there must be exactly one incoming/dialing/active call to be removed.
        // At this point, there must be exactly one incoming/dialing/alerting/active call to be
        // removed.
        self.call_list.retain(|x| match x.state {
            CallState::Active | CallState::Incoming | CallState::Dialing => false,
            CallState::Active | CallState::Incoming | CallState::Dialing | CallState::Alerting => {
                false
            }
            _ => true,
        });
        true
@@ -1382,6 +1456,20 @@ impl BluetoothMedia {
        true
    }

    fn dialing_to_alerting(&mut self) -> bool {
        if !self.phone_ops_enabled || self.phone_state.state != CallState::Dialing {
            return false;
        }
        for c in self.call_list.iter_mut() {
            if c.state == CallState::Dialing {
                c.state = CallState::Alerting;
                break;
            }
        }
        self.phone_state.state = CallState::Alerting;
        true
    }

    fn release_held_impl(&mut self) -> bool {
        if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle {
            return false;
@@ -1976,16 +2064,7 @@ impl IBluetoothMedia for BluetoothMedia {
    }

    fn start_audio_request(&mut self) -> bool {
        // TODO(b/254808917): revert to debug log once fixed
        info!("Start audio request");

        match self.a2dp.as_mut() {
            Some(a2dp) => a2dp.start_audio_request(),
            None => {
                warn!("Uninitialized A2DP to start audio request");
                false
            }
        }
        self.start_audio_request_impl()
    }

    fn stop_audio_request(&mut self) {
@@ -2145,6 +2224,7 @@ impl IBluetoothTelephony for BluetoothMedia {
        self.phone_state.state = CallState::Idle;
        self.memory_dialing_number = None;
        self.last_dialing_number = None;
        self.a2dp_has_interrupted_stream = false;

        if !enable {
            if self.hfp_states.values().any(|x| x == &BthfConnectionState::SlcConnected) {
@@ -2177,6 +2257,7 @@ impl IBluetoothTelephony for BluetoothMedia {
        });
        self.phone_state.state = CallState::Incoming;
        self.phone_state_change(number);
        self.try_a2dp_suspend();
        true
    }

@@ -2185,6 +2266,10 @@ impl IBluetoothTelephony for BluetoothMedia {
            return false;
        }
        self.phone_state_change("".into());
        self.try_a2dp_suspend();
        // Change to alerting state and inform libbluetooth.
        self.dialing_to_alerting();
        self.phone_state_change("".into());
        true
    }

@@ -2214,6 +2299,11 @@ impl IBluetoothTelephony for BluetoothMedia {
            return false;
        }
        self.phone_state_change("".into());
        // Try resume the A2DP stream (per MPS v1.0) on rejecting an incoming call or an
        // outgoing call is rejected.
        // It may fail if a SCO connection is still active (terminate call case), in that
        // case we will retry on SCO disconnected.
        self.try_a2dp_resume();
        true
    }

+3 −0
Original line number Diff line number Diff line
@@ -304,6 +304,9 @@ bool A2dpIntf::start_audio_request() const {
bool A2dpIntf::stop_audio_request() const {
  return bluetooth::audio::a2dp::StopRequest();
}
bool A2dpIntf::suspend_audio_request() const {
  return bluetooth::audio::a2dp::SuspendRequest();
}
RustPresentationPosition A2dpIntf::get_presentation_position() const {
  bluetooth::audio::a2dp::PresentationPosition p = bluetooth::audio::a2dp::GetPresentationPosition();
  RustPresentationPosition rposition = {
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ class A2dpIntf {
  bool set_audio_config(A2dpCodecConfig rconfig) const;
  bool start_audio_request() const;
  bool stop_audio_request() const;
  bool suspend_audio_request() const;
  RustPresentationPosition get_presentation_position() const;

 private:
Loading