AES67 Stream Monitor

repository·main·Indexed 43 days ago

https://github.com/philhartung/aes67-monitor

A cross-platform Audio-over-IP monitoring tool for professional audio environments. It allows users to discover, manage, and analyze AES67, RAVENNA, and ST 2110-30 streams, supporting uncompressed L16 and L24 PCM audio up to 64 channels. Features include SAP-based stream discovery, manual SDP addition, and customizable network and audio interface configuration.

Tokens
2.3K
Snippets
9
Records
12
Agent score
56%

What's inside AES67 Stream Monitor

  1. Overview of AES67 Stream Monitor features

    main

    AES67 Stream Monitor is a cross-platform Audio-over-IP monitoring application for live sound, studio, and broadcast environments. Key capabilities include:

    • Format Support: Supports AES67, RAVENNA, and ST 2110-30 standards, including uncompressed L16 and L24 PCM audio (up to 64 channels) with various sampling rates (48kHz, 96kHz, etc.).
    • Stream Discovery: Automatically detects streams via Session Announcement Protocol (SAP) or allows manual addition via raw SDP data.
    • Management: Features stream filtering, sorting, and selective channel listening (stereo pairs or individual mono channels).
    • Configuration: Allows customization of network interfaces, audio devices, and RTP buffering.
  2. Build AES67 Stream Monitor from source

    main

    To build the application from source, clone the repository, install dependencies, and run the build command. The audio backend, Audify, typically uses prebuilt binaries for most major platforms and NodeJS versions. If you need to build Audify from source, refer to the Audify documentation.

    git clone https://github.com/philhartung/aes67-monitor.git
    cd aes67-monitor
    npm install
    npm run build
  3. Develop AES67 Stream Monitor

    main

    If you are contributing to the project, use the following commands to manage the development environment:

    • Frontend Development: Use npm run serve to compile and enable hot-reloading for the frontend.
    • Electron Development: To run the full Electron application in development mode, you must first run npm run serve in a separate terminal, then run npm start.
    • Code Quality: Use npm run lint to check for linting errors and npm run format to format the code.
    # Compile and hot-reload frontend
    npm run serve
    
    # Start electron (requires npm run serve to be running)
    npm start
    
    # Lint and format
    npm run lint
    npm run format
  4. Manage application state and reactive data

    main

    The application uses Vue ref and computed objects to manage global state. Developers can import these reactive variables to synchronize UI components with the current state of streams, interfaces, and user settings.

    Core State Variables

    • page: The current active view (e.g., 'streams', 'stream', 'sdp', 'interfaces', 'settings').
    • streams: An array of discovered AES67 stream objects.
    • search: An object containing search queries for streams, interfaces, and devices.
    • audioInterfaces: Available audio hardware interfaces.
    • networkInterfaces: Available network interfaces.
    • persistentData: User settings and preferences, including bufferSize, bufferEnabled, and hideUnsupported.
    • selectedStream: The currently inspected stream object.
    • playing: The ID of the stream currently being played, or an empty string if nothing is playing.
    import { streams, page, search, persistentData } from "./app.js";
    
    // Example: Accessing reactive state
    console.log(streams.value);
    console.log(page.value);
  5. Handle incoming messages from the backend

    main

    The application listens for messages from the Electron backend using window.electronAPI.recvMessage. When a message is received, the application updates its internal reactive state based on the message.type:

    TypeAction
    streamsUpdates streams and streamCount
    interfacesUpdates networkInterfaces
    audioDevicesUpdates audioInterfaces and interfaceCount
    updatePersistentDataUpdates the entire persistentData object
    devicesLogs device information (currently used for debugging)
  6. Configure Vue CLI build settings in vue.config.js

    main

    The project uses @vue/cli-service for its build process. The vue.config.js file defines the build configuration, specifically ensuring that dependencies are transpiled and setting the public path for assets.

    const { defineConfig } = require("@vue/cli-service");
    module.exports = defineConfig({
    	transpileDependencies: true,
    	publicPath: "./",
    });
  7. Communicate with the Electron backend

    main

    The application communicates with the backend via sendMessage(message). This function uses the window.electronAPI bridge provided by Electron.

    Supported Message Types

    • play: Starts stream playback with specific RTP/media parameters.
    • stop: Stops current playback.
    • setAudioInterface: Configures the selected audio hardware.
    • addStream: Adds a new stream via SDP data.
    • save: Persists a specific key from persistentData to disk.
    • setNetwork: Sets the active network interface address.
    • restart: Restarts the audio engine (typically called after changing audio interfaces).
    • update: Notifies the backend to sync/update.
    import { sendMessage } from "./app.js";
    
    // Example: Manually sending a message
    sendMessage({
      type: "stop"
    });
  8. Configure audio input and output devices

    main

    The application provides utility functions to filter and select audio hardware:

    • getAudioOutputDevices(): Returns audioInterfaces that have outputChannels > 0.
    • getAudioInputDevices(): Returns audioInterfaces that have inputChannels > 0.
    • getCurrentAudioOutput(): Returns the currently active output device.
    • setCurrentAudioInterface(device): Sends a setAudioInterface message to the backend to switch the active hardware. If a stream is currently playing, it triggers a restart message to re-initialize audio with the new device.
    import { getAudioOutputDevices, setCurrentAudioInterface } from "./app.js";
    
    const outputs = getAudioOutputDevices();
    if (outputs.length > 0) {
      setCurrentAudioInterface(outputs[0]);
    }
  9. Navigate between application pages

    main

    Use viewPage(newPage) to change the current application view. If navigating away from the 'settings' page, the application automatically triggers saveSettings() to persist changes.

    • goBack(): Navigates back to the 'streams' page from either the 'stream' or 'sdp' views.
    • viewStream(stream): Navigates to the detailed view of a specific stream.
    • viewDevice(device): Filters the stream list to a specific device and navigates to the 'streams' page.
    import { viewPage, goBack, viewStream } from "./app.js";
    
    viewPage('settings');
    goBack();
    viewStream(someStreamObject);
  10. Play or stop an AES67 stream

    main

    The playStream(stream) function manages the playback lifecycle.

    • To Play: It constructs a data payload containing the stream's RTP parameters (port, codec, ptime, samplerate, etc.), channel mappings, and jitter buffer settings, then sends a play message to the backend.
    • To Stop: If the provided stream.id matches the currently playing ID, it sends a stop message to the backend.

    Note: Playback requires the stream to have valid media information in stream.media[streamIndex].

    import { playStream } from "./app.js";
    
    // Play a stream
    playStream(streamObject);
    
    // Calling it again with the same stream will stop it
    playStream(streamObject);
  11. Search and filter streams and devices

    main

    The application provides methods to filter the available data based on the current search state.

    • searchStreams(): Returns a filtered array of streams based on the search.streams query (matching name, origin address, or ID) and the persistentData.settings.hideUnsupported flag.
    • searchDevices: A computed property that returns a list of unique device addresses derived from the current streams list, filtered by the search.devices query.
    import { searchStreams, searchDevices } from "./app.js";
    
    // To get the current filtered list of streams:
    const filtered = searchStreams();
    
    // To get the current filtered list of devices (computed):
    const devices = searchDevices.value;