1// Copyright 2022 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15syntax = "proto3"; 16 17package pandora; 18 19import "pandora/host.proto"; 20import "google/protobuf/empty.proto"; 21import "google/protobuf/wrappers.proto"; 22 23option java_outer_classname = "A2DPProto"; 24 25// Service to trigger A2DP (Advanced Audio Distribution Profile) procedures. 26// 27// Requirements for the implementer: 28// - Streams must not be automatically opened, even if discovered. 29// - The `Host` service must be implemented 30// 31// References: 32// - [A2DP] Bluetooth SIG, Specification of the Bluetooth System, 33// Advanced Audio Distribution, Version 1.3 or Later 34// - [AVDTP] Bluetooth SIG, Specification of the Bluetooth System, 35// Audio/Video Distribution Transport Protocol, Version 1.3 or Later 36service A2DP { 37 // Open a stream from a local **Source** endpoint to a remote **Sink** 38 // endpoint. 39 // 40 // The returned source should be in the AVDTP_OPEN state (see [AVDTP] 9.1). 41 // The rpc must block until the stream has reached this state. 42 // 43 // A cancellation of this call must result in aborting the current 44 // AVDTP procedure (see [AVDTP] 9.9). 45 rpc OpenSource(OpenSourceRequest) returns (OpenSourceResponse); 46 // Open a stream from a local **Sink** endpoint to a remote **Source** 47 // endpoint. 48 // 49 // The returned sink must be in the AVDTP_OPEN state (see [AVDTP] 9.1). 50 // The rpc must block until the stream has reached this state. 51 // 52 // A cancellation of this call must result in aborting the current 53 // AVDTP procedure (see [AVDTP] 9.9). 54 rpc OpenSink(OpenSinkRequest) returns (OpenSinkResponse); 55 // Wait for a stream from a local **Source** endpoint to 56 // a remote **Sink** endpoint to open. 57 // 58 // The returned source should be in the AVDTP_OPEN state (see [AVDTP] 9.1). 59 // The rpc must block until the stream has reached this state. 60 // 61 // If the peer has opened a source prior to this call, the server will 62 // return it. The server must return the same source only once. 63 rpc WaitSource(WaitSourceRequest) returns (WaitSourceResponse); 64 // Wait for a stream from a local **Sink** endpoint to 65 // a remote **Source** endpoint to open. 66 // 67 // The returned sink should be in the AVDTP_OPEN state (see [AVDTP] 9.1). 68 // The rpc must block until the stream has reached this state. 69 // 70 // If the peer has opened a sink prior to this call, the server will 71 // return it. The server must return the same sink only once. 72 rpc WaitSink(WaitSinkRequest) returns (WaitSinkResponse); 73 // Get if the stream is suspended 74 rpc IsSuspended(IsSuspendedRequest) returns (google.protobuf.BoolValue); 75 // Start an opened stream. 76 // 77 // The rpc must block until the stream has reached the 78 // AVDTP_STREAMING state (see [AVDTP] 9.1). 79 rpc Start(StartRequest) returns (StartResponse); 80 // Suspend a streaming stream. 81 // 82 // The rpc must block until the stream has reached the AVDTP_OPEN 83 // state (see [AVDTP] 9.1). 84 rpc Suspend(SuspendRequest) returns (SuspendResponse); 85 // Close a stream, the source or sink tokens must not be reused afterwards. 86 rpc Close(CloseRequest) returns (CloseResponse); 87 // Get the `AudioEncoding` value of a stream 88 rpc GetAudioEncoding(GetAudioEncodingRequest) 89 returns (GetAudioEncodingResponse); 90 // Playback audio by a `Source` 91 rpc PlaybackAudio(stream PlaybackAudioRequest) 92 returns (PlaybackAudioResponse); 93 // Capture audio from a `Sink` 94 rpc CaptureAudio(CaptureAudioRequest) returns (stream CaptureAudioResponse); 95} 96 97// Audio encoding formats. 98enum AudioEncoding { 99 // Interleaved stereo frames with 16-bit signed little-endian linear PCM 100 // samples at 44100Hz sample rate 101 PCM_S16_LE_44K1_STEREO = 0; 102 // Interleaved stereo frames with 16-bit signed little-endian linear PCM 103 // samples at 48000Hz sample rate 104 PCM_S16_LE_48K_STEREO = 1; 105} 106 107// A Token representing a Source stream (see [A2DP] 2.2). 108// It's acquired via an OpenSource on the A2DP service. 109message Source { 110 // Opaque value filled by the GRPC server, must not 111 // be modified nor crafted. 112 bytes cookie = 1; 113} 114 115// A Token representing a Sink stream (see [A2DP] 2.2). 116// It's acquired via an OpenSink on the A2DP service. 117message Sink { 118 // Opaque value filled by the GRPC server, must not 119 // be modified nor crafted. 120 bytes cookie = 1; 121} 122 123// Request for the `OpenSource` method. 124message OpenSourceRequest { 125 // The connection that will open the stream. 126 Connection connection = 1; 127} 128 129// Response for the `OpenSource` method. 130message OpenSourceResponse { 131 // Result of the `OpenSource` call. 132 oneof result { 133 // Opened stream. 134 Source source = 1; 135 // The Connection disconnected. 136 google.protobuf.Empty disconnected = 2; 137 } 138} 139 140// Request for the `OpenSink` method. 141message OpenSinkRequest { 142 // The connection that will open the stream. 143 Connection connection = 1; 144} 145 146// Response for the `OpenSink` method. 147message OpenSinkResponse { 148 // Result of the `OpenSink` call. 149 oneof result { 150 // Opened stream. 151 Sink sink = 1; 152 // The Connection disconnected. 153 google.protobuf.Empty disconnected = 2; 154 } 155} 156 157// Request for the `WaitSource` method. 158message WaitSourceRequest { 159 // The connection that is awaiting the stream. 160 Connection connection = 1; 161} 162 163// Response for the `WaitSource` method. 164message WaitSourceResponse { 165 // Result of the `WaitSource` call. 166 oneof result { 167 // Awaited stream. 168 Source source = 1; 169 // The Connection disconnected. 170 google.protobuf.Empty disconnected = 2; 171 } 172} 173 174// Request for the `WaitSink` method. 175message WaitSinkRequest { 176 // The connection that is awaiting the stream. 177 Connection connection = 1; 178} 179 180// Response for the `WaitSink` method. 181message WaitSinkResponse { 182 // Result of the `WaitSink` call. 183 oneof result { 184 // Awaited stream. 185 Sink sink = 1; 186 // The Connection disconnected. 187 google.protobuf.Empty disconnected = 2; 188 } 189} 190 191// Request for the `IsSuspended` method. 192message IsSuspendedRequest { 193 // The stream on which the function will check if it's suspended 194 oneof target { 195 Sink sink = 1; 196 Source source = 2; 197 } 198} 199 200// Request for the `Start` method. 201message StartRequest { 202 // Target of the start, either a Sink or a Source. 203 oneof target { 204 Sink sink = 1; 205 Source source = 2; 206 } 207} 208 209// Response for the `Start` method. 210message StartResponse { 211 // Result of the `Start` call. 212 oneof result { 213 // Stream successfully started. 214 google.protobuf.Empty started = 1; 215 // Stream is already in AVDTP_STREAMING state. 216 google.protobuf.Empty already_started = 2; 217 // The Connection disconnected. 218 google.protobuf.Empty disconnected = 3; 219 } 220} 221 222// Request for the `Suspend` method. 223message SuspendRequest { 224 // Target of the suspend, either a Sink or a Source. 225 oneof target { 226 Sink sink = 1; 227 Source source = 2; 228 } 229} 230 231// Response for the `Suspend` method. 232message SuspendResponse { 233 // Result of the `Suspend` call. 234 oneof result { 235 // Stream successfully suspended. 236 google.protobuf.Empty suspended = 1; 237 // Stream is already in AVDTP_OPEN state. 238 google.protobuf.Empty already_suspended = 2; 239 // The Connection disconnected. 240 google.protobuf.Empty disconnected = 3; 241 } 242} 243 244// Request for the `Close` method. 245message CloseRequest { 246 // Target of the close, either a Sink or a Source. 247 oneof target { 248 Sink sink = 1; 249 Source source = 2; 250 } 251} 252 253// Response for the `Close` method. 254message CloseResponse {} 255 256// Request for the `GetAudioEncoding` method. 257message GetAudioEncodingRequest { 258 // The stream on which the function will read the `AudioEncoding`. 259 oneof target { 260 Sink sink = 1; 261 Source source = 2; 262 } 263} 264 265// Response for the `GetAudioEncoding` method. 266message GetAudioEncodingResponse { 267 // Audio encoding of the stream. 268 AudioEncoding encoding = 1; 269} 270 271// Request for the `PlaybackAudio` method. 272message PlaybackAudioRequest { 273 // Source that will playback audio. 274 Source source = 1; 275 // Audio data to playback. 276 // The audio data must be encoded in the specified `AudioEncoding` value 277 // obtained in response of a `GetAudioEncoding` method call. 278 bytes data = 2; 279} 280 281// Response for the `PlaybackAudio` method. 282message PlaybackAudioResponse {} 283 284// Request for the `CaptureAudio` method. 285message CaptureAudioRequest { 286 // Sink that will capture audio 287 Sink sink = 1; 288} 289 290// Response for the `CaptureAudio` method. 291message CaptureAudioResponse { 292 // Captured audio data. 293 // The audio data is encoded in the specified `AudioEncoding` value 294 // obtained in response of a `GetAudioEncoding` method call. 295 bytes data = 1; 296} 297