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

Commit ce55abda authored by En-Shuo Hsu's avatar En-Shuo Hsu
Browse files

floss: Add call status and hook to CLCC callback

The report of the call status indicator is required for some headset to
work properly. Add a call_status private field and abstract the set of
the call status to a private helper function for better readability in
the ConnectionStateCallback. Also hook the CLCC callback to reflect the
correct call status.

We sent HF the following +CIND thus the call status index should be 1.
+CIND: ("CALL",(0,1)),("CALLSETUP",(0-3)), ...

Got +CIEV: 1,1 when SCO connection started
> HCI Event: Synchronous Connect Complete (0x2c) plen 17
        Status: Success (0x00)
        Handle: 257
        Address: 7C:96:D2:8B:F8:BC (OUI 7C-96-D2)
        Link type: eSCO (0x02)
        Transmission interval: 0x0c
        Retransmission window: 0x02
        RX packet length: 60
        TX packet length: 60
        Air mode: CVSD (0x02)
< HCI Command: Sniff Subrating (0x02|0x0011) plen 8
        Handle: 256
        Max latency: 0.000 msec (0x0000)
        Min remote timeout: 0.000 msec (0x0000)
        Min local timeout: 0.000 msec (0x0000)
< ACL Data TX: Handle 256 flags 0x00 dlen 22
      Channel: 449 len 18 [PSM 0 mode Basic (0x00)] {chan 65535}
        19 ef 1d 0d 0a 2b 43 49 45 56 3a 20 31 2c 31 0d  .....+CIEV: 1,1.
        0a 55                                            .U

Got +CIEV: 1,0 when disconnect
> HCI Event: Disconnect Complete (0x05) plen 4
        Status: Success (0x00)
        Handle: 257
        Reason: Connection Terminated By Local Host (0x16)
< HCI Command: Sniff Subrating (0x02|0x0011) plen 8
        Handle: 256
        Max latency: 750.000 msec (0x04b0)
        Min remote timeout: 1.250 msec (0x0002)
        Min local timeout: 1.250 msec (0x0002)
< ACL Data TX: Handle 256 flags 0x00 dlen 22
      Channel: 2563 len 18 [PSM 3 mode Basic (0x00)] {chan 2}
      RFCOMM: Unnumbered Info with Header Check (UIH) (0xef)
         Address: 0x63 cr 1 dlci 0x18
         Control: 0xef poll/final 0
         Length: 14
         FCS: 0x0e
        0d 0a 2b 43 49 45 56 3a 20 31 2c 30 0d 0a 0e     ..+CIEV: 1,0...

Tag: #floss
Bug: 213408429
Test: Build, flush, put to HFP mode, start then stop call, capture
btsnoop and verify +CIEV commands show up at when the call starts/stops
with correct call status

BYPASS_LONG_LINES_REASON: Bluetooth likes 120 char lines

Change-Id: Ib9af4bf0ebe695ede4614703a6d0ca2adf5478a8
parent fb2277f3
Loading
Loading
Loading
Loading
+50 −39
Original line number Diff line number Diff line
@@ -50,8 +50,11 @@ class DBusHeadsetCallbacks : public headset::Callbacks {
    return instance;
  }

  DBusHeadsetCallbacks(headset::Interface* headset) : headset_(headset){};
  DBusHeadsetCallbacks(headset::Interface* headset) : headset_(headset) {
    call_status = 0;
  };

  // headset::Callbacks
  void ConnectionStateCallback(headset::bthf_connection_state_t state, RawAddress* bd_addr) override {
    LOG_INFO("ConnectionStateCallback from %s", bd_addr->ToString().c_str());
    topshim::rust::internal::connection_state_cb(state, bd_addr);
@@ -63,17 +66,7 @@ class DBusHeadsetCallbacks : public headset::Callbacks {

    switch (state) {
      case headset::bthf_audio_state_t::BTHF_AUDIO_STATE_CONNECTED:
        // This triggers a +CIEV command to set the call status for HFP
        // devices. It is required along with the SCO establishment for some
        // devices to provide sound.
        headset_->PhoneStateChange(
            /*num_active=*/1,
            /*num_held=*/0,
            /*call_setup_state=*/headset::bthf_call_state_t::BTHF_CALL_STATE_IDLE,
            /*number=*/"",
            /*type=*/(headset::bthf_call_addrtype_t)0,
            /*name=*/"",
            /*bd_addr=*/bd_addr);
        SetCallStatus(1, bd_addr);
        // This triggers a +VGS command to set the speaker volume for HFP
        // devices.
        // TODO(b/215089433): Add a set volume API and have client to handle the
@@ -81,22 +74,7 @@ class DBusHeadsetCallbacks : public headset::Callbacks {
        headset_->VolumeControl(headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK, 5, bd_addr);
        return;
      case headset::bthf_audio_state_t::BTHF_AUDIO_STATE_DISCONNECTED:
        headset_->PhoneStateChange(
            /*num_active=*/0,
            /*num_held=*/0,
            /*call_setup_state=*/headset::bthf_call_state_t::BTHF_CALL_STATE_DISCONNECTED,
            /*number=*/"",
            /*type=*/(headset::bthf_call_addrtype_t)0,
            /*name=*/"",
            /*bd_addr=*/bd_addr);
        headset_->PhoneStateChange(
            /*num_active=*/0,
            /*num_held=*/0,
            /*call_setup_state=*/headset::bthf_call_state_t::BTHF_CALL_STATE_IDLE,
            /*number=*/"",
            /*type=*/(headset::bthf_call_addrtype_t)0,
            /*name=*/"",
            /*bd_addr=*/bd_addr);
        SetCallStatus(0, bd_addr);
        return;
      default:
        return;
@@ -148,17 +126,20 @@ class DBusHeadsetCallbacks : public headset::Callbacks {
  }

  void AtClccCallback(RawAddress* bd_addr) override {
    // If we want to support the Enhanced Call Status feature, we need to use this
    // callback to send response like "+CLCC: 0,0,0,0,0," with the following codes.
    // headset_->ClccResponse(
    //    0,
    //    headset::BTHF_CALL_DIRECTION_OUTGOING,
    //    headset::BTHF_CALL_STATE_ACTIVE,
    //    headset::BTHF_CALL_TYPE_VOICE,
    //    headset::BTHF_CALL_MPTY_TYPE_SINGLE,
    //    NULL,
    //    headset::BTHF_CALL_ADDRTYPE_UNKNOWN,
    //    bd_addr);
    // Reply +CLCC:<idx>,<dir>,<status>,<mode>,<mprty>[,<number>,<type>] if
    // there is an active audio connection. Simply rely OK otherwise.
    // This is required for some headsets to start to send actual data to AG.
    if (call_status)
      headset_->ClccResponse(
          /*index=*/1,
          /*dir=*/headset::BTHF_CALL_DIRECTION_OUTGOING,
          /*state=*/headset::BTHF_CALL_STATE_ACTIVE,
          /*mode=*/headset::BTHF_CALL_TYPE_VOICE,
          /*multi_party=*/headset::BTHF_CALL_MPTY_TYPE_SINGLE,
          /*number=*/"",
          /*type=*/headset::BTHF_CALL_ADDRTYPE_UNKNOWN,
          bd_addr);

    headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
  }

@@ -188,6 +169,36 @@ class DBusHeadsetCallbacks : public headset::Callbacks {

 private:
  headset::Interface* headset_;
  int call_status;

  void SetCallStatus(int call, RawAddress* bd_addr) {
    if (call == call_status) return;

    if (call) {
      // This triggers a +CIEV command to set the call status for HFP
      // devices. It is required along with the SCO establishment for some
      // devices to provide sound.
      headset_->PhoneStateChange(
          /*num_active=*/1,
          /*num_held=*/0,
          /*call_setup_state=*/headset::bthf_call_state_t::BTHF_CALL_STATE_IDLE,
          /*number=*/"",
          /*type=*/(headset::bthf_call_addrtype_t)0,
          /*name=*/"",
          /*bd_addr=*/bd_addr);
    } else {
      headset_->PhoneStateChange(
          /*num_active=*/0,
          /*num_held=*/0,
          /*call_setup_state=*/headset::bthf_call_state_t::BTHF_CALL_STATE_IDLE,
          /*number=*/"",
          /*type=*/(headset::bthf_call_addrtype_t)0,
          /*name=*/"",
          /*bd_addr=*/bd_addr);
    }

    call_status = call;
  }
};

int HfpIntf::init() {