summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/webrtc/modules/media_file
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/webrtc/modules/media_file')
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/BUILD.gn67
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/DEPS4
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/OWNERS8
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/media_file.h180
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/media_file_defines.h50
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/media_file_gn/moz.build229
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.cc893
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.h148
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/media_file_unittest.cc106
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.cc1238
-rw-r--r--third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.h281
11 files changed, 3204 insertions, 0 deletions
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/BUILD.gn b/third_party/libwebrtc/webrtc/modules/media_file/BUILD.gn
new file mode 100644
index 0000000000..77b2637497
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/BUILD.gn
@@ -0,0 +1,67 @@
+# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../webrtc.gni")
+
+config("media_file_config") {
+ visibility = [ ":*" ] # Only targets in this file can depend on this.
+}
+
+rtc_static_library("media_file") {
+ sources = [
+ "media_file.h",
+ "media_file_defines.h",
+ "media_file_impl.cc",
+ "media_file_impl.h",
+ "media_file_utility.cc",
+ "media_file_utility.h",
+ ]
+
+ public_configs = [ ":media_file_config" ]
+
+ # TODO(jschuh): Bug 1348: fix this warning.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+ if (!build_with_chromium && is_clang) {
+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+ }
+
+ deps = [
+ "..:module_api",
+ "../..:webrtc_common",
+ "../../common_audio",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_source_set("media_file_unittests") {
+ testonly = true
+
+ sources = [
+ "media_file_unittest.cc",
+ ]
+ deps = [
+ ":media_file",
+ "../../system_wrappers:system_wrappers",
+ "../../test:test_support",
+ ]
+ if (is_win) {
+ cflags = [
+ # TODO(kjellander): bugs.webrtc.org/261: Fix this warning.
+ "/wd4373", # virtual function override.
+ ]
+ }
+ if (!build_with_chromium && is_clang) {
+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+ }
+ }
+}
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/DEPS b/third_party/libwebrtc/webrtc/modules/media_file/DEPS
new file mode 100644
index 0000000000..dc17ef44fe
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+common_audio",
+ "+system_wrappers",
+]
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/OWNERS b/third_party/libwebrtc/webrtc/modules/media_file/OWNERS
new file mode 100644
index 0000000000..f5e93f0138
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/OWNERS
@@ -0,0 +1,8 @@
+mflodman@webrtc.org
+perkj@webrtc.org
+niklas.enbom@webrtc.org
+
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from a reviewer in this file.
+per-file *.gn=*
+per-file *.gni=*
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/media_file.h b/third_party/libwebrtc/webrtc/modules/media_file/media_file.h
new file mode 100644
index 0000000000..6a7a02efcc
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/media_file.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_MEDIA_FILE_MEDIA_FILE_H_
+#define MODULES_MEDIA_FILE_MEDIA_FILE_H_
+
+#include "common_types.h" // NOLINT(build/include)
+#include "modules/include/module.h"
+#include "modules/include/module_common_types.h"
+#include "modules/media_file/media_file_defines.h"
+#include "typedefs.h" // NOLINT(build/include)
+
+namespace webrtc {
+class MediaFile : public Module
+{
+public:
+ // Factory method. Constructor disabled. id is the identifier for the
+ // MediaFile instance.
+ static MediaFile* CreateMediaFile(const int32_t id);
+ static void DestroyMediaFile(MediaFile* module);
+
+ // Put 10-60ms of audio data from file into the audioBuffer depending on
+ // codec frame size. dataLengthInBytes is both an input and output
+ // parameter. As input parameter it indicates the size of audioBuffer.
+ // As output parameter it indicates the number of bytes written to
+ // audioBuffer.
+ // Note: This API only play mono audio but can be used on file containing
+ // audio with more channels (in which case the audio will be converted to
+ // mono).
+ virtual int32_t PlayoutAudioData(
+ int8_t* audioBuffer,
+ size_t& dataLengthInBytes) = 0;
+
+ // Put 10-60ms, depending on codec frame size, of audio data from file into
+ // audioBufferLeft and audioBufferRight. The buffers contain the left and
+ // right channel of played out stereo audio.
+ // dataLengthInBytes is both an input and output parameter. As input
+ // parameter it indicates the size of both audioBufferLeft and
+ // audioBufferRight. As output parameter it indicates the number of bytes
+ // written to both audio buffers.
+ // Note: This API can only be successfully called for WAV files with stereo
+ // audio.
+ virtual int32_t PlayoutStereoData(
+ int8_t* audioBufferLeft,
+ int8_t* audioBufferRight,
+ size_t& dataLengthInBytes) = 0;
+
+ // Open the file specified by fileName (relative path is allowed) for
+ // reading. FileCallback::PlayNotification(..) will be called after
+ // notificationTimeMs of the file has been played if notificationTimeMs is
+ // greater than zero. If loop is true the file will be played until
+ // StopPlaying() is called. When end of file is reached the file is read
+ // from the start. format specifies the type of file fileName refers to.
+ // codecInst specifies the encoding of the audio data. Note that
+ // file formats that contain this information (like WAV files) don't need to
+ // provide a non-NULL codecInst. startPointMs and stopPointMs, unless zero,
+ // specify what part of the file should be read. From startPointMs ms to
+ // stopPointMs ms.
+ // Note: codecInst.channels should be set to 2 for stereo (and 1 for
+ // mono). Stereo audio is only supported for WAV files.
+ virtual int32_t StartPlayingAudioFile(
+ const char* fileName,
+ const uint32_t notificationTimeMs = 0,
+ const bool loop = false,
+ const FileFormats format = kFileFormatPcm16kHzFile,
+ const CodecInst* codecInst = NULL,
+ const uint32_t startPointMs = 0,
+ const uint32_t stopPointMs = 0) = 0;
+
+ // Prepare for playing audio from stream.
+ // FileCallback::PlayNotification(..) will be called after
+ // notificationTimeMs of the file has been played if notificationTimeMs is
+ // greater than zero. format specifies the type of file fileName refers to.
+ // codecInst specifies the encoding of the audio data. Note that
+ // file formats that contain this information (like WAV files) don't need to
+ // provide a non-NULL codecInst. startPointMs and stopPointMs, unless zero,
+ // specify what part of the file should be read. From startPointMs ms to
+ // stopPointMs ms.
+ // Note: codecInst.channels should be set to 2 for stereo (and 1 for
+ // mono). Stereo audio is only supported for WAV files.
+ virtual int32_t StartPlayingAudioStream(
+ InStream& stream,
+ const uint32_t notificationTimeMs = 0,
+ const FileFormats format = kFileFormatPcm16kHzFile,
+ const CodecInst* codecInst = NULL,
+ const uint32_t startPointMs = 0,
+ const uint32_t stopPointMs = 0) = 0;
+
+ // Stop playing from file or stream.
+ virtual int32_t StopPlaying() = 0;
+
+ // Return true if playing.
+ virtual bool IsPlaying() = 0;
+
+
+ // Set durationMs to the number of ms that has been played from file.
+ virtual int32_t PlayoutPositionMs(
+ uint32_t& durationMs) const = 0;
+
+ // Write one audio frame, i.e. the bufferLength first bytes of audioBuffer,
+ // to file. The audio frame size is determined by the codecInst.pacsize
+ // parameter of the last sucessfull StartRecordingAudioFile(..) call.
+ // Note: bufferLength must be exactly one frame.
+ virtual int32_t IncomingAudioData(
+ const int8_t* audioBuffer,
+ const size_t bufferLength) = 0;
+
+ // Open/creates file specified by fileName for writing (relative path is
+ // allowed). FileCallback::RecordNotification(..) will be called after
+ // notificationTimeMs of audio data has been recorded if
+ // notificationTimeMs is greater than zero.
+ // format specifies the type of file that should be created/opened.
+ // codecInst specifies the encoding of the audio data. maxSizeBytes
+ // specifies the number of bytes allowed to be written to file if it is
+ // greater than zero.
+ // Note: codecInst.channels should be set to 2 for stereo (and 1 for
+ // mono). Stereo is only supported for WAV files.
+ virtual int32_t StartRecordingAudioFile(
+ const char* fileName,
+ const FileFormats format,
+ const CodecInst& codecInst,
+ const uint32_t notificationTimeMs = 0,
+ const uint32_t maxSizeBytes = 0) = 0;
+
+ // Prepare for recording audio to stream.
+ // FileCallback::RecordNotification(..) will be called after
+ // notificationTimeMs of audio data has been recorded if
+ // notificationTimeMs is greater than zero.
+ // format specifies the type of file that stream should correspond to.
+ // codecInst specifies the encoding of the audio data.
+ // Note: codecInst.channels should be set to 2 for stereo (and 1 for
+ // mono). Stereo is only supported for WAV files.
+ virtual int32_t StartRecordingAudioStream(
+ OutStream& stream,
+ const FileFormats format,
+ const CodecInst& codecInst,
+ const uint32_t notificationTimeMs = 0) = 0;
+
+ // Stop recording to file or stream.
+ virtual int32_t StopRecording() = 0;
+
+ // Return true if recording.
+ virtual bool IsRecording() = 0;
+
+ // Set durationMs to the number of ms that has been recorded to file.
+ virtual int32_t RecordDurationMs(uint32_t& durationMs) = 0;
+
+ // Return true if recording or playing is stereo.
+ virtual bool IsStereo() = 0;
+
+ // Register callback to receive media file related notifications. Disables
+ // callbacks if callback is NULL.
+ virtual int32_t SetModuleFileCallback(FileCallback* callback) = 0;
+
+ // Set durationMs to the size of the file (in ms) specified by fileName.
+ // format specifies the type of file fileName refers to. freqInHz specifies
+ // the sampling frequency of the file.
+ virtual int32_t FileDurationMs(
+ const char* fileName,
+ uint32_t& durationMs,
+ const FileFormats format,
+ const uint32_t freqInHz = 16000) = 0;
+
+ // Update codecInst according to the current audio codec being used for
+ // reading or writing.
+ virtual int32_t codec_info(CodecInst& codecInst) const = 0;
+
+protected:
+ MediaFile() {}
+ virtual ~MediaFile() {}
+};
+} // namespace webrtc
+#endif // MODULES_MEDIA_FILE_MEDIA_FILE_H_
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/media_file_defines.h b/third_party/libwebrtc/webrtc/modules/media_file/media_file_defines.h
new file mode 100644
index 0000000000..73b3b059ce
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/media_file_defines.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_MEDIA_FILE_MEDIA_FILE_DEFINES_H_
+#define MODULES_MEDIA_FILE_MEDIA_FILE_DEFINES_H_
+
+#include "modules/include/module_common_types.h"
+#include "typedefs.h" // NOLINT(build/include)
+
+namespace webrtc {
+// Callback class for the MediaFile class.
+class FileCallback
+{
+public:
+ virtual ~FileCallback(){}
+
+ // This function is called by MediaFile when a file has been playing for
+ // durationMs ms. id is the identifier for the MediaFile instance calling
+ // the callback.
+ virtual void PlayNotification(const int32_t id,
+ const uint32_t durationMs) = 0;
+
+ // This function is called by MediaFile when a file has been recording for
+ // durationMs ms. id is the identifier for the MediaFile instance calling
+ // the callback.
+ virtual void RecordNotification(const int32_t id,
+ const uint32_t durationMs) = 0;
+
+ // This function is called by MediaFile when a file has been stopped
+ // playing. id is the identifier for the MediaFile instance calling the
+ // callback.
+ virtual void PlayFileEnded(const int32_t id) = 0;
+
+ // This function is called by MediaFile when a file has been stopped
+ // recording. id is the identifier for the MediaFile instance calling the
+ // callback.
+ virtual void RecordFileEnded(const int32_t id) = 0;
+
+protected:
+ FileCallback() {}
+};
+} // namespace webrtc
+#endif // MODULES_MEDIA_FILE_MEDIA_FILE_DEFINES_H_
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/media_file_gn/moz.build b/third_party/libwebrtc/webrtc/modules/media_file/media_file_gn/moz.build
new file mode 100644
index 0000000000..d2969fa6c5
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/media_file_gn/moz.build
@@ -0,0 +1,229 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["CHROMIUM_BUILD"] = True
+DEFINES["V8_DEPRECATION_WARNINGS"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_RESTRICT_LOGGING"] = True
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "/ipc/chromium/src",
+ "/ipc/glue",
+ "/third_party/libwebrtc/webrtc/",
+ "/third_party/libwebrtc/webrtc/common_audio/resampler/include/",
+ "/third_party/libwebrtc/webrtc/common_audio/signal_processing/include/",
+ "/third_party/libwebrtc/webrtc/common_audio/vad/include/"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.cc",
+ "/third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+ DEFINES["WTF_USE_DYNAMIC_ANNOTATIONS"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION"] = "r12b"
+ DEFINES["DISABLE_NACL"] = True
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["NO_TCMALLOC"] = True
+ DEFINES["USE_OPENSSL_CERTS"] = "1"
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["__GNU_SOURCE"] = "1"
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["NO_TCMALLOC"] = True
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORE"] = "0"
+
+ OS_LIBS += [
+ "-framework Foundation"
+ ]
+
+if CONFIG["OS_TARGET"] == "DragonFly":
+
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+if CONFIG["OS_TARGET"] == "FreeBSD":
+
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+ OS_LIBS += [
+ "rt"
+ ]
+
+if CONFIG["OS_TARGET"] == "NetBSD":
+
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NO_TCMALLOC"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "1"
+ DEFINES["UNICODE"] = True
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_CRT_SECURE_NO_WARNINGS"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_USING_V110_SDK71_"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "DragonFly":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "FreeBSD":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "NetBSD":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["CR_XCODE_VERSION"] = "0120"
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["CR_XCODE_VERSION"] = "0920"
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "FreeBSD":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["DISABLE_NACL"] = True
+ DEFINES["NO_TCMALLOC"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "NetBSD":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+Library("media_file_gn")
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.cc b/third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.cc
new file mode 100644
index 0000000000..0fd9d9ee6a
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.cc
@@ -0,0 +1,893 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <assert.h>
+
+#include "modules/media_file/media_file_impl.h"
+#include "rtc_base/format_macros.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/file_wrapper.h"
+
+namespace webrtc {
+MediaFile* MediaFile::CreateMediaFile(const int32_t id) {
+ return new MediaFileImpl(id);
+}
+
+void MediaFile::DestroyMediaFile(MediaFile* module) {
+ delete static_cast<MediaFileImpl*>(module);
+}
+
+MediaFileImpl::MediaFileImpl(const int32_t id)
+ : _id(id),
+ _ptrFileUtilityObj(NULL),
+ codec_info_(),
+ _ptrInStream(NULL),
+ _ptrOutStream(NULL),
+ _fileFormat((FileFormats)-1),
+ _recordDurationMs(0),
+ _playoutPositionMs(0),
+ _notificationMs(0),
+ _playingActive(false),
+ _recordingActive(false),
+ _isStereo(false),
+ _openFile(false),
+ _fileName(),
+ _ptrCallback(NULL) {
+ RTC_LOG(LS_INFO) << "MediaFileImpl()";
+
+ codec_info_.plname[0] = '\0';
+ _fileName[0] = '\0';
+}
+
+MediaFileImpl::~MediaFileImpl() {
+ RTC_LOG(LS_INFO) << "~MediaFileImpl()";
+ {
+ rtc::CritScope lock(&_crit);
+
+ if (_playingActive) {
+ StopPlaying();
+ }
+
+ if (_recordingActive) {
+ StopRecording();
+ }
+
+ delete _ptrFileUtilityObj;
+
+ if (_openFile) {
+ delete _ptrInStream;
+ _ptrInStream = NULL;
+ delete _ptrOutStream;
+ _ptrOutStream = NULL;
+ }
+ }
+}
+
+int64_t MediaFileImpl::TimeUntilNextProcess() {
+ RTC_LOG(LS_WARNING)
+ << "TimeUntilNextProcess: This method is not used by MediaFile class.";
+ return -1;
+}
+
+void MediaFileImpl::Process() {
+ RTC_LOG(LS_WARNING) << "Process: This method is not used by MediaFile class.";
+}
+
+int32_t MediaFileImpl::PlayoutAudioData(int8_t* buffer,
+ size_t& dataLengthInBytes) {
+ RTC_LOG(LS_INFO) << "MediaFileImpl::PlayoutData(buffer= "
+ << static_cast<void*>(buffer)
+ << ", bufLen= " << dataLengthInBytes << ")";
+
+ const size_t bufferLengthInBytes = dataLengthInBytes;
+ dataLengthInBytes = 0;
+
+ if (buffer == NULL || bufferLengthInBytes == 0) {
+ RTC_LOG(LS_ERROR) << "Buffer pointer or length is NULL!";
+ return -1;
+ }
+
+ int32_t bytesRead = 0;
+ {
+ rtc::CritScope lock(&_crit);
+
+ if (!_playingActive) {
+ RTC_LOG(LS_WARNING) << "Not currently playing!";
+ return -1;
+ }
+
+ if (!_ptrFileUtilityObj) {
+ RTC_LOG(LS_ERROR) << "Playing, but no FileUtility object!";
+ StopPlaying();
+ return -1;
+ }
+
+ switch (_fileFormat) {
+ case kFileFormatPcm48kHzFile:
+ case kFileFormatPcm32kHzFile:
+ case kFileFormatPcm16kHzFile:
+ case kFileFormatPcm8kHzFile:
+ bytesRead = _ptrFileUtilityObj->ReadPCMData(*_ptrInStream, buffer,
+ bufferLengthInBytes);
+ break;
+ case kFileFormatCompressedFile:
+ bytesRead = _ptrFileUtilityObj->ReadCompressedData(
+ *_ptrInStream, buffer, bufferLengthInBytes);
+ break;
+ case kFileFormatWavFile:
+ bytesRead = _ptrFileUtilityObj->ReadWavDataAsMono(*_ptrInStream, buffer,
+ bufferLengthInBytes);
+ break;
+ case kFileFormatPreencodedFile:
+ bytesRead = _ptrFileUtilityObj->ReadPreEncodedData(
+ *_ptrInStream, buffer, bufferLengthInBytes);
+ if (bytesRead > 0) {
+ dataLengthInBytes = static_cast<size_t>(bytesRead);
+ return 0;
+ }
+ break;
+ default: {
+ RTC_LOG(LS_ERROR) << "Invalid file format: " << _fileFormat;
+ assert(false);
+ break;
+ }
+ }
+
+ if (bytesRead > 0) {
+ dataLengthInBytes = static_cast<size_t>(bytesRead);
+ }
+ }
+ HandlePlayCallbacks(bytesRead);
+ return 0;
+}
+
+void MediaFileImpl::HandlePlayCallbacks(int32_t bytesRead) {
+ bool playEnded = false;
+ uint32_t callbackNotifyMs = 0;
+
+ if (bytesRead > 0) {
+ // Check if it's time for PlayNotification(..).
+ _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs();
+ if (_notificationMs) {
+ if (_playoutPositionMs >= _notificationMs) {
+ _notificationMs = 0;
+ callbackNotifyMs = _playoutPositionMs;
+ }
+ }
+ } else {
+ // If no bytes were read assume end of file.
+ StopPlaying();
+ playEnded = true;
+ }
+
+ // Only _callbackCrit may and should be taken when making callbacks.
+ rtc::CritScope lock(&_callbackCrit);
+ if (_ptrCallback) {
+ if (callbackNotifyMs) {
+ _ptrCallback->PlayNotification(_id, callbackNotifyMs);
+ }
+ if (playEnded) {
+ _ptrCallback->PlayFileEnded(_id);
+ }
+ }
+}
+
+int32_t MediaFileImpl::PlayoutStereoData(int8_t* bufferLeft,
+ int8_t* bufferRight,
+ size_t& dataLengthInBytes) {
+ RTC_LOG(LS_INFO) << "MediaFileImpl::PlayoutStereoData(Left = "
+ << static_cast<void*>(bufferLeft)
+ << ", Right = " << static_cast<void*>(bufferRight)
+ << ", Len= " << dataLengthInBytes << ")";
+
+ const size_t bufferLengthInBytes = dataLengthInBytes;
+ dataLengthInBytes = 0;
+
+ if (bufferLeft == NULL || bufferRight == NULL || bufferLengthInBytes == 0) {
+ RTC_LOG(LS_ERROR) << "A buffer pointer or the length is NULL!";
+ return -1;
+ }
+
+ bool playEnded = false;
+ uint32_t callbackNotifyMs = 0;
+ {
+ rtc::CritScope lock(&_crit);
+
+ if (!_playingActive || !_isStereo) {
+ RTC_LOG(LS_WARNING) << "Not currently playing stereo!";
+ return -1;
+ }
+
+ if (!_ptrFileUtilityObj) {
+ RTC_LOG(LS_ERROR)
+ << "Playing stereo, but the FileUtility objects is NULL!";
+ StopPlaying();
+ return -1;
+ }
+
+ // Stereo playout only supported for WAV files.
+ int32_t bytesRead = 0;
+ switch (_fileFormat) {
+ case kFileFormatWavFile:
+ bytesRead = _ptrFileUtilityObj->ReadWavDataAsStereo(
+ *_ptrInStream, bufferLeft, bufferRight, bufferLengthInBytes);
+ break;
+ default:
+ RTC_LOG(LS_ERROR)
+ << "Trying to read non-WAV as stereo audio (not supported)";
+ break;
+ }
+
+ if (bytesRead > 0) {
+ dataLengthInBytes = static_cast<size_t>(bytesRead);
+
+ // Check if it's time for PlayNotification(..).
+ _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs();
+ if (_notificationMs) {
+ if (_playoutPositionMs >= _notificationMs) {
+ _notificationMs = 0;
+ callbackNotifyMs = _playoutPositionMs;
+ }
+ }
+ } else {
+ // If no bytes were read assume end of file.
+ StopPlaying();
+ playEnded = true;
+ }
+ }
+
+ rtc::CritScope lock(&_callbackCrit);
+ if (_ptrCallback) {
+ if (callbackNotifyMs) {
+ _ptrCallback->PlayNotification(_id, callbackNotifyMs);
+ }
+ if (playEnded) {
+ _ptrCallback->PlayFileEnded(_id);
+ }
+ }
+ return 0;
+}
+
+int32_t MediaFileImpl::StartPlayingAudioFile(const char* fileName,
+ const uint32_t notificationTimeMs,
+ const bool loop,
+ const FileFormats format,
+ const CodecInst* codecInst,
+ const uint32_t startPointMs,
+ const uint32_t stopPointMs) {
+ if (!ValidFileName(fileName)) {
+ return -1;
+ }
+ if (!ValidFileFormat(format, codecInst)) {
+ return -1;
+ }
+ if (!ValidFilePositions(startPointMs, stopPointMs)) {
+ return -1;
+ }
+
+ // Check that the file will play longer than notificationTimeMs ms.
+ if ((startPointMs && stopPointMs && !loop) &&
+ (notificationTimeMs > (stopPointMs - startPointMs))) {
+ RTC_LOG(LS_ERROR) << "specified notification time is longer than amount of"
+ << " ms that will be played";
+ return -1;
+ }
+
+ FileWrapper* inputStream = FileWrapper::Create();
+ if (inputStream == NULL) {
+ RTC_LOG(LS_INFO) << "Failed to allocate input stream for file " << fileName;
+ return -1;
+ }
+
+ if (!inputStream->OpenFile(fileName, true)) {
+ delete inputStream;
+ RTC_LOG(LS_ERROR) << "Could not open input file " << fileName;
+ return -1;
+ }
+
+ if (StartPlayingStream(*inputStream, loop, notificationTimeMs, format,
+ codecInst, startPointMs, stopPointMs) == -1) {
+ inputStream->CloseFile();
+ delete inputStream;
+ return -1;
+ }
+
+ rtc::CritScope lock(&_crit);
+ _openFile = true;
+ strncpy(_fileName, fileName, sizeof(_fileName));
+ _fileName[sizeof(_fileName) - 1] = '\0';
+ return 0;
+}
+
+int32_t MediaFileImpl::StartPlayingAudioStream(
+ InStream& stream,
+ const uint32_t notificationTimeMs,
+ const FileFormats format,
+ const CodecInst* codecInst,
+ const uint32_t startPointMs,
+ const uint32_t stopPointMs) {
+ return StartPlayingStream(stream, false, notificationTimeMs, format,
+ codecInst, startPointMs, stopPointMs);
+}
+
+int32_t MediaFileImpl::StartPlayingStream(InStream& stream,
+ bool loop,
+ const uint32_t notificationTimeMs,
+ const FileFormats format,
+ const CodecInst* codecInst,
+ const uint32_t startPointMs,
+ const uint32_t stopPointMs) {
+ if (!ValidFileFormat(format, codecInst)) {
+ return -1;
+ }
+
+ if (!ValidFilePositions(startPointMs, stopPointMs)) {
+ return -1;
+ }
+
+ rtc::CritScope lock(&_crit);
+ if (_playingActive || _recordingActive) {
+ RTC_LOG(LS_ERROR)
+ << "StartPlaying called, but already playing or recording file "
+ << ((_fileName[0] == '\0') ? "(name not set)" : _fileName);
+ return -1;
+ }
+
+ if (_ptrFileUtilityObj != NULL) {
+ RTC_LOG(LS_ERROR)
+ << "StartPlaying called, but FileUtilityObj already exists!";
+ StopPlaying();
+ return -1;
+ }
+
+ _ptrFileUtilityObj = new ModuleFileUtility();
+ if (_ptrFileUtilityObj == NULL) {
+ RTC_LOG(LS_INFO) << "Failed to create FileUtilityObj!";
+ return -1;
+ }
+
+ switch (format) {
+ case kFileFormatWavFile: {
+ if (_ptrFileUtilityObj->InitWavReading(stream, startPointMs,
+ stopPointMs) == -1) {
+ RTC_LOG(LS_ERROR) << "Not a valid WAV file!";
+ StopPlaying();
+ return -1;
+ }
+ _fileFormat = kFileFormatWavFile;
+ break;
+ }
+ case kFileFormatCompressedFile: {
+ if (_ptrFileUtilityObj->InitCompressedReading(stream, startPointMs,
+ stopPointMs) == -1) {
+ RTC_LOG(LS_ERROR) << "Not a valid Compressed file!";
+ StopPlaying();
+ return -1;
+ }
+ _fileFormat = kFileFormatCompressedFile;
+ break;
+ }
+ case kFileFormatPcm8kHzFile:
+ case kFileFormatPcm16kHzFile:
+ case kFileFormatPcm32kHzFile:
+ case kFileFormatPcm48kHzFile: {
+ // ValidFileFormat() called in the beginneing of this function
+ // prevents codecInst from being NULL here.
+ assert(codecInst != NULL);
+ if (!ValidFrequency(codecInst->plfreq) ||
+ _ptrFileUtilityObj->InitPCMReading(stream, startPointMs, stopPointMs,
+ codecInst->plfreq) == -1) {
+ RTC_LOG(LS_ERROR) << "Not a valid raw 8 or 16 KHz PCM file!";
+ StopPlaying();
+ return -1;
+ }
+
+ _fileFormat = format;
+ break;
+ }
+ case kFileFormatPreencodedFile: {
+ // ValidFileFormat() called in the beginneing of this function
+ // prevents codecInst from being NULL here.
+ assert(codecInst != NULL);
+ if (_ptrFileUtilityObj->InitPreEncodedReading(stream, *codecInst) == -1) {
+ RTC_LOG(LS_ERROR) << "Not a valid PreEncoded file!";
+ StopPlaying();
+ return -1;
+ }
+
+ _fileFormat = kFileFormatPreencodedFile;
+ break;
+ }
+ default: {
+ RTC_LOG(LS_ERROR) << "Invalid file format: " << format;
+ assert(false);
+ break;
+ }
+ }
+ if (_ptrFileUtilityObj->codec_info(codec_info_) == -1) {
+ RTC_LOG(LS_ERROR) << "Failed to retrieve codec info!";
+ StopPlaying();
+ return -1;
+ }
+
+ _isStereo = (codec_info_.channels == 2);
+ if (_isStereo && (_fileFormat != kFileFormatWavFile)) {
+ RTC_LOG(LS_WARNING) << "Stereo is only allowed for WAV files";
+ StopPlaying();
+ return -1;
+ }
+ _playingActive = true;
+ _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs();
+ _ptrInStream = &stream;
+ _notificationMs = notificationTimeMs;
+
+ return 0;
+}
+
+int32_t MediaFileImpl::StopPlaying() {
+ rtc::CritScope lock(&_crit);
+ _isStereo = false;
+ if (_ptrFileUtilityObj) {
+ delete _ptrFileUtilityObj;
+ _ptrFileUtilityObj = NULL;
+ }
+ if (_ptrInStream) {
+ // If MediaFileImpl opened the InStream it must be reclaimed here.
+ if (_openFile) {
+ delete _ptrInStream;
+ _openFile = false;
+ }
+ _ptrInStream = NULL;
+ }
+
+ codec_info_.pltype = 0;
+ codec_info_.plname[0] = '\0';
+
+ if (!_playingActive) {
+ RTC_LOG(LS_WARNING) << "playing is not active!";
+ return -1;
+ }
+
+ _playingActive = false;
+ return 0;
+}
+
+bool MediaFileImpl::IsPlaying() {
+ RTC_LOG(LS_VERBOSE) << "MediaFileImpl::IsPlaying()";
+ rtc::CritScope lock(&_crit);
+ return _playingActive;
+}
+
+int32_t MediaFileImpl::IncomingAudioData(const int8_t* buffer,
+ const size_t bufferLengthInBytes) {
+ RTC_LOG(LS_INFO) << "MediaFile::IncomingData(buffer= "
+ << static_cast<const void*>(buffer)
+ << ", bufLen= " << bufferLengthInBytes << ")";
+
+ if (buffer == NULL || bufferLengthInBytes == 0) {
+ RTC_LOG(LS_ERROR) << "Buffer pointer or length is NULL!";
+ return -1;
+ }
+
+ bool recordingEnded = false;
+ uint32_t callbackNotifyMs = 0;
+ {
+ rtc::CritScope lock(&_crit);
+
+ if (!_recordingActive) {
+ RTC_LOG(LS_WARNING) << "Not currently recording!";
+ return -1;
+ }
+ if (_ptrOutStream == NULL) {
+ RTC_LOG(LS_ERROR) << "Recording is active, but output stream is NULL!";
+ assert(false);
+ return -1;
+ }
+
+ int32_t bytesWritten = 0;
+ uint32_t samplesWritten = codec_info_.pacsize;
+ if (_ptrFileUtilityObj) {
+ switch (_fileFormat) {
+ case kFileFormatPcm8kHzFile:
+ case kFileFormatPcm16kHzFile:
+ case kFileFormatPcm32kHzFile:
+ case kFileFormatPcm48kHzFile:
+ bytesWritten = _ptrFileUtilityObj->WritePCMData(
+ *_ptrOutStream, buffer, bufferLengthInBytes);
+
+ // Sample size is 2 bytes.
+ if (bytesWritten > 0) {
+ samplesWritten = bytesWritten / sizeof(int16_t);
+ }
+ break;
+ case kFileFormatCompressedFile:
+ bytesWritten = _ptrFileUtilityObj->WriteCompressedData(
+ *_ptrOutStream, buffer, bufferLengthInBytes);
+ break;
+ case kFileFormatWavFile:
+ bytesWritten = _ptrFileUtilityObj->WriteWavData(
+ *_ptrOutStream, buffer, bufferLengthInBytes);
+ if (bytesWritten > 0 &&
+ STR_NCASE_CMP(codec_info_.plname, "L16", 4) == 0) {
+ // Sample size is 2 bytes.
+ samplesWritten = bytesWritten / sizeof(int16_t);
+ }
+ break;
+ case kFileFormatPreencodedFile:
+ bytesWritten = _ptrFileUtilityObj->WritePreEncodedData(
+ *_ptrOutStream, buffer, bufferLengthInBytes);
+ break;
+ default:
+ RTC_LOG(LS_ERROR) << "Invalid file format: " << _fileFormat;
+ assert(false);
+ break;
+ }
+ } else {
+ // TODO (hellner): quick look at the code makes me think that this
+ // code is never executed. Remove?
+ if (_ptrOutStream) {
+ if (_ptrOutStream->Write(buffer, bufferLengthInBytes)) {
+ bytesWritten = static_cast<int32_t>(bufferLengthInBytes);
+ }
+ }
+ }
+
+ _recordDurationMs += samplesWritten / (codec_info_.plfreq / 1000);
+
+ // Check if it's time for RecordNotification(..).
+ if (_notificationMs) {
+ if (_recordDurationMs >= _notificationMs) {
+ _notificationMs = 0;
+ callbackNotifyMs = _recordDurationMs;
+ }
+ }
+ if (bytesWritten < (int32_t)bufferLengthInBytes) {
+ RTC_LOG(LS_WARNING) << "Failed to write all requested bytes!";
+ StopRecording();
+ recordingEnded = true;
+ }
+ }
+
+ // Only _callbackCrit may and should be taken when making callbacks.
+ rtc::CritScope lock(&_callbackCrit);
+ if (_ptrCallback) {
+ if (callbackNotifyMs) {
+ _ptrCallback->RecordNotification(_id, callbackNotifyMs);
+ }
+ if (recordingEnded) {
+ _ptrCallback->RecordFileEnded(_id);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int32_t MediaFileImpl::StartRecordingAudioFile(
+ const char* fileName,
+ const FileFormats format,
+ const CodecInst& codecInst,
+ const uint32_t notificationTimeMs,
+ const uint32_t maxSizeBytes) {
+ if (!ValidFileName(fileName)) {
+ return -1;
+ }
+ if (!ValidFileFormat(format, &codecInst)) {
+ return -1;
+ }
+
+ FileWrapper* outputStream = FileWrapper::Create();
+ if (outputStream == NULL) {
+ RTC_LOG(LS_INFO) << "Failed to allocate memory for output stream";
+ return -1;
+ }
+
+ if (!outputStream->OpenFile(fileName, false)) {
+ delete outputStream;
+ RTC_LOG(LS_ERROR) << "Could not open output file '" << fileName
+ << "' for writing!";
+ return -1;
+ }
+
+ if (maxSizeBytes) {
+ outputStream->SetMaxFileSize(maxSizeBytes);
+ }
+
+ if (StartRecordingAudioStream(*outputStream, format, codecInst,
+ notificationTimeMs) == -1) {
+ outputStream->CloseFile();
+ delete outputStream;
+ return -1;
+ }
+
+ rtc::CritScope lock(&_crit);
+ _openFile = true;
+ strncpy(_fileName, fileName, sizeof(_fileName));
+ _fileName[sizeof(_fileName) - 1] = '\0';
+ return 0;
+}
+
+int32_t MediaFileImpl::StartRecordingAudioStream(
+ OutStream& stream,
+ const FileFormats format,
+ const CodecInst& codecInst,
+ const uint32_t notificationTimeMs) {
+ // Check codec info
+ if (!ValidFileFormat(format, &codecInst)) {
+ return -1;
+ }
+
+ rtc::CritScope lock(&_crit);
+ if (_recordingActive || _playingActive) {
+ RTC_LOG(LS_ERROR)
+ << "StartRecording called, but already recording or playing file "
+ << _fileName << "!";
+ return -1;
+ }
+
+ if (_ptrFileUtilityObj != NULL) {
+ RTC_LOG(LS_ERROR)
+ << "StartRecording called, but fileUtilityObj already exists!";
+ StopRecording();
+ return -1;
+ }
+
+ _ptrFileUtilityObj = new ModuleFileUtility();
+ if (_ptrFileUtilityObj == NULL) {
+ RTC_LOG(LS_INFO) << "Cannot allocate fileUtilityObj!";
+ return -1;
+ }
+
+ CodecInst tmpAudioCodec;
+ memcpy(&tmpAudioCodec, &codecInst, sizeof(CodecInst));
+ switch (format) {
+ case kFileFormatWavFile: {
+ if (_ptrFileUtilityObj->InitWavWriting(stream, codecInst) == -1) {
+ RTC_LOG(LS_ERROR) << "Failed to initialize WAV file!";
+ delete _ptrFileUtilityObj;
+ _ptrFileUtilityObj = NULL;
+ return -1;
+ }
+ _fileFormat = kFileFormatWavFile;
+ break;
+ }
+ case kFileFormatCompressedFile: {
+ // Write compression codec name at beginning of file
+ if (_ptrFileUtilityObj->InitCompressedWriting(stream, codecInst) == -1) {
+ RTC_LOG(LS_ERROR) << "Failed to initialize Compressed file!";
+ delete _ptrFileUtilityObj;
+ _ptrFileUtilityObj = NULL;
+ return -1;
+ }
+ _fileFormat = kFileFormatCompressedFile;
+ break;
+ }
+ case kFileFormatPcm8kHzFile:
+ case kFileFormatPcm16kHzFile:
+ case kFileFormatPcm32kHzFile:
+ case kFileFormatPcm48kHzFile: {
+ if (!ValidFrequency(codecInst.plfreq) ||
+ _ptrFileUtilityObj->InitPCMWriting(stream, codecInst.plfreq) == -1) {
+ RTC_LOG(LS_ERROR) << "Failed to initialize PCM file!";
+ delete _ptrFileUtilityObj;
+ _ptrFileUtilityObj = NULL;
+ return -1;
+ }
+ _fileFormat = format;
+ break;
+ }
+ case kFileFormatPreencodedFile: {
+ if (_ptrFileUtilityObj->InitPreEncodedWriting(stream, codecInst) == -1) {
+ RTC_LOG(LS_ERROR) << "Failed to initialize Pre-Encoded file!";
+ delete _ptrFileUtilityObj;
+ _ptrFileUtilityObj = NULL;
+ return -1;
+ }
+
+ _fileFormat = kFileFormatPreencodedFile;
+ break;
+ }
+ default: {
+ RTC_LOG(LS_ERROR) << "Invalid file format " << format << " specified!";
+ delete _ptrFileUtilityObj;
+ _ptrFileUtilityObj = NULL;
+ return -1;
+ }
+ }
+ _isStereo = (tmpAudioCodec.channels == 2);
+ if (_isStereo) {
+ if (_fileFormat != kFileFormatWavFile) {
+ RTC_LOG(LS_WARNING) << "Stereo is only allowed for WAV files";
+ StopRecording();
+ return -1;
+ }
+ if ((STR_NCASE_CMP(tmpAudioCodec.plname, "L16", 4) != 0) &&
+ (STR_NCASE_CMP(tmpAudioCodec.plname, "PCMU", 5) != 0) &&
+ (STR_NCASE_CMP(tmpAudioCodec.plname, "PCMA", 5) != 0)) {
+ RTC_LOG(LS_WARNING)
+ << "Stereo is only allowed for codec PCMU, PCMA and L16 ";
+ StopRecording();
+ return -1;
+ }
+ }
+ memcpy(&codec_info_, &tmpAudioCodec, sizeof(CodecInst));
+ _recordingActive = true;
+ _ptrOutStream = &stream;
+ _notificationMs = notificationTimeMs;
+ _recordDurationMs = 0;
+ return 0;
+}
+
+int32_t MediaFileImpl::StopRecording() {
+ rtc::CritScope lock(&_crit);
+ if (!_recordingActive) {
+ RTC_LOG(LS_WARNING) << "recording is not active!";
+ return -1;
+ }
+
+ _isStereo = false;
+
+ if (_ptrFileUtilityObj != NULL) {
+ // Both AVI and WAV header has to be updated before closing the stream
+ // because they contain size information.
+ if ((_fileFormat == kFileFormatWavFile) && (_ptrOutStream != NULL)) {
+ _ptrFileUtilityObj->UpdateWavHeader(*_ptrOutStream);
+ }
+ delete _ptrFileUtilityObj;
+ _ptrFileUtilityObj = NULL;
+ }
+
+ if (_ptrOutStream != NULL) {
+ // If MediaFileImpl opened the OutStream it must be reclaimed here.
+ if (_openFile) {
+ delete _ptrOutStream;
+ _openFile = false;
+ }
+ _ptrOutStream = NULL;
+ }
+
+ _recordingActive = false;
+ codec_info_.pltype = 0;
+ codec_info_.plname[0] = '\0';
+
+ return 0;
+}
+
+bool MediaFileImpl::IsRecording() {
+ RTC_LOG(LS_VERBOSE) << "MediaFileImpl::IsRecording()";
+ rtc::CritScope lock(&_crit);
+ return _recordingActive;
+}
+
+int32_t MediaFileImpl::RecordDurationMs(uint32_t& durationMs) {
+ rtc::CritScope lock(&_crit);
+ if (!_recordingActive) {
+ durationMs = 0;
+ return -1;
+ }
+ durationMs = _recordDurationMs;
+ return 0;
+}
+
+bool MediaFileImpl::IsStereo() {
+ RTC_LOG(LS_VERBOSE) << "MediaFileImpl::IsStereo()";
+ rtc::CritScope lock(&_crit);
+ return _isStereo;
+}
+
+int32_t MediaFileImpl::SetModuleFileCallback(FileCallback* callback) {
+ rtc::CritScope lock(&_callbackCrit);
+
+ _ptrCallback = callback;
+ return 0;
+}
+
+int32_t MediaFileImpl::FileDurationMs(const char* fileName,
+ uint32_t& durationMs,
+ const FileFormats format,
+ const uint32_t freqInHz) {
+ if (!ValidFileName(fileName)) {
+ return -1;
+ }
+ if (!ValidFrequency(freqInHz)) {
+ return -1;
+ }
+
+ ModuleFileUtility* utilityObj = new ModuleFileUtility();
+ if (utilityObj == NULL) {
+ RTC_LOG(LS_ERROR) << "failed to allocate utility object!";
+ return -1;
+ }
+
+ const int32_t duration =
+ utilityObj->FileDurationMs(fileName, format, freqInHz);
+ delete utilityObj;
+ if (duration == -1) {
+ durationMs = 0;
+ return -1;
+ }
+
+ durationMs = duration;
+ return 0;
+}
+
+int32_t MediaFileImpl::PlayoutPositionMs(uint32_t& positionMs) const {
+ rtc::CritScope lock(&_crit);
+ if (!_playingActive) {
+ positionMs = 0;
+ return -1;
+ }
+ positionMs = _playoutPositionMs;
+ return 0;
+}
+
+int32_t MediaFileImpl::codec_info(CodecInst& codecInst) const {
+ rtc::CritScope lock(&_crit);
+ if (!_playingActive && !_recordingActive) {
+ RTC_LOG(LS_ERROR) << "Neither playout nor recording has been initialized!";
+ return -1;
+ }
+ if (codec_info_.pltype == 0 && codec_info_.plname[0] == '\0') {
+ RTC_LOG(LS_ERROR) << "The CodecInst for "
+ << (_playingActive ? "Playback" : "Recording")
+ << " is unknown!";
+ return -1;
+ }
+ memcpy(&codecInst, &codec_info_, sizeof(CodecInst));
+ return 0;
+}
+
+bool MediaFileImpl::ValidFileFormat(const FileFormats format,
+ const CodecInst* codecInst) {
+ if (codecInst == NULL) {
+ if (format == kFileFormatPreencodedFile ||
+ format == kFileFormatPcm8kHzFile || format == kFileFormatPcm16kHzFile ||
+ format == kFileFormatPcm32kHzFile ||
+ format == kFileFormatPcm48kHzFile) {
+ RTC_LOG(LS_ERROR) << "Codec info required for file format specified!";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool MediaFileImpl::ValidFileName(const char* fileName) {
+ if ((fileName == NULL) || (fileName[0] == '\0')) {
+ RTC_LOG(LS_ERROR) << "FileName not specified!";
+ return false;
+ }
+ return true;
+}
+
+bool MediaFileImpl::ValidFilePositions(const uint32_t startPointMs,
+ const uint32_t stopPointMs) {
+ if (startPointMs == 0 && stopPointMs == 0) // Default values
+ {
+ return true;
+ }
+ if (stopPointMs && (startPointMs >= stopPointMs)) {
+ RTC_LOG(LS_ERROR) << "startPointMs must be less than stopPointMs!";
+ return false;
+ }
+ if (stopPointMs && ((stopPointMs - startPointMs) < 20)) {
+ RTC_LOG(LS_ERROR) << "minimum play duration for files is 20 ms!";
+ return false;
+ }
+ return true;
+}
+
+bool MediaFileImpl::ValidFrequency(const uint32_t frequency) {
+ if ((frequency == 8000) || (frequency == 16000) || (frequency == 32000) ||
+ (frequency == 48000)) {
+ return true;
+ }
+ RTC_LOG(LS_ERROR) << "Frequency should be 8000, 16000, 32000, or 48000 (Hz)";
+ return false;
+}
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.h b/third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.h
new file mode 100644
index 0000000000..7716d81078
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/media_file_impl.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_MEDIA_FILE_MEDIA_FILE_IMPL_H_
+#define MODULES_MEDIA_FILE_MEDIA_FILE_IMPL_H_
+
+#include "common_types.h" // NOLINT(build/include)
+#include "modules/include/module_common_types.h"
+#include "modules/media_file/media_file.h"
+#include "modules/media_file/media_file_defines.h"
+#include "modules/media_file/media_file_utility.h"
+#include "rtc_base/criticalsection.h"
+
+namespace webrtc {
+class MediaFileImpl : public MediaFile
+{
+
+public:
+ MediaFileImpl(const int32_t id);
+ ~MediaFileImpl();
+
+ void Process() override;
+ int64_t TimeUntilNextProcess() override;
+
+ // MediaFile functions
+ int32_t PlayoutAudioData(int8_t* audioBuffer,
+ size_t& dataLengthInBytes) override;
+
+ int32_t PlayoutStereoData(int8_t* audioBufferLeft,
+ int8_t* audioBufferRight,
+ size_t& dataLengthInBytes) override;
+
+ int32_t StartPlayingAudioFile(
+ const char* fileName,
+ const uint32_t notificationTimeMs = 0,
+ const bool loop = false,
+ const FileFormats format = kFileFormatPcm16kHzFile,
+ const CodecInst* codecInst = NULL,
+ const uint32_t startPointMs = 0,
+ const uint32_t stopPointMs = 0) override;
+
+ int32_t StartPlayingAudioStream(
+ InStream& stream,
+ const uint32_t notificationTimeMs = 0,
+ const FileFormats format = kFileFormatPcm16kHzFile,
+ const CodecInst* codecInst = NULL,
+ const uint32_t startPointMs = 0,
+ const uint32_t stopPointMs = 0) override;
+
+ int32_t StopPlaying() override;
+
+ bool IsPlaying() override;
+
+ int32_t PlayoutPositionMs(uint32_t& positionMs) const override;
+
+ int32_t IncomingAudioData(const int8_t* audioBuffer,
+ const size_t bufferLength) override;
+
+ int32_t StartRecordingAudioFile(const char* fileName,
+ const FileFormats format,
+ const CodecInst& codecInst,
+ const uint32_t notificationTimeMs = 0,
+ const uint32_t maxSizeBytes = 0) override;
+
+ int32_t StartRecordingAudioStream(
+ OutStream& stream,
+ const FileFormats format,
+ const CodecInst& codecInst,
+ const uint32_t notificationTimeMs = 0) override;
+
+ int32_t StopRecording() override;
+
+ bool IsRecording() override;
+
+ int32_t RecordDurationMs(uint32_t& durationMs) override;
+
+ bool IsStereo() override;
+
+ int32_t SetModuleFileCallback(FileCallback* callback) override;
+
+ int32_t FileDurationMs(const char* fileName,
+ uint32_t& durationMs,
+ const FileFormats format,
+ const uint32_t freqInHz = 16000) override;
+
+ int32_t codec_info(CodecInst& codecInst) const override;
+
+private:
+ // Returns true if the combination of format and codecInst is valid.
+ static bool ValidFileFormat(const FileFormats format,
+ const CodecInst* codecInst);
+
+
+ // Returns true if the filename is valid
+ static bool ValidFileName(const char* fileName);
+
+ // Returns true if the combination of startPointMs and stopPointMs is valid.
+ static bool ValidFilePositions(const uint32_t startPointMs,
+ const uint32_t stopPointMs);
+
+ // Returns true if frequencyInHz is a supported frequency.
+ static bool ValidFrequency(const uint32_t frequencyInHz);
+
+ void HandlePlayCallbacks(int32_t bytesRead);
+
+ int32_t StartPlayingStream(
+ InStream& stream,
+ bool loop,
+ const uint32_t notificationTimeMs,
+ const FileFormats format,
+ const CodecInst* codecInst,
+ const uint32_t startPointMs,
+ const uint32_t stopPointMs);
+
+ int32_t _id;
+ rtc::CriticalSection _crit;
+ rtc::CriticalSection _callbackCrit;
+
+ ModuleFileUtility* _ptrFileUtilityObj;
+ CodecInst codec_info_;
+
+ InStream* _ptrInStream;
+ OutStream* _ptrOutStream;
+
+ FileFormats _fileFormat;
+ uint32_t _recordDurationMs;
+ uint32_t _playoutPositionMs;
+ uint32_t _notificationMs;
+
+ bool _playingActive;
+ bool _recordingActive;
+ bool _isStereo;
+ bool _openFile;
+
+ char _fileName[512];
+
+ FileCallback* _ptrCallback;
+};
+} // namespace webrtc
+
+#endif // MODULES_MEDIA_FILE_MEDIA_FILE_IMPL_H_
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/media_file_unittest.cc b/third_party/libwebrtc/webrtc/modules/media_file/media_file_unittest.cc
new file mode 100644
index 0000000000..7df1a68cde
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/media_file_unittest.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/media_file/media_file.h"
+#include "system_wrappers/include/sleep.h"
+#include "test/gtest.h"
+#include "test/testsupport/fileutils.h"
+
+class MediaFileTest : public testing::Test {
+ protected:
+ void SetUp() {
+ // Use number 0 as the the identifier and pass to CreateMediaFile.
+ media_file_ = webrtc::MediaFile::CreateMediaFile(0);
+ ASSERT_TRUE(media_file_ != NULL);
+ }
+ void TearDown() {
+ webrtc::MediaFile::DestroyMediaFile(media_file_);
+ media_file_ = NULL;
+ }
+ webrtc::MediaFile* media_file_;
+};
+
+#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
+#define MAYBE_StartPlayingAudioFileWithoutError \
+ DISABLED_StartPlayingAudioFileWithoutError
+#else
+#define MAYBE_StartPlayingAudioFileWithoutError \
+ StartPlayingAudioFileWithoutError
+#endif
+TEST_F(MediaFileTest, MAYBE_StartPlayingAudioFileWithoutError) {
+ // TODO(leozwang): Use hard coded filename here, we want to
+ // loop through all audio files in future
+ const std::string audio_file =
+ webrtc::test::ResourcePath("voice_engine/audio_tiny48", "wav");
+ ASSERT_EQ(0, media_file_->StartPlayingAudioFile(
+ audio_file.c_str(),
+ 0,
+ false,
+ webrtc::kFileFormatWavFile));
+
+ ASSERT_EQ(true, media_file_->IsPlaying());
+
+ webrtc::SleepMs(1);
+
+ ASSERT_EQ(0, media_file_->StopPlaying());
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_WriteWavFile DISABLED_WriteWavFile
+#else
+#define MAYBE_WriteWavFile WriteWavFile
+#endif
+TEST_F(MediaFileTest, MAYBE_WriteWavFile) {
+ // Write file.
+ static const size_t kHeaderSize = 44;
+ static const size_t kPayloadSize = 320;
+ webrtc::CodecInst codec = {
+ 0, "L16", 16000, static_cast<int>(kPayloadSize), 1
+ };
+ std::string outfile = webrtc::test::OutputPath() + "wavtest.wav";
+ ASSERT_EQ(0,
+ media_file_->StartRecordingAudioFile(
+ outfile.c_str(), webrtc::kFileFormatWavFile, codec));
+ static const int8_t kFakeData[kPayloadSize] = {0};
+ ASSERT_EQ(0, media_file_->IncomingAudioData(kFakeData, kPayloadSize));
+ ASSERT_EQ(0, media_file_->StopRecording());
+
+ // Check the file we just wrote.
+ static const uint8_t kExpectedHeader[] = {
+ 'R', 'I', 'F', 'F',
+ 0x64, 0x1, 0, 0, // size of whole file - 8: 320 + 44 - 8
+ 'W', 'A', 'V', 'E',
+ 'f', 'm', 't', ' ',
+ 0x10, 0, 0, 0, // size of fmt block - 8: 24 - 8
+ 0x1, 0, // format: PCM (1)
+ 0x1, 0, // channels: 1
+ 0x80, 0x3e, 0, 0, // sample rate: 16000
+ 0, 0x7d, 0, 0, // byte rate: 2 * 16000
+ 0x2, 0, // block align: NumChannels * BytesPerSample
+ 0x10, 0, // bits per sample: 2 * 8
+ 'd', 'a', 't', 'a',
+ 0x40, 0x1, 0, 0, // size of payload: 320
+ };
+ static_assert(sizeof(kExpectedHeader) == kHeaderSize, "header size");
+
+ EXPECT_EQ(kHeaderSize + kPayloadSize, webrtc::test::GetFileSize(outfile));
+ FILE* f = fopen(outfile.c_str(), "rb");
+ ASSERT_TRUE(f);
+
+ uint8_t header[kHeaderSize];
+ ASSERT_EQ(1u, fread(header, kHeaderSize, 1, f));
+ EXPECT_EQ(0, memcmp(kExpectedHeader, header, kHeaderSize));
+
+ uint8_t payload[kPayloadSize];
+ ASSERT_EQ(1u, fread(payload, kPayloadSize, 1, f));
+ EXPECT_EQ(0, memcmp(kFakeData, payload, kPayloadSize));
+
+ EXPECT_EQ(0, fclose(f));
+}
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.cc b/third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.cc
new file mode 100644
index 0000000000..f4ccba10df
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.cc
@@ -0,0 +1,1238 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/media_file/media_file_utility.h"
+
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <limits>
+
+#include "common_audio/wav_header.h"
+#include "common_types.h" // NOLINT(build/include)
+#include "modules/include/module_common_types.h"
+#include "rtc_base/format_macros.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/file_wrapper.h"
+#include "typedefs.h" // NOLINT(build/include)
+
+namespace {
+
+// First 16 bytes the WAVE header. ckID should be "RIFF", wave_ckID should be
+// "WAVE" and ckSize is the chunk size (4 + n)
+struct WAVE_RIFF_header {
+ int8_t ckID[4];
+ int32_t ckSize;
+ int8_t wave_ckID[4];
+};
+
+// First 8 byte of the format chunk. fmt_ckID should be "fmt ". fmt_ckSize is
+// the chunk size (16, 18 or 40 byte)
+struct WAVE_CHUNK_header {
+ int8_t fmt_ckID[4];
+ uint32_t fmt_ckSize;
+};
+} // unnamed namespace
+
+namespace webrtc {
+ModuleFileUtility::ModuleFileUtility()
+ : _wavFormatObj(),
+ _dataSize(0),
+ _readSizeBytes(0),
+ _stopPointInMs(0),
+ _startPointInMs(0),
+ _playoutPositionMs(0),
+ _bytesWritten(0),
+ codec_info_(),
+ _codecId(kCodecNoCodec),
+ _bytesPerSample(0),
+ _readPos(0),
+ _reading(false),
+ _writing(false),
+ _tempData() {
+ RTC_LOG(LS_INFO) << "ModuleFileUtility::ModuleFileUtility()";
+ memset(&codec_info_, 0, sizeof(CodecInst));
+ codec_info_.pltype = -1;
+}
+
+ModuleFileUtility::~ModuleFileUtility() {
+ RTC_LOG(LS_INFO) << "ModuleFileUtility::~ModuleFileUtility()";
+}
+
+int32_t ModuleFileUtility::ReadWavHeader(InStream& wav) {
+ WAVE_RIFF_header RIFFheaderObj;
+ WAVE_CHUNK_header CHUNKheaderObj;
+ // TODO (hellner): tmpStr and tmpStr2 seems unnecessary here.
+ char tmpStr[6] = "FOUR";
+ unsigned char tmpStr2[4];
+ size_t i;
+ bool dataFound = false;
+ bool fmtFound = false;
+ int8_t dummyRead;
+
+ _dataSize = 0;
+ int len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header));
+ if (len != static_cast<int>(sizeof(WAVE_RIFF_header))) {
+ RTC_LOG(LS_ERROR) << "Not a wave file (too short)";
+ return -1;
+ }
+
+ for (i = 0; i < 4; i++) {
+ tmpStr[i] = RIFFheaderObj.ckID[i];
+ }
+ if (strcmp(tmpStr, "RIFF") != 0) {
+ RTC_LOG(LS_ERROR) << "Not a wave file (does not have RIFF)";
+ return -1;
+ }
+ for (i = 0; i < 4; i++) {
+ tmpStr[i] = RIFFheaderObj.wave_ckID[i];
+ }
+ if (strcmp(tmpStr, "WAVE") != 0) {
+ RTC_LOG(LS_ERROR) << "Not a wave file (does not have WAVE)";
+ return -1;
+ }
+
+ len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
+
+ // WAVE files are stored in little endian byte order. Make sure that the
+ // data can be read on big endian as well.
+ // TODO (hellner): little endian to system byte order should be done in
+ // in a subroutine.
+ memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
+ CHUNKheaderObj.fmt_ckSize =
+ (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
+ (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
+
+ memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
+
+ while ((len == static_cast<int>(sizeof(WAVE_CHUNK_header))) &&
+ (!fmtFound || !dataFound)) {
+ if (strcmp(tmpStr, "fmt ") == 0) {
+ len = wav.Read(&_wavFormatObj, sizeof(WAVE_FMTINFO_header));
+
+ memcpy(tmpStr2, &_wavFormatObj.formatTag, 2);
+ _wavFormatObj.formatTag =
+ (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8);
+ memcpy(tmpStr2, &_wavFormatObj.nChannels, 2);
+ _wavFormatObj.nChannels =
+ (int16_t)((uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8));
+ memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4);
+ _wavFormatObj.nSamplesPerSec = (int32_t)(
+ (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
+ (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24));
+ memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4);
+ _wavFormatObj.nAvgBytesPerSec = (int32_t)(
+ (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
+ (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24));
+ memcpy(tmpStr2, &_wavFormatObj.nBlockAlign, 2);
+ _wavFormatObj.nBlockAlign =
+ (int16_t)((uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8));
+ memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2);
+ _wavFormatObj.nBitsPerSample =
+ (int16_t)((uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8));
+
+ if (CHUNKheaderObj.fmt_ckSize < sizeof(WAVE_FMTINFO_header)) {
+ RTC_LOG(LS_ERROR) << "Chunk size is too small";
+ return -1;
+ }
+ for (i = 0; i < CHUNKheaderObj.fmt_ckSize - sizeof(WAVE_FMTINFO_header);
+ i++) {
+ len = wav.Read(&dummyRead, 1);
+ if (len != 1) {
+ RTC_LOG(LS_ERROR) << "File corrupted, reached EOF (reading fmt)";
+ return -1;
+ }
+ }
+ fmtFound = true;
+ } else if (strcmp(tmpStr, "data") == 0) {
+ _dataSize = CHUNKheaderObj.fmt_ckSize;
+ dataFound = true;
+ break;
+ } else {
+ for (i = 0; i < CHUNKheaderObj.fmt_ckSize; i++) {
+ len = wav.Read(&dummyRead, 1);
+ if (len != 1) {
+ RTC_LOG(LS_ERROR) << "File corrupted, reached EOF (reading other)";
+ return -1;
+ }
+ }
+ }
+
+ len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
+
+ memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
+ CHUNKheaderObj.fmt_ckSize =
+ (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
+ (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
+
+ memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
+ }
+
+ // Either a proper format chunk has been read or a data chunk was come
+ // across.
+ if ((_wavFormatObj.formatTag != kWavFormatPcm) &&
+ (_wavFormatObj.formatTag != kWavFormatALaw) &&
+ (_wavFormatObj.formatTag != kWavFormatMuLaw)) {
+ RTC_LOG(LS_ERROR) << "Coding formatTag value=" << _wavFormatObj.formatTag
+ << " not supported!";
+ return -1;
+ }
+ if ((_wavFormatObj.nChannels < 1) || (_wavFormatObj.nChannels > 2)) {
+ RTC_LOG(LS_ERROR) << "nChannels value=" << _wavFormatObj.nChannels
+ << " not supported!";
+ return -1;
+ }
+
+ if ((_wavFormatObj.nBitsPerSample != 8) &&
+ (_wavFormatObj.nBitsPerSample != 16)) {
+ RTC_LOG(LS_ERROR) << "nBitsPerSample value=" << _wavFormatObj.nBitsPerSample
+ << " not supported!";
+ return -1;
+ }
+
+ // Calculate the number of bytes that 10 ms of audio data correspond to.
+ size_t samples_per_10ms =
+ ((_wavFormatObj.formatTag == kWavFormatPcm) &&
+ (_wavFormatObj.nSamplesPerSec == 44100))
+ ? 440
+ : static_cast<size_t>(_wavFormatObj.nSamplesPerSec / 100);
+ _readSizeBytes = samples_per_10ms * _wavFormatObj.nChannels *
+ (_wavFormatObj.nBitsPerSample / 8);
+ return 0;
+}
+
+int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec,
+ size_t channels,
+ uint32_t bitsPerSample,
+ uint32_t formatTag) {
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = samplesPerSec;
+ codec_info_.channels = channels;
+ codec_info_.rate = bitsPerSample * samplesPerSec;
+
+ // Calculate the packet size for 10ms frames
+ switch (formatTag) {
+ case kWavFormatALaw:
+ strcpy(codec_info_.plname, "PCMA");
+ _codecId = kCodecPcma;
+ codec_info_.pltype = 8;
+ codec_info_.pacsize = codec_info_.plfreq / 100;
+ break;
+ case kWavFormatMuLaw:
+ strcpy(codec_info_.plname, "PCMU");
+ _codecId = kCodecPcmu;
+ codec_info_.pltype = 0;
+ codec_info_.pacsize = codec_info_.plfreq / 100;
+ break;
+ case kWavFormatPcm:
+ codec_info_.pacsize = (bitsPerSample * (codec_info_.plfreq / 100)) / 8;
+ if (samplesPerSec == 8000) {
+ strcpy(codec_info_.plname, "L16");
+ _codecId = kCodecL16_8Khz;
+ } else if (samplesPerSec == 16000) {
+ strcpy(codec_info_.plname, "L16");
+ _codecId = kCodecL16_16kHz;
+ } else if (samplesPerSec == 32000) {
+ strcpy(codec_info_.plname, "L16");
+ _codecId = kCodecL16_32Khz;
+ }
+ // Set the packet size for "odd" sampling frequencies so that it
+ // properly corresponds to _readSizeBytes.
+ else if (samplesPerSec == 11025) {
+ strcpy(codec_info_.plname, "L16");
+ _codecId = kCodecL16_16kHz;
+ codec_info_.pacsize = 110;
+ codec_info_.plfreq = 11000;
+ } else if (samplesPerSec == 22050) {
+ strcpy(codec_info_.plname, "L16");
+ _codecId = kCodecL16_16kHz;
+ codec_info_.pacsize = 220;
+ codec_info_.plfreq = 22000;
+ } else if (samplesPerSec == 44100) {
+ strcpy(codec_info_.plname, "L16");
+ _codecId = kCodecL16_16kHz;
+ codec_info_.pacsize = 441;
+ codec_info_.plfreq = 44100;
+ } else if (samplesPerSec == 48000) {
+ strcpy(codec_info_.plname, "L16");
+ _codecId = kCodecL16_16kHz;
+ codec_info_.pacsize = 480;
+ codec_info_.plfreq = 48000;
+ } else {
+ RTC_LOG(LS_ERROR) << "Unsupported PCM frequency!";
+ return -1;
+ }
+ break;
+ default:
+ RTC_LOG(LS_ERROR) << "unknown WAV format TAG!";
+ return -1;
+ break;
+ }
+ return 0;
+}
+
+int32_t ModuleFileUtility::InitWavReading(InStream& wav,
+ const uint32_t start,
+ const uint32_t stop) {
+ _reading = false;
+
+ if (ReadWavHeader(wav) == -1) {
+ RTC_LOG(LS_ERROR) << "failed to read WAV header!";
+ return -1;
+ }
+
+ _playoutPositionMs = 0;
+ _readPos = 0;
+
+ if (start > 0) {
+ uint8_t dummy[WAV_MAX_BUFFER_SIZE];
+ int readLength;
+ if (_readSizeBytes <= WAV_MAX_BUFFER_SIZE) {
+ while (_playoutPositionMs < start) {
+ readLength = wav.Read(dummy, _readSizeBytes);
+ if (readLength == static_cast<int>(_readSizeBytes)) {
+ _readPos += _readSizeBytes;
+ _playoutPositionMs += 10;
+ } else // Must have reached EOF before start position!
+ {
+ RTC_LOG(LS_ERROR) << "InitWavReading(), EOF before start position";
+ return -1;
+ }
+ }
+ } else {
+ return -1;
+ }
+ }
+ if (InitWavCodec(_wavFormatObj.nSamplesPerSec, _wavFormatObj.nChannels,
+ _wavFormatObj.nBitsPerSample,
+ _wavFormatObj.formatTag) != 0) {
+ return -1;
+ }
+ _bytesPerSample = static_cast<size_t>(_wavFormatObj.nBitsPerSample / 8);
+
+ _startPointInMs = start;
+ _stopPointInMs = stop;
+ _reading = true;
+ return 0;
+}
+
+int32_t ModuleFileUtility::ReadWavDataAsMono(InStream& wav,
+ int8_t* outData,
+ const size_t bufferSize) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::ReadWavDataAsMono(wav= " << &wav
+ << ", outData= " << static_cast<void*>(outData)
+ << ", bufSize= " << bufferSize << ")";
+
+ // The number of bytes that should be read from file.
+ const size_t totalBytesNeeded = _readSizeBytes;
+ // The number of bytes that will be written to outData.
+ const size_t bytesRequested =
+ (codec_info_.channels == 2) ? totalBytesNeeded >> 1 : totalBytesNeeded;
+ if (bufferSize < bytesRequested) {
+ RTC_LOG(LS_ERROR) << "ReadWavDataAsMono: output buffer is too short!";
+ return -1;
+ }
+ if (outData == NULL) {
+ RTC_LOG(LS_ERROR) << "ReadWavDataAsMono: output buffer NULL!";
+ return -1;
+ }
+
+ if (!_reading) {
+ RTC_LOG(LS_ERROR) << "ReadWavDataAsMono: no longer reading file.";
+ return -1;
+ }
+
+ int32_t bytesRead = ReadWavData(
+ wav, (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData,
+ totalBytesNeeded);
+ if (bytesRead == 0) {
+ return 0;
+ }
+ if (bytesRead < 0) {
+ RTC_LOG(LS_ERROR)
+ << "ReadWavDataAsMono: failed to read data from WAV file.";
+ return -1;
+ }
+ // Output data is should be mono.
+ if (codec_info_.channels == 2) {
+ for (size_t i = 0; i < bytesRequested / _bytesPerSample; i++) {
+ // Sample value is the average of left and right buffer rounded to
+ // closest integer value. Note samples can be either 1 or 2 byte.
+ if (_bytesPerSample == 1) {
+ _tempData[i] = ((_tempData[2 * i] + _tempData[(2 * i) + 1] + 1) >> 1);
+ } else {
+ int16_t* sampleData = (int16_t*)_tempData;
+ sampleData[i] =
+ ((sampleData[2 * i] + sampleData[(2 * i) + 1] + 1) >> 1);
+ }
+ }
+ memcpy(outData, _tempData, bytesRequested);
+ }
+ return static_cast<int32_t>(bytesRequested);
+}
+
+int32_t ModuleFileUtility::ReadWavDataAsStereo(InStream& wav,
+ int8_t* outDataLeft,
+ int8_t* outDataRight,
+ const size_t bufferSize) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::ReadWavDataAsStereo(wav= " << &wav
+ << ", outLeft= " << static_cast<void*>(outDataLeft)
+ << ", outRight= " << static_cast<void*>(outDataRight)
+ << ", bufSize= " << bufferSize << ")";
+
+ if ((outDataLeft == NULL) || (outDataRight == NULL)) {
+ RTC_LOG(LS_ERROR) << "ReadWavDataAsStereo: an input buffer is NULL!";
+ return -1;
+ }
+ if (codec_info_.channels != 2) {
+ RTC_LOG(LS_ERROR)
+ << "ReadWavDataAsStereo: WAV file does not contain stereo data!";
+ return -1;
+ }
+ if (!_reading) {
+ RTC_LOG(LS_ERROR) << "ReadWavDataAsStereo: no longer reading file.";
+ return -1;
+ }
+
+ // The number of bytes that should be read from file.
+ const size_t totalBytesNeeded = _readSizeBytes;
+ // The number of bytes that will be written to the left and the right
+ // buffers.
+ const size_t bytesRequested = totalBytesNeeded >> 1;
+ if (bufferSize < bytesRequested) {
+ RTC_LOG(LS_ERROR) << "ReadWavDataAsStereo: Output buffers are too short!";
+ assert(false);
+ return -1;
+ }
+
+ int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded);
+ if (bytesRead <= 0) {
+ RTC_LOG(LS_ERROR)
+ << "ReadWavDataAsStereo: failed to read data from WAV file.";
+ return -1;
+ }
+
+ // Turn interleaved audio to left and right buffer. Note samples can be
+ // either 1 or 2 bytes
+ if (_bytesPerSample == 1) {
+ for (size_t i = 0; i < bytesRequested; i++) {
+ outDataLeft[i] = _tempData[2 * i];
+ outDataRight[i] = _tempData[(2 * i) + 1];
+ }
+ } else if (_bytesPerSample == 2) {
+ int16_t* sampleData = reinterpret_cast<int16_t*>(_tempData);
+ int16_t* outLeft = reinterpret_cast<int16_t*>(outDataLeft);
+ int16_t* outRight = reinterpret_cast<int16_t*>(outDataRight);
+
+ // Bytes requested to samples requested.
+ size_t sampleCount = bytesRequested >> 1;
+ for (size_t i = 0; i < sampleCount; i++) {
+ outLeft[i] = sampleData[2 * i];
+ outRight[i] = sampleData[(2 * i) + 1];
+ }
+ } else {
+ RTC_LOG(LS_ERROR) << "ReadWavStereoData: unsupported sample size "
+ << _bytesPerSample << "!";
+ assert(false);
+ return -1;
+ }
+ return static_cast<int32_t>(bytesRequested);
+}
+
+int32_t ModuleFileUtility::ReadWavData(InStream& wav,
+ uint8_t* buffer,
+ size_t dataLengthInBytes) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::ReadWavData(wav= " << &wav
+ << ", buffer= " << static_cast<void*>(buffer)
+ << ", dataLen= " << dataLengthInBytes << ")";
+
+ if (buffer == NULL) {
+ RTC_LOG(LS_ERROR) << "ReadWavDataAsMono: output buffer NULL!";
+ return -1;
+ }
+
+ // Make sure that a read won't return too few samples.
+ // TODO (hellner): why not read the remaining bytes needed from the start
+ // of the file?
+ if (_dataSize < (_readPos + dataLengthInBytes)) {
+ // Rewind() being -1 may be due to the file not supposed to be looped.
+ if (wav.Rewind() == -1) {
+ _reading = false;
+ return 0;
+ }
+ if (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1) {
+ _reading = false;
+ return -1;
+ }
+ }
+
+ int32_t bytesRead = wav.Read(buffer, dataLengthInBytes);
+ if (bytesRead < 0) {
+ _reading = false;
+ return -1;
+ }
+
+ // This should never happen due to earlier sanity checks.
+ // TODO (hellner): change to an assert and fail here since this should
+ // never happen...
+ if (bytesRead < (int32_t)dataLengthInBytes) {
+ if ((wav.Rewind() == -1) ||
+ (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)) {
+ _reading = false;
+ return -1;
+ } else {
+ bytesRead = wav.Read(buffer, dataLengthInBytes);
+ if (bytesRead < (int32_t)dataLengthInBytes) {
+ _reading = false;
+ return -1;
+ }
+ }
+ }
+
+ _readPos += bytesRead;
+
+ // TODO (hellner): Why is dataLengthInBytes let dictate the number of bytes
+ // to read when exactly 10ms should be read?!
+ _playoutPositionMs += 10;
+ if ((_stopPointInMs > 0) && (_playoutPositionMs >= _stopPointInMs)) {
+ if ((wav.Rewind() == -1) ||
+ (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)) {
+ _reading = false;
+ }
+ }
+ return bytesRead;
+}
+
+int32_t ModuleFileUtility::InitWavWriting(OutStream& wav,
+ const CodecInst& codecInst) {
+ if (set_codec_info(codecInst) != 0) {
+ RTC_LOG(LS_ERROR) << "codecInst identifies unsupported codec!";
+ return -1;
+ }
+ _writing = false;
+ size_t channels = (codecInst.channels == 0) ? 1 : codecInst.channels;
+
+ if (STR_CASE_CMP(codecInst.plname, "PCMU") == 0) {
+ _bytesPerSample = 1;
+ if (WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatMuLaw,
+ 0) == -1) {
+ return -1;
+ }
+ } else if (STR_CASE_CMP(codecInst.plname, "PCMA") == 0) {
+ _bytesPerSample = 1;
+ if (WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw,
+ 0) == -1) {
+ return -1;
+ }
+ } else if (STR_CASE_CMP(codecInst.plname, "L16") == 0) {
+ _bytesPerSample = 2;
+ if (WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels,
+ kWavFormatPcm, 0) == -1) {
+ return -1;
+ }
+ } else {
+ RTC_LOG(LS_ERROR) << "codecInst identifies unsupported codec for WAV file!";
+ return -1;
+ }
+ _writing = true;
+ _bytesWritten = 0;
+ return 0;
+}
+
+int32_t ModuleFileUtility::WriteWavData(OutStream& out,
+ const int8_t* buffer,
+ const size_t dataLength) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::WriteWavData(out= " << &out
+ << ", buf= " << static_cast<const void*>(buffer)
+ << ", dataLen= " << dataLength << ")";
+
+ if (buffer == NULL) {
+ RTC_LOG(LS_ERROR) << "WriteWavData: input buffer NULL!";
+ return -1;
+ }
+
+ if (!out.Write(buffer, dataLength)) {
+ return -1;
+ }
+ _bytesWritten += dataLength;
+ return static_cast<int32_t>(dataLength);
+}
+
+int32_t ModuleFileUtility::WriteWavHeader(OutStream& wav,
+ uint32_t freq,
+ size_t bytesPerSample,
+ size_t channels,
+ uint32_t format,
+ size_t lengthInBytes) {
+ // Frame size in bytes for 10 ms of audio.
+ // TODO (hellner): 44.1 kHz has 440 samples frame size. Doesn't seem to
+ // be taken into consideration here!
+ const size_t frameSize = (freq / 100) * channels;
+
+ // Calculate the number of full frames that the wave file contain.
+ const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
+
+ uint8_t buf[kWavHeaderSize];
+ webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
+ bytesPerSample, dataLengthInBytes / bytesPerSample);
+ wav.Write(buf, kWavHeaderSize);
+ return 0;
+}
+
+int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav) {
+ int32_t res = -1;
+ if (wav.Rewind() == -1) {
+ return -1;
+ }
+ size_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
+
+ if (STR_CASE_CMP(codec_info_.plname, "L16") == 0) {
+ res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels, kWavFormatPcm,
+ _bytesWritten);
+ } else if (STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
+ res =
+ WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw, _bytesWritten);
+ } else if (STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
+ res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw, _bytesWritten);
+ } else {
+ // Allow calling this API even if not writing to a WAVE file.
+ // TODO (hellner): why?!
+ return 0;
+ }
+ return res;
+}
+
+int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
+ const CodecInst& cinst) {
+ uint8_t preEncodedID;
+ in.Read(&preEncodedID, 1);
+
+ MediaFileUtility_CodecType codecType =
+ (MediaFileUtility_CodecType)preEncodedID;
+
+ if (set_codec_info(cinst) != 0) {
+ RTC_LOG(LS_ERROR) << "Pre-encoded file send codec mismatch!";
+ return -1;
+ }
+ if (codecType != _codecId) {
+ RTC_LOG(LS_ERROR) << "Pre-encoded file format codec mismatch!";
+ return -1;
+ }
+ memcpy(&codec_info_, &cinst, sizeof(CodecInst));
+ _reading = true;
+ return 0;
+}
+
+int32_t ModuleFileUtility::ReadPreEncodedData(InStream& in,
+ int8_t* outData,
+ const size_t bufferSize) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::ReadPreEncodedData(in= " << &in
+ << ", outData= " << static_cast<void*>(outData)
+ << ", bufferSize= " << bufferSize << ")";
+
+ if (outData == NULL) {
+ RTC_LOG(LS_ERROR) << "output buffer NULL";
+ }
+
+ size_t frameLen;
+ uint8_t buf[64];
+ // Each frame has a two byte header containing the frame length.
+ int32_t res = in.Read(buf, 2);
+ if (res != 2) {
+ if (!in.Rewind()) {
+ // The first byte is the codec identifier.
+ in.Read(buf, 1);
+ res = in.Read(buf, 2);
+ } else {
+ return -1;
+ }
+ }
+ frameLen = buf[0] + buf[1] * 256;
+ if (bufferSize < frameLen) {
+ RTC_LOG(LS_ERROR) << "buffer not large enough to read " << frameLen
+ << " bytes of pre-encoded data!";
+ return -1;
+ }
+ return in.Read(outData, frameLen);
+}
+
+int32_t ModuleFileUtility::InitPreEncodedWriting(OutStream& out,
+ const CodecInst& codecInst) {
+ if (set_codec_info(codecInst) != 0) {
+ RTC_LOG(LS_ERROR) << "CodecInst not recognized!";
+ return -1;
+ }
+ _writing = true;
+ _bytesWritten = 1;
+ out.Write(&_codecId, 1);
+ return 0;
+}
+
+int32_t ModuleFileUtility::WritePreEncodedData(OutStream& out,
+ const int8_t* buffer,
+ const size_t dataLength) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::WritePreEncodedData(out= " << &out
+ << " , inData= " << static_cast<const void*>(buffer)
+ << ", dataLen= " << dataLength << ")";
+
+ if (buffer == NULL) {
+ RTC_LOG(LS_ERROR) << "buffer NULL";
+ }
+
+ size_t bytesWritten = 0;
+ // The first two bytes is the size of the frame.
+ int16_t lengthBuf;
+ lengthBuf = (int16_t)dataLength;
+ if (dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
+ !out.Write(&lengthBuf, 2)) {
+ return -1;
+ }
+ bytesWritten = 2;
+
+ if (!out.Write(buffer, dataLength)) {
+ return -1;
+ }
+ bytesWritten += dataLength;
+ return static_cast<int32_t>(bytesWritten);
+}
+
+int32_t ModuleFileUtility::InitCompressedReading(InStream& in,
+ const uint32_t start,
+ const uint32_t stop) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::InitCompressedReading(in= " << &in
+ << ", start= " << start << ", stop= " << stop << ")";
+
+#if defined(WEBRTC_CODEC_ILBC)
+ int16_t read_len = 0;
+#endif
+ _codecId = kCodecNoCodec;
+ _playoutPositionMs = 0;
+ _reading = false;
+
+ _startPointInMs = start;
+ _stopPointInMs = stop;
+
+ // Read the codec name
+ int32_t cnt = 0;
+ char buf[64];
+ do {
+ in.Read(&buf[cnt++], 1);
+ } while ((buf[cnt - 1] != '\n') && (64 > cnt));
+
+ if (cnt == 64) {
+ return -1;
+ }
+ buf[cnt] = 0;
+
+#ifdef WEBRTC_CODEC_ILBC
+ if (!strcmp("#!iLBC20\n", buf)) {
+ codec_info_.pltype = 102;
+ strcpy(codec_info_.plname, "ilbc");
+ codec_info_.plfreq = 8000;
+ codec_info_.pacsize = 160;
+ codec_info_.channels = 1;
+ codec_info_.rate = 13300;
+ _codecId = kCodecIlbc20Ms;
+
+ if (_startPointInMs > 0) {
+ while (_playoutPositionMs <= _startPointInMs) {
+ read_len = in.Read(buf, 38);
+ if (read_len != 38) {
+ return -1;
+ }
+ _playoutPositionMs += 20;
+ }
+ }
+ }
+
+ if (!strcmp("#!iLBC30\n", buf)) {
+ codec_info_.pltype = 102;
+ strcpy(codec_info_.plname, "ilbc");
+ codec_info_.plfreq = 8000;
+ codec_info_.pacsize = 240;
+ codec_info_.channels = 1;
+ codec_info_.rate = 13300;
+ _codecId = kCodecIlbc30Ms;
+
+ if (_startPointInMs > 0) {
+ while (_playoutPositionMs <= _startPointInMs) {
+ read_len = in.Read(buf, 50);
+ if (read_len != 50) {
+ return -1;
+ }
+ _playoutPositionMs += 20;
+ }
+ }
+ }
+#endif
+ if (_codecId == kCodecNoCodec) {
+ return -1;
+ }
+ _reading = true;
+ return 0;
+}
+
+int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
+ int8_t* outData,
+ size_t bufferSize) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::ReadCompressedData(in=" << &in
+ << ", outData=" << static_cast<void*>(outData)
+ << ", bytes=" << bufferSize << ")";
+
+ int bytesRead = 0;
+
+ if (!_reading) {
+ RTC_LOG(LS_ERROR) << "not currently reading!";
+ return -1;
+ }
+
+#ifdef WEBRTC_CODEC_ILBC
+ if ((_codecId == kCodecIlbc20Ms) || (_codecId == kCodecIlbc30Ms)) {
+ size_t byteSize = 0;
+ if (_codecId == kCodecIlbc30Ms) {
+ byteSize = 50;
+ }
+ if (_codecId == kCodecIlbc20Ms) {
+ byteSize = 38;
+ }
+ if (bufferSize < byteSize) {
+ RTC_LOG(LS_ERROR)
+ << "output buffer is too short to read ILBC compressed data.";
+ assert(false);
+ return -1;
+ }
+
+ bytesRead = in.Read(outData, byteSize);
+ if (bytesRead != static_cast<int>(byteSize)) {
+ if (!in.Rewind()) {
+ InitCompressedReading(in, _startPointInMs, _stopPointInMs);
+ bytesRead = in.Read(outData, byteSize);
+ if (bytesRead != static_cast<int>(byteSize)) {
+ _reading = false;
+ return -1;
+ }
+ } else {
+ _reading = false;
+ return -1;
+ }
+ }
+ }
+#endif
+ if (bytesRead == 0) {
+ RTC_LOG(LS_ERROR)
+ << "ReadCompressedData() no bytes read, codec not supported";
+ return -1;
+ }
+
+ _playoutPositionMs += 20;
+ if ((_stopPointInMs > 0) && (_playoutPositionMs >= _stopPointInMs)) {
+ if (!in.Rewind()) {
+ InitCompressedReading(in, _startPointInMs, _stopPointInMs);
+ } else {
+ _reading = false;
+ }
+ }
+ return bytesRead;
+}
+
+int32_t ModuleFileUtility::InitCompressedWriting(OutStream& out,
+ const CodecInst& codecInst) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::InitCompressedWriting(out= "
+ << &out << ", codecName= " << codecInst.plname << ")";
+
+ _writing = false;
+
+#ifdef WEBRTC_CODEC_ILBC
+ if (STR_CASE_CMP(codecInst.plname, "ilbc") == 0) {
+ if (codecInst.pacsize == 160) {
+ _codecId = kCodecIlbc20Ms;
+ out.Write("#!iLBC20\n", 9);
+ } else if (codecInst.pacsize == 240) {
+ _codecId = kCodecIlbc30Ms;
+ out.Write("#!iLBC30\n", 9);
+ } else {
+ RTC_LOG(LS_ERROR) << "codecInst defines unsupported compression codec!";
+ return -1;
+ }
+ memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
+ _writing = true;
+ return 0;
+ }
+#endif
+
+ RTC_LOG(LS_ERROR) << "codecInst defines unsupported compression codec!";
+ return -1;
+}
+
+int32_t ModuleFileUtility::WriteCompressedData(OutStream& out,
+ const int8_t* buffer,
+ const size_t dataLength) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::WriteCompressedData(out= " << &out
+ << ", buf= " << static_cast<const void*>(buffer)
+ << ", dataLen= " << dataLength << ")";
+
+ if (buffer == NULL) {
+ RTC_LOG(LS_ERROR) << "buffer NULL";
+ }
+
+ if (!out.Write(buffer, dataLength)) {
+ return -1;
+ }
+ return static_cast<int32_t>(dataLength);
+}
+
+int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
+ const uint32_t start,
+ const uint32_t stop,
+ uint32_t freq) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::InitPCMReading(pcm= " << &pcm
+ << ", start=" << start << ", stop=" << stop
+ << ", freq=" << freq << ")";
+
+ int8_t dummy[320];
+ int read_len;
+
+ _playoutPositionMs = 0;
+ _startPointInMs = start;
+ _stopPointInMs = stop;
+ _reading = false;
+
+ if (freq == 8000) {
+ strcpy(codec_info_.plname, "L16");
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = 8000;
+ codec_info_.pacsize = 160;
+ codec_info_.channels = 1;
+ codec_info_.rate = 128000;
+ _codecId = kCodecL16_8Khz;
+ } else if (freq == 16000) {
+ strcpy(codec_info_.plname, "L16");
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = 16000;
+ codec_info_.pacsize = 320;
+ codec_info_.channels = 1;
+ codec_info_.rate = 256000;
+ _codecId = kCodecL16_16kHz;
+ } else if (freq == 32000) {
+ strcpy(codec_info_.plname, "L16");
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = 32000;
+ codec_info_.pacsize = 320;
+ codec_info_.channels = 1;
+ codec_info_.rate = 512000;
+ _codecId = kCodecL16_32Khz;
+ } else if (freq == 48000) {
+ strcpy(codec_info_.plname, "L16");
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = 48000;
+ codec_info_.pacsize = 480;
+ codec_info_.channels = 1;
+ codec_info_.rate = 768000;
+ _codecId = kCodecL16_48Khz;
+ }
+
+ // Readsize for 10ms of audio data (2 bytes per sample).
+ _readSizeBytes = 2 * codec_info_.plfreq / 100;
+ if (_startPointInMs > 0) {
+ while (_playoutPositionMs < _startPointInMs) {
+ read_len = pcm.Read(dummy, _readSizeBytes);
+ if (read_len != static_cast<int>(_readSizeBytes)) {
+ return -1; // Must have reached EOF before start position!
+ }
+ _playoutPositionMs += 10;
+ }
+ }
+ _reading = true;
+ return 0;
+}
+
+int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
+ int8_t* outData,
+ size_t bufferSize) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::ReadPCMData(pcm= " << &pcm
+ << ", outData= " << static_cast<void*>(outData)
+ << ", bufSize= " << bufferSize << ")";
+
+ if (outData == NULL) {
+ RTC_LOG(LS_ERROR) << "buffer NULL";
+ }
+
+ // Readsize for 10ms of audio data (2 bytes per sample).
+ size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
+ if (bufferSize < bytesRequested) {
+ RTC_LOG(LS_ERROR)
+ << "ReadPCMData: buffer not long enough for a 10ms frame.";
+ assert(false);
+ return -1;
+ }
+
+ int bytesRead = pcm.Read(outData, bytesRequested);
+ if (bytesRead < static_cast<int>(bytesRequested)) {
+ if (pcm.Rewind() == -1) {
+ _reading = false;
+ } else {
+ if (InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
+ codec_info_.plfreq) == -1) {
+ _reading = false;
+ } else {
+ size_t rest = bytesRequested - bytesRead;
+ int len = pcm.Read(&(outData[bytesRead]), rest);
+ if (len == static_cast<int>(rest)) {
+ bytesRead += len;
+ } else {
+ _reading = false;
+ }
+ }
+ if (bytesRead <= 0) {
+ RTC_LOG(LS_ERROR) << "ReadPCMData: Failed to rewind audio file.";
+ return -1;
+ }
+ }
+ }
+
+ if (bytesRead <= 0) {
+ RTC_LOG(LS_VERBOSE) << "ReadPCMData: end of file";
+ return -1;
+ }
+ _playoutPositionMs += 10;
+ if (_stopPointInMs && _playoutPositionMs >= _stopPointInMs) {
+ if (!pcm.Rewind()) {
+ if (InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
+ codec_info_.plfreq) == -1) {
+ _reading = false;
+ }
+ }
+ }
+ return bytesRead;
+}
+
+int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq) {
+ if (freq == 8000) {
+ strcpy(codec_info_.plname, "L16");
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = 8000;
+ codec_info_.pacsize = 160;
+ codec_info_.channels = 1;
+ codec_info_.rate = 128000;
+
+ _codecId = kCodecL16_8Khz;
+ } else if (freq == 16000) {
+ strcpy(codec_info_.plname, "L16");
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = 16000;
+ codec_info_.pacsize = 320;
+ codec_info_.channels = 1;
+ codec_info_.rate = 256000;
+
+ _codecId = kCodecL16_16kHz;
+ } else if (freq == 32000) {
+ strcpy(codec_info_.plname, "L16");
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = 32000;
+ codec_info_.pacsize = 320;
+ codec_info_.channels = 1;
+ codec_info_.rate = 512000;
+
+ _codecId = kCodecL16_32Khz;
+ } else if (freq == 48000) {
+ strcpy(codec_info_.plname, "L16");
+ codec_info_.pltype = -1;
+ codec_info_.plfreq = 48000;
+ codec_info_.pacsize = 480;
+ codec_info_.channels = 1;
+ codec_info_.rate = 768000;
+
+ _codecId = kCodecL16_48Khz;
+ }
+ if ((_codecId != kCodecL16_8Khz) && (_codecId != kCodecL16_16kHz) &&
+ (_codecId != kCodecL16_32Khz) && (_codecId != kCodecL16_48Khz)) {
+ RTC_LOG(LS_ERROR) << "CodecInst is not 8KHz, 16KHz, 32kHz or 48kHz PCM!";
+ return -1;
+ }
+ _writing = true;
+ _bytesWritten = 0;
+ return 0;
+}
+
+int32_t ModuleFileUtility::WritePCMData(OutStream& out,
+ const int8_t* buffer,
+ const size_t dataLength) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::WritePCMData(out= " << &out
+ << ", buf= " << static_cast<const void*>(buffer)
+ << ", dataLen= " << dataLength << ")";
+
+ if (buffer == NULL) {
+ RTC_LOG(LS_ERROR) << "buffer NULL";
+ }
+
+ if (!out.Write(buffer, dataLength)) {
+ return -1;
+ }
+
+ _bytesWritten += dataLength;
+ return static_cast<int32_t>(dataLength);
+}
+
+int32_t ModuleFileUtility::codec_info(CodecInst& codecInst) {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::codec_info(codecInst= "
+ << &codecInst << ")";
+
+ if (!_reading && !_writing) {
+ RTC_LOG(LS_ERROR) << "CodecInst: not currently reading audio file!";
+ return -1;
+ }
+ memcpy(&codecInst, &codec_info_, sizeof(CodecInst));
+ return 0;
+}
+
+int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst) {
+ _codecId = kCodecNoCodec;
+ if (STR_CASE_CMP(codecInst.plname, "PCMU") == 0) {
+ _codecId = kCodecPcmu;
+ } else if (STR_CASE_CMP(codecInst.plname, "PCMA") == 0) {
+ _codecId = kCodecPcma;
+ } else if (STR_CASE_CMP(codecInst.plname, "L16") == 0) {
+ if (codecInst.plfreq == 8000) {
+ _codecId = kCodecL16_8Khz;
+ } else if (codecInst.plfreq == 16000) {
+ _codecId = kCodecL16_16kHz;
+ } else if (codecInst.plfreq == 32000) {
+ _codecId = kCodecL16_32Khz;
+ } else if (codecInst.plfreq == 48000) {
+ _codecId = kCodecL16_48Khz;
+ }
+ }
+#ifdef WEBRTC_CODEC_ILBC
+ else if (STR_CASE_CMP(codecInst.plname, "ilbc") == 0) {
+ if (codecInst.pacsize == 160) {
+ _codecId = kCodecIlbc20Ms;
+ } else if (codecInst.pacsize == 240) {
+ _codecId = kCodecIlbc30Ms;
+ }
+ }
+#endif
+#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
+ else if (STR_CASE_CMP(codecInst.plname, "isac") == 0) {
+ if (codecInst.plfreq == 16000) {
+ _codecId = kCodecIsac;
+ } else if (codecInst.plfreq == 32000) {
+ _codecId = kCodecIsacSwb;
+ }
+ }
+#endif
+ else if (STR_CASE_CMP(codecInst.plname, "G722") == 0) {
+ _codecId = kCodecG722;
+ }
+ if (_codecId == kCodecNoCodec) {
+ return -1;
+ }
+ memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
+ return 0;
+}
+
+int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
+ const FileFormats fileFormat,
+ const uint32_t freqInHz) {
+ if (fileName == NULL) {
+ RTC_LOG(LS_ERROR) << "filename NULL";
+ return -1;
+ }
+
+ int32_t time_in_ms = -1;
+ struct stat file_size;
+ if (stat(fileName, &file_size) == -1) {
+ RTC_LOG(LS_ERROR) << "failed to retrieve file size with stat!";
+ return -1;
+ }
+ FileWrapper* inStreamObj = FileWrapper::Create();
+ if (inStreamObj == NULL) {
+ RTC_LOG(LS_INFO) << "failed to create InStream object!";
+ return -1;
+ }
+ if (!inStreamObj->OpenFile(fileName, true)) {
+ delete inStreamObj;
+ RTC_LOG(LS_ERROR) << "failed to open file " << fileName << "!";
+ return -1;
+ }
+
+ switch (fileFormat) {
+ case kFileFormatWavFile: {
+ if (ReadWavHeader(*inStreamObj) == -1) {
+ RTC_LOG(LS_ERROR) << "failed to read WAV file header!";
+ return -1;
+ }
+ time_in_ms =
+ ((file_size.st_size - 44) / (_wavFormatObj.nAvgBytesPerSec / 1000));
+ break;
+ }
+ case kFileFormatPcm16kHzFile: {
+ // 16 samples per ms. 2 bytes per sample.
+ int32_t denominator = 16 * 2;
+ time_in_ms = (file_size.st_size) / denominator;
+ break;
+ }
+ case kFileFormatPcm8kHzFile: {
+ // 8 samples per ms. 2 bytes per sample.
+ int32_t denominator = 8 * 2;
+ time_in_ms = (file_size.st_size) / denominator;
+ break;
+ }
+ case kFileFormatCompressedFile: {
+ int32_t cnt = 0;
+ int read_len = 0;
+ char buf[64];
+ do {
+ read_len = inStreamObj->Read(&buf[cnt++], 1);
+ if (read_len != 1) {
+ return -1;
+ }
+ } while ((buf[cnt - 1] != '\n') && (64 > cnt));
+
+ if (cnt == 64) {
+ return -1;
+ } else {
+ buf[cnt] = 0;
+ }
+#ifdef WEBRTC_CODEC_ILBC
+ if (!strcmp("#!iLBC20\n", buf)) {
+ // 20 ms is 304 bits
+ time_in_ms = ((file_size.st_size) * 160) / 304;
+ break;
+ }
+ if (!strcmp("#!iLBC30\n", buf)) {
+ // 30 ms takes 400 bits.
+ // file size in bytes * 8 / 400 is the number of
+ // 30 ms frames in the file ->
+ // time_in_ms = file size * 8 / 400 * 30
+ time_in_ms = ((file_size.st_size) * 240) / 400;
+ break;
+ }
+#endif
+ break;
+ }
+ case kFileFormatPreencodedFile: {
+ RTC_LOG(LS_ERROR) << "cannot determine duration of Pre-Encoded file!";
+ break;
+ }
+ default:
+ RTC_LOG(LS_ERROR) << "unsupported file format " << fileFormat << "!";
+ break;
+ }
+ inStreamObj->CloseFile();
+ delete inStreamObj;
+ return time_in_ms;
+}
+
+uint32_t ModuleFileUtility::PlayoutPositionMs() {
+ RTC_LOG(LS_VERBOSE) << "ModuleFileUtility::PlayoutPosition()";
+
+ return _reading ? _playoutPositionMs : 0;
+}
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.h b/third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.h
new file mode 100644
index 0000000000..94785be64c
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/media_file/media_file_utility.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// Note: the class cannot be used for reading and writing at the same time.
+#ifndef MODULES_MEDIA_FILE_MEDIA_FILE_UTILITY_H_
+#define MODULES_MEDIA_FILE_MEDIA_FILE_UTILITY_H_
+
+#include <stdio.h>
+
+#include "common_types.h" // NOLINT(build/include)
+#include "modules/media_file/media_file_defines.h"
+
+namespace webrtc {
+class InStream;
+class OutStream;
+
+class ModuleFileUtility
+{
+public:
+
+ ModuleFileUtility();
+ ~ModuleFileUtility();
+
+ // Prepare for playing audio from stream.
+ // startPointMs and stopPointMs, unless zero, specify what part of the file
+ // should be read. From startPointMs ms to stopPointMs ms.
+ int32_t InitWavReading(InStream& stream,
+ const uint32_t startPointMs = 0,
+ const uint32_t stopPointMs = 0);
+
+ // Put 10-60ms of audio data from stream into the audioBuffer depending on
+ // codec frame size. dataLengthInBytes indicates the size of audioBuffer.
+ // The return value is the number of bytes written to audioBuffer.
+ // Note: This API only play mono audio but can be used on file containing
+ // audio with more channels (in which case the audio will be converted to
+ // mono).
+ int32_t ReadWavDataAsMono(InStream& stream, int8_t* audioBuffer,
+ const size_t dataLengthInBytes);
+
+ // Put 10-60ms, depending on codec frame size, of audio data from file into
+ // audioBufferLeft and audioBufferRight. The buffers contain the left and
+ // right channel of played out stereo audio.
+ // dataLengthInBytes indicates the size of both audioBufferLeft and
+ // audioBufferRight.
+ // The return value is the number of bytes read for each buffer.
+ // Note: This API can only be successfully called for WAV files with stereo
+ // audio.
+ int32_t ReadWavDataAsStereo(InStream& wav,
+ int8_t* audioBufferLeft,
+ int8_t* audioBufferRight,
+ const size_t bufferLength);
+
+ // Prepare for recording audio to stream.
+ // codecInst specifies the encoding of the audio data.
+ // Note: codecInst.channels should be set to 2 for stereo (and 1 for
+ // mono). Stereo is only supported for WAV files.
+ int32_t InitWavWriting(OutStream& stream, const CodecInst& codecInst);
+
+ // Write one audio frame, i.e. the bufferLength first bytes of audioBuffer,
+ // to file. The audio frame size is determined by the codecInst.pacsize
+ // parameter of the last sucessfull StartRecordingAudioFile(..) call.
+ // The return value is the number of bytes written to audioBuffer.
+ int32_t WriteWavData(OutStream& stream,
+ const int8_t* audioBuffer,
+ const size_t bufferLength);
+
+ // Finalizes the WAV header so that it is correct if nothing more will be
+ // written to stream.
+ // Note: this API must be called before closing stream to ensure that the
+ // WAVE header is updated with the file size. Don't call this API
+ // if more samples are to be written to stream.
+ int32_t UpdateWavHeader(OutStream& stream);
+
+ // Prepare for playing audio from stream.
+ // startPointMs and stopPointMs, unless zero, specify what part of the file
+ // should be read. From startPointMs ms to stopPointMs ms.
+ // freqInHz is the PCM sampling frequency.
+ // NOTE, allowed frequencies are 8000, 16000 and 32000 (Hz)
+ int32_t InitPCMReading(InStream& stream,
+ const uint32_t startPointMs = 0,
+ const uint32_t stopPointMs = 0,
+ const uint32_t freqInHz = 16000);
+
+ // Put 10-60ms of audio data from stream into the audioBuffer depending on
+ // codec frame size. dataLengthInBytes indicates the size of audioBuffer.
+ // The return value is the number of bytes written to audioBuffer.
+ int32_t ReadPCMData(InStream& stream, int8_t* audioBuffer,
+ const size_t dataLengthInBytes);
+
+ // Prepare for recording audio to stream.
+ // freqInHz is the PCM sampling frequency.
+ // NOTE, allowed frequencies are 8000, 16000 and 32000 (Hz)
+ int32_t InitPCMWriting(OutStream& stream, const uint32_t freqInHz = 16000);
+
+ // Write one 10ms audio frame, i.e. the bufferLength first bytes of
+ // audioBuffer, to file. The audio frame size is determined by the freqInHz
+ // parameter of the last sucessfull InitPCMWriting(..) call.
+ // The return value is the number of bytes written to audioBuffer.
+ int32_t WritePCMData(OutStream& stream,
+ const int8_t* audioBuffer,
+ size_t bufferLength);
+
+ // Prepare for playing audio from stream.
+ // startPointMs and stopPointMs, unless zero, specify what part of the file
+ // should be read. From startPointMs ms to stopPointMs ms.
+ int32_t InitCompressedReading(InStream& stream,
+ const uint32_t startPointMs = 0,
+ const uint32_t stopPointMs = 0);
+
+ // Put 10-60ms of audio data from stream into the audioBuffer depending on
+ // codec frame size. dataLengthInBytes indicates the size of audioBuffer.
+ // The return value is the number of bytes written to audioBuffer.
+ int32_t ReadCompressedData(InStream& stream,
+ int8_t* audioBuffer,
+ const size_t dataLengthInBytes);
+
+ // Prepare for recording audio to stream.
+ // codecInst specifies the encoding of the audio data.
+ int32_t InitCompressedWriting(OutStream& stream,
+ const CodecInst& codecInst);
+
+ // Write one audio frame, i.e. the bufferLength first bytes of audioBuffer,
+ // to file. The audio frame size is determined by the codecInst.pacsize
+ // parameter of the last sucessfull InitCompressedWriting(..) call.
+ // The return value is the number of bytes written to stream.
+ // Note: bufferLength must be exactly one frame.
+ int32_t WriteCompressedData(OutStream& stream,
+ const int8_t* audioBuffer,
+ const size_t bufferLength);
+
+ // Prepare for playing audio from stream.
+ // codecInst specifies the encoding of the audio data.
+ int32_t InitPreEncodedReading(InStream& stream,
+ const CodecInst& codecInst);
+
+ // Put 10-60ms of audio data from stream into the audioBuffer depending on
+ // codec frame size. dataLengthInBytes indicates the size of audioBuffer.
+ // The return value is the number of bytes written to audioBuffer.
+ int32_t ReadPreEncodedData(InStream& stream,
+ int8_t* audioBuffer,
+ const size_t dataLengthInBytes);
+
+ // Prepare for recording audio to stream.
+ // codecInst specifies the encoding of the audio data.
+ int32_t InitPreEncodedWriting(OutStream& stream,
+ const CodecInst& codecInst);
+
+ // Write one audio frame, i.e. the bufferLength first bytes of audioBuffer,
+ // to stream. The audio frame size is determined by the codecInst.pacsize
+ // parameter of the last sucessfull InitPreEncodedWriting(..) call.
+ // The return value is the number of bytes written to stream.
+ // Note: bufferLength must be exactly one frame.
+ int32_t WritePreEncodedData(OutStream& stream,
+ const int8_t* inData,
+ const size_t dataLengthInBytes);
+
+ // Set durationMs to the size of the file (in ms) specified by fileName.
+ // freqInHz specifies the sampling frequency of the file.
+ int32_t FileDurationMs(const char* fileName,
+ const FileFormats fileFormat,
+ const uint32_t freqInHz = 16000);
+
+ // Return the number of ms that have been played so far.
+ uint32_t PlayoutPositionMs();
+
+ // Update codecInst according to the current audio codec being used for
+ // reading or writing.
+ int32_t codec_info(CodecInst& codecInst);
+
+private:
+ // Biggest WAV frame supported is 10 ms at 48kHz of 2 channel, 16 bit audio.
+ static const size_t WAV_MAX_BUFFER_SIZE = 480 * 2 * 2;
+
+
+ int32_t InitWavCodec(uint32_t samplesPerSec,
+ size_t channels,
+ uint32_t bitsPerSample,
+ uint32_t formatTag);
+
+ // Parse the WAV header in stream.
+ int32_t ReadWavHeader(InStream& stream);
+
+ // Update the WAV header. freqInHz, bytesPerSample, channels, format,
+ // lengthInBytes specify characterists of the audio data.
+ // freqInHz is the sampling frequency. bytesPerSample is the sample size in
+ // bytes. channels is the number of channels, e.g. 1 is mono and 2 is
+ // stereo. format is the encode format (e.g. PCMU, PCMA, PCM etc).
+ // lengthInBytes is the number of bytes the audio samples are using up.
+ int32_t WriteWavHeader(OutStream& stream,
+ uint32_t freqInHz,
+ size_t bytesPerSample,
+ size_t channels,
+ uint32_t format,
+ size_t lengthInBytes);
+
+ // Put dataLengthInBytes of audio data from stream into the audioBuffer.
+ // The return value is the number of bytes written to audioBuffer.
+ int32_t ReadWavData(InStream& stream, uint8_t* audioBuffer,
+ size_t dataLengthInBytes);
+
+ // Update the current audio codec being used for reading or writing
+ // according to codecInst.
+ int32_t set_codec_info(const CodecInst& codecInst);
+
+ struct WAVE_FMTINFO_header
+ {
+ int16_t formatTag;
+ int16_t nChannels;
+ int32_t nSamplesPerSec;
+ int32_t nAvgBytesPerSec;
+ int16_t nBlockAlign;
+ int16_t nBitsPerSample;
+ };
+ // Identifiers for preencoded files.
+ enum MediaFileUtility_CodecType
+ {
+ kCodecNoCodec = 0,
+ kCodecIsac,
+ kCodecIsacSwb,
+ kCodecIsacLc,
+ kCodecL16_8Khz,
+ kCodecL16_16kHz,
+ kCodecL16_32Khz,
+ kCodecL16_48Khz,
+ kCodecPcmu,
+ kCodecPcma,
+ kCodecIlbc20Ms,
+ kCodecIlbc30Ms,
+ kCodecG722,
+ kCodecG722_1_32Kbps,
+ kCodecG722_1_24Kbps,
+ kCodecG722_1_16Kbps,
+ kCodecG722_1c_48,
+ kCodecG722_1c_32,
+ kCodecG722_1c_24,
+ kCodecAmr,
+ kCodecAmrWb,
+ kCodecG729,
+ kCodecG729_1,
+ kCodecG726_40,
+ kCodecG726_32,
+ kCodecG726_24,
+ kCodecG726_16
+ };
+
+ // TODO (hellner): why store multiple formats. Just store either codec_info_
+ // or _wavFormatObj and supply conversion functions.
+ WAVE_FMTINFO_header _wavFormatObj;
+ size_t _dataSize; // Chunk size if reading a WAV file
+ // Number of bytes to read. I.e. frame size in bytes. May be multiple
+ // chunks if reading WAV.
+ size_t _readSizeBytes;
+
+ uint32_t _stopPointInMs;
+ uint32_t _startPointInMs;
+ uint32_t _playoutPositionMs;
+ size_t _bytesWritten;
+
+ CodecInst codec_info_;
+ MediaFileUtility_CodecType _codecId;
+
+ // The amount of bytes, on average, used for one audio sample.
+ size_t _bytesPerSample;
+ size_t _readPos;
+
+ // Only reading or writing can be enabled, not both.
+ bool _reading;
+ bool _writing;
+
+ // Scratch buffer used for turning stereo audio to mono.
+ uint8_t _tempData[WAV_MAX_BUFFER_SIZE];
+};
+} // namespace webrtc
+#endif // MODULES_MEDIA_FILE_MEDIA_FILE_UTILITY_H_