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

Commit 9ab368d0 authored by Charlie Boutier's avatar Charlie Boutier Committed by Automerger Merge Worker
Browse files

Merge "Blueberry: Implement A2dp and Host interface" am: f03b15b7 am:...

Merge "Blueberry: Implement A2dp and Host interface" am: f03b15b7 am: b7fd1c18 am: 3b4ddfba am: 39f9de0b

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/1998890

Change-Id: I3a407ce3b88b6c5171413b69936d318425122073
parents 4af6e264 39f9de0b
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ package {
android_test {
    name: "BlueberryServer",
    srcs: ["src/**/*.kt"],
    platform_apis: true,
    certificate: "platform",

    static_libs: [
@@ -14,6 +15,10 @@ android_test {
        "grpc-java-lite",
        "guava",
        "opencensus-java-api",
        "kotlinx_coroutines",
        "blueberry-grpc-java",
        "blueberry-proto-java",
        "opencensus-java-contrib-grpc-metrics",
    ],

    dex_preopt: {
@@ -23,3 +28,48 @@ android_test {
        enabled: false,
    },
}

java_library {
    name: "blueberry-grpc-java",
    visibility: ["//visibility:private"],
    srcs: [
        "proto/blueberry/*.proto",
    ],
    static_libs: [
        "blueberry-proto-java",
        "grpc-java-lite",
        "guava",
        "opencensus-java-api",
        "libprotobuf-java-lite",
        "javax_annotation-api_1.3.2",
    ],
    proto: {
        include_dirs: [
            "packages/modules/Bluetooth/android/blueberry/server/proto",
            "external/protobuf/src",
        ],
        plugin: "grpc-java-plugin",
        output_params: [
           "lite",
        ],
    },
}

java_library {
    name: "blueberry-proto-java",
    visibility: ["//visibility:private"],
    srcs: [
        "proto/blueberry/*.proto",
        ":libprotobuf-internal-protos",
    ],
    static_libs: [
        "libprotobuf-java-lite",
    ],
    proto: {
        type: "lite",
        include_dirs: [
            "packages/modules/Bluetooth/android/blueberry/server/proto",
            "external/protobuf/src",
        ],
    },
}
+5 −1
Original line number Diff line number Diff line
@@ -21,9 +21,13 @@
        <uses-library android:name="android.test.runner" />
    </application>

    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />

    <instrumentation android:name="com.android.blueberry.Server"
    <instrumentation android:name="com.android.blueberry.Main"
                     android:targetPackage="com.android.blueberry"
                     android:label="Blueberry Android Server" />
</manifest>
+250 −0
Original line number Diff line number Diff line
syntax = "proto3";

option java_outer_classname = "A2dpProto";

package blueberry;

import "blueberry/host.proto";
import "google/protobuf/wrappers.proto";

// Service to trigger A2DP (Advanced Audio Distribution Profile) procedures.
//
// Requirements for the implementor:
// - Streams must not be automatically opened, even if discovered.
// - The `Host` service must be implemented
//
// References:
// - [A2DP] Bluetooth SIG, Specification of the Bluetooth System,
//    Advanced Audio Distribution, Version 1.3 or Later
// - [AVDTP] Bluetooth SIG, Specification of the Bluetooth System,
//    Audio/Video Distribution Transport Protocol, Version 1.3 or Later
service A2DP {
  // Open a stream from a local **Source** endpoint to a remote **Sink**
  // endpoint.
  //
  // The returned source should be in the AVDTP_OPEN state (see [AVDTP] 9.1).
  // The rpc must block until the stream has reached this state.
  //
  // A cancellation of this call must result in aborting the current
  // AVDTP procedure (see [AVDTP] 9.9).
  rpc OpenSource(OpenSourceRequest) returns (OpenSourceResponse);
  // Open a stream from a local **Sink** endpoint to a remote **Source**
  // endpoint.
  //
  // The returned sink must be in the AVDTP_OPEN state (see [AVDTP] 9.1).
  // The rpc must block until the stream has reached this state.
  //
  // A cancellation of this call must result in aborting the current
  // AVDTP procedure (see [AVDTP] 9.9).
  rpc OpenSink(OpenSinkRequest) returns (OpenSinkResponse);
  // Wait for a stream from a local **Source** endpoint to
  // a remote **Sink** endpoint to open.
  //
  // The returned source should be in the AVDTP_OPEN state (see [AVDTP] 9.1).
  // The rpc must block until the stream has reached this state.
  //
  // If the peer has opened a source prior to this call, the server will
  // return it. The server must return the same source only once.
  rpc WaitSource(WaitSourceRequest) returns (WaitSourceResponse);
  // Wait for a stream from a local **Sink** endpoint to
  // a remote **Source** endpoint to open.
  //
  // The returned sink should be in the AVDTP_OPEN state (see [AVDTP] 9.1).
  // The rpc must block until the stream has reached this state.
  //
  // If the peer has opened a sink prior to this call, the server will
  // return it. The server must return the same sink only once.
  rpc WaitSink(WaitSinkRequest) returns (WaitSinkResponse);
  // Get if the stream is suspended
  rpc IsSuspended(IsSuspendedRequest) returns (IsSuspendedResponse);
  // Start a suspended stream.
  rpc Start(StartRequest) returns (StartResponse);
  // Suspend a started stream.
  rpc Suspend(SuspendRequest) returns (SuspendResponse);
  // Close a stream, the source or sink tokens must not be reused afterwards.
  rpc Close(CloseRequest) returns (CloseResponse);
  // Get the `AudioEncoding` value of a stream
  rpc GetAudioEncoding(GetAudioEncodingRequest) returns (GetAudioEncodingResponse);
  // Playback audio by a `Source`
  rpc PlaybackAudio(stream PlaybackAudioRequest) returns (PlaybackAudioResponse);
  // Capture audio from a `Sink`
  rpc CaptureAudio(CaptureAudioRequest) returns (stream CaptureAudioResponse);
}

// Audio encoding formats.
enum AudioEncoding {
  // Interleaved stereo frames with 16-bit signed little-endian linear PCM
  // samples at 44100Hz sample rate
  PCM_S16_LE_44K1_STEREO = 0;
  // Interleaved stereo frames with 16-bit signed little-endian linear PCM
  // samples at 48000Hz sample rate
  PCM_S16_LE_48K_STEREO = 1;
}

// A Token representing a Source stream (see [A2DP] 2.2).
// It's acquired via an OpenSource on the A2DP service.
message Source {
  // Opaque value filled by the GRPC server, must not
  // be modified nor crafted.
  bytes cookie = 1;
}

// A Token representing a Sink stream (see [A2DP] 2.2).
// It's acquired via an OpenSink on the A2DP service.
message Sink {
  // Opaque value filled by the GRPC server, must not
  // be modified nor crafted.
  bytes cookie = 1;
}

// Request for the `OpenSource` method.
message OpenSourceRequest {
  // The connection that will open the stream.
  Connection connection = 1;
}

// Response for the `OpenSource` method.
message OpenSourceResponse {
  // Result of the `OpenSource` call:
  // - If successful: a Source
  oneof result {
    Source source = 1;
  }
}

// Request for the `OpenSink` method.
message OpenSinkRequest {
  // The connection that will open the stream.
  Connection connection = 1;
}

// Response for the `OpenSink` method.
message OpenSinkResponse {
  // Result of the `OpenSink` call:
  // - If successful: a Sink
  oneof result {
    Sink sink = 1;
  }
}

// Request for the `WaitSource` method.
message WaitSourceRequest {
  // The connection that is awaiting the stream.
  Connection connection = 1;
}

// Response for the `WaitSource` method.
message WaitSourceResponse {
  // Result of the `WaitSource` call:
  // - If successful: a Source
  oneof result {
    Source source = 1;
  }
}

// Request for the `WaitSink` method.
message WaitSinkRequest {
  // The connection that is awaiting the stream.
  Connection connection = 1;
}

// Response for the `WaitSink` method.
message WaitSinkResponse {
  // Result of the `WaitSink` call:
  // - If successful: a Sink
  oneof result {
    Sink sink = 1;
  }
}

// Request for the `IsSuspended` method.
message IsSuspendedRequest {
  // The stream on which the function will check if it's suspended
  oneof target {
    Sink sink = 1;
    Source source = 2;
  }
}

// Response for the `IsSuspended` method.
message IsSuspendedResponse {
  bool is_suspended = 1;
}

// Request for the `Start` method.
message StartRequest {
  // Target of the start, either a Sink or a Source.
  oneof target {
    Sink sink = 1;
    Source source = 2;
  }
}

// Response for the `Start` method.
message StartResponse {}

// Request for the `Suspend` method.
message SuspendRequest {
  // Target of the suspend, either a Sink or a Source.
  oneof target {
    Sink sink = 1;
    Source source = 2;
  }
}

// Response for the `Suspend` method.
message SuspendResponse {}

// Request for the `Close` method.
message CloseRequest {
  // Target of the close, either a Sink or a Source.
  oneof target {
    Sink sink = 1;
    Source source = 2;
  }
}

// Response for the `Close` method.
message CloseResponse {}

// Request for the `GetAudioEncoding` method.
message GetAudioEncodingRequest {
  // The stream on which the function will read the `AudioEncoding`.
  oneof target {
    Sink sink = 1;
    Source source = 2;
  }
}

// Response for the `GetAudioEncoding` method.
message GetAudioEncodingResponse {
  // Audio encoding of the stream.
  AudioEncoding encoding = 1;
}

// Request for the `PlaybackAudio` method.
message PlaybackAudioRequest {
  // Source that will playback audio.
  Source source = 1;
  // Audio data to playback.
  // The audio data must be encoded in the specified `AudioEncoding` value
  // obtained in response of a `GetAudioEncoding` method call.
  bytes data = 2;
}

// Response for the `PlaybackAudio` method.
message PlaybackAudioResponse {}

// Request for the `CaptureAudio` method.
message CaptureAudioRequest {
  // Sink that will capture audio
  Sink sink = 1;
}

// Response for the `CaptureAudio` method.
message CaptureAudioResponse {
  // Captured audio data.
  // The audio data is encoded in the specified `AudioEncoding` value
  // obained in response of a `GetAudioEncoding` method call.
  bytes data = 1;
}
 No newline at end of file
+103 −0
Original line number Diff line number Diff line
syntax = "proto3";

option java_outer_classname = "HostProto";

package blueberry;

import "google/protobuf/empty.proto";

// Service to trigger Bluetooth Host procedures
//
// At startup, the Host must be in BR/EDR connectable mode
// (see GAP connectability modes)
service Host {
  // Reset the host.
  // **After** responding to this command, the GRPC server should loose
  // all its state.
  // This is comparable to a process restart or an hardware reset.
  // The GRPC server might take some time to be available after
  // this command.
  rpc Reset(google.protobuf.Empty) returns (google.protobuf.Empty);
  // Create an ACL BR/EDR connection to a peer.
  // This should send a CreateConnection on the HCI level.
  // If the two devices have not established a previous bond,
  // the peer must be discoverable.
  rpc Connect(ConnectRequest) returns (ConnectResponse);
  // Get an active ACL BR/EDR connection to a peer.
  rpc GetConnection(GetConnectionRequest) returns (GetConnectionResponse);
  // Wait for an ACL BR/EDR connection from a peer.
  rpc WaitConnection(WaitConnectionRequest) returns (WaitConnectionResponse);
  // Disconnect an ACL BR/EDR connection. The Connection must not be reused afterwards.
  rpc Disconnect(DisconnectRequest) returns (DisconnectResponse);
  // Read the local Bluetooth device address.
  // This should return the same value as a Read BD_ADDR HCI command.
  rpc ReadLocalAddress(google.protobuf.Empty) returns (ReadLocalAddressResponse);
}

// A Token representing an ACL connection.
// It's acquired via a Connect on the Host service.
message Connection {
  // Opaque value filled by the GRPC server, must not
  // be modified nor crafted.
  bytes cookie = 1;
}

// Request of the `Connect` method.
message ConnectRequest {
  // Peer Bluetooth Device Address as array of 6 bytes.
  bytes address = 1;
}

// Response of the `Connect` method.
message ConnectResponse {
  // Result of the `Connect` call:
  // - If successful: a Connection
  oneof result {
    Connection connection = 1;
  }
}

// Request of the `GetConnection` method.
message GetConnectionRequest {
  // Peer Bluetooth Device Address as array of 6 bytes.
  bytes address = 1;
}

// Response of the `GetConnection` method.
message GetConnectionResponse {
  // Result of the `GetConnection` call:
  // - If successful: a Connection
  oneof result {
    Connection connection = 1;
  }
}

// Request of the `WaitConnection` method.
message WaitConnectionRequest {
  // Peer Bluetooth Device Address as array of 6 bytes.
  bytes address = 1;
}

// Response of the `WaitConnection` method.
message WaitConnectionResponse {
  // Result of the `WaitConnection` call:
  // - If successful: a Connection
  oneof result {
    Connection connection = 1;
  }
}

// Request of the `Disconnect` method.
message DisconnectRequest {
  // Connection that should be disconnected.
  Connection connection = 1;
}

// Response of the `Disconnect` method.
message DisconnectResponse {}

// Response of the `ReadLocalAddress` method.
message ReadLocalAddressResponse {
  // Local Bluetooth Device Address as array of 6 bytes.
  bytes address = 1;
}
 No newline at end of file
+326 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading