desktop-audio-proxy
Version:
A comprehensive audio streaming solution for Tauri and Electron apps that bypasses CORS and WebKit codec issues
681 lines (515 loc) • 20.9 kB
Markdown
<p align="center">
<img src="assets/logo.png" alt="DAP Logo" width="200"/>
</p>
<h1 align="center">DAP - Desktop Audio Proxy</h1>
<p align="center" style="font-size:1.1em;">
<strong>Bypasses CORS & WebKit codec issues in Tauri and Electron audio apps with ease.</strong>
</p>
<p align="center">
<a href="https://github.com/Bandonker/desktop-audio-proxy/actions/workflows/ci.yml">
<img src="https://img.shields.io/github/actions/workflow/status/Bandonker/desktop-audio-proxy/ci.yml?branch=main&style=flat-square&label=build" alt="Build Status"/>
</a>
<a href="https://www.npmjs.com/package/desktop-audio-proxy">
<img src="https://img.shields.io/npm/v/desktop-audio-proxy?style=flat-square&color=blue&label=npm" alt="npm version"/>
</a>
<a href="https://github.com/Bandonker/desktop-audio-proxy/blob/main/LICENSE">
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="License"/>
</a>
<img src="https://img.shields.io/npm/dt/desktop-audio-proxy?style=flat-square&color=orange&label=downloads" alt="Total Downloads"/>
<img src="https://img.shields.io/github/stars/Bandonker/desktop-audio-proxy?style=flat-square&color=yellow&label=stars" alt="GitHub Stars"/>
<a href="https://codecov.io/gh/Bandonker/desktop-audio-proxy">
<img src="https://img.shields.io/codecov/c/github/Bandonker/desktop-audio-proxy?style=flat-square&label=coverage" alt="Coverage"/>
</a>
<a href="https://ko-fi.com/bandonker">
<img src="https://img.shields.io/badge/Ko--fi-Bandonker-29ABE0?style=flat-square&logo=ko-fi&logoColor=white" alt="Support on Ko-fi"/>
</a>
<a href="https://www.buymeacoffee.com/Bandonker">
<img src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Bandonker-yellow?style=flat-square&logo=buymeacoffee&logoColor=black" alt="Coffee Me"/>
</a>
<a href="https://patreon.com/Bandonker">
<img src="https://img.shields.io/badge/Patreon-Bandonker-F96854?style=flat-square&logo=patreon&logoColor=white" alt="Support on Patreon"/>
</a>
</p>
## Features
- **CORS Bypass** - Play external audio URLs without CORS restrictions
- **React/Vue Integration** - Ready-to-use hooks and composables for seamless framework integration
- **Enhanced Codec Detection** - Comprehensive format testing with real-time capabilities mapping
- **Audio Metadata Extraction** - Get duration, format, bitrate from audio files
- **Audio Device Enumeration** - List and manage available audio devices
- **WebKit Compatibility** - Solves codec issues in Tauri/Electron WebView
- **Environment Detection** - Automatically detects Tauri, Electron, or web environment
- **Smart Fallbacks** - Graceful degradation when proxy unavailable
- **Retry Logic** - Configurable retry attempts with delays
- **Health Monitoring** - Built-in health and info endpoints
- **TypeScript** - Full type safety and IntelliSense support
- **Range Requests** - Support for audio seeking and streaming
- **Interactive Demo** - Live testing environment with auto-detection
## Demos
### Web Browser Demo
Visual demonstration of CORS bypass functionality in action:
<p align="center">
<img src="assets/visualdemo1.PNG" alt="Web Demo - Overview" width="800"/>
<br><em>Complete web interface showing system status and library capabilities</em>
</p>
<p align="center">
<img src="assets/visualdemo2.PNG" alt="Web Demo - CORS Testing" width="800"/>
<br><em>Side-by-side comparison: Direct access fails, proxy access succeeds</em>
</p>
<p align="center">
<img src="assets/visualdemo3.PNG" alt="Web Demo - Code Examples" width="800"/>
<br><em>Interactive code examples with copy-to-clipboard functionality</em>
</p>
### CLI Terminal Demo
Professional terminal interface with real-time CORS testing and browser automation:
<p align="center">
<img src="assets/clidemo1.PNG" alt="CLI Demo - Main Interface" width="600"/>
<br><em>Interactive command interface with system status and real-time proxy detection</em>
</p>
<p align="center">
<img src="assets/clidemo2.PNG" alt="CLI Demo - CORS Testing" width="600"/>
<br><em>Real browser CORS testing with actual HTTP requests showing blocked vs allowed URLs</em>
</p>
### Proxy Server Integration
Seamless proxy server integration with automatic port detection:
<p align="center">
<img src="assets/cliproxy1.PNG" alt="Proxy Server Status" width="600"/>
<br><em>Live proxy server status with health monitoring and configuration details</em>
</p>
> Try it yourself: Run `npm run demo:cli` for the terminal demo or `npm run demo` for the web demo
## The Problem
When building desktop applications with web technologies (Tauri, Electron), developers often face:
1. **CORS Issues**: External audio URLs (podcasts, radio streams) are blocked due to Cross-Origin Resource Sharing policies
2. **Codec Compatibility**: WebKit may not support certain audio codecs even with proper GStreamer plugins installed
3. **Authentication**: Some audio streams require special headers or authentication
4. **Redirects**: Many podcast/streaming URLs use multiple redirects that cause issues
## The Solution
Desktop Audio Proxy provides:
- **Automatic CORS bypass** for external audio URLs
- **Codec transcoding** support (optional, requires ffmpeg)
- **Smart redirect handling** with configurable limits
- **Automatic environment detection** (Tauri/Electron/Web)
- **Optional caching** for better performance
- **Simple API** that works like a drop-in replacement
## Installation
```bash
npm install desktop-audio-proxy
# or
yarn add desktop-audio-proxy
# or
pnpm add desktop-audio-proxy
```
## Package Exports
This library provides multiple entry points optimized for different environments:
```typescript
// Main entry - includes all functionality (client + server)
import { createAudioClient, startProxyServer } from 'desktop-audio-proxy';
// Browser-only entry - excludes server dependencies for smaller bundles
import { createAudioClient, TauriAudioService } from 'desktop-audio-proxy/browser';
// Server-only entry - for Node.js environments
import { startProxyServer, AudioProxyServer } from 'desktop-audio-proxy/server';
```
**When to use each:**
- **Main (`desktop-audio-proxy`)**: Full-stack applications, development, testing
- **Browser (`/browser`)**: Client-only applications, smaller bundle size needed
- **Server (`/server`)**: Node.js backends, standalone proxy servers, Electron main process
## Interactive Demo
**See Desktop Audio Proxy in action!** Our comprehensive demo provides real-time testing with automatic library detection:
```bash
npm run demo
```
**v1.1.3 Demo Features:**
- **Auto-Detection** - Automatically finds and loads available library builds (local, CDN, various formats)
- **Version Detection** - Shows current library version with upgrade recommendations
- **Enhanced Features Showcase** - Live codec detection, metadata extraction, device enumeration
- **Real-time CORS Testing** - Compare direct URL vs proxy with live playback
- **Developer Tools** - Exposed internals for manual testing (`window.dapDemo`)
- **Smart Fallbacks** - Works with any version of the library
- **Visual Upgrade Guidance** - Clear recommendations when using older versions
**What you can test:**
- **Any audio URL** - Paste podcast, radio, or music URLs
- **Environment detection** - See if you're in Tauri, Electron, or web
- **Codec capabilities** - Test what formats your system supports
- **Metadata extraction** - View audio file information
- **Device enumeration** - List available audio devices
**Perfect for:**
- **Evaluating before installing** - See the value immediately
- **Testing your URLs** - Verify compatibility before integration
- **Learning the API** - Interactive code examples
- **Demos and presentations** - Live proof of concept
- **Debugging integration** - Test with your actual URLs
## CLI Demo
**Experience the power in your terminal!** Our CLI demo features professional ASCII art and terminal effects:
```bash
npm run demo:cli
```
**Features:**
- **Sick ASCII Art** - Matrix-style banner with terminal effects
- **Real-time System Status** - Live proxy detection and version info
- **Audio URL Testing** - Compare direct vs proxy access with detailed analysis
- **System Diagnostics** - Network scanning, capability testing, version detection
- **Test Results History** - Track all your URL tests with timestamps
- **Proxy Server Monitoring** - Real-time server status and configuration
- **Interactive Help** - Built-in documentation and examples
- **Command Interface** - Easy-to-use menu system
**CLI Commands:**
```
1) Test Audio URL - Test any audio URL with CORS bypass
2) System Diagnostics - Check library capabilities and network
3) Proxy Server Status - Monitor proxy server health
4) Show Example URLs - Curated list of test URLs
5) Advanced Features Demo - Showcase enhanced v1.1.3 features
6) View Test Results - History of all URL tests
7) Show Startup Commands - Display setup commands for full demo
h) Help & Documentation - Learn about the library
q) Quit System - Exit the CLI
```
**Perfect for:**
- **Quick testing** - Fast audio URL validation
- **Debugging** - Terminal-based diagnostics
- **Presentations** - Professional CLI aesthetic for demos
- **CI/CD pipelines** - Automated testing workflows
- **Server environments** - No browser needed
## Quick Start
### Basic Usage (Automatic Setup)
```typescript
import { createAudioClient } from 'desktop-audio-proxy';
// Create client with auto-detection
const audioClient = createAudioClient();
// Convert any audio URL to a playable URL
const playableUrl = await audioClient.getPlayableUrl('https://example.com/podcast.mp3');
// Use in your audio element
audioElement.src = playableUrl;
```
### With Proxy Server
```typescript
import { startProxyServer, createAudioClient } from 'desktop-audio-proxy';
// Start the proxy server
const proxyServer = await startProxyServer({ port: 3001 });
// Create client that uses the proxy
const audioClient = createAudioClient({
proxyUrl: 'http://localhost:3001'
});
// Convert URL
const playableUrl = await audioClient.getPlayableUrl('https://example.com/audio.mp3');
```
### Tauri Integration
```typescript
import { TauriAudioService } from 'desktop-audio-proxy';
const audioService = new TauriAudioService({
// Automatically uses proxy in dev, direct URLs in production
autoDetect: true
});
// In your audio player
const streamUrl = await audioService.getStreamableUrl(originalUrl);
audioElement.src = streamUrl;
```
### Electron Integration
```typescript
import { ElectronAudioService } from 'desktop-audio-proxy';
const audioService = new ElectronAudioService({
enableTranscoding: true // Optional: transcode unsupported formats
});
const streamUrl = await audioService.getStreamableUrl(originalUrl);
```
## Advanced Configuration
```typescript
const audioClient = createAudioClient({
proxyUrl: 'http://localhost:3002',
autoDetect: true,
fallbackToOriginal: true,
retryAttempts: 3,
retryDelay: 1000,
// Optional proxy server config
proxyConfig: {
port: 3002,
corsOrigins: '*',
timeout: 60000,
maxRedirects: 20,
enableLogging: true,
enableTranscoding: false,
cacheEnabled: true,
cacheTTL: 3600
}
});
```
## Framework Integration
### React Hooks
Seamless React integration with automatic state management:
```jsx
import { useAudioProxy, useAudioCapabilities } from 'desktop-audio-proxy/react';
function AudioPlayer({ url }) {
const { audioUrl, isLoading, error, retry } = useAudioProxy(url);
const { capabilities } = useAudioCapabilities();
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error} <button onClick={retry}>Retry</button></div>;
return <audio controls src={audioUrl} />;
}
// Advanced usage with provider
import { AudioProxyProvider } from 'desktop-audio-proxy/react';
function App() {
return (
<AudioProxyProvider options={{
proxyUrl: 'http://localhost:3002',
retryAttempts: 3
}}>
<AudioPlayer url="https://example.com/audio.mp3" />
</AudioProxyProvider>
);
}
```
**Available React Hooks:**
- `useAudioProxy(url)` - Complete audio URL processing with loading states
- `useAudioCapabilities()` - System codec detection and device enumeration
- `useProxyStatus()` - Real-time proxy server monitoring
- `useAudioMetadata(filePath)` - Audio file metadata extraction (Tauri/Electron)
### Vue Composables
Modern Vue 3 Composition API integration:
```vue
<script setup>
import { ref } from 'vue';
import { useAudioProxy, useAudioCapabilities } from 'desktop-audio-proxy/vue';
const url = ref('https://example.com/audio.mp3');
const { audioUrl, isLoading, error, retry } = useAudioProxy(url);
const { capabilities } = useAudioCapabilities();
</script>
<template>
<div v-if="isLoading">Loading...</div>
<div v-else-if="error">
Error: {{ error }}
<button @click="retry">Retry</button>
</div>
<audio v-else controls :src="audioUrl" />
</template>
```
**Available Vue Composables:**
- `useAudioProxy(url)` - Reactive audio URL processing with Vue refs
- `useAudioCapabilities()` - Reactive system capabilities detection
- `useProxyStatus()` - Reactive proxy server status monitoring
- `useAudioMetadata(filePath)` - Reactive metadata extraction (Tauri/Electron)
## API Reference
### AudioProxyClient
```typescript
class AudioProxyClient {
constructor(options?: AudioProxyOptions);
// Core Methods
getPlayableUrl(url: string): Promise<string>;
canPlayUrl(url: string): Promise<StreamInfo>;
getEnvironment(): Environment;
isProxyAvailable(): Promise<boolean>;
// Stream Management
canPlayStream(url: string): Promise<boolean>;
checkStreamHealth(url: string): Promise<HealthStatus>;
// Debug and Utilities
enableDebug(): void;
getClientInfo(): ClientInfo;
}
```
### TauriAudioService
```typescript
class TauriAudioService {
constructor(options?: TauriAudioOptions);
// URL Processing
getStreamableUrl(url: string): Promise<string>;
convertLocalFile(filePath: string): Promise<string>;
// Environment Detection
getEnvironment(): Environment;
// Enhanced v1.1.0 Features
checkCodecSupport(): Promise<CodecInfo>;
getAudioMetadata(filePath: string): Promise<AudioMetadata>;
getAudioDevices(): Promise<AudioDevice[]>;
// Health Checks
isProxyAvailable(): Promise<boolean>;
}
```
### ElectronAudioService
```typescript
class ElectronAudioService {
constructor(options?: ElectronAudioOptions);
// URL Processing
getStreamableUrl(url: string): Promise<string>;
resolveLocalPath(path: string): Promise<string>;
// Environment Detection
getEnvironment(): Environment;
// Enhanced v1.1.0 Features
checkCodecSupport(): Promise<CodecInfo>;
getAudioMetadata(filePath: string): Promise<AudioMetadata>;
getAudioDevices(): Promise<AudioDevice[]>;
getSystemAudioSettings(): Promise<SystemAudioSettings>;
// System Integration
getSystemAudioInfo(): Promise<SystemAudioInfo>;
}
```
### AudioProxyServer
```typescript
class AudioProxyServer {
constructor(config?: ProxyConfig);
// Server Management
start(): Promise<void>;
stop(): Promise<void>;
restart(): Promise<void>;
// Server Info
getInfo(): ServerInfo;
getHealth(): Promise<HealthStatus>;
isRunning(): boolean;
// Configuration
updateConfig(config: Partial<ProxyConfig>): void;
getConfig(): ProxyConfig;
}
```
### Factory Functions
```typescript
// Create audio client with auto-detection
function createAudioClient(options?: AudioProxyOptions): AudioProxyClient;
// Create and start proxy server
function startProxyServer(config?: ProxyConfig): Promise<AudioProxyServer>;
// Create server instance without starting
function createProxyServer(config?: ProxyConfig): AudioProxyServer;
```
## Testing
### Running Tests
```bash
# Run all tests (Jest + Integration)
npm test
# Run Jest tests only
npm run test
# Run tests in watch mode during development
npm run test:watch
# Generate coverage report
npm run test:coverage
# Run legacy integration tests
npm run test:client
npm run test:integration
# Build and run all tests
npm run test:all
```
### Code Quality
```bash
# Lint code
npm run lint
# Auto-fix linting issues
npm run lint:fix
```
## Examples
### Standalone Server
You can run a standalone proxy server using the included example:
```bash
# Start standalone proxy server
npm run proxy:start
# Or run the example directly
node examples/standalone-server.js
```
### Complete Integration Examples
The `examples/` directory contains full integration examples updated for v1.1.0:
- **`standalone-server.js`** - Production-ready proxy server with v1.1.0 configuration
- **`tauri-integration.js`** - Complete Tauri app integration with enhanced codec detection and metadata extraction
- **`electron-integration.js`** - Electron main/renderer process setup with audio device enumeration
**v1.1.0 Example Features:**
- Enhanced codec detection usage
- Audio metadata extraction examples
- Device enumeration integration
- System audio settings management
## Troubleshooting
### Common Issues
1. **"Media format not supported"**: Install GStreamer plugins or enable transcoding
2. **"CORS error"**: Ensure the proxy server is running
3. **"Connection refused"**: Check if the proxy port is available
### Debug Mode
```typescript
const audioClient = createAudioClient({
proxyConfig: {
enableLogging: true
}
});
// Enable debug logs
if (process.env.NODE_ENV === 'development') {
audioClient.enableDebug();
}
// v1.1.0: Enhanced debugging with feature detection
const environment = audioClient.getEnvironment();
if (environment === 'tauri') {
const service = new TauriAudioService();
const codecInfo = await service.checkSystemCodecs();
console.log('Supported codecs:', codecInfo);
} else if (environment === 'electron') {
const service = new ElectronAudioService();
const codecInfo = await service.checkSystemCodecs();
console.log('Supported codecs:', codecInfo);
}
```
### Using the Interactive Demo for Debugging
The included demo is perfect for debugging integration issues:
```bash
# 1. Build the library
npm run build
# 2. Start proxy server
npm run proxy:start
npm run demo:cli
```
## Development
### Build System
The project uses Rollup for multi-target builds:
```bash
# Build all variants (ESM + CJS for each entry point)
npm run build
# Development build with watch mode
npm run dev
```
**Build Outputs:**
- `dist/index.{esm.js,cjs}` - Main entry with all features
- `dist/browser.{esm.js,cjs}` - Browser-optimized (no Node.js deps)
- `dist/server.{esm.js,cjs}` - Server-only functionality
- `dist/*.d.ts` - TypeScript definitions for all variants
### Project Structure
```
src/
├── index.ts # Main exports (client + server)
├── browser.ts # Browser-safe exports only
├── server.ts # Server-only exports
├── client.ts # AudioProxyClient implementation
├── server-impl.ts # AudioProxyServer implementation
├── tauri-service.ts # Tauri-specific service
├── electron-service.ts # Electron-specific service
├── types.ts # TypeScript type definitions
└── __tests__/ # Jest test suites
```
### Contributing
1. **Setup Development Environment:**
```bash
git clone https://github.com/bandonker/desktop-audio-proxy
cd desktop-audio-proxy
npm install
```
2. **Development Workflow:**
```bash
npm run dev # Start build in watch mode
npm run test:watch # Run tests in watch mode
npm run lint:fix # Auto-fix code style issues
```
3. **Before Committing:**
```bash
npm run build # Ensure clean build
npm test # Run all tests
npm run lint # Check code style
```
### CI/CD Pipeline
This project uses GitHub Actions for:
- ✅ Automated testing on Node.js 14, 16, 18, 20
- ✅ Code coverage reporting with Codecov
- ✅ ESLint and Prettier checks
- ✅ Build verification for all entry points
- ✅ Automated npm publishing on releases
## License
MIT License - see [LICENSE](LICENSE) for details.
<div align="center">
<sub>MIT · Bandonker</sub>
</div>
## Related Projects
- [Tauri](https://tauri.app) - Build smaller, faster, and more secure desktop applications
- [Electron](https://www.electronjs.org) - Build cross-platform desktop apps with web technologies
## Support
- [Report bugs](https://github.com/Bandonker/desktop-audio-proxy/issues)
- [Request features](https://github.com/Bandonker/desktop-audio-proxy/discussions)
- [Read the docs](https://github.com/Bandonker/desktop-audio-proxy/wiki)
<div align="center">
<sub>Made with ❤️ by Bandonker</sub>
</div>