/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is libguac. * * The Initial Developer of the Original Code is * Michael Jumper. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #define WAV_BUFFER_SIZE 0x4000 #include #include #include #include #include #include "wav_encoder.h" void wav_encoder_begin_handler(guac_audio_stream* audio) { /* Allocate stream state */ wav_encoder_state* state = (wav_encoder_state*) malloc(sizeof(wav_encoder_state)); /* Initialize buffer */ state->length = WAV_BUFFER_SIZE; state->used = 0; state->data_buffer = (unsigned char*) malloc(state->length); audio->data = state; } void _wav_encoder_write_le(unsigned char* buffer, int value, int length) { int offset; /* Write all bytes in the given value in little-endian byte order */ for (offset=0; offset>= 8; buffer++; } } void wav_encoder_end_handler(guac_audio_stream* audio) { /* * Static header init */ wav_encoder_riff_header riff_header = { .chunk_id = "RIFF", .chunk_format = "WAVE" }; wav_encoder_fmt_header fmt_header = { .subchunk_id = "fmt ", .subchunk_size = {0x10, 0x00, 0x00, 0x00}, /* 16 */ .subchunk_format = {0x01, 0x00} /* 1 = PCM */ }; wav_encoder_data_header data_header = { .subchunk_id = "data" }; /* Get state */ wav_encoder_state* state = (wav_encoder_state*) audio->data; /* * RIFF HEADER */ /* Chunk size */ _wav_encoder_write_le(riff_header.chunk_size, 4 + sizeof(fmt_header) + sizeof(data_header) + state->used, sizeof(riff_header.chunk_size)); guac_audio_stream_write_encoded(audio, (unsigned char*) &riff_header, sizeof(riff_header)); /* * FMT HEADER */ /* Channels */ _wav_encoder_write_le(fmt_header.subchunk_channels, audio->channels, sizeof(fmt_header.subchunk_channels)); /* Sample rate */ _wav_encoder_write_le(fmt_header.subchunk_sample_rate, audio->rate, sizeof(fmt_header.subchunk_sample_rate)); /* Byte rate */ _wav_encoder_write_le(fmt_header.subchunk_byte_rate, audio->rate * audio->channels * audio->bps / 8, sizeof(fmt_header.subchunk_byte_rate)); /* Block align */ _wav_encoder_write_le(fmt_header.subchunk_block_align, audio->channels * audio->bps / 8, sizeof(fmt_header.subchunk_block_align)); /* Bits per second */ _wav_encoder_write_le(fmt_header.subchunk_bps, audio->bps, sizeof(fmt_header.subchunk_bps)); guac_audio_stream_write_encoded(audio, (unsigned char*) &fmt_header, sizeof(fmt_header)); /* * DATA HEADER */ /* PCM data size */ _wav_encoder_write_le(data_header.subchunk_size, state->used, sizeof(data_header.subchunk_size)); guac_audio_stream_write_encoded(audio, (unsigned char*) &data_header, sizeof(data_header)); /* Write .wav data */ guac_audio_stream_write_encoded(audio, state->data_buffer, state->used); /* Free stream state */ free(state); } void wav_encoder_write_handler(guac_audio_stream* audio, const unsigned char* pcm_data, int length) { /* Get state */ wav_encoder_state* state = (wav_encoder_state*) audio->data; /* Increase size of buffer if necessary */ if (state->used + length > state->length) { /* Increase to double concatenated size to accomodate */ state->length = (state->length + length)*2; state->data_buffer = realloc(state->data_buffer, state->length); } /* Append to buffer */ memcpy(&(state->data_buffer[state->used]), pcm_data, length); state->used += length; } /* Encoder handlers */ guac_audio_encoder _wav_encoder = { .mimetype = "audio/wav", .begin_handler = wav_encoder_begin_handler, .write_handler = wav_encoder_write_handler, .end_handler = wav_encoder_end_handler }; /* Actual encoder */ guac_audio_encoder* wav_encoder = &_wav_encoder;