summaryrefslogtreecommitdiffstats
path: root/libfreerdp/codec/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/codec/audio.c')
-rw-r--r--libfreerdp/codec/audio.c298
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);
+ }
+}