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

Commit e7615c27 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "A2DP: BluetoothA2dp@1.0 is deprecated"

parents d2ff3b06 a5131a64
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ cc_library_static {
        "src/bluetooth.cc",
        // BTIF implementation
        "src/btif_a2dp.cc",
        "src/btif_a2dp_audio_interface.cc",
        "src/btif_a2dp_control.cc",
        "src/btif_a2dp_sink.cc",
        "src/btif_a2dp_source.cc",
+0 −3
Original line number Diff line number Diff line
@@ -36,9 +36,6 @@ static_library("btif") {
    # BTIF implementation
    "src/btif_a2dp.cc",

    # "TODO(abps) - Move this abstraction elsewhere
    # "src/btif_a2dp_audio_interface.cc",
    "src/btif_a2dp_audio_interface_linux.cc",
    "src/btif_a2dp_control.cc",
    "src/btif_a2dp_sink.cc",
    "src/btif_a2dp_source.cc",
+0 −35
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright (C) 2016 The Android Open Source Project
 *  Copyright (C) 2009-2012 Broadcom Corporation
 *
 *  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_A2DP_AUDIO_INTERFACE_H
#define BTIF_A2DP_AUDIO_INTERFACE_H

#include "bta_av_api.h"

/*Default LDAC bitrate */
#define DEFAULT_LDAC_BITRATE_48KHZ 660000
#define DEFAULT_LDAC_BITRATE_441KHZ 606000

void btif_a2dp_audio_on_started(tBTA_AV_STATUS status);
void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status);
void btif_a2dp_audio_on_suspended(tBTA_AV_STATUS status);
void btif_a2dp_audio_interface_start_session(void);
void btif_a2dp_audio_interface_end_session(void);

#endif /* BTIF_A2DP_AUDIO_INTERFACE_H */
+0 −16
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@
#include "bt_common.h"
#include "bta_av_api.h"
#include "btif_a2dp.h"
#include "btif_a2dp_audio_interface.h"
#include "btif_a2dp_control.h"
#include "btif_a2dp_sink.h"
#include "btif_a2dp_source.h"
@@ -59,10 +58,6 @@ bool btif_a2dp_on_started(const RawAddress& peer_addr, tBTA_AV_START* p_av_start
     * this is not for BTA_AV_START_EVT. */
    if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
      bluetooth::audio::a2dp::ack_stream_started(status);
    } else if (btif_av_is_a2dp_offload_enabled()) {
      // TODO: BluetoothA2dp@1.0 is deprecated
      btif_a2dp_audio_on_started(
          (status == A2DP_CTRL_ACK_SUCCESS) ? BTA_AV_SUCCESS : BTA_AV_FAIL_SDP);
    } else {
      btif_a2dp_command_ack(status);
    }
@@ -99,9 +94,6 @@ bool btif_a2dp_on_started(const RawAddress& peer_addr, tBTA_AV_START* p_av_start
    LOG(ERROR) << __func__ << ": peer " << peer_addr << " A2DP start request failed: status = " << +p_av_start->status;
    if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
      bluetooth::audio::a2dp::ack_stream_started(A2DP_CTRL_ACK_FAILURE);
    } else if (btif_av_is_a2dp_offload_enabled()) {
      // TODO: BluetoothA2dp@1.0 is deprecated
      btif_a2dp_audio_on_started(p_av_start->status);
    } else {
      btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
    }
@@ -120,9 +112,6 @@ void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
  if (bluetooth::audio::a2dp::is_hal_2_0_enabled() ||
      !btif_av_is_a2dp_offload_running()) {
    btif_a2dp_source_on_stopped(p_av_suspend);
  } else if (p_av_suspend != NULL) {
    // TODO: BluetoothA2dp@1.0 is deprecated
    btif_a2dp_audio_on_stopped(p_av_suspend->status);
  }
}

@@ -136,9 +125,6 @@ void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
  if (bluetooth::audio::a2dp::is_hal_2_0_enabled() ||
      !btif_av_is_a2dp_offload_running()) {
    btif_a2dp_source_on_suspended(p_av_suspend);
  } else if (p_av_suspend != NULL) {
    // TODO: BluetoothA2dp@1.0 is deprecated
    btif_a2dp_audio_on_suspended(p_av_suspend->status);
  }
}

@@ -177,8 +163,6 @@ void btif_a2dp_on_offload_started(const RawAddress& peer_addr,
    bluetooth::audio::a2dp::ack_stream_started(ack);
  } else {
    btif_a2dp_command_ack(ack);
    // TODO: BluetoothA2dp@1.0 is deprecated
    btif_a2dp_audio_on_started(status);
  }
}

+0 −505
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright (C) 2017 Google, Inc.
 *
 *  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.
 *
 ******************************************************************************/

#define LOG_TAG "btif_a2dp_audio_interface"

#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioHost.h>
#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
#include <android/hardware/bluetooth/a2dp/1.0/types.h>
#include <base/bind.h>
#include <base/callback.h>
#include <base/location.h>
#include <hwbinder/ProcessState.h>
#include <mutex>

#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
#include "bta/av/bta_av_int.h"
#include "bta/include/bta_av_api.h"
#include "btif/include/btif_a2dp_source.h"
#include "btif/include/btif_av.h"
#include "btif/include/btif_av_co.h"
#include "btif/include/btif_hf.h"
#include "common/metrics.h"
#include "common/time_util.h"
#include "osi/include/log.h"
#include "stack/include/a2dp_codec_api.h"
#include "stack/include/avdt_api.h"
#include "stack/include/btu.h"  // do_in_main_thread

using bluetooth::common::A2dpSessionMetrics;
using bluetooth::common::BluetoothMetricsLogger;

using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
using android::hardware::bluetooth::a2dp::V1_0::Status;
using android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration;
using android::hardware::bluetooth::a2dp::V1_0::CodecType;
using android::hardware::bluetooth::a2dp::V1_0::SampleRate;
using android::hardware::bluetooth::a2dp::V1_0::BitsPerSample;
using android::hardware::bluetooth::a2dp::V1_0::ChannelMode;
using android::hardware::ProcessState;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_vec;
using ::android::sp;
using ::android::wp;
android::sp<IBluetoothAudioOffload> btAudio;

#define CASE_RETURN_STR(const) \
  case const:                  \
    return #const;
static uint8_t a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
static Status mapToStatus(uint8_t resp);
uint8_t btif_a2dp_audio_process_request(uint8_t cmd);

static void btif_a2dp_audio_send_start_req();
static void btif_a2dp_audio_send_suspend_req();
static void btif_a2dp_audio_send_stop_req();
static void btif_a2dp_audio_interface_init();
static void btif_a2dp_audio_interface_deinit();
static void btif_a2dp_audio_interface_restart_session();
// Delay reporting
// static void btif_a2dp_audio_send_sink_latency();

class A2dpOffloadAudioStats {
 public:
  A2dpOffloadAudioStats() { Reset(); }
  void Reset() {
    std::lock_guard<std::recursive_mutex> lock(lock_);
    ResetPreserveSession();
    codec_index_ = -1;
  }
  void ResetPreserveSession() {
    std::lock_guard<std::recursive_mutex> lock(lock_);
    audio_start_time_ms_ = -1;
    audio_stop_time_ms_ = -1;
  }
  void StoreMetrics() {
    std::lock_guard<std::recursive_mutex> lock(lock_);
    if (audio_start_time_ms_ < 0 || audio_stop_time_ms_ < 0) {
      return;
    }
    A2dpSessionMetrics metrics;
    metrics.codec_index = codec_index_;
    metrics.is_a2dp_offload = true;
    if (audio_stop_time_ms_ > audio_start_time_ms_) {
      metrics.audio_duration_ms = audio_stop_time_ms_ - audio_start_time_ms_;
    }
    BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics);
  }
  void LogAudioStart() {
    std::lock_guard<std::recursive_mutex> lock(lock_);
    audio_start_time_ms_ = bluetooth::common::time_get_os_boottime_ms();
  }
  void LogAudioStop() {
    std::lock_guard<std::recursive_mutex> lock(lock_);
    audio_stop_time_ms_ = bluetooth::common::time_get_os_boottime_ms();
  }
  void LogAudioStopMetricsAndReset() {
    std::lock_guard<std::recursive_mutex> lock(lock_);
    LogAudioStop();
    StoreMetrics();
    ResetPreserveSession();
  }
  void SetCodecIndex(int64_t codec_index) {
    std::lock_guard<std::recursive_mutex> lock(lock_);
    codec_index_ = codec_index;
  }

 private:
  std::recursive_mutex lock_;
  int64_t audio_start_time_ms_ = -1;
  int64_t audio_stop_time_ms_ = -1;
  int64_t codec_index_ = -1;
};

static A2dpOffloadAudioStats a2dp_offload_audio_stats;

class BluetoothAudioHost : public IBluetoothAudioHost {
 public:
  Return<void> startStream() override {
    btif_a2dp_audio_send_start_req();
    return Void();
  }
  Return<void> suspendStream() override {
    btif_a2dp_audio_send_suspend_req();
    return Void();
  }
  Return<void> stopStream() override {
    btif_a2dp_audio_send_stop_req();
    return Void();
  }

  // TODO : Delay reporting
  /*    Return<void> a2dp_get_sink_latency() {
          LOG_INFO("%s:start ", __func__);
          btif_a2dp_audio_send_sink_latency();
          return Void();
      }*/
};

class BluetoothAudioDeathRecipient : public hidl_death_recipient {
 public:
  void serviceDied(
      uint64_t /*cookie*/,
      const wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
    LOG_ERROR("%s", __func__);
    // Restart the session on the correct thread
    do_in_main_thread(FROM_HERE,
                      base::Bind(&btif_a2dp_audio_interface_restart_session));
  }
};
sp<BluetoothAudioDeathRecipient> bluetoothAudioDeathRecipient =
    new BluetoothAudioDeathRecipient();

static Status mapToStatus(uint8_t resp) {
  switch (resp) {
    case A2DP_CTRL_ACK_SUCCESS:
      return Status::SUCCESS;
      break;
    case A2DP_CTRL_ACK_PENDING:
      return Status::PENDING;
      break;
    case A2DP_CTRL_ACK_FAILURE:
    case A2DP_CTRL_ACK_INCALL_FAILURE:
    case A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS:
      return Status::FAILURE;
    default:
      APPL_TRACE_WARNING("%s: unknown status recevied :%d", __func__, resp);
      return Status::FAILURE;
      break;
  }
}

static void btif_a2dp_get_codec_configuration(
    CodecConfiguration* p_codec_info) {
  LOG_INFO("%s", __func__);
  tBT_A2DP_OFFLOAD a2dp_offload;
  A2dpCodecConfig* a2dpCodecConfig = bta_av_get_a2dp_current_codec();
  a2dpCodecConfig->getCodecSpecificConfig(&a2dp_offload);
  btav_a2dp_codec_config_t codec_config;
  codec_config = a2dpCodecConfig->getCodecConfig();
  a2dp_offload_audio_stats.SetCodecIndex(a2dpCodecConfig->codecIndex());
  switch (codec_config.codec_type) {
    case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
      p_codec_info->codecType =
          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
              BTA_AV_CODEC_TYPE_SBC;
      p_codec_info->codecSpecific.sbcData.codecParameters =
          a2dp_offload.codec_info[0];
      LOG_INFO(" %s: codec parameters =%d", __func__,
               a2dp_offload.codec_info[0]);
      p_codec_info->codecSpecific.sbcData.minBitpool =
          a2dp_offload.codec_info[1];
      p_codec_info->codecSpecific.sbcData.maxBitpool =
          a2dp_offload.codec_info[2];
      break;
    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
      p_codec_info->codecType =
          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
              BTA_AV_CODEC_TYPE_AAC;
      break;
    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
      p_codec_info->codecType =
          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
              BTA_AV_CODEC_TYPE_APTX;
      break;
    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
      p_codec_info->codecType =
          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
              BTA_AV_CODEC_TYPE_APTXHD;
      break;
    case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
      p_codec_info->codecType =
          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
              BTA_AV_CODEC_TYPE_LDAC;
      p_codec_info->codecSpecific.ldacData.bitrateIndex =
          a2dp_offload.codec_info[6];
      break;
    default:
      APPL_TRACE_ERROR("%s: Unknown Codec type :%d ", __func__,
                       codec_config.codec_type);
  }

  // Obtain the MTU
  RawAddress peer_addr = btif_av_source_active_peer();
  tA2DP_ENCODER_INIT_PEER_PARAMS peer_param;
  bta_av_co_get_peer_params(peer_addr, &peer_param);
  int effectiveMtu = a2dpCodecConfig->getEffectiveMtu();
  if (effectiveMtu > 0 && effectiveMtu < peer_param.peer_mtu) {
    p_codec_info->peerMtu = effectiveMtu;
  } else {
    p_codec_info->peerMtu = peer_param.peer_mtu;
  }
  LOG_INFO("%s: peer MTU: %d effective MTU: %d result MTU: %d", __func__,
           peer_param.peer_mtu, effectiveMtu, p_codec_info->peerMtu);

  p_codec_info->sampleRate =
      (::android::hardware::bluetooth::a2dp::V1_0::SampleRate)
          codec_config.sample_rate;
  p_codec_info->bitsPerSample =
      (::android::hardware::bluetooth::a2dp::V1_0::BitsPerSample)
          codec_config.bits_per_sample;
  p_codec_info->channelMode =
      (::android::hardware::bluetooth::a2dp::V1_0::ChannelMode)
          codec_config.channel_mode;
  p_codec_info->encodedAudioBitrate = a2dpCodecConfig->getTrackBitRate();
}

static void btif_a2dp_audio_interface_init() {
  LOG_INFO("%s", __func__);

  btAudio = IBluetoothAudioOffload::getService();
  CHECK(btAudio != nullptr);

  auto death_link = btAudio->linkToDeath(bluetoothAudioDeathRecipient, 0);
  if (!death_link.isOk()) {
    LOG_ERROR("%s: Cannot observe the Bluetooth Audio HAL's death", __func__);
  }

  LOG_INFO("%s: IBluetoothAudioOffload::getService() returned %p (%s)",
           __func__, btAudio.get(), (btAudio->isRemote() ? "remote" : "local"));

  LOG_INFO("%s:Init returned", __func__);
}

static void btif_a2dp_audio_interface_deinit() {
  LOG_INFO("%s: start", __func__);
  if (btAudio != nullptr) {
    auto death_unlink = btAudio->unlinkToDeath(bluetoothAudioDeathRecipient);
    if (!death_unlink.isOk()) {
      LOG_ERROR("%s: Error unlinking death observer from Bluetooth Audio HAL",
                __func__);
    }
  }
  btAudio = nullptr;
}

void btif_a2dp_audio_interface_start_session() {
  LOG_INFO("%s", __func__);
  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
      bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
  a2dp_offload_audio_stats.Reset();
  btif_a2dp_audio_interface_init();
  CHECK(btAudio != nullptr);
  CodecConfiguration codec_info;
  btif_a2dp_get_codec_configuration(&codec_info);
  android::sp<IBluetoothAudioHost> host_if = new BluetoothAudioHost();
  btAudio->startSession(host_if, codec_info);
}

void btif_a2dp_audio_interface_end_session() {
  LOG_INFO("%s", __func__);
  a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
      bluetooth::common::DISCONNECT_REASON_UNKNOWN, 0);
  a2dp_offload_audio_stats.Reset();
  if (btAudio == nullptr) return;
  auto ret = btAudio->endSession();
  if (!ret.isOk()) {
    LOG_ERROR("HAL server is dead");
  }
  btif_a2dp_audio_interface_deinit();
}

// Conditionally restart the session only if it was started before
static void btif_a2dp_audio_interface_restart_session() {
  LOG_INFO("%s", __func__);
  if (btAudio == nullptr) {
    LOG_INFO("%s: nothing to restart - session was not started", __func__);
    return;
  }
  btAudio = nullptr;
  btif_a2dp_audio_interface_start_session();
}

void btif_a2dp_audio_on_started(tBTA_AV_STATUS status) {
  LOG_INFO("%s: status = %d", __func__, status);
  if (btAudio != nullptr) {
    if (a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
      if (status != A2DP_CTRL_ACK_PENDING) {
        a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
      }
      LOG_INFO("%s: calling method onStarted", __func__);
      auto hal_status = mapToStatus(status);
      btAudio->streamStarted(hal_status);
      if (hal_status == Status::SUCCESS) {
        a2dp_offload_audio_stats.LogAudioStart();
      }
    }
  }
}

void btif_a2dp_audio_on_suspended(tBTA_AV_STATUS status) {
  LOG_INFO("%s: status = %d", __func__, status);
  if (btAudio != nullptr) {
    if (a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND) {
      if (status != A2DP_CTRL_ACK_PENDING) {
        a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
      }
      LOG_INFO("calling method onSuspended");
      auto hal_status = mapToStatus(status);
      btAudio->streamSuspended(hal_status);
      if (hal_status == Status::SUCCESS) {
        a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
      }
    }
  }
}

void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status) {
  LOG_INFO("%s: status = %d", __func__, status);
  if (btAudio != nullptr && a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
    a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
    LOG_INFO("%s: Remote disconnected when start under progress", __func__);
    btAudio->streamStarted(mapToStatus(A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS));
    a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
  }
}
void btif_a2dp_audio_send_start_req() {
  LOG_INFO("%s", __func__);
  uint8_t resp;
  resp = btif_a2dp_audio_process_request(A2DP_CTRL_CMD_START);
  if (btAudio != nullptr) {
    auto status = mapToStatus(resp);
    auto ret = btAudio->streamStarted(status);
    if (status == Status::SUCCESS) {
      a2dp_offload_audio_stats.LogAudioStart();
    }
    if (!ret.isOk()) LOG_ERROR("HAL server died");
  }
}
void btif_a2dp_audio_send_suspend_req() {
  LOG_INFO("%s", __func__);
  uint8_t resp;
  resp = btif_a2dp_audio_process_request(A2DP_CTRL_CMD_SUSPEND);
  if (btAudio != nullptr) {
    auto status = mapToStatus(resp);
    auto ret = btAudio->streamSuspended(status);
    if (status == Status::SUCCESS) {
      a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
    }
    if (!ret.isOk()) LOG_ERROR("HAL server died");
  }
}

void btif_a2dp_audio_send_stop_req() {
  LOG_INFO("%s", __func__);
  btif_a2dp_audio_process_request(A2DP_CTRL_CMD_STOP);
  a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
}

/*void btif_a2dp_audio_send_sink_latency()
{
  LOG_INFO("%s", __func__);
  uint16_t sink_latency = btif_av_get_sink_latency();
  if (btAudio != nullptr) {
    auto ret = btAudio->a2dp_on_get_sink_latency(sink_latency);
    if (!ret.isOk()) LOG_ERROR("server died");
  }
}*/

uint8_t btif_a2dp_audio_process_request(uint8_t cmd) {
  LOG_INFO("%s: cmd: %s", __func__,
           audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
  uint8_t status;
  switch (cmd) {
    case A2DP_CTRL_CMD_START:
      /*
       * Don't send START request to stack while we are in a call.
       * Some headsets such as "Sony MW600", don't allow AVDTP START
       * while in a call, and respond with BAD_STATE.
       */
      if (!bluetooth::headset::IsCallIdle()) {
        APPL_TRACE_WARNING("%s: A2DP command %s failed as call state is busy",
                           __func__,
                           audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
        status = A2DP_CTRL_ACK_INCALL_FAILURE;
        break;
      }
      if (btif_av_stream_started_ready()) {
        /*
         * Already started, setup audio data channel listener and ACK
         * back immediately.
         */
        status = A2DP_CTRL_ACK_SUCCESS;
        break;
      }
      if (btif_av_stream_ready()) {
        /*
         * Post start event and wait for audio path to open.
         * If we are the source, the ACK will be sent after the start
         * procedure is completed, othewise send it now.
         */
        btif_av_stream_start();
        if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
          status = A2DP_CTRL_ACK_SUCCESS;
          break;
        }
        /*Return pending and ack when start stream cfm received from remote*/
        status = A2DP_CTRL_ACK_PENDING;
        break;
      }

      APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
                         __func__,
                         audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
      status = A2DP_CTRL_ACK_FAILURE;
      break;

    case A2DP_CTRL_CMD_STOP:
      if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
          !btif_a2dp_source_is_streaming()) {
        /* We are already stopped, just ack back */
        status = A2DP_CTRL_ACK_SUCCESS;
        break;
      }
      btif_av_stream_stop(RawAddress::kEmpty);
      status = A2DP_CTRL_ACK_SUCCESS;
      break;

    case A2DP_CTRL_CMD_SUSPEND:
      /* Local suspend */
      if (btif_av_stream_started_ready()) {
        btif_av_stream_suspend();
        status = A2DP_CTRL_ACK_PENDING;
        break;
      }
      /* If we are not in started state, just ack back ok and let
       * audioflinger close the channel. This can happen if we are
       * remotely suspended, clear REMOTE SUSPEND flag.
       */
      btif_av_clear_remote_suspend_flag();
      status = A2DP_CTRL_ACK_SUCCESS;
      break;

    default:
      APPL_TRACE_ERROR("UNSUPPORTED CMD (%d)", cmd);
      status = A2DP_CTRL_ACK_FAILURE;
      break;
  }
  LOG_INFO("a2dp-ctrl-cmd : %s DONE returning status %d",
           audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd), status);
  if (status == A2DP_CTRL_ACK_PENDING) {
    a2dp_cmd_pending = cmd;
  } else {
    a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
  }
  return status;
}
Loading