Builds Opus as a shared library
(opus.dll + opus.lib import library) on Windows and packages the public
headers + binaries into zip files that
FreeSWITCH's mod_opus (and
mod_opusfile) can link against — replacing the in-tree source build of
opus-1.1 that w32\download_opus.props + libs\win32\opus\*.vcxproj do today.
On Linux, those modules build against the distro's libopus-dev. There is no
equivalent prebuilt package on Windows, so this repo builds one: it clones a
chosen Opus tag, builds it with CMake + MSVC, and ships the result as versioned
zips. Publish them to a GitHub Release (or a CDN) and FreeSWITCH's MSBuild props
fetches them at build time — the same pattern as
libnode-packaging,
ffmpeg-packaging and
libcodec2-packaging.
Default version: v1.6.1 (the current Opus release).
For Opus v1.6.1, building x64 Win32 × Release Debug:
opus-1.6.1-headers.zip opus-1.6.1/include/opus/{opus.h, opus_defines.h,
opus_multistream.h,
opus_projection.h,
opus_types.h, + licenses}
opus-1.6.1-binaries-x64-release.zip opus-1.6.1/binaries/x64/Release/{opus.dll, opus.lib,
opus.pdb, + licenses}
opus-1.6.1-binaries-x64-debug.zip opus-1.6.1/binaries/x64/Debug/...
opus-1.6.1-binaries-win32-release.zip opus-1.6.1/binaries/Win32/Release/...
opus-1.6.1-binaries-win32-debug.zip opus-1.6.1/binaries/Win32/Debug/...
SHA256SUMS.txt
All zips share the opus-<ver>\ root, so they extract over each other into one
tree. Zip filenames are lower-cased (...-win32-release.zip); the paths
inside keep MSBuild's casing (binaries\Win32\Release\...), so the props can
address them with $(Platform) and $(Configuration) directly.
Each archive ships Opus's COPYING (3-clause BSD), LICENSE_PLEASE_READ.txt
(the patent grant notice) and AUTHORS next to its payload rather than at
the package root — a root-level copy would be overwritten as the archives extract
into the same folder.
.github/workflows/build-opus.yml CI: build on a Windows runner, upload zip artifacts
build-opus.ps1 the build + package script (shared by CI and Docker)
Dockerfile Windows-container toolchain image (for local/offline builds)
examples/freeswitch/w32/ reference MSBuild props for wiring up mod_opus
├─ opus.props downloads the zips, links opus.lib, copies opus.dll
└─ opus-version.props single place to set the Opus version
README.md
The Build Opus (Windows) workflow runs on a windows-2022 runner (which
already has Visual Studio 2022, CMake and Git) and runs build-opus.ps1.
- Manually: Actions tab → Build Opus (Windows) → Run workflow, then
enter the Opus tag (e.g.
v1.6.1), configs (Release Debug) and platforms (x64 Win32). - By tag: push a tag like
opus-v1.6.1. The workflow builds it and also attaches the zips to a GitHub Release — which is exactly whereopus.propsexpects to find them.
A full x64 Win32 × Release Debug matrix takes only a few minutes; Opus is a
small C library.
Useful for offline/air-gapped builds or reproducing CI locally. Requires Docker with Windows containers enabled.
# Build the toolchain image once (installs VS Build Tools, Git, CMake). This layer
# is large and slow; subsequent version builds reuse it.
docker build -t opus-packaging .
# Produce zips for an Opus tag (writes to .\artifacts on the host):
docker run --rm --cpus 8 --memory 8g `
-e OPUS_VERSION=v1.6.1 `
-v ${PWD}\artifacts:C:\artifacts `
opus-packagingcmd.exe: replace ${PWD} with %cd%.
Override any parameter with -e, e.g. x64 Release only:
docker run --rm --memory 8g -e OPUS_VERSION=v1.6.1 -e PLATFORMS=x64 -e CONFIGS=Release `
-v ${PWD}\artifacts:C:\artifacts opus-packagingThe host must run a Windows base image of equal-or-older build for process
isolation (the Dockerfile defaults to servercore:ltsc2025); otherwise pass
--build-arg WINDOWS_BASE=...:ltsc2022 or run with --isolation=hyperv.
If you already have Visual Studio 2017+ (C++ workload), CMake ≥ 3.16 and
Git, just run the script directly — it locates VS via vswhere and picks the
matching CMake generator itself:
$env:OPUS_VERSION = 'v1.6.1'
$env:CONFIGS = 'Release Debug'
$env:PLATFORMS = 'x64'
$env:OUT_DIR = "$PWD\artifacts"
.\build-opus.ps1| Var | Default | Notes |
|---|---|---|
OPUS_VERSION |
v1.6.1 |
Any Opus git tag. A bare 1.6.1 is accepted too. |
CONFIGS |
Release Debug |
Space-separated; set to Release to skip the Debug build. |
PLATFORMS |
x64 Win32 |
Space-separated: x64, Win32, ARM64. These are MSBuild $(Platform) names. |
PKG_PREFIX |
opus |
Zip/folder name prefix. |
OUT_DIR |
C:\artifacts |
Where the zips are written (mount this in Docker). |
OPUS_REPO |
https://gitlab.xiph.org/xiph/opus.git |
Override for a fork/mirror (e.g. the GitHub mirror). |
OPUS_BUILD_ROOT |
C:\ob |
Scratch build dir (kept short to dodge MAX_PATH). |
OPUS_CUSTOM_MODES |
OFF |
ON enables Opus custom modes and adds opus_custom.h to the headers zip. |
CMAKE_GENERATOR |
(auto) | Force a CMake generator. Auto-detected from the installed VS otherwise. |
Copy the two files from examples/freeswitch/w32/
into your FreeSWITCH build tree's w32\ directory, then in
src\mod\codecs\mod_opus\mod_opus.2017.vcxproj:
-
Import the props in each configuration's
PropertySheetsgroup (next tomodule_release.props/module_debug.props):<Import Project="..\..\..\..\w32\opus.props" />
-
Drop the four in-tree Opus
ProjectReferenceentries —opus.2017.vcxproj,opus.celt.2017.vcxproj,opus.silk_common.2017.vcxproj,opus.silk_float.2017.vcxproj. The props links the prebuiltopus.libinstead. Keep theFreeSwitchCore.2017.vcxprojreference. -
Drop the four
..\..\..\..\libs\opus-1.1\includeentries fromAdditionalIncludeDirectories; the props supplies the include paths.
Set the target version in opus-version.props, and if you publish the zips
somewhere other than this repo's GitHub Releases, edit $(opusPkgBase) in
opus.props. w32\download_opus.props and libs\win32\opus\ are then unused by
mod_opus and can go.
The props handles the three consumer-side requirements automatically:
- Downloads and extracts the headers + the matching
$(Platform)/$(Configuration)binaries intolibs\opus-<ver>\. - Adds both
includeandinclude\opusto the include path, so#include "opus.h"(whatmod_opususes) and#include <opus/opus.h>both resolve. - Links
opus.liband copiesopus.dllnext to the FreeSWITCH binary.
build-opus.ps1:
git clone --depth 1 --branch <tag>the Opus source into a short scratch dir.- Per platform × configuration, configures with CMake (Visual Studio generator,
-A <Platform>) usingOPUS_BUILD_SHARED_LIBRARY=ON— which is what definesDLL_EXPORTand so puts__declspec(dllexport)on Opus'sOPUS_EXPORTpublic API — thencmake --buildandcmake --install. - Packages
bin\opus.dll+lib\opus.libfrom the install tree andopus.pdbfrom the build tree into the per-config binaries zip; packagesinclude\opus\*.hinto the headers zip; drops Opus's licences next to each payload; writesSHA256SUMS.txt.
Everything goes through cmake --install rather than being picked out of the
build tree, so the layout is the same no matter which generator ran.
- Shared library, not static. FreeSWITCH currently links Opus statically
from
libs\win32\opus\; this package is a DLL, soopus.dllmust ship alongsideFreeSwitch.exe(the props copies it, exactly as the libnode and FFmpeg props do for theirs). To build static instead, flipOPUS_BUILD_SHARED_LIBRARYtoOFFinbuild-opus.ps1— but then drop theopusCopyTargetfrom the props, since there is no DLL to copy. - MSVC runtime. Built with the dynamic CRT (
/MD,/MDdfor Debug) —OPUS_STATIC_RUNTIME=OFF— which is what FreeSWITCH uses. A consumer built against a different CRT will crash on the first allocation crossing the DLL boundary. - Release PDBs. CMake's MSVC Release flags omit
/Zi, so upstream ships no Release PDB. The script adds/Ziplus/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NOso release crash dumps stay symbolizable without changing the generated code. opus_get_version_string(). Opus derives its own version fromgit describe, which resolves fine for the tagged shallow clone this script makes. The script passes-DOPUS_PACKAGE_VERSION=<ver>anyway to pin it for the cases wheredescribeyields nothing — a source tarball, a mirror without tags, or a build tree detached from its.git— where the library would reportlibopus 0.- One benign build warning.
cl : command line warning D9002: ignoring unknown option '-msse4.1'comes from Opus's own CMake handing MSVC a GCC-style flag. MSVC needs no switch to compile SSE4.1 intrinsics, so the vectorized paths are still built: the configure summary listsOPUS_X86_MAY_HAVE_SSE,SSE2,SSE4_1andAVX2as enabled, and Opus dispatches between them at run time. - DRED / OSCE / deep PLC are off. Those Opus 1.5+ features need the neural
network model blobs (
download_model.sh), which the CMake build does not fetch. Enabling them would mean vendoring or downloading the model data as well. - Custom modes are off (
OPUS_CUSTOM_MODES=OFF), matching the in-tree FreeSWITCH build.mod_opusdoes not use them; setOPUS_CUSTOM_MODES=ONif some other consumer needsopus_custom.h. - 32-bit is supported here. Unlike
libnode-packaging, Opus builds fine forWin32, so both platforms are produced by default. - No pkg-config or CMake package files. They bake in absolute install
prefixes that this repo's zip layout invalidates, so
OPUS_INSTALL_PKG_CONFIG_MODULEandOPUS_INSTALL_CMAKE_CONFIG_MODULEare bothOFF. - Refreshing a dev checkout. The props re-copies
opus.dllwhenever it differs (SkipUnchangedFiles), but the download is skipped wheneverlibs\opus-<ver>\...already exists. After republishing a package for the same version, delete the extractedlibs\opus-<ver>\so it gets fetched again.