audio-buffer.h (10557B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#ifndef GUAC_RDP_CHANNELS_AUDIO_INPUT_AUDIO_BUFFER_H 21#define GUAC_RDP_CHANNELS_AUDIO_INPUT_AUDIO_BUFFER_H 22 23#include <guacamole/stream.h> 24#include <guacamole/user.h> 25#include <pthread.h> 26#include <time.h> 27 28/** 29 * The minimum number of milliseconds of audio data that each instance of 30 * guac_rdp_audio_buffer should provide storage for. This buffer space does not 31 * induce additional latency, but is required to compensate for latency and 32 * functions as an upper limit on the amount of latency the buffer will 33 * compensate for. 34 */ 35#define GUAC_RDP_AUDIO_BUFFER_MIN_DURATION 250 36 37/** 38 * A buffer of arbitrary audio data. Received audio data can be written to this 39 * buffer, and will automatically be flushed via a given handler once the 40 * internal buffer reaches capacity. 41 */ 42typedef struct guac_rdp_audio_buffer guac_rdp_audio_buffer; 43 44/** 45 * Handler which is invoked when a guac_rdp_audio_buffer's internal packet 46 * buffer has reached capacity and must be flushed. 47 * 48 * @param audio_buffer 49 * The guac_rdp_audio_buffer that has reached capacity and needs to be 50 * flushed. 51 * 52 * @param length 53 * The number of bytes stored within the buffer. This is guaranteed to be 54 * identical to the packet_size value specified when the audio buffer was 55 * initialized. 56 */ 57typedef void guac_rdp_audio_buffer_flush_handler(guac_rdp_audio_buffer* audio_buffer, int length); 58 59/** 60 * A description of an arbitrary PCM audio format. 61 */ 62typedef struct guac_rdp_audio_format { 63 64 /** 65 * The rate of the audio data in samples per second. 66 */ 67 int rate; 68 69 /** 70 * The number of channels included in the audio data. This will be 1 for 71 * monaural audio and 2 for stereo. 72 */ 73 int channels; 74 75 /** 76 * The size of each sample within the audio data, in bytes. 77 */ 78 int bps; 79 80} guac_rdp_audio_format; 81 82struct guac_rdp_audio_buffer { 83 84 /** 85 * Lock which is acquired/released to ensure accesses to the audio buffer 86 * are atomic. This lock is also bound to the modified pthread_cond_t, 87 * which should be signalled whenever the audio buffer structure has been 88 * modified. 89 */ 90 pthread_mutex_t lock; 91 92 /** 93 * Condition which is signalled when any part of the audio buffer structure 94 * has been modified. 95 */ 96 pthread_cond_t modified; 97 98 /** 99 * The guac_client instance handling the relevant RDP connection. 100 */ 101 guac_client* client; 102 103 /** 104 * The user from which this audio buffer will receive data. If no user has 105 * yet opened an associated audio stream, or if the audio stream has been 106 * closed, this will be NULL. 107 */ 108 guac_user* user; 109 110 /** 111 * The stream from which this audio buffer will receive data. If no user 112 * has yet opened an associated audio stream, or if the audio stream has 113 * been closed, this will be NULL. 114 */ 115 guac_stream* stream; 116 117 /** 118 * The PCM format of the audio stream being received from the user, if any. 119 * If no stream is yet associated, the values stored within this format are 120 * undefined. 121 */ 122 guac_rdp_audio_format in_format; 123 124 /** 125 * The PCM format of the audio stream expected by RDP, if any. If no audio 126 * stream has yet been requested by the RDP server, the values stored 127 * within this format are undefined. 128 */ 129 guac_rdp_audio_format out_format; 130 131 /** 132 * The size that each audio packet must be, in bytes. The packet buffer 133 * within this structure will be at least this size. 134 */ 135 size_t packet_size; 136 137 /** 138 * The total number of bytes available within the packet buffer. 139 */ 140 size_t packet_buffer_size; 141 142 /** 143 * The number of bytes currently stored within the packet buffer. 144 */ 145 int bytes_written; 146 147 /** 148 * The total number of bytes having ever been received by the Guacamole 149 * server for the current audio stream. 150 */ 151 int total_bytes_received; 152 153 /** 154 * The total number of bytes having ever been sent to the RDP server for 155 * the current audio stream. 156 */ 157 int total_bytes_sent; 158 159 /** 160 * All audio data being prepared for sending to the AUDIO_INPUT channel. 161 */ 162 char* packet; 163 164 /** 165 * Thread which flushes the audio buffer at a rate that does not exceed the 166 * the audio sample rate (which might result in dropped samples due to 167 * overflow of the remote audio buffer). 168 */ 169 pthread_t flush_thread; 170 171 /** 172 * The absolute point in time that the next packet of audio data sould be 173 * flushed. Another packet of received data should not be flushed prior to 174 * this time. 175 */ 176 struct timespec next_flush; 177 178 /** 179 * Handler function which will be invoked when a full audio packet is 180 * ready to be flushed to the AUDIO_INPUT channel, if defined. If NULL, 181 * audio packets will simply be ignored. 182 */ 183 guac_rdp_audio_buffer_flush_handler* flush_handler; 184 185 /** 186 * Whether guac_rdp_audio_buffer_free() has been invoked and the audio 187 * buffer is being cleaned up. 188 */ 189 int stopping; 190 191 /** 192 * Arbitrary data assigned by the AUDIO_INPUT plugin implementation. 193 */ 194 void* data; 195 196}; 197 198/** 199 * Allocates a new audio buffer. The new audio buffer will ignore any received 200 * data until guac_rdp_audio_buffer_begin() is invoked, and will resume 201 * ignoring received data once guac_rdp_audio_buffer_end() is invoked. 202 * 203 * @param client 204 * The guac_client instance handling the relevant RDP connection. 205 * 206 * @return 207 * A newly-allocated audio buffer. 208 */ 209guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc(guac_client* client); 210 211/** 212 * Associates the given audio buffer with the underlying audio stream which 213 * has been received from the given Guacamole user. Once both the Guacamole 214 * audio stream and the RDP audio stream are ready, an appropriate "ack" 215 * message will be sent. 216 * 217 * @param audio_buffer 218 * The audio buffer associated with the audio stream just received. 219 * 220 * @param user 221 * The Guacamole user that created the audio stream. 222 * 223 * @param stream 224 * The guac_stream object representing the audio stream. 225 * 226 * @param rate 227 * The rate of the audio stream being received from the user, if any, in 228 * samples per second. 229 * 230 * @param channels 231 * The number of channels included in the audio stream being received from 232 * the user, if any. 233 * 234 * @param bps 235 * The size of each sample within the audio stream being received from the 236 * user, if any, in bytes. 237 */ 238void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer, 239 guac_user* user, guac_stream* stream, int rate, int channels, int bps); 240 241/** 242 * Defines the output format that should be used by the audio buffer when 243 * flushing packets of audio data received via guac_rdp_audio_buffer_write(). 244 * As this format determines how the underlying packet buffer will be 245 * allocated, this function MUST be called prior to the call to 246 * guac_rdp_audio_buffer_begin(). 247 * 248 * @param audio_buffer 249 * The audio buffer to set the output format of. 250 * 251 * @param rate 252 * The rate of the audio stream expected by RDP, in samples per second. 253 * 254 * @param channels 255 * The number of channels included in the audio stream expected by RDP. 256 * 257 * @param bps 258 * The size of each sample within the audio stream expected by RDP, in 259 * bytes. 260 */ 261void guac_rdp_audio_buffer_set_output(guac_rdp_audio_buffer* audio_buffer, 262 int rate, int channels, int bps); 263 264/** 265 * Begins handling of audio data received via guac_rdp_audio_buffer_write() and 266 * allocates the necessary underlying packet buffer. Audio packets having 267 * exactly packet_frames frames will be flushed as available using the provided 268 * flush_handler. An audio frame is a set of single samples, one sample per 269 * channel. The guac_rdp_audio_buffer_set_output() function MUST have 270 * been invoked first. 271 * 272 * @param audio_buffer 273 * The audio buffer to begin. 274 * 275 * @param packet_frames 276 * The exact number of frames (a set of samples, one for each channel) 277 * which MUST be included in all audio packets provided to the 278 * given flush_handler. 279 * 280 * @param flush_handler 281 * The function to invoke when an audio packet must be flushed. 282 * 283 * @param data 284 * Arbitrary data to provide to the flush_handler when an audio packet 285 * needs to be flushed. 286 */ 287void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer, 288 int packet_frames, guac_rdp_audio_buffer_flush_handler* flush_handler, 289 void* data); 290 291/** 292 * Writes the given buffer of audio data to the given audio buffer. A new 293 * packet will be flushed using the associated flush handler once sufficient 294 * bytes have been accumulated. 295 * 296 * @param audio_buffer 297 * The audio buffer to which the given audio data should be written. 298 * 299 * @param buffer 300 * The buffer of audio data to write to the given audio buffer. 301 * 302 * @param length 303 * The number of bytes to write. 304 */ 305void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer, 306 char* buffer, int length); 307 308/** 309 * Stops handling of audio data received via guac_rdp_audio_buffer_write() and 310 * frees the underlying packet buffer. Further audio data will be ignored until 311 * guac_rdp_audio_buffer_begin() is invoked again. 312 * 313 * @param audio_buffer 314 * The audio buffer to end. 315 */ 316void guac_rdp_audio_buffer_end(guac_rdp_audio_buffer* audio_buffer); 317 318/** 319 * Frees the given audio buffer. If guac_rdp_audio_buffer_end() has not yet 320 * been called, its associated packet buffer will also be freed. 321 * 322 * @param audio_buffer 323 * The audio buffer to free. 324 */ 325void guac_rdp_audio_buffer_free(guac_rdp_audio_buffer* audio_buffer); 326 327#endif 328