cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

audio.c (6857B)


      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#include "config.h"
     21
     22#include "guacamole/mem.h"
     23#include "guacamole/audio.h"
     24#include "guacamole/client.h"
     25#include "guacamole/protocol.h"
     26#include "guacamole/stream.h"
     27#include "guacamole/user.h"
     28#include "raw_encoder.h"
     29
     30#include <stdlib.h>
     31#include <string.h>
     32
     33/**
     34 * Sets the encoder associated with the given guac_audio_stream, automatically
     35 * invoking its begin_handler. The guac_audio_stream MUST NOT already be
     36 * associated with an encoder.
     37 *
     38 * @param audio
     39 *     The guac_audio_stream whose encoder is being set.
     40 *
     41 * @param encoder
     42 *     The encoder to associate with the given guac_audio_stream.
     43 */
     44static void guac_audio_stream_set_encoder(guac_audio_stream* audio,
     45        guac_audio_encoder* encoder) {
     46
     47    /* Call handler, if defined */
     48    if (encoder != NULL && encoder->begin_handler)
     49        encoder->begin_handler(audio);
     50
     51    /* Assign encoder, which may be NULL */
     52    audio->encoder = encoder;
     53
     54}
     55
     56/**
     57 * Assigns a new audio encoder to the given guac_audio_stream based on the
     58 * audio mimetypes declared as supported by the given user. If no audio encoder
     59 * can be found, no new audio encoder is assigned, and the existing encoder is
     60 * left untouched (if any).
     61 *
     62 * @param user
     63 *     The user whose supported audio mimetypes should determine the audio
     64 *     encoder selected.
     65 *
     66 * @param data
     67 *     The guac_audio_stream to which the new encoder should be assigned.
     68 *     Existing properties set on this audio stream, such as the bits per
     69 *     sample, may affect the encoder chosen.
     70 *
     71 * @return
     72 *     The assigned audio encoder. If no new audio encoder can be assigned,
     73 *     this will be the currently-assigned audio encoder (which may be NULL).
     74 */
     75static void* guac_audio_assign_encoder(guac_user* user, void* data) {
     76
     77    int i;
     78
     79    guac_audio_stream* audio = (guac_audio_stream*) data;
     80    int bps = audio->bps;
     81
     82    /* If no user is provided, or an encoder has already been assigned,
     83     * do not attempt to assign a new encoder */
     84    if (user == NULL || audio->encoder != NULL)
     85        return audio->encoder;
     86
     87    /* For each supported mimetype, check for an associated encoder */
     88    for (i=0; user->info.audio_mimetypes[i] != NULL; i++) {
     89
     90        const char* mimetype = user->info.audio_mimetypes[i];
     91
     92        /* If 16-bit raw audio is supported, done. */
     93        if (bps == 16 && strcmp(mimetype, raw16_encoder->mimetype) == 0) {
     94            guac_audio_stream_set_encoder(audio, raw16_encoder);
     95            break;
     96        }
     97
     98        /* If 8-bit raw audio is supported, done. */
     99        if (bps == 8 && strcmp(mimetype, raw8_encoder->mimetype) == 0) {
    100            guac_audio_stream_set_encoder(audio, raw8_encoder);
    101            break;
    102        }
    103
    104    } /* end for each mimetype */
    105
    106    /* Return assigned encoder, if any */
    107    return audio->encoder;
    108
    109}
    110
    111guac_audio_stream* guac_audio_stream_alloc(guac_client* client,
    112        guac_audio_encoder* encoder, int rate, int channels, int bps) {
    113
    114    guac_audio_stream* audio;
    115
    116    /* Allocate stream */
    117    audio = (guac_audio_stream*) guac_mem_zalloc(sizeof(guac_audio_stream));
    118    audio->client = client;
    119    audio->stream = guac_client_alloc_stream(client);
    120
    121    /* Abort allocation if underlying stream cannot be allocated */
    122    if (audio->stream == NULL) {
    123        guac_mem_free(audio);
    124        return NULL;
    125    }
    126
    127    /* Load PCM properties */
    128    audio->rate = rate;
    129    audio->channels = channels;
    130    audio->bps = bps;
    131
    132    /* Assign encoder if explicitly provided */
    133    if (encoder != NULL)
    134        guac_audio_stream_set_encoder(audio, encoder);
    135
    136    /* Otherwise, attempt to automatically assign encoder for owner */
    137    if (audio->encoder == NULL)
    138        guac_client_for_owner(client, guac_audio_assign_encoder, audio);
    139
    140    /* Failing that, attempt to assign encoder for ANY connected user */
    141    if (audio->encoder == NULL)
    142        guac_client_foreach_user(client, guac_audio_assign_encoder, audio);
    143
    144    return audio;
    145
    146}
    147
    148void guac_audio_stream_reset(guac_audio_stream* audio,
    149        guac_audio_encoder* encoder, int rate, int channels, int bps) {
    150
    151    /* Pull assigned encoder if no other encoder is requested */
    152    if (encoder == NULL)
    153        encoder = audio->encoder;
    154
    155    /* Do nothing if nothing is changing */
    156    if (encoder == audio->encoder
    157            && rate     == audio->rate
    158            && channels == audio->channels
    159            && bps      == audio->bps) {
    160        return;
    161    }
    162
    163    /* Free old encoder data */
    164    if (audio->encoder != NULL && audio->encoder->end_handler)
    165        audio->encoder->end_handler(audio);
    166
    167    /* Set PCM properties */
    168    audio->rate = rate;
    169    audio->channels = channels;
    170    audio->bps = bps;
    171
    172    /* Re-init encoder */
    173    guac_audio_stream_set_encoder(audio, encoder);
    174
    175}
    176
    177void guac_audio_stream_add_user(guac_audio_stream* audio, guac_user* user) {
    178
    179    /* Attempt to assign encoder if no encoder has yet been assigned */
    180    if (audio->encoder == NULL)
    181        guac_audio_assign_encoder(user, audio);
    182
    183    /* Notify encoder that a new user is present */
    184    if (audio->encoder != NULL && audio->encoder->join_handler)
    185        audio->encoder->join_handler(audio, user);
    186
    187}
    188
    189void guac_audio_stream_free(guac_audio_stream* audio) {
    190
    191    /* Flush stream encoding */
    192    guac_audio_stream_flush(audio);
    193
    194    /* Clean up encoder */
    195    if (audio->encoder != NULL && audio->encoder->end_handler)
    196        audio->encoder->end_handler(audio);
    197
    198    /* Release stream back to client pool */
    199    guac_client_free_stream(audio->client, audio->stream);
    200
    201    /* Free associated data */
    202    guac_mem_free(audio);
    203
    204}
    205
    206void guac_audio_stream_write_pcm(guac_audio_stream* audio, 
    207        const unsigned char* data, int length) {
    208
    209    /* Write data */
    210    if (audio->encoder != NULL && audio->encoder->write_handler)
    211        audio->encoder->write_handler(audio, data, length);
    212
    213}
    214
    215void guac_audio_stream_flush(guac_audio_stream* audio) {
    216
    217    /* Flush any buffered data */
    218    if (audio->encoder != NULL && audio->encoder->flush_handler)
    219        audio->encoder->flush_handler(audio);
    220
    221}
    222