raw_encoder.c (4670B)
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/socket.h" 27#include "guacamole/user.h" 28#include "raw_encoder.h" 29 30#include <stdlib.h> 31#include <stdio.h> 32#include <string.h> 33 34static void raw_encoder_send_audio(guac_audio_stream* audio, 35 guac_socket* socket) { 36 37 char mimetype[256]; 38 39 /* Produce mimetype string from format info */ 40 snprintf(mimetype, sizeof(mimetype), "audio/L%i;rate=%i,channels=%i", 41 audio->bps, audio->rate, audio->channels); 42 43 /* Associate stream */ 44 guac_protocol_send_audio(socket, audio->stream, mimetype); 45 46} 47 48static void raw_encoder_begin_handler(guac_audio_stream* audio) { 49 50 raw_encoder_state* state; 51 52 /* Broadcast existence of stream */ 53 raw_encoder_send_audio(audio, audio->client->socket); 54 55 /* Allocate and init encoder state */ 56 audio->data = state = guac_mem_alloc(sizeof(raw_encoder_state)); 57 state->written = 0; 58 state->length = guac_mem_ckd_mul_or_die(GUAC_RAW_ENCODER_BUFFER_SIZE, 59 audio->rate, audio->channels, audio->bps) / 8 / 1000; 60 61 state->buffer = guac_mem_alloc(state->length); 62 63} 64 65static void raw_encoder_join_handler(guac_audio_stream* audio, 66 guac_user* user) { 67 68 /* Notify user of existence of stream */ 69 raw_encoder_send_audio(audio, user->socket); 70 71} 72 73static void raw_encoder_end_handler(guac_audio_stream* audio) { 74 75 raw_encoder_state* state = (raw_encoder_state*) audio->data; 76 77 /* Send end of stream */ 78 guac_protocol_send_end(audio->client->socket, audio->stream); 79 80 /* Free state information */ 81 guac_mem_free(state->buffer); 82 guac_mem_free(state); 83 84} 85 86static void raw_encoder_write_handler(guac_audio_stream* audio, 87 const unsigned char* pcm_data, int length) { 88 89 raw_encoder_state* state = (raw_encoder_state*) audio->data; 90 91 while (length > 0) { 92 93 /* Prefer to copy a chunk of equal size to available buffer space */ 94 int chunk_size = state->length - state->written; 95 96 /* If no space remains, flush and retry */ 97 if (chunk_size == 0) { 98 guac_audio_stream_flush(audio); 99 continue; 100 } 101 102 /* Do not copy more data than is available in source PCM */ 103 if (chunk_size > length) 104 chunk_size = length; 105 106 /* Copy block of PCM data into buffer */ 107 memcpy(state->buffer + state->written, pcm_data, chunk_size); 108 109 /* Advance to next block */ 110 state->written += chunk_size; 111 pcm_data += chunk_size; 112 length -= chunk_size; 113 114 } 115 116} 117 118static void raw_encoder_flush_handler(guac_audio_stream* audio) { 119 120 raw_encoder_state* state = (raw_encoder_state*) audio->data; 121 guac_socket* socket = audio->client->socket; 122 guac_stream* stream = audio->stream; 123 124 /* Flush all data in buffer as blobs */ 125 guac_protocol_send_blobs(socket, stream, state->buffer, state->written); 126 127 /* All data has been flushed */ 128 state->written = 0; 129 130} 131 132/* 8-bit raw encoder handlers */ 133guac_audio_encoder _raw8_encoder = { 134 .mimetype = "audio/L8", 135 .begin_handler = raw_encoder_begin_handler, 136 .write_handler = raw_encoder_write_handler, 137 .flush_handler = raw_encoder_flush_handler, 138 .join_handler = raw_encoder_join_handler, 139 .end_handler = raw_encoder_end_handler 140}; 141 142/* 16-bit raw encoder handlers */ 143guac_audio_encoder _raw16_encoder = { 144 .mimetype = "audio/L16", 145 .begin_handler = raw_encoder_begin_handler, 146 .write_handler = raw_encoder_write_handler, 147 .flush_handler = raw_encoder_flush_handler, 148 .join_handler = raw_encoder_join_handler, 149 .end_handler = raw_encoder_end_handler 150}; 151 152/* Actual encoder definitions */ 153guac_audio_encoder* raw8_encoder = &_raw8_encoder; 154guac_audio_encoder* raw16_encoder = &_raw16_encoder; 155