diff options
Diffstat (limited to 'libfreerdp/codec/audio.c')
-rw-r--r-- | libfreerdp/codec/audio.c | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/libfreerdp/codec/audio.c b/libfreerdp/codec/audio.c new file mode 100644 index 0000000..ff2786d --- /dev/null +++ b/libfreerdp/codec/audio.c @@ -0,0 +1,298 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Formats + * + * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <freerdp/config.h> + +#include <winpr/crt.h> + +#include <freerdp/log.h> +#include <freerdp/codec/audio.h> + +#define TAG FREERDP_TAG("codec") + +UINT32 audio_format_compute_time_length(const AUDIO_FORMAT* format, size_t size) +{ + UINT32 mstime = 0; + UINT32 wSamples = 0; + + /** + * [MSDN-AUDIOFORMAT]: + * http://msdn.microsoft.com/en-us/library/ms713497.aspx + */ + + if (format->wBitsPerSample) + { + const size_t samples = (size * 8) / format->wBitsPerSample; + WINPR_ASSERT(samples <= UINT32_MAX); + wSamples = (UINT32)samples; + mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels); + } + else + { + mstime = 0; + + if (format->wFormatTag == WAVE_FORMAT_GSM610) + { + UINT16 nSamplesPerBlock = 0; + + if ((format->cbSize == 2) && (format->data)) + { + nSamplesPerBlock = *((UINT16*)format->data); + const size_t samples = (size / format->nBlockAlign) * nSamplesPerBlock; + WINPR_ASSERT(samples <= UINT32_MAX); + wSamples = (UINT32)samples; + mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels); + } + else + { + WLog_ERR(TAG, + "audio_format_compute_time_length: invalid WAVE_FORMAT_GSM610 format"); + } + } + else + { + WLog_ERR(TAG, "audio_format_compute_time_length: unknown format %" PRIu16 "", + format->wFormatTag); + } + } + + return mstime; +} + +char* audio_format_get_tag_string(UINT16 wFormatTag) +{ + switch (wFormatTag) + { + case WAVE_FORMAT_PCM: + return "WAVE_FORMAT_PCM"; + + case WAVE_FORMAT_ADPCM: + return "WAVE_FORMAT_ADPCM"; + + case WAVE_FORMAT_ALAW: + return "WAVE_FORMAT_ALAW"; + + case WAVE_FORMAT_MULAW: + return "WAVE_FORMAT_MULAW"; + + case WAVE_FORMAT_DVI_ADPCM: + return "WAVE_FORMAT_DVI_ADPCM"; + + case WAVE_FORMAT_GSM610: + return "WAVE_FORMAT_GSM610"; + + case WAVE_FORMAT_MSG723: + return "WAVE_FORMAT_MSG723"; + + case WAVE_FORMAT_DSPGROUP_TRUESPEECH: + return "WAVE_FORMAT_DSPGROUP_TRUESPEECH "; + + case WAVE_FORMAT_MPEGLAYER3: + return "WAVE_FORMAT_MPEGLAYER3"; + + case WAVE_FORMAT_WMAUDIO2: + return "WAVE_FORMAT_WMAUDIO2"; + + case WAVE_FORMAT_AAC_MS: + return "WAVE_FORMAT_AAC_MS"; + } + + return "WAVE_FORMAT_UNKNOWN"; +} + +void audio_format_print(wLog* log, DWORD level, const AUDIO_FORMAT* format) +{ + WLog_Print(log, level, + "%s:\t wFormatTag: 0x%04" PRIX16 " nChannels: %" PRIu16 " nSamplesPerSec: %" PRIu32 + " " + "nAvgBytesPerSec: %" PRIu32 " nBlockAlign: %" PRIu16 " wBitsPerSample: %" PRIu16 + " cbSize: %" PRIu16 "", + audio_format_get_tag_string(format->wFormatTag), format->wFormatTag, + format->nChannels, format->nSamplesPerSec, format->nAvgBytesPerSec, + format->nBlockAlign, format->wBitsPerSample, format->cbSize); +} + +void audio_formats_print(wLog* log, DWORD level, const AUDIO_FORMAT* formats, UINT16 count) +{ + if (formats) + { + WLog_Print(log, level, "AUDIO_FORMATS (%" PRIu16 ") ={", count); + + for (UINT32 index = 0; index < count; index++) + { + const AUDIO_FORMAT* format = &formats[index]; + WLog_Print(log, level, "\t"); + audio_format_print(log, level, format); + } + + WLog_Print(log, level, "}"); + } +} + +BOOL audio_format_read(wStream* s, AUDIO_FORMAT* format) +{ + if (!s || !format) + return FALSE; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 18)) + return FALSE; + + Stream_Read_UINT16(s, format->wFormatTag); + Stream_Read_UINT16(s, format->nChannels); + Stream_Read_UINT32(s, format->nSamplesPerSec); + Stream_Read_UINT32(s, format->nAvgBytesPerSec); + Stream_Read_UINT16(s, format->nBlockAlign); + Stream_Read_UINT16(s, format->wBitsPerSample); + Stream_Read_UINT16(s, format->cbSize); + + if (!Stream_CheckAndLogRequiredLength(TAG, s, format->cbSize)) + return FALSE; + + format->data = NULL; + + if (format->cbSize > 0) + { + format->data = malloc(format->cbSize); + + if (!format->data) + return FALSE; + + Stream_Read(s, format->data, format->cbSize); + } + + return TRUE; +} + +BOOL audio_format_write(wStream* s, const AUDIO_FORMAT* format) +{ + if (!s || !format) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(s, 18 + format->cbSize)) + return FALSE; + + Stream_Write_UINT16(s, format->wFormatTag); /* wFormatTag (WAVE_FORMAT_PCM) */ + Stream_Write_UINT16(s, format->nChannels); /* nChannels */ + Stream_Write_UINT32(s, format->nSamplesPerSec); /* nSamplesPerSec */ + Stream_Write_UINT32(s, format->nAvgBytesPerSec); /* nAvgBytesPerSec */ + Stream_Write_UINT16(s, format->nBlockAlign); /* nBlockAlign */ + Stream_Write_UINT16(s, format->wBitsPerSample); /* wBitsPerSample */ + Stream_Write_UINT16(s, format->cbSize); /* cbSize */ + + if (format->cbSize > 0) + Stream_Write(s, format->data, format->cbSize); + + return TRUE; +} + +BOOL audio_format_copy(const AUDIO_FORMAT* srcFormat, AUDIO_FORMAT* dstFormat) +{ + if (!srcFormat || !dstFormat) + return FALSE; + + *dstFormat = *srcFormat; + + if (srcFormat->cbSize > 0) + { + dstFormat->data = malloc(srcFormat->cbSize); + + if (!dstFormat->data) + return FALSE; + + memcpy(dstFormat->data, srcFormat->data, dstFormat->cbSize); + } + + return TRUE; +} + +BOOL audio_format_compatible(const AUDIO_FORMAT* with, const AUDIO_FORMAT* what) +{ + if (!with || !what) + return FALSE; + + if (with->wFormatTag != WAVE_FORMAT_UNKNOWN) + { + if (with->wFormatTag != what->wFormatTag) + return FALSE; + } + + if (with->nChannels != 0) + { + if (with->nChannels != what->nChannels) + return FALSE; + } + + if (with->nSamplesPerSec != 0) + { + if (with->nSamplesPerSec != what->nSamplesPerSec) + return FALSE; + } + + if (with->wBitsPerSample != 0) + { + if (with->wBitsPerSample != what->wBitsPerSample) + return FALSE; + } + + return TRUE; +} + +static BOOL audio_format_valid(const AUDIO_FORMAT* format) +{ + if (!format) + return FALSE; + + if (format->nChannels == 0) + return FALSE; + + if (format->nSamplesPerSec == 0) + return FALSE; + + return TRUE; +} + +AUDIO_FORMAT* audio_format_new(void) +{ + return audio_formats_new(1); +} + +AUDIO_FORMAT* audio_formats_new(size_t count) +{ + return calloc(count, sizeof(AUDIO_FORMAT)); +} + +void audio_format_free(AUDIO_FORMAT* format) +{ + if (format) + free(format->data); +} + +void audio_formats_free(AUDIO_FORMAT* formats, size_t count) +{ + if (formats) + { + for (size_t index = 0; index < count; index++) + { + AUDIO_FORMAT* format = &formats[index]; + audio_format_free(format); + } + + free(formats); + } +} |