Add support for Multi-A2DP state machines per device
* Reimplement most of the BTIF AV state machinery in C++
- Separate the BTIF AV Source from BTIF AV Sink state:
btif_av_source and btif_av_sink
- Remove the single btif_av_cb control block instance
- Add C++ based BtifStateMachine and remove the older C-based
btif_sm state machine
- Introduce C++ class BtifAvPeer to keep state per peer, and use
a single state machine instance per peer
- Update BTA_AvStart() and BTA_AvStop() to take tBTA_AV_HNDL handle
argument
- Register the BTA handles when enabling the Source/Sink service.
This needs to be done in advance during service startup, otherwise
a connection to a remote device will fail.
- Move local event_handler functions inside C++ ProcessEvent methods,
and pocess the BTIF, BTA AV and BTA AVRCP events per state machine
instance
- Cleanup callbacks and use do_in_jni_thread() to schedule the processing
- Add BTIF AV API that needs to be called by the AVRCP module for certain
AVRCP events: btif_av_avrcp_event_open(), btif_av_avrcp_event_close()
btif_av_avrcp_event_remote_play()
- Add a mechanism to set the active device
- Add BluetoothDevice argument to the codec-related internal Binder
APIs: getCodecStatus(), enableOptionalCodecs(),
disableOptionalCodecs(), setCodecConfigPreference()
- Rename btif_av_move_idle() to btif_av_acl_disconnected() and
refactor the processing to happen within each state machine on the
correct thread.
- Process cleanup_src and cleanup_sink on the JNI thread
- Add a mechanism to track the maximum number of connected devices.
- Add unit tests for the new BtifStateMachine class
* Redesign some of the AVDTP internals so it can handle multiple connected
devices
- Change some of the AVDTP struct entries to C++ classes.
This simplifies significantly the design fixes
- Reorganize the AvdtpScb entries: for each connection the
corresponding SEP entries are within the corresponding AvdtpCcb entry.
- Pass peer address as argument to the API functions inside bta_av_co.cc,
and update the peer address inside the corresponding peer entry in
bta_av_co.cc
- Add various log mesages
- Store precomputed BTA AV SCB index in the AvdtpCcb entry and use it as
appropriate.
- Fix the TCID computation and handling for the AvdtpAdaptationLayer
- Fix the computed value for AVDT_NUM_RT_TBL
- Remove video-related code inside AVDTP
- Refactor/cleanup hard-coded callbacks that depend on the BTA_AV_NUM_STRS
value.
- Update various #define values to support a larger number of connected
devices:
- Maximum number of streams:
BTA_AV_NUM_STRS: 2 -> 6
- BT_RC_NUM_APP: 1 -> 12 (AVRCP-related - 2 * MaxDevices)
- MAX_L2CAP_LINKS: 7 -> 13
- MAX_L2CAP_CHANNELS: 16 -> 32
- AVDT_NUM_LINKS: 2 -> 6
- AVDT_NUM_SEPS: (6 * AVDT_NUM_LINKS) -> 6
Now the value is used for the maximum number of SEPs per device
- AVDT_NUM_TC_TBL: 6 -> (AVDT_NUM_SEPS + AVDT_NUM_LINKS)
- AVCT_NUM_LINKS: 2 -> 6
- AVCT_NUM_CONN: 3 -> 14 (2 * MaxDevices + 2)
Also:
- Update the JNI codec-related calls to use const reference
instead of a pointer
- Update the implementation of bta_av_chk_2nd_start() so it is aligned
with bta_av_chk_start() and cleaned up both functions.
- Rename btif_dispatch_sm_event() to btif_av_dispatch_sm_event() and
btif_report_source_codec_state() to btif_av_report_source_codec_state()
for consistency with the rest of the BTIF AV API.
- Add new function btif_rc_is_connected_peer() and remove
btif_rc_get_connected_peer()
- Add new AVRCP header file btif/include/btif_rc.h
and move the AVRCP "extern" declarations from btif_av.cc there.
- Rename btif_av_execute_service() to btif_av_source_execute_service()
- Cleanup the btif_av.h API descriptions
- Print the BTIF AV state in the "dumpsys bluetooth_manager" output
- Print the BTA AV state in the "dumpsys bluetooth_manager" output
- Print the AVDTP state in the "dumpsys bluetooth_manager" output
- Refactor btif_a2dp_source_cb into a class with internal state.
- Refactor A2DP Source worker thread handling and replace it with
libchrome message handler
- Refactor BtaAvCo component (bta_av_co.cc)
- C++ classes and state
- Rename bta_av_co_audio_src_data_path to
bta_av_co_audio_source_data_path
- Remove most BTA_AV_CO_CP_SCMS_T checks
- Replace mutex_global_lock() usage with local mutex
- Keep codec-specific state per peer
- Keep state about the active peer - the first connected peer is the
default active peer
- Report source codec state only for valid peers; i.e., don't report
source codec state for empty RawAddress
- Keep the contect_protect_active flag per peer
- Print the BTA AV CO state in the dumpsys bluetooth_manager" output
- Misc cleanup in BTA AV
- Add ToString() method to struct btav_a2dp_codec_config_t
- Additional cleanup
Bug: 70350399
Test: Manual and unit tests
Change-Id: Icecd7fd44a222d939b63a7473a2239ae0679f08c
Merged-In: Icecd7fd44a222d939b63a7473a2239ae0679f08c
(cherry picked from commit c7242818d4180dec4eae2e75f9fb91f7f6a160aa)
diff --git a/btif/include/btif_state_machine.h b/btif/include/btif_state_machine.h
new file mode 100644
index 0000000..49b1583
--- /dev/null
+++ b/btif/include/btif_state_machine.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BTIF_STATE_MACHINE_H
+#define BTIF_STATE_MACHINE_H
+
+#include <map>
+#include <utility>
+
+#include <base/logging.h>
+
+/**
+ * State machine used by BTIF components.
+ */
+class BtifStateMachine {
+ public:
+ enum { kStateInvalid = -1 };
+
+ /**
+ * A class to represent the state in the State Machine.
+ */
+ class State {
+ friend class BtifStateMachine;
+
+ public:
+ /**
+ * Constructor.
+ *
+ * @param sm the State Machine to use
+ * @param state_id the unique State ID. It should be a non-negative number.
+ */
+ State(BtifStateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {}
+
+ virtual ~State() = default;
+
+ /**
+ * Process an event.
+ * TODO: The arguments are wrong - used for backward compatibility.
+ * Will be replaced later.
+ *
+ * @param event the event type
+ * @param p_data the event data
+ * @return true if the processing was completed, otherwise false
+ */
+ virtual bool ProcessEvent(uint32_t event, void* p_data) = 0;
+
+ /**
+ * Get the State ID.
+ *
+ * @return the State ID
+ */
+ int StateId() const { return state_id_; }
+
+ protected:
+ /**
+ * Called when a state is entered.
+ */
+ virtual void OnEnter() {}
+
+ /**
+ * Called when a state is exited.
+ */
+ virtual void OnExit() {}
+
+ /**
+ * Transition the State Machine to a new state.
+ *
+ * @param dest_state_id the state ID to transition to. It must be one
+ * of the unique state IDs when the corresponding state was created.
+ */
+ void TransitionTo(int dest_state_id) { sm_.TransitionTo(dest_state_id); }
+
+ /**
+ * Transition the State Machine to a new state.
+ *
+ * @param dest_state the state to transition to. It cannot be nullptr.
+ */
+ void TransitionTo(BtifStateMachine::State* dest_state) {
+ sm_.TransitionTo(dest_state);
+ }
+
+ private:
+ BtifStateMachine& sm_;
+ int state_id_;
+ };
+
+ BtifStateMachine()
+ : initial_state_(nullptr),
+ previous_state_(nullptr),
+ current_state_(nullptr) {}
+ ~BtifStateMachine() {
+ for (auto& kv : states_) delete kv.second;
+ }
+
+ /**
+ * Start the State Machine operation.
+ */
+ void Start() { TransitionTo(initial_state_); }
+
+ /**
+ * Quit the State Machine operation.
+ */
+ void Quit() { previous_state_ = current_state_ = nullptr; }
+
+ /**
+ * Get the current State ID.
+ *
+ * @return the current State ID
+ */
+ int StateId() const {
+ if (current_state_ != nullptr) {
+ return current_state_->StateId();
+ }
+ return kStateInvalid;
+ }
+
+ /**
+ * Get the previous current State ID.
+ *
+ * @return the previous State ID
+ */
+ int PreviousStateId() const {
+ if (previous_state_ != nullptr) {
+ return previous_state_->StateId();
+ }
+ return kStateInvalid;
+ }
+
+ /**
+ * Process an event.
+ * TODO: The arguments are wrong - used for backward compatibility.
+ * Will be replaced later.
+ *
+ * @param event the event type
+ * @param p_data the event data
+ * @return true if the processing was completed, otherwise false
+ */
+ bool ProcessEvent(uint32_t event, void* p_data) {
+ if (current_state_ == nullptr) return false;
+ return current_state_->ProcessEvent(event, p_data);
+ }
+
+ /**
+ * Transition the State Machine to a new state.
+ *
+ * @param dest_state_id the state ID to transition to. It must be one
+ * of the unique state IDs when the corresponding state was created.
+ */
+ void TransitionTo(int dest_state_id) {
+ auto it = states_.find(dest_state_id);
+
+ CHECK(it != states_.end()) << "Unknown State ID: " << dest_state_id;
+ State* dest_state = it->second;
+ TransitionTo(dest_state);
+ }
+
+ /**
+ * Transition the State Machine to a new state.
+ *
+ * @param dest_state the state to transition to. It cannot be nullptr.
+ */
+ void TransitionTo(BtifStateMachine::State* dest_state) {
+ if (current_state_ != nullptr) {
+ current_state_->OnExit();
+ }
+ previous_state_ = current_state_;
+ current_state_ = dest_state;
+ current_state_->OnEnter();
+ }
+
+ /**
+ * Add a state to the State Machine.
+ * The state machine takes ownership on the state - i.e., the state will
+ * be deleted by the State Machine itself.
+ *
+ * @param state the state to add
+ */
+ void AddState(State* state) {
+ states_.insert(std::make_pair(state->StateId(), state));
+ }
+
+ /**
+ * Set the initial state of the State Machine.
+ *
+ * @param initial_state the initial state
+ */
+ void SetInitialState(State* initial_state) { initial_state_ = initial_state; }
+
+ private:
+ State* initial_state_;
+ State* previous_state_;
+ State* current_state_;
+ std::map<int, State*> states_;
+};
+
+#endif // BTIF_STATE_MACHINE_H