From 9887bf14ee751a2d3299bd066567e901d45fd248 Mon Sep 17 00:00:00 2001
From: Marcus Llewellyn <marcus.llewellyn@gmail.com>
Date: Sat, 21 Dec 2019 09:30:16 -0600
Subject: [PATCH] Initial work on Opus audio plugin

This commit is made up of changes to VCPKG and CMake to include the Opus libraries, as well as a skeleton project for an Opus audio plugin.
---
 cmake/macros/TargetOpus.cmake               | 18 ++++++
 cmake/ports/hifi-deps/CONTROL               |  4 +-
 cmake/ports/opus/CONTROL                    |  4 ++
 cmake/ports/opus/portfile.cmake             | 28 +++++++++
 plugins/CMakeLists.txt                      |  2 +
 plugins/opusCodec/CMakeLists.txt            | 15 +++++
 plugins/opusCodec/src/OpusCodecManager.cpp  | 63 +++++++++++++++++++++
 plugins/opusCodec/src/OpusCodecManager.h    | 54 ++++++++++++++++++
 plugins/opusCodec/src/OpusCodecProvider.cpp | 45 +++++++++++++++
 plugins/opusCodec/src/plugin.json           |  4 ++
 10 files changed, 235 insertions(+), 2 deletions(-)
 create mode 100644 cmake/macros/TargetOpus.cmake
 create mode 100644 cmake/ports/opus/CONTROL
 create mode 100644 cmake/ports/opus/portfile.cmake
 create mode 100644 plugins/opusCodec/CMakeLists.txt
 create mode 100644 plugins/opusCodec/src/OpusCodecManager.cpp
 create mode 100644 plugins/opusCodec/src/OpusCodecManager.h
 create mode 100644 plugins/opusCodec/src/OpusCodecProvider.cpp
 create mode 100644 plugins/opusCodec/src/plugin.json

diff --git a/cmake/macros/TargetOpus.cmake b/cmake/macros/TargetOpus.cmake
new file mode 100644
index 0000000000..20fcadfc57
--- /dev/null
+++ b/cmake/macros/TargetOpus.cmake
@@ -0,0 +1,18 @@
+#
+#  Created by Michael Bailey on 12/20/2019
+#  Copyright 2019 Michael Bailey
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+#
+macro(TARGET_opus)
+    if (ANDROID)
+        # no idea if this is correct
+        target_link_libraries(${TARGET_NAME})
+    else()
+        # using VCPKG for opus
+        find_package(OPUS REQUIRED)
+        target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${OPUS_INCLUDE_DIRS})
+        target_link_libraries(${TARGET_NAME} ${OPUS_LIBRARIES})
+    endif()
+endmacro()
diff --git a/cmake/ports/hifi-deps/CONTROL b/cmake/ports/hifi-deps/CONTROL
index 4cf952ccf0..b1a7f96a00 100644
--- a/cmake/ports/hifi-deps/CONTROL
+++ b/cmake/ports/hifi-deps/CONTROL
@@ -1,4 +1,4 @@
 Source: hifi-deps
-Version: 0.3
+Version: 0.4
 Description: Collected dependencies for High Fidelity applications
-Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), tbb (!android&!osx), zlib, webrtc (!android)
+Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), opus, tbb (!android&!osx), zlib, webrtc (!android)
diff --git a/cmake/ports/opus/CONTROL b/cmake/ports/opus/CONTROL
new file mode 100644
index 0000000000..c7b8d246f5
--- /dev/null
+++ b/cmake/ports/opus/CONTROL
@@ -0,0 +1,4 @@
+Source: opus
+Version: 1.3.1
+Homepage: https://github.com/xiph/opus
+Description: Totally open, royalty-free, highly versatile audio codec
diff --git a/cmake/ports/opus/portfile.cmake b/cmake/ports/opus/portfile.cmake
new file mode 100644
index 0000000000..bf23718df8
--- /dev/null
+++ b/cmake/ports/opus/portfile.cmake
@@ -0,0 +1,28 @@
+include(vcpkg_common_functions)
+
+vcpkg_from_github(
+  OUT_SOURCE_PATH
+  SOURCE_PATH
+  REPO
+  xiph/opus
+  REF
+  e85ed7726db5d677c9c0677298ea0cb9c65bdd23
+  SHA512
+  a8c7e5bf383c06f1fdffd44d9b5f658f31eb4800cb59d12da95ddaeb5646f7a7b03025f4663362b888b1374d4cc69154f006ba07b5840ec61ddc1a1af01d6c54
+  HEAD_REF
+  master)
+
+vcpkg_configure_cmake(SOURCE_PATH ${SOURCE_PATH} PREFER_NINJA)
+vcpkg_install_cmake()
+vcpkg_fixup_cmake_targets(CONFIG_PATH lib/cmake/Opus)
+vcpkg_copy_pdbs()
+
+file(INSTALL
+     ${SOURCE_PATH}/COPYING
+     DESTINATION
+     ${CURRENT_PACKAGES_DIR}/share/opus
+     RENAME copyright)
+
+file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/lib/cmake
+                    ${CURRENT_PACKAGES_DIR}/lib/cmake
+                    ${CURRENT_PACKAGES_DIR}/debug/include)
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index c9bc3e4c33..c88bb8a00d 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -43,6 +43,8 @@ set(DIR "pcmCodec")
 add_subdirectory(${DIR})
 set(DIR "hifiCodec")
 add_subdirectory(${DIR})
+set(DIR "opusCodec")
+add_subdirectory(${DIR})
 
 # example plugins
 set(DIR "KasenAPIExample")
