Developer Guide
Complete guide for developers contributing to the LegacyStream project
Introduction
LegacyStream is an open-source, high-performance audio streaming server built with C++ and Qt. This guide provides comprehensive information for developers who want to contribute to the project.
Project Goals
- High Performance: Optimized for Windows with IOCP
- Multi-Protocol Support: IceCast and SHOUTcast compatibility
- Modern Architecture: Modular, extensible design
- Developer Friendly: Comprehensive documentation and tools
- Cross-Platform: Windows-focused with potential for other platforms
Technology Stack
- Language: C++17/20
- Framework: Qt 6.x
- Build System: CMake
- Testing: Google Test
- Documentation: Doxygen
- Version Control: Git
Architecture Overview
Core Components
LegacyStream follows a modular architecture with clear separation of concerns:
Core Module
- ServerManager: Central coordination and lifecycle management
- ConfigurationManager: Settings and configuration management
- PerformanceManager: Performance optimization and monitoring
- LogManager: Logging and debugging facilities
Streaming Module
- StreamManager: Audio stream management
- CodecManager: Audio codec handling
- ProtocolManager: IceCast/SHOUTcast protocols
- HttpServer: HTTP server implementation
GUI Module
- MainWindow: Primary GUI interface
- ThemeManager: UI theming and customization
- AccessibilityManager: Accessibility features
Design Patterns
- Singleton Pattern: Used for managers and global services
- Observer Pattern: Event-driven architecture
- Factory Pattern: Object creation and management
- Strategy Pattern: Pluggable algorithms and protocols
Data Flow
- Audio input is captured or loaded from files
- Audio data is processed and encoded
- Encoded data is buffered and queued
- HTTP server delivers streams to clients
- Real-time statistics are collected and displayed
Development Setup
Prerequisites
- Windows 10/11: Development environment
- Visual Studio 2019/2022: C++ compiler and IDE
- Qt 6.x: Application framework
- CMake 3.16+: Build system
- Git: Version control
Environment Setup
- Clone the repository:
git clone https://github.com/legacystream/legacystream.git cd legacystream
- Install Qt 6.x and set environment variables
- Install Visual Studio with C++ development tools
- Install CMake and add to PATH
- Install additional dependencies:
# Install vcpkg for dependencies git clone https://github.com/Microsoft/vcpkg.git cd vcpkg .\bootstrap-vcpkg.bat .\vcpkg install openssl:x64-windows .\vcpkg install zlib:x64-windows
Building from Source
# Create build directory
mkdir build
cd build
# Configure with CMake
cmake .. -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
# Build the project
cmake --build . --config Release
# Run tests
ctest --output-on-failure
Tip: Use Visual Studio's CMake integration for a better development experience.
Code Organization
Directory Structure
LegacyStream/
├── include/ # Header files
│ ├── core/ # Core functionality
│ ├── gui/ # GUI components
│ ├── streaming/ # Streaming modules
│ ├── ssl/ # Security components
│ └── realtime/ # Real-time features
├── src/ # Source files
│ ├── core/ # Core implementation
│ ├── gui/ # GUI implementation
│ ├── streaming/ # Streaming implementation
│ └── ssl/ # Security implementation
├── tests/ # Test files
├── docs/ # Documentation
├── scripts/ # Build and deployment scripts
└── resources/ # Application resources
Naming Conventions
- Classes: PascalCase (e.g.,
StreamManager
) - Functions: camelCase (e.g.,
startStream()
) - Variables: camelCase (e.g.,
streamName
) - Constants: UPPER_SNAKE_CASE (e.g.,
MAX_CONNECTIONS
) - Files: PascalCase (e.g.,
StreamManager.h
)
File Organization
- One class per header/source file pair
- Header files contain declarations only
- Source files contain implementations
- Use forward declarations when possible
- Include guards for all header files
Coding Standards
C++ Standards
- Use C++17/20 features where appropriate
- Prefer modern C++ over C-style code
- Use smart pointers instead of raw pointers
- Use RAII for resource management
- Prefer const correctness
Code Style
// Good example
class StreamManager {
public:
explicit StreamManager(QObject* parent = nullptr);
~StreamManager();
bool startStream(const QString& streamName);
void stopStream(const QString& streamName);
private:
void initializeStream();
void cleanupStream();
QString m_streamName;
bool m_isRunning = false;
};
Documentation
- Use Doxygen comments for all public APIs
- Include examples in documentation
- Document exceptions and error conditions
- Keep documentation up to date
Error Handling
- Use exceptions for exceptional conditions
- Return error codes for expected failures
- Log errors with appropriate detail
- Provide meaningful error messages
Testing
Test Types
- Unit Tests: Test individual components
- Integration Tests: Test component interactions
- Performance Tests: Test performance characteristics
- GUI Tests: Test user interface functionality
Writing Tests
#include
#include "StreamManager.h"
class StreamManagerTest : public ::testing::Test {
protected:
void SetUp() override {
manager = std::make_unique();
}
void TearDown() override {
manager.reset();
}
std::unique_ptr manager;
};
TEST_F(StreamManagerTest, StartStream_ValidName_ReturnsTrue) {
// Arrange
QString streamName = "test_stream";
// Act
bool result = manager->startStream(streamName);
// Assert
EXPECT_TRUE(result);
EXPECT_TRUE(manager->isStreamRunning(streamName));
}
Running Tests
# Run all tests
ctest --output-on-failure
# Run specific test
./tests/StreamManagerTest --gtest_filter=StartStream_ValidName_ReturnsTrue
# Run with verbose output
ctest --verbose
Documentation
Code Documentation
/**
* @brief Manages audio streams and their lifecycle
*
* The StreamManager class provides functionality to create, start, stop,
* and monitor audio streams. It handles stream configuration, encoding,
* and delivery to clients.
*
* @example
* @code
* StreamManager manager;
* manager.startStream("my_stream");
* @endcode
*/
class StreamManager : public QObject {
Q_OBJECT
public:
/**
* @brief Starts a new audio stream
* @param streamName The name of the stream to start
* @return true if stream started successfully, false otherwise
* @throws std::runtime_error if stream configuration is invalid
*/
bool startStream(const QString& streamName);
};
API Documentation
- Document all public APIs with Doxygen
- Include usage examples
- Document parameters and return values
- Explain error conditions and exceptions
Architecture Documentation
- Maintain architecture diagrams
- Document design decisions
- Keep component relationships current
- Document data flow and state management
Contribution Guidelines
Before Contributing
- Read the project documentation
- Check existing issues and pull requests
- Discuss major changes in issues first
- Ensure your development environment is set up
Development Workflow
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name
- Make your changes following coding standards
- Write tests for new functionality
- Update documentation as needed
- Run the full test suite
- Commit your changes with clear messages
- Push to your fork and create a pull request
Commit Messages
Use clear, descriptive commit messages:
feat: add support for AAC audio codec
fix: resolve memory leak in StreamManager
docs: update API documentation
test: add unit tests for new features
refactor: improve error handling in HttpServer
Pull Request Guidelines
- Provide a clear description of changes
- Include tests for new functionality
- Update documentation if needed
- Ensure all tests pass
- Follow the project's coding standards
Build System
CMake Configuration
# CMakeLists.txt example
cmake_minimum_required(VERSION 3.16)
project(LegacyStream VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Network)
find_package(OpenSSL REQUIRED)
add_executable(LegacyStream
src/main.cpp
src/core/ServerManager.cpp
src/streaming/StreamManager.cpp
)
target_link_libraries(LegacyStream
Qt6::Core
Qt6::Widgets
Qt6::Network
OpenSSL::SSL
OpenSSL::Crypto
)
Build Configurations
- Debug: Development with debug symbols
- Release: Optimized production build
- RelWithDebInfo: Release with debug info
- MinSizeRel: Minimal size release
Dependencies
- Qt 6.x: Application framework
- OpenSSL: SSL/TLS support
- Google Test: Testing framework
- Doxygen: Documentation generation
Deployment
Release Process
- Update version numbers in CMakeLists.txt
- Update CHANGELOG.md with release notes
- Create a release tag:
git tag -a v1.0.0 -m "Release version 1.0.0" git push origin v1.0.0
- Build release packages
- Test release packages
- Upload to release page
Packaging
- Create Windows installer with NSIS
- Include all required dependencies
- Provide portable version
- Include documentation and examples
Continuous Integration
- Automated builds on multiple platforms
- Automated testing
- Code quality checks
- Automated deployment
API Reference
Core APIs
// ServerManager API
class ServerManager {
public:
bool initialize();
void shutdown();
bool isRunning() const;
// Stream management
bool createStream(const QString& name);
bool startStream(const QString& name);
bool stopStream(const QString& name);
bool deleteStream(const QString& name);
};
// ConfigurationManager API
class ConfigurationManager {
public:
void loadConfiguration(const QString& file);
void saveConfiguration(const QString& file);
QVariant getValue(const QString& key);
void setValue(const QString& key, const QVariant& value);
};
Streaming APIs
// StreamManager API
class StreamManager {
public:
bool addMountPoint(const QString& path, const StreamConfig& config);
bool removeMountPoint(const QString& path);
QList getActiveStreams() const;
// Audio processing
void setAudioFormat(const QString& stream, const AudioFormat& format);
void setBitrate(const QString& stream, int bitrate);
void setSampleRate(const QString& stream, int sampleRate);
};
GUI APIs
// MainWindow API
class MainWindow : public QMainWindow {
public:
void showStreamManager();
void showConfiguration();
void showStatistics();
void showLogs();
};
Troubleshooting
Common Build Issues
Qt Not Found
# Set Qt6_DIR environment variable
set Qt6_DIR=C:\Qt\6.5.0\msvc2019_64\lib\cmake\Qt6
# Or specify in CMake
cmake .. -DQt6_DIR=C:\Qt\6.5.0\msvc2019_64\lib\cmake\Qt6
OpenSSL Not Found
# Use vcpkg for dependencies
cmake .. -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
Compiler Errors
- Ensure you're using C++17 or later
- Check that all required headers are included
- Verify Qt modules are properly linked
- Check for missing dependencies
Runtime Issues
Application Won't Start
- Check if all DLLs are in PATH
- Verify Qt plugins are accessible
- Check for missing configuration files
- Review application logs
Streaming Issues
- Verify audio codecs are available
- Check network port availability
- Review stream configuration
- Check firewall settings
Debugging
- Use Visual Studio debugger
- Enable debug logging
- Use Qt Creator for GUI debugging
- Check Windows Event Viewer