Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ updates:
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
- "github-actions"
open-pull-requests-limit: 10
4 changes: 2 additions & 2 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ categories:
version-resolver:
major:
labels:
- "major"
- "force-major"
- "breaking-change"
minor:
labels:
- "minor"
- "force-minor"
- "new-feature"
patch:
labels:
Expand Down
70 changes: 68 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,70 @@ jobs:
CLANG_TIDY: clang-tidy-18
run: ./script/clang-tidy.sh

include-check:
name: Include check
if: github.event.action != 'labeled'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: false

- name: Initialize library submodules
run: git submodule update --init --depth 1 lib/opus lib/micro-ogg-demuxer

- name: Install clang-include-cleaner
run: |
sudo apt-get update
sudo apt-get install -y clang-tools-18

- name: Run include check
env:
CLANG_INCLUDE_CLEANER: clang-include-cleaner-18
run: ./script/check-includes.sh

cppcheck:
name: Cppcheck
if: github.event.action != 'labeled'
runs-on: ubuntu-latest
timeout-minutes: 15
env:
# Pin cppcheck and build it from source: ubuntu-latest's apt package lags
# by several minor versions and produces different findings than the
# version developers run locally (Homebrew). Bump deliberately, in step
# with local installs. The build is cached, so only the first run per
# version pays the compile.
CPPCHECK_VERSION: "2.21.0"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: false

- name: Initialize library submodules
run: git submodule update --init --depth 1 lib/opus lib/micro-ogg-demuxer

- name: Cache pinned cppcheck
id: cache-cppcheck
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/cppcheck-install
key: cppcheck-${{ env.CPPCHECK_VERSION }}-${{ runner.os }}

- name: Build pinned cppcheck
if: steps.cache-cppcheck.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch "$CPPCHECK_VERSION" https://github.com/danmar/cppcheck /tmp/cppcheck
cmake -S /tmp/cppcheck -B /tmp/cppcheck/build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$HOME/cppcheck-install"
cmake --build /tmp/cppcheck/build -j"$(nproc)"
cmake --install /tmp/cppcheck/build

- name: Add pinned cppcheck to PATH
run: echo "$HOME/cppcheck-install/bin" >> "$GITHUB_PATH"

- name: Run cppcheck
run: ./script/cppcheck.sh

build:
name: Build
if: github.event.action != 'labeled'
Expand Down Expand Up @@ -133,7 +197,7 @@ jobs:

- name: Configure CMake with sanitizers
run: >
cmake -B build -DENABLE_SANITIZERS=ON
cmake -B build -DENABLE_SANITIZERS=ON -DENABLE_WERROR=ON
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
-DOPUS_ALLOCATION_MODE=${{ matrix.alloc_mode }} tests

Expand Down Expand Up @@ -339,7 +403,7 @@ jobs:
path: |
~/.platformio
examples/${{ matrix.example }}/.pio
key: pio-${{ matrix.example }}-${{ hashFiles('examples/${{ matrix.example }}/platformio.ini') }}
key: pio-${{ matrix.example }}-${{ hashFiles(format('examples/{0}/platformio.ini', matrix.example)) }}
restore-keys: |
pio-${{ matrix.example }}-

Expand All @@ -358,6 +422,8 @@ jobs:
needs:
- pre-commit
- lint
- include-check
- cppcheck
- build
- test
- conformance
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
verify-version:
name: Verify version matches tag
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Check library.json and idf_component.yml against the release tag
Expand All @@ -31,6 +32,9 @@ jobs:
ci-gate:
name: CI gate
runs-on: ubuntu-latest
timeout-minutes: 5
# Reads check-run conclusions via the API; no checkout, so contents is not
# needed, but checks:read is.
permissions:
checks: read
steps:
Expand All @@ -57,8 +61,9 @@ jobs:

publish-platformio:
name: Publish to PlatformIO
needs: [verify-version, ci-gate]
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [verify-version, ci-gate]
environment: platformio
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -79,12 +84,14 @@ jobs:

publish-espressif:
name: Publish to Espressif
needs: [verify-version, ci-gate]
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [verify-version, ci-gate]
environment: espressif
permissions:
contents: read
id-token: write
# Job-level permissions replace the workflow default, so re-grant the read checkout needs.
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand Down
18 changes: 13 additions & 5 deletions .github/workflows/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,32 @@ on:
branches:
- main

permissions:
contents: write
pull-requests: read
# Release automation routes every repo operation (release-drafter, checkout, and the version-bump
# push) through the GitHub App token generated below, so the default GITHUB_TOKEN is unused here.
# Grant it no permissions at all. GitHub always mints the token; the empty set just strips its powers.
permissions: {}

jobs:
release-drafter:
name: Release Drafter
environment: release-drafter
runs-on: ubuntu-latest
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}

