diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 0000000..b98e106 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,64 @@ +name: Build & Static Checks + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + workflow_dispatch: + +jobs: + analyze: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - name: Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build SDK image (cached) + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile.ci + tags: freeswitch-sdk:ci + load: true + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Run analysis inside container + uses: addnab/docker-run-action@v3 + with: + image: freeswitch-sdk:ci + options: -v ${{ github.workspace }}:/work + run: | + set -eux + cd /work + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_C_COMPILER=clang \ + -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + scan-build --status-bugs cmake --build build -j"$(nproc)" + + clang-tidy -p build $(git ls-files '*.c' '*.cc' '*.cpp' '*.cxx') \ + FILES="$(git ls-files '*.c' '*.cc' '*.cpp' '*.cxx')" + if [ -n "$FILES" ]; then + clang-tidy -p build $FILES \ + --warnings-as-errors='clang-analyzer-*,bugprone-*,performance-*' + else + echo "No source files found for clang-tidy analysis." + fi + + + cppcheck --enable=warning,style,performance,portability --std=c++17 --force \ + --project=build/compile_commands.json \ + --suppress=missingIncludeSystem \ + -i build . 2> cppcheck.log || true + cat cppcheck.log diff --git a/Dockerfile.ci b/Dockerfile.ci new file mode 100644 index 0000000..58c18f4 --- /dev/null +++ b/Dockerfile.ci @@ -0,0 +1,81 @@ +# syntax=docker/dockerfile:1.7 + +############################ +# Stage 1: Build dependencies + FreeSWITCH +############################ +FROM debian:12 AS builder + +ENV DEBIAN_FRONTEND=noninteractive + + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates git curl wget \ + build-essential cmake automake autoconf libtool libtool-bin libltdl-dev pkg-config \ + libssl-dev zlib1g-dev libdb-dev unixodbc-dev libncurses5-dev libexpat1-dev \ + libgdbm-dev bison erlang-dev libtpl-dev libtiff5-dev uuid-dev \ + libpcre3-dev libpcre2-dev libedit-dev libsqlite3-dev libcurl4-openssl-dev nasm \ + libogg-dev libspeex-dev libspeexdsp-dev libldns-dev python3-dev \ + libavformat-dev libswscale-dev libswresample-dev \ + liblua5.2-dev libopus-dev libpq-dev \ + libsndfile1-dev libflac-dev libvorbis-dev \ + && rm -rf /var/lib/apt/lists/* + + +WORKDIR /src + +RUN git clone https://github.com/signalwire/libks && \ + git clone https://github.com/freeswitch/sofia-sip && \ + git clone https://github.com/freeswitch/spandsp && \ + git clone https://github.com/signalwire/signalwire-c && \ + git clone https://github.com/signalwire/freeswitch + +# libks +WORKDIR /src/libks +RUN cmake . -DCMAKE_INSTALL_PREFIX=/usr -DWITH_LIBBACKTRACE=1 && \ + make -j"$(nproc)" && make install + +# sofia-sip +WORKDIR /src/sofia-sip +RUN ./bootstrap.sh && \ + ./configure --with-pic --with-glib=no --without-doxygen --disable-stun --prefix=/usr && \ + make -j"$(nproc)" && make install + +# spandsp +WORKDIR /src/spandsp +RUN ./bootstrap.sh && \ + ./configure --with-pic --prefix=/usr && \ + make -j"$(nproc)" && make install + +# signalwire-c +WORKDIR /src/signalwire-c +RUN PKG_CONFIG_PATH=/usr/lib/pkgconfig cmake . -DCMAKE_INSTALL_PREFIX=/usr && \ + make -j"$(nproc)" && make install + +# FreeSWITCH SDK +WORKDIR /src/freeswitch +RUN ./bootstrap.sh -j && \ + ./configure --prefix=/usr && \ + make -j"$(nproc)" && make install + +############################ +# Stage 2: Slim SDK image (no FreeSWITCH runtime) +############################ +FROM debian:12 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + clang clang-tidy clang-tools \ + cppcheck cmake pkg-config ccache \ + libssl-dev zlib1g-dev \ + libspeexdsp-dev libspandsp-dev \ + git curl wget \ + && rm -rf /var/lib/apt/lists/* + +# Copy only SDK bits +COPY --from=builder /usr/include/freeswitch/ /usr/include/freeswitch/ +COPY --from=builder /usr/lib/pkgconfig/freeswitch.pc /usr/lib/pkgconfig/ +COPY --from=builder /usr/lib/libfreeswitch.so* /usr/lib/ + +WORKDIR /work diff --git a/README.md b/README.md index 9d033f4..9ee293c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ # mod_openai_audio_stream -A fork of [mod_audio_stream](https://github.com/amigniter/mod_audio_stream) specifically designed for streaming audio to OpenAI's realtime API and playing the responses back to the user via FreeSWITCH and WebSocket. -**mod_openai_audio_stream** is a FreeSWITCH module that streams L16 audio from a channel to an OpenAI realtime websocket endpoint. The stream is adherent to OpenAI's Realtime API specification and allows for real-time audio playback directly in the channel. +![Build & Static Code Checks](https://github.com/VoiSmart/mod_openai_audio_stream/actions/workflows/checks.yml/badge.svg) + +**mod_openai_audio_stream** is a FreeSWITCH module that streams L16 audio from a channel to an OpenAI Realtime WebSocket endpoint. The stream follows OpenAI's Realtime API specification and enables real-time audio playback directly in the channel. + +It is a fork of [mod_audio_stream](https://github.com/amigniter/mod_audio_stream), specifically adapted for streaming audio to OpenAI's Realtime API and playing the responses back to the user via FreeSWITCH and WebSocket. + +The goal of **mod_openai_audio_stream** is to provide a simple, lightweight, yet effective module for streaming audio and receiving responses directly from OpenAI’s Realtime WebSocket into the call through FreeSWITCH. It uses [ixwebsocket](https://machinezone.github.io/IXWebSocket/), a C++ WebSocket library compiled as a static library. -The purpose of **mod_openai_audio_stream** was to make a simple, less dependent but yet effective module to stream audio and receive responses directly from OpenAI realtime websocket into the call via switch. It uses [ixwebsocket](https://machinezone.github.io/IXWebSocket/), c++ library for websocket protocol which is compiled as a static library. ## Notes