diff --git a/plugins/opusCodec/CMakeLists.txt b/plugins/opusCodec/CMakeLists.txt
new file mode 100644
index 0000000000..761e275929
--- /dev/null
+++ b/plugins/opusCodec/CMakeLists.txt
@@ -0,0 +1,15 @@
+#
+#  Created by Michael Bailey on 12/20/2019
+#  Copyright 2019 Michael Bailey
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
+#
+
+set(TARGET_NAME opusCodec)
+setup_hifi_client_server_plugin()
+link_hifi_libraries(shared plugins)
+
+if (BUILD_SERVER)
+  install_beside_console()
+endif ()
diff --git a/plugins/opusCodec/src/OpusCodecManager.cpp b/plugins/opusCodec/src/OpusCodecManager.cpp
new file mode 100644
index 0000000000..3c47ac15fb
--- /dev/null
+++ b/plugins/opusCodec/src/OpusCodecManager.cpp
@@ -0,0 +1,63 @@
+//
+//  opusCodec.cpp
+//  plugins/opusCodec/src
+//
+//  Created by Michael Bailey on 12/20/2019
+//  Copyright 2019 Michael Bailey
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "OpusCodecManager.h"
+
+#include <QtCore/QCoreApplication>
+
+#include <PerfStat.h>
+
+// Not sure how many of these are needed, but here they are.
+#include <opus/opus.h>
+#include <opus/opus_types.h>
+#include <opus/opus_defines.h>
+#include <opus/opus_multistream.h>
+#include <opus/opus_projection.h>
+
+const char* OpusCodec::NAME { "opus" };
+
+void OpusCodec::init() {
+}
+
+void OpusCodec::deinit() {
+}
+
+bool OpusCodec::activate() {
+    CodecPlugin::activate();
+    return true;
+}
+
+void OpusCodec::deactivate() {
+    CodecPlugin::deactivate();
+}
+
+
+bool OpusCodec::isSupported() const {
+    return true;
+}
+
+
+
+Encoder* OpusCodec::createEncoder(int sampleRate, int numChannels) {
+    return this;
+}
+
+Decoder* OpusCodec::createDecoder(int sampleRate, int numChannels) {
+    return this;
+}
+
+void OpusCodec::releaseEncoder(Encoder* encoder) {
+    // do nothing
+}
+
+void OpusCodec::releaseDecoder(Decoder* decoder) {
+    // do nothing
+}
\ No newline at end of file
diff --git a/plugins/opusCodec/src/OpusCodecManager.h b/plugins/opusCodec/src/OpusCodecManager.h
new file mode 100644
index 0000000000..b02a549e8c
--- /dev/null
+++ b/plugins/opusCodec/src/OpusCodecManager.h
@@ -0,0 +1,54 @@
+//
+//  OpusCodecManager.h
+//  plugins/opusCodec/src
+//
+//  Created by Michael Bailey on 12/20/2019
+//  Copyright 2019 Michael Bailey
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi__opusCodecManager_h
+#define hifi__opusCodecManager_h
+
+#include <plugins/CodecPlugin.h>
+
+class OpusCodec : public CodecPlugin, public Encoder, public Decoder {
+    Q_OBJECT
+
+public:
+    // Plugin functions
+    bool isSupported() const override;
+    const QString getName() const override { return NAME; }
+
+    void init() override;
+    void deinit() override;
+
+    /// Called when a plugin is being activated for use.  May be called multiple times.
+    bool activate() override;
+    /// Called when a plugin is no longer being used.  May be called multiple times.
+    void deactivate() override;
+
+    virtual Encoder* createEncoder(int sampleRate, int numChannels) override;
+    virtual Decoder* createDecoder(int sampleRate, int numChannels) override;
+    virtual void releaseEncoder(Encoder* encoder) override;
+    virtual void releaseDecoder(Decoder* decoder) override;
+
+    virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override {
+        encodedBuffer = decodedBuffer;
+    }
+
+    virtual void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) override {
+        decodedBuffer = encodedBuffer;
+    }
+
+    virtual void lostFrame(QByteArray& decodedBuffer) override {
+        memset(decodedBuffer.data(), 0, decodedBuffer.size());
+    }
+
+private:
+    static const char* NAME;
+};
+
+#endif // hifi__opusCodecManager_h
diff --git a/plugins/opusCodec/src/OpusCodecProvider.cpp b/plugins/opusCodec/src/OpusCodecProvider.cpp
new file mode 100644
index 0000000000..ab72f25023
--- /dev/null
+++ b/plugins/opusCodec/src/OpusCodecProvider.cpp
@@ -0,0 +1,45 @@
+//
+//  Created by Michael Bailey on 12/20/2019
+//  Copyright 2019 Michael Bailey
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <mutex>
+
+#include <QtCore/QObject>
+#include <QtCore/QtPlugin>
+#include <QtCore/QStringList>
+
+#include <plugins/RuntimePlugin.h>
+#include <plugins/CodecPlugin.h>
+
+#include "OpusCodecManager.h"
+
+class OpusCodecProvider : public QObject, public CodecProvider {
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID CodecProvider_iid FILE "plugin.json")
+    Q_INTERFACES(CodecProvider)
+
+public:
+    OpusCodecProvider(QObject* parent = nullptr) : QObject(parent) {}
+    virtual ~OpusCodecProvider() {}
+
+    virtual CodecPluginList getCodecPlugins() override {
+        static std::once_flag once;
+        std::call_once(once, [&] {
+
+            CodecPluginPointer opusCodec(new OpusCodec());
+            if (opusCodec->isSupported()) {
+                _codecPlugins.push_back(opusCodec);
+            }
+        });
+        return _codecPlugins;
+    }
+
+private:
+    CodecPluginList _codecPlugins;
+};
+
+#include "OpusCodecProvider.moc"
diff --git a/plugins/opusCodec/src/plugin.json b/plugins/opusCodec/src/plugin.json
new file mode 100644
index 0000000000..bd7c707f7d
--- /dev/null
+++ b/plugins/opusCodec/src/plugin.json
@@ -0,0 +1,4 @@
+{
+    "name":"Opus Codec",
+    "version":1
+}