- uses: release-drafter/release-drafter@34d80673e067bdc0c24568d3af899c216adcfaa9 # v7.7.0
id: drafter
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ssh-key: ${{ secrets.DEPLOY_KEY }}
token: ${{ steps.generate-token.outputs.token }}

- name: Update version files
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ build/
.libs/
.deps/

# Local marker recording which internal conventions version is used for this project.
.conventions-version

# ESP-IDF specific
sdkconfig
sdkconfig.old
Expand Down
27 changes: 23 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,26 @@ if(ESP_IDF_BUILD)
# Apply ESP-IDF configuration
opus_configure_esp_idf(${COMPONENT_LIB} ${COMPONENT_DIR} ${OPUS_STAGED_DIR})

# Strict warnings for our own wrapper sources on the ESP-IDF build too - this is the build that
# ships to hardware and the only place ESP-only code paths (#ifdef ESP_PLATFORM branches, Xtensa
# sources) ever compile, so local warnings are most useful here. Scoped per-source to src/ via the
# same helper as the host build; the bundled upstream Opus C (registered in the same component) is
# never put through them. -Werror is gated behind ENABLE_WERROR exactly as on host (default off, so
# a consumer building the component against an arbitrary future IDF toolchain gets warnings only);
# CI's pinned ESP build passes -DENABLE_WERROR=ON, the only place ESP-only wrapper warnings actually
# become errors (the host -Werror build never compiles these branches).
option(ENABLE_WERROR "Treat warnings as errors" OFF)
opus_wrapper_warning_flags(MICRO_OPUS_ESP_WRAPPER_WARNINGS)
if(ENABLE_WERROR)
list(APPEND MICRO_OPUS_ESP_WRAPPER_WARNINGS -Werror)
# These sources build at -O2, where GCC's -Wmaybe-uninitialized is false-positive-prone, so
# keep it non-fatal (a definite -Wuninitialized still errors), matching the host block and
# opus_set_optimization_flags. The ESP toolchain is always GCC, so no compiler guard is needed.
list(APPEND MICRO_OPUS_ESP_WRAPPER_WARNINGS -Wno-error=maybe-uninitialized)
endif()
set_source_files_properties(${OGG_OPUS_SOURCES} PROPERTIES
COMPILE_OPTIONS "${MICRO_OPUS_ESP_WRAPPER_WARNINGS}")

# ==============================================================================
# Host Build
# ==============================================================================
Expand Down Expand Up @@ -148,10 +168,9 @@ else()
# Strict warnings for our own wrapper sources only. The bundled upstream Opus C is not clean
# under this set and is never edited here, so it keeps the relaxed flags from
# opus_set_optimization_flags(); scoping these per-source confines them to src/. ENABLE_WERROR
# makes them fatal in CI. Mirrors the warning set used across the micro-* libraries.
set(MICRO_OPUS_WRAPPER_WARNINGS
-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wsign-conversion -Wdouble-promotion
-Wformat=2 -Wimplicit-fallthrough)
# makes them fatal in CI. Mirrors the warning set used across the micro-* libraries (shared with
# the ESP-IDF build via opus_wrapper_warning_flags()).
opus_wrapper_warning_flags(MICRO_OPUS_WRAPPER_WARNINGS)
if(ENABLE_WERROR)
list(APPEND MICRO_OPUS_WRAPPER_WARNINGS -Werror)
# These sources build at -O2 (above), where GCC's -Wmaybe-uninitialized is
Expand Down
31 changes: 31 additions & 0 deletions cmake/functions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,37 @@ function(opus_set_common_definitions TARGET)
)
endfunction()

# ==============================================================================
# opus_wrapper_warning_flags
# ==============================================================================
# Returns (in OUT_VAR, in the caller's scope) the strict warning set applied to
# our own first-party C++ wrapper sources (src/*.cpp) on BOTH the host and the
# ESP-IDF component build. The bundled upstream Opus C is never put through these
# (it is not clean under them by design), so callers scope the result to the
# wrapper sources via set_source_files_properties().
#
# -Werror is deliberately NOT included here: each caller (host and ESP) appends it
# under the ENABLE_WERROR guard, which defaults off. These sources are
# source-distributed and consumers compile them with arbitrary future toolchains,
# so with the guard off they get warnings only; CI's pinned host and ESP builds
# pass -DENABLE_WERROR=ON, which is where the warnings actually become errors.
#
# Arguments:
# OUT_VAR - Name of the variable to populate in the caller's scope
# ==============================================================================
function(opus_wrapper_warning_flags OUT_VAR)
set(${OUT_VAR}
-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wsign-conversion -Wdouble-promotion
-Wformat=2 -Wimplicit-fallthrough
# Any function not declared in a header must be static, so -Wunused-function can see it go
# dead. Clang and GCC spell the C++ variant differently.
$<$<CXX_COMPILER_ID:Clang,AppleClang>:-Wmissing-prototypes>
$<$<CXX_COMPILER_ID:GNU>:-Wmissing-declarations>
# Require static_cast/reinterpret_cast over C-style casts (the wrapper sources are all C++).
$<$<COMPILE_LANGUAGE:CXX>:-Wold-style-cast>
PARENT_SCOPE)
endfunction()

