### Enumerate and Open ASIO Drivers Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Lists installed ASIO drivers and initializes the SAR ASIO driver. Requires a window handle for configuration dialogs. ```cpp // Enumerate installed ASIO drivers std::vector drivers = Sar::InstalledAsioDrivers(); for (auto& driver : drivers) { std::cout << "Driver: " << driver.name << " CLSID: " << driver.clsid << std::endl; } // Open the SAR ASIO driver Sar::IASIO* asio = nullptr; GUID sarClsid; CLSIDFromString(L"{0569D852-1F6A-44A7-B7B5-EFB78B66BE21}", &sarClsid); CoCreateInstance(sarClsid, nullptr, CLSCTX_INPROC_SERVER, sarClsid, (void**)&asio); // Initialize with window handle for configuration dialogs if (asio->init(hwnd) == Sar::AsioBool::True) { char driverName[32]; asio->getDriverName(driverName); // Returns "Synchronous Audio Router" // Query channel counts (physical + virtual channels) long inputs, outputs; asio->getChannels(&inputs, &outputs); std::cout << "Inputs: " << inputs << " Outputs: " << outputs << std::endl; // Get buffer size constraints long minSize, maxSize, preferredSize, granularity; asio->getBufferSize(&minSize, &maxSize, &preferredSize, &granularity); // Query sample rate support double sampleRate = 48000.0; if (asio->canSampleRate(sampleRate) == Sar::AsioStatus::OK) { asio->setSampleRate(sampleRate); } } ``` -------------------------------- ### Configure ASIO Buffers and Callbacks Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Sets up ASIO buffer information, including physical and virtual channels, and defines callbacks for audio processing and status changes. The 'tick' callback is invoked during buffer swaps for audio processing. ```cpp // Define channels to use (physical + virtual) std::vector bufferInfos; // Add physical input channel 0 Sar::AsioBufferInfo physicalIn = {}; physicalIn.isInput = Sar::AsioBool::True; physicalIn.index = 0; bufferInfos.push_back(physicalIn); // Add virtual input channel (from SAR endpoint, index after physical channels) long physicalInputs, physicalOutputs; asio->getChannels(&physicalInputs, &physicalOutputs); Sar::AsioBufferInfo virtualIn = {}; virtualIn.isInput = Sar::AsioBool::True; virtualIn.index = physicalInputs; // First virtual input bufferInfos.push_back(virtualIn); // Setup callbacks Sar::AsioCallbacks callbacks = {}; callbacks.tick = [](long bufferIndex, Sar::AsioBool directProcess) { // Called when buffer swap occurs - process audio here // bufferIndex alternates between 0 and 1 (double buffering) }; callbacks.sampleRateDidChange = [](double newRate) { std::cout << "Sample rate changed to: " << newRate << std::endl; }; cbs.asioMessage = [](Sar::AsioMessage selector, long value, void* msg, double* opt) -> long { if (selector == Sar::AsioMessage::SupportsTimeInfo) return 1; return 0; }; // Create buffers with 256 sample buffer size long bufferSize = 256; auto status = asio->createBuffers(bufferInfos.data(), bufferInfos.size(), bufferSize, &callbacks); if (status == Sar::AsioStatus::OK) { // Start audio streaming asio->start(); // Audio processing happens in tick callback... // Stop and cleanup asio->stop(); asio->disposeBuffers(); } ``` -------------------------------- ### Configure Per-Application Routing with ApplicationConfig Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Define routing rules to automatically redirect audio from specific applications to designated endpoints. Regex matching allows for flexible path-based application identification. ```cpp // Route all Spotify audio to a dedicated endpoint Sar::ApplicationConfig spotifyRule; spotifyRule.description = L"Spotify"; spotifyRule.path = L"Spotify"; // Match any path containing "Spotify" spotifyRule.regexMatch = true; // Enable regex matching // Set default endpoints for all audio roles Sar::DefaultEndpointConfig playbackDefault; playbackDefault.type = EDataFlow::eRender; // Playback device playbackDefault.role = ERole::eMultimedia; // Multimedia role playbackDefault.id = "ep_bgm"; // Route to BGM endpoint spotifyRule.defaults.push_back(playbackDefault); // Route all Steam games to a separate endpoint using path pattern Sar::ApplicationConfig steamRule; steamRule.description = L"Steam Games"; steamRule.path = L".*steamapps.*"; // Regex to match Steam game directory steamRule.regexMatch = true; Sar::DefaultEndpointConfig gameDefault; gameDefault.type = EDataFlow::eRender; gameDefault.role = ERole::eConsole; // Console/system sounds role gameDefault.id = "ep_game"; steamRule.defaults.push_back(gameDefault); config.applications.push_back(steamRule); ``` -------------------------------- ### Define Virtual Audio Endpoints with EndpointConfig Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Create and manage virtual playback or recording endpoints. Playback endpoints route Windows audio to the DAW, while recording endpoints route DAW output to Windows applications. ```cpp // Create a new playback endpoint for background music Sar::EndpointConfig bgmEndpoint; bgmEndpoint.id = "ep_bgm"; // Unique identifier bgmEndpoint.description = L"Background Music"; // Display name in Windows bgmEndpoint.type = Sar::EndpointType::Playback; // Playback = Windows app -> DAW bgmEndpoint.channelCount = 2; // Stereo // Create a recording endpoint for streaming output Sar::EndpointConfig broadcastEndpoint; broadcastEndpoint.id = "ep_broadcast"; broadcastEndpoint.description = L"Broadcast Output"; broadcastEndpoint.type = Sar::EndpointType::Recording; // Recording = DAW -> Windows app broadcastEndpoint.channelCount = 2; // Add to configuration config.endpoints.push_back(bgmEndpoint); config.endpoints.push_back(broadcastEndpoint); // Find endpoint by ID Sar::EndpointConfig* found = config.findEndpoint("ep_bgm"); if (found) { found->channelCount = 4; // Upgrade to quad } ``` -------------------------------- ### EndpointConfig API Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Defines virtual Windows audio devices that appear in the system for routing between Windows apps and ASIO. ```APIDOC ## EndpointConfig ### Description EndpointConfig defines a virtual Windows audio device. Playback endpoints receive audio from Windows apps and expose it as ASIO input channels, while recording endpoints send ASIO output to Windows apps. ### Request Body - **id** (string) - Required - Unique identifier for the endpoint. - **description** (string) - Required - Display name in Windows. - **type** (enum) - Required - Playback or Recording. - **channelCount** (integer) - Required - Number of audio channels. ``` -------------------------------- ### ApplicationConfig API Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Defines rules for automatic audio routing based on application path patterns. ```APIDOC ## ApplicationConfig ### Description ApplicationConfig enables automatic audio routing for specific applications using path pattern matching. ### Request Body - **description** (string) - Required - Name of the rule. - **path** (string) - Required - Path pattern to match. - **regexMatch** (boolean) - Required - Whether to use regex for path matching. - **defaults** (array) - Required - List of default endpoint configurations for audio roles. ``` -------------------------------- ### Manage Driver Configuration with DriverConfig Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Load, inspect, and persist the main SAR configuration file. Ensure the file path is accessible and valid before calling fromFile or writeFile. ```cpp // Load configuration from file Sar::DriverConfig config = Sar::DriverConfig::fromFile(L"C:\\config\\default.json"); // Access the underlying hardware ASIO driver CLSID std::string hardwareDriver = config.driverClsid; // e.g., "{23638883-0B8C-4324-BBD5-35C3CF1B73BF}" // Check if per-application routing is enabled bool routingEnabled = config.enableApplicationRouting; // Access configured endpoints for (auto& endpoint : config.endpoints) { std::wcout << L"Endpoint: " << endpoint.description << L" Type: " << (endpoint.type == Sar::EndpointType::Playback ? L"Playback" : L"Recording") << L" Channels: " << endpoint.channelCount << std::endl; } // Modify and save configuration config.enableApplicationRouting = true; config.writeFile(L"C:\\config\\default.json"); ``` -------------------------------- ### DriverConfig API Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Manages the global SAR configuration, including hardware ASIO driver selection and persistence to JSON. ```APIDOC ## DriverConfig ### Description The DriverConfig class manages the complete SAR configuration including the hardware ASIO driver selection, virtual endpoints, and per-application routing rules. Configuration is persisted as JSON. ### Request Body - **driverClsid** (string) - Required - The CLSID of the hardware ASIO driver. - **enableApplicationRouting** (boolean) - Required - Flag to enable or disable per-application routing. - **endpoints** (array) - Required - List of configured virtual audio endpoints. ### Request Example { "driverClsid": "{23638883-0B8C-4324-BBD5-35C3CF1B73BF}", "enableApplicationRouting": true, "endpoints": [] } ``` -------------------------------- ### Configure Kernel Driver Buffer Layout Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Sets the shared buffer layout for the kernel driver using DeviceIoControl. This configures buffer size, period, sample rate, and sample size. ```cpp // Open the SAR control device HANDLE device = CreateFile( L"\\\\.\\SynchronousAudioRouter\\{0EB287D4-6C04-4926-AE19-3C066A4C3F3A}", GENERIC_ALL, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); // Configure shared buffer layout SarSetBufferLayoutRequest layoutReq = {}; layoutReq.bufferSize = 16 * 1024 * 1024; // 16MB shared buffer layoutReq.periodSizeBytes = 256 * 4; // 256 frames * 4 bytes (32-bit) layoutReq.sampleRate = 48000; layoutReq.sampleSize = 4; // 32-bit samples layoutReq.minimumFrameCount = 0; // Use default SarSetBufferLayoutResponse layoutResp = {}; DWORD bytesReturned; DeviceIoControl(device, SAR_SET_BUFFER_LAYOUT, &layoutReq, sizeof(layoutReq), &layoutResp, sizeof(layoutResp), &bytesReturned, nullptr); // Access shared memory buffer and endpoint registers void* sharedBuffer = layoutResp.virtualAddress; SarEndpointRegisters* registers = (SarEndpointRegisters*) ((char*)sharedBuffer + layoutResp.registerBase); // Create a virtual endpoint SarCreateEndpointRequest epReq = {}; epReq.type = SAR_ENDPOINT_TYPE_PLAYBACK; // or SAR_ENDPOINT_TYPE_RECORDING epReq.index = 0; // Endpoint index epReq.channelCount = 2; // Stereo wcscpy_s(epReq.name, L"My Virtual Speaker"); wcscpy_s(epReq.id, L"ep_virtual_1"); DeviceIoControl(device, SAR_CREATE_ENDPOINT, &epReq, sizeof(epReq), nullptr, 0, &bytesReturned, nullptr); ``` -------------------------------- ### Defining SAR Configuration in JSON Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Configure audio endpoints and application routing rules using this JSON structure. The configuration defines how Windows applications map to virtual ASIO channels. ```json { "driverClsid": "{23638883-0B8C-4324-BBD5-35C3CF1B73BF}", "enableApplicationRouting": true, "waveRtMinimumFrames": 480, "endpoints": [ { "id": "ep_desktop", "description": "Desktop Audio", "type": "playback", "channelCount": 2 }, { "id": "ep_game", "description": "Game Audio", "type": "playback", "channelCount": 2 }, { "id": "ep_music", "description": "Music", "type": "playback", "channelCount": 2 }, { "id": "ep_voip_out", "description": "VoIP Output", "type": "recording", "channelCount": 2 }, { "id": "ep_stream", "description": "Stream Mix", "type": "recording", "channelCount": 2 } ], "applications": [ { "description": "Discord", "path": "Discord", "regexMatch": true, "defaults": [ { "type": "playback", "role": "communications", "id": "ep_desktop" }, { "type": "recording", "role": "communications", "id": "ep_voip_out" } ] }, { "description": "Steam Games", "path": ".*[Ss]teamapps.*", "regexMatch": true, "defaults": [ { "type": "playback", "role": "console", "id": "ep_game" }, { "type": "playback", "role": "multimedia", "id": "ep_game" } ] }, { "description": "Spotify", "path": "Spotify\\.exe$", "regexMatch": true, "defaults": [ { "type": "playback", "role": "multimedia", "id": "ep_music" } ] } ] } ``` -------------------------------- ### Accessing Endpoint Registers in C++ Source: https://context7.com/eiz/synchronousaudiorouter/llms.txt Use this pattern within an ASIO tick callback to read and update endpoint state via shared memory. Ensure the pointer is volatile to prevent compiler optimization of shared memory access. ```cpp // Read endpoint state (from ASIO callback) volatile SarEndpointRegisters* regs = ®isters[endpointIndex]; // Check if endpoint is active (has an audio client connected) ULONG generation = regs->generation; bool isActive = GENERATION_IS_ACTIVE(generation); if (isActive) { // Get buffer position and size DWORD bufferOffset = regs->bufferOffset; DWORD bufferSize = regs->bufferSize; DWORD position = regs->positionRegister; DWORD activeChannels = regs->activeChannelCount; // Calculate audio data location in shared buffer void* audioData = (char*)sharedBuffer + bufferOffset + position; // Process audio: demux from interleaved ring buffer to ASIO channel buffers // ... audio processing ... // Update position register (wraps around) DWORD frameSize = periodFrameSize * sampleSize * activeChannels; regs->positionRegister = (position + frameSize) % bufferSize; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.