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

Commit a7358f37 authored by Ian Coolidge's avatar Ian Coolidge
Browse files

Add bthost, a simple BLE GATT server.

This is accessible via Unix socket.
It only has a couple of interesting features:

 * Built in support for large blob attributes (>512 octets)
 * Attribute caching (avoid frame-level IO for IPC clients)

Some string utilies are taken from modp_b64 and Chromium base.

Bug: 21076037
Change-Id: I6a29959159de76f8dd68d6bbaabe2100daabb6fa
parent 913deefe
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
#
#  Copyright (C) 2015 Google
#
#  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.
#

LOCAL_PATH:= $(call my-dir)

BASE_SRC := \
	base/base64.cpp \
	base/string_split.cpp \
	base/string_number_conversions.cpp \
	modp_b64/modp_b64.cpp

CORE_SRC := \
	a2dp_source.cpp \
	logging_helpers.cpp \
	core_stack.cpp \
	uuid.cpp \
	gatt_server.cpp

include $(CLEAR_VARS)
LOCAL_SRC_FILES := uuid_test.cpp uuid.cpp
LOCAL_CFLAGS += -std=c++11
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := uuid_test_bd
include $(BUILD_HOST_NATIVE_TEST)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
    $(BASE_SRC) \
    $(CORE_SRC) \
    host.cpp \
    main.cpp

LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/../

LOCAL_CFLAGS += -std=c++11
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := bthost
LOCAL_REQUIRED_MODULES = bluetooth.default
LOCAL_SHARED_LIBRARIES += \
    libhardware \
    libcutils \
    liblog

include $(BUILD_EXECUTABLE)
+82 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 2015 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.
//
#include "a2dp_source.h"

#define LOG_TAG "A2dpSource"
#include "osi/include/log.h"

#include "core_stack.h"
#include "logging_helpers.h"
#include "osi/include/osi.h"

namespace {

void ConnectionStateCallback(btav_connection_state_t state,
                             UNUSED_ATTR bt_bdaddr_t *bd_addr) {
  LOG_INFO("%s: %s", __func__, BtAvConnectionStateText(state));
}

void AudioStateCallback(btav_audio_state_t state,
                        UNUSED_ATTR bt_bdaddr_t *bd_addr) {
  LOG_INFO("%s: %s", __func__, BtAvAudioStateText(state));
}

void AudioConfigCallback(UNUSED_ATTR bt_bdaddr_t *bd_addr,
                         UNUSED_ATTR uint32_t sample_rate,
                         UNUSED_ATTR uint8_t channel_count) {
  // I think these are used for audio sink only?
  // TODO(icoolidge): revisit.
}

btav_callbacks_t av_callbacks = {
    sizeof(btav_callbacks_t), ConnectionStateCallback, AudioStateCallback,
    AudioConfigCallback,
};

}  // namespace

namespace bluetooth {

A2dpSource::A2dpSource(CoreStack *bt) : av_(nullptr), bt_(bt) {
  // TODO(icoolidge): DCHECK(bt);
}

int A2dpSource::Start() {
  // Get the interface to the a2dp source profile.
  const void *interface = bt_->GetInterface(BT_PROFILE_ADVANCED_AUDIO_ID);
  if (!interface) {
    LOG_ERROR("Error getting audio source interface");
    return -1;
  }

  av_ = reinterpret_cast<const btav_interface_t *>(interface);

  bt_status_t btstat = av_->init(&av_callbacks);
  if (btstat != BT_STATUS_SUCCESS && btstat != BT_STATUS_DONE) {
    LOG_ERROR("Failed to initialize audio source interface: %s %d",
              BtStatusText(btstat), btstat);
    return -1;
  }
  return 0;
}

int A2dpSource::Stop() {
  // TODO(icoolidge): DCHECK(av_);
  av_->cleanup();
  return 0;
}

}  // namespace bluetooth
+44 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 2015 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.
//
#pragma once

#include "hardware/bluetooth.h"
#include "hardware/bt_av.h"

namespace bluetooth {

class CoreStack;

// This class is just experimental to test out BlueDroid A2DP
// interface, capability, and functionality.
class A2dpSource {
 public:
  explicit A2dpSource(CoreStack* bt);

  // Enables the A2DP source profile in the stack.
  // Creates audio Unix sockets. (see audio_a2dp_hw.h)
  int Start();

  // Disables the A2DP source profile in the stack.
  int Stop();

 private:
  const btav_interface_t* av_;
  // Weak reference.
  CoreStack* bt_;
};

}  // namespace bluetooth
+37 −0
Original line number Diff line number Diff line
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/base64.h"

#include "modp_b64/modp_b64.h"

namespace base {

void Base64Encode(const std::string& input, std::string* output) {
  std::string temp;
  temp.resize(modp_b64_encode_len(input.size()));  // makes room for null byte

  // modp_b64_encode_len() returns at least 1, so temp[0] is safe to use.
  size_t output_size = modp_b64_encode(&(temp[0]), input.data(), input.size());

  temp.resize(output_size);  // strips off null byte
  output->swap(temp);
}

bool Base64Decode(const std::string& input, std::string* output) {
  std::string temp;
  temp.resize(modp_b64_decode_len(input.size()));

  // does not null terminate result since result is binary data!
  size_t input_size = input.size();
  size_t output_size = modp_b64_decode(&(temp[0]), input.data(), input_size);
  if (output_size == MODP_B64_ERROR)
    return false;

  temp.resize(output_size);
  output->swap(temp);
  return true;
}

}  // namespace base
+22 −0
Original line number Diff line number Diff line
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_BASE64_H__
#define BASE_BASE64_H__

#include <string>

namespace base {

// Encodes the input string in base64. The encoding can be done in-place.
void Base64Encode(const std::string& input, std::string* output);

// Decodes the base64 input string.  Returns true if successful and false
// otherwise. The output string is only modified if successful. The decoding can
// be done in-place.
bool Base64Decode(const std::string& input, std::string* output);

}  // namespace base

#endif  // BASE_BASE64_H__
Loading