# ==============================================================================
# opus_set_optimization_flags
# ==============================================================================
Expand Down
5 changes: 5 additions & 0 deletions examples/decode_benchmark/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
framework = espidf
monitor_speed = 115200
; CI builds this example as the pinned ESP-IDF gate for the micro-opus component's first-party
; wrapper warnings: -DENABLE_WERROR=ON turns them into errors here, the only place the ESP-only code
; paths ever compile (the host -Werror build never sees them). Remove this line if you copy the
; example and build against a newer/unpinned toolchain, where a new warning could hard-fail the build.
board_build.cmake_extra_args = -DENABLE_WERROR=ON

[env:esp32-s3]
board = esp32-s3-devkitm-1
Expand Down
2 changes: 1 addition & 1 deletion examples/decode_benchmark/src/decode_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ static void log_decode_result(const char* prefix, DecodeResult* result) {

// FreeRTOS task function for concurrent decoding
static void decode_task(void* params) {
TaskParams* task_params = (TaskParams*)params;
TaskParams* task_params = static_cast<TaskParams*>(params);
const AudioConfig* config = task_params->audio_config;

ESP_LOGI(TAG, "Task %d starting %s decode...", task_params->task_id, config->name);
Expand Down
5 changes: 5 additions & 0 deletions examples/encode_benchmark/platformio.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
[env]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
framework = espidf
; CI builds this example as the pinned ESP-IDF gate for the micro-opus component's first-party
; wrapper warnings: -DENABLE_WERROR=ON turns them into errors here, the only place the ESP-only code
; paths ever compile (the host -Werror build never sees them). Remove this line if you copy the
; example and build against a newer/unpinned toolchain, where a new warning could hard-fail the build.
board_build.cmake_extra_args = -DENABLE_WERROR=ON

[env:esp32-s3]
board = esp32-s3-devkitm-1
Expand Down
2 changes: 1 addition & 1 deletion examples/encode_benchmark/src/encode_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ static void log_stats(const char* prefix, const char* name, const Stats* s) {
// Run a single encoder configuration test
// Decodes the audio packet by packet, encoding each frame and timing only the encode step
static EncodeResult run_encode_test(const AudioConfig* audio, const EncoderConfig* config) {
EncodeResult result;
EncodeResult result = {}; // zero-init so the early error-return path returns defined fields
init_stats(&result.frame_stats);
result.success = true;
result.total_bytes_encoded = 0;
Expand Down
6 changes: 6 additions & 0 deletions host_examples/opus_to_wav/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ target_compile_options(opus_to_wav PRIVATE
-Wdouble-promotion
-Wformat=2
-Wimplicit-fallthrough
# Any function not declared in a header must be static, so -Wunused-function can see it go dead.
# Clang and GCC spell the C++ variant differently.
$<$<CXX_COMPILER_ID:Clang,AppleClang>:-Wmissing-prototypes>
$<$<CXX_COMPILER_ID:GNU>:-Wmissing-declarations>
# Require static_cast/reinterpret_cast over C-style casts (C++ sources only).
$<$<COMPILE_LANGUAGE:CXX>:-Wold-style-cast>
$<$<BOOL:${ENABLE_WERROR}>:-Werror>
# GCC's -Wmaybe-uninitialized is false-positive-prone under optimization; keep it non-fatal
# under GCC (matching the wrapper sources). Clang lacks the warning and would reject the flag.
Expand Down
5 changes: 3 additions & 2 deletions host_examples/opus_to_wav/opus_to_wav.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@
#include "micro_opus/ogg_opus_decoder.h"
#include "wav_writer.h"

#include <cstdint>
#include <cstring>
#include <exception>
#include <fstream>
#include <iostream>
#include <vector>

void print_usage(const char* program_name) {
static void print_usage(const char* program_name) {
std::cerr << "Usage: " << program_name << " <input.opus> <output.wav>\n";
std::cerr << "\nConverts an Ogg Opus file to WAV format.\n";
}

void print_error_description(micro_opus::OggOpusResult result) {
static void print_error_description(micro_opus::OggOpusResult result) {
switch (result) {
case micro_opus::OGG_OPUS_INPUT_INVALID:
std::cerr << " (OGG_OPUS_INPUT_INVALID - Invalid Ogg/Opus stream)";
Expand Down
Loading
Loading