
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
tonelisten-react-native
Advanced tools
ToneListen React Native Framework - Audio tone detection for React Native apps
A React Native framework for audio tone detection and in-app content delivery, based on patented tone technology. This library provides real-time dual-tone multi-frequency (DTMF) detection, bridge tone recognition, and automatic content display using the Goertzel algorithm, optimized for React Native applications.
npm install tonelisten-react-native
npm install react-native-audio-recorder-player react-native-permissions
After installation, run:
cd ios && pod install
If you updated to version 1.0.61 or later (iOS playback decode support), rebuild your iOS app:
This is required because native iOS code changed.
import React, { useEffect } from 'react';
import { ToneListenReactNative } from 'tonelisten-react-native';
const App = () => {
useEffect(() => {
const toneListener = new ToneListenReactNative({
clientId: '562', // Your client ID
apiKey: 'your-user-specific-api-key', // Get this from your admin dashboard
baseURL: 'https://api.toneadmin.com',
// CORS proxy not needed if API has proper CORS headers
debug: true,
enableInAppContent: true, // Enable automatic content display
});
// Initialize and start
toneListener.initialize().then(() => {
toneListener.start();
});
return () => {
toneListener.destroy();
};
}, []);
return <YourAppComponent />;
};
The framework includes an automatic content modal that displays images, videos, and other content when tone sequences are detected:
import React, { useEffect, useState } from 'react';
import { View } from 'react-native';
import ToneListenReactNative, {
InAppContentModal,
InAppContentPayload,
NotificationCenter
} from 'tonelisten-react-native';
const App = () => {
const [modalVisible, setModalVisible] = useState(false);
const [modalContent, setModalContent] = useState<InAppContentPayload | null>(null);
useEffect(() => {
// Set up automatic content display
const notificationCenter = NotificationCenter.getInstance();
notificationCenter.addObserver('InAppContentReceived', (content) => {
console.log('Content received:', content);
setModalContent(content);
setModalVisible(true);
});
// Initialize ToneListen
const toneListener = new ToneListenReactNative({
clientId: '562',
apiKey: 'your-api-key',
baseURL: 'https://api.toneadmin.com',
enableInAppContent: true, // This enables automatic content fetching
});
toneListener.initialize().then(() => {
toneListener.start();
});
return () => {
toneListener.destroy();
notificationCenter.removeObserver('InAppContentReceived');
};
}, []);
return (
<View style={{ flex: 1 }}>
{/* Your app content */}
{/* Automatic content modal */}
<InAppContentModal
visible={modalVisible}
content={modalContent}
onClose={() => setModalVisible(false)}
/>
</View>
);
};
If you prefer to build your own UI instead of using the automatic modal, you can listen for notifications and create custom components:
import React, { useEffect, useState } from 'react';
import { View, Text, Image, Modal, TouchableOpacity } from 'react-native';
import ToneListenReactNative, {
NotificationCenter,
InAppContentPayload
} from 'tonelisten-react-native';
const CustomContentDisplay = () => {
const [content, setContent] = useState<InAppContentPayload | null>(null);
const [visible, setVisible] = useState(false);
useEffect(() => {
const notificationCenter = NotificationCenter.getInstance();
notificationCenter.addObserver('InAppContentReceived', (receivedContent) => {
console.log('Custom UI received content:', receivedContent);
setContent(receivedContent);
setVisible(true);
});
return () => {
notificationCenter.removeObserver('InAppContentReceived');
};
}, []);
const renderContent = () => {
if (!content) return null;
switch (content.actionType) {
case 'image':
return (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, marginBottom: 10 }}>
{content.title}
</Text>
<Image
source={{ uri: content.actionUrl }}
style={{ width: 300, height: 200 }}
resizeMode="contain"
/>
</View>
);
case 'video':
return (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, marginBottom: 10 }}>
{content.title}
</Text>
<Text>Video: {content.actionUrl}</Text>
</View>
);
case 'webpage':
return (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, marginBottom: 10 }}>
{content.title}
</Text>
<Text>{content.actionUrl}</Text>
</View>
);
default:
return (
<View style={{ padding: 20 }}>
<Text>{content.title || 'Content received'}</Text>
</View>
);
}
};
return (
<Modal visible={visible} transparent animationType="slide">
<View style={{
flex: 1,
backgroundColor: 'rgba(0,0,0,0.8)',
justifyContent: 'center',
alignItems: 'center'
}}>
<View style={{
backgroundColor: 'white',
borderRadius: 10,
padding: 20,
maxWidth: '90%',
maxHeight: '80%'
}}>
{renderContent()}
<TouchableOpacity
style={{
backgroundColor: '#007AFF',
padding: 10,
borderRadius: 5,
marginTop: 20
}}
onPress={() => setVisible(false)}
>
<Text style={{ color: 'white', textAlign: 'center' }}>Close</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
);
};
const App = () => {
useEffect(() => {
const toneListener = new ToneListenReactNative({
clientId: '562',
apiKey: 'your-api-key',
baseURL: 'https://api.toneadmin.com',
enableInAppContent: true,
});
toneListener.initialize().then(() => {
toneListener.start();
});
return () => {
toneListener.destroy();
};
}, []);
return (
<View style={{ flex: 1 }}>
{/* Your app content */}
<CustomContentDisplay />
</View>
);
};
To detect tones embedded in your app’s media at full playback volume, use playback decode.
// When starting media playback in your app
await toneListener.startPlaybackDecode(mediaUrl); // returns true/false
// ...start your AV playback (video/audio) as normal...
// When pausing/stopping media
await toneListener.stopPlaybackDecode(); // Restores mic-based detection
Debug logs to expect when working:
If frames show "source -> mic" during playback, playback decode isn’t active.
import React from 'react';
import { View, Text, Button } from 'react-native';
import { useToneDetection } from 'tonelisten-react-native';
const ToneDetectionScreen = () => {
const {
isListening,
isInitialized,
lastSequence,
startListening,
stopListening
} = useToneDetection({
clientId: '562',
apiKey: 'your-api-key',
baseURL: 'https://api.toneadmin.com',
enableInAppContent: true,
onSequence: (event) => {
console.log('Sequence detected:', event.sequence);
}
});
return (
<View style={{ padding: 20 }}>
<Text>Status: {isListening ? 'Listening' : 'Stopped'}</Text>
{lastSequence && <Text>Last Sequence: {lastSequence}</Text>}
<Button
title={isListening ? 'Stop' : 'Start'}
onPress={isListening ? stopListening : startListening}
/>
</View>
);
};
The framework uses user-specific API keys to ensure only authorized users can access tone detection endpoints. Each user has their own unique API key that must be obtained from your admin dashboard.
clientId matches the user's companyconst toneListener = new ToneListenReactNative({
clientId: '562', // Must match the user's company ID
apiKey: 'a1b2c3d4e5f6...', // User-specific API key from admin dashboard
baseURL: 'https://api.toneadmin.com',
debug: true,
});
interface ToneListenReactNativeConfig {
// Audio Configuration
sampleRate?: number; // Audio sample rate (default: 44100)
bufferSize?: number; // Audio buffer size (default: 4800)
tolerance?: number; // Frequency matching tolerance in Hz (default: 5)
bridgeTolerance?: number; // Bridge tone tolerance in Hz (default: 10)
minPower?: number; // Minimum power threshold (default: 0.01)
// API Configuration
clientId?: string; // Your client ID
apiKey?: string; // Your API key
baseURL?: string; // API base URL (default: 'https://api.toneadmin.com')
corsProxyBaseURL?: string; // CORS proxy URL for web platforms
useProxyOnWeb?: boolean; // Use proxy on web platforms (default: true)
// Behavior Configuration
autoStart?: boolean; // Start automatically (default: false)
debug?: boolean; // Enable debug logging (default: false)
enableInAppContent?: boolean; // Enable automatic content display (default: false)
// Callbacks
onSequence?: (event: ToneSequenceEvent) => void;
onDualTone?: (result: DualToneResult) => void;
onBridgeTone?: (result: BridgeToneResult) => void;
onError?: (error: Error) => void;
onPermissionDenied?: () => void;
onPresentContent?: (content: InAppContentPayload) => void; // Custom content handler
}
interface InAppContentModalProps {
visible: boolean; // Whether modal is visible
content?: InAppContentPayload | null; // Content to display
onClose: () => void; // Close handler
}
interface InAppContentPayload {
actionType: 'image' | 'video' | 'webpage' | 'text'; // Content type
actionUrl?: string; // URL for the content
actionData?: string; // Additional data
title?: string; // Content title
}
Main class for tone detection and content delivery.
initialize(): Initialize the tone detection systemstart(): Start listening for tonesstop(): Stop listening for tonesstartPlaybackDecode(url: string): iOS only. Start decoding media for detection while keeping device playback loudstopPlaybackDecode(): iOS only. Stop media decoding and return to mic-based detectionupdateConfig(config): Update configurationgetState(): Get current detection statedestroy(): Clean up resourcesTLRN_AudioFrame payload now includes an optional source field on iOS:{
sampleRate: number;
buffer: number[]; // Float32 PCM
source?: 'mic' | 'playback';
}
Singleton class for handling notifications between framework and app.
getInstance(): Get singleton instanceaddObserver(name, callback): Add notification observerremoveObserver(name, callback?): Remove notification observerpost(name, object?, userInfo?): Post notification'InAppContentReceived': Fired when content is received from APIReact hook for easy integration.
isListening: Whether currently listeningisInitialized: Whether system is initializederror: Current error statelastSequence: Last detected sequencelastDualTone: Last detected dual tonelastBridgeTone: Last detected bridge tonestartListening(): Start listening functionstopListening(): Stop listening functionupdateConfig(config): Update configuration functiongetState(): Get current state functionThe framework supports various content types that can be displayed automatically:
{
actionType: 'image',
actionUrl: 'https://example.com/image.jpg',
title: 'Image Title'
}
{
actionType: 'video',
actionUrl: 'https://example.com/video.mp4',
title: 'Video Title'
}
{
actionType: 'webpage',
actionUrl: 'https://example.com/page',
title: 'Webpage Title'
}
{
actionType: 'text',
actionData: 'Your text content here',
title: 'Text Title'
}
The framework requires microphone and location permissions for full functionality. Make sure to add the necessary permissions to your app:
<!-- Microphone permission for tone detection -->
<key>NSMicrophoneUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
<!-- Location permissions for enhanced tone detection features -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to provide location-based content when tones are detected.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location access to provide location-based content when tones are detected.</string>
<!-- Microphone permission for tone detection -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Location permissions for enhanced tone detection features -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Internet permission for API calls -->
<uses-permission android:name="android.permission.INTERNET" />
CORS (Cross-Origin Resource Sharing) is a browser security feature that blocks requests between different domains. When your React Native app runs on web platforms, browsers enforce CORS policies that can prevent API calls to your ToneListen server.
The framework includes built-in CORS proxy support. Simply configure your proxy URL:
const toneListener = new ToneListenReactNative({
clientId: '562',
apiKey: 'your-api-key',
baseURL: 'https://api.toneadmin.com',
corsProxyBaseURL: 'https://proxy.toneadmin.com', // Public CORS proxy
useProxyOnWeb: true, // Only use proxy on web platforms
});
If you prefer to run your own proxy, you can use a simple Node.js server:
// cors-proxy.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const cors = require('cors');
const app = express();
// Enable CORS for all routes
app.use(cors({
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-api-key']
}));
// Proxy requests to your API
app.use('/api', createProxyMiddleware({
target: 'https://api.toneadmin.com',
changeOrigin: true,
pathRewrite: {
'^/api': '' // Remove /api prefix
}
}));
app.listen(3001, () => {
console.log('CORS proxy running on port 3001');
});
Configure your API server to include proper CORS headers:
// Express.js example
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*'); // Or specific domains
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, x-api-key');
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
The framework automatically detects the platform and only uses the proxy when running on web platforms.
# Install dependencies
npm install
# Build the library
npm run build
# Run tests
npm test
# Lint code
npm run lint
clientId, apiKey, and baseURL are correctNotificationCenter.getInstance() (singleton)actionType and actionUrldebug: true to see detailed logsenableInAppContent: true is setstartPlaybackDecode(url) before starting media, and stopPlaybackDecode() when stopping. Check logs for "AudioFrame source -> playback". Ensure you performed a clean Xcode rebuild after installing 1.0.61+.Playback decode downloads remote media with URLSession. Prefer HTTPS media URLs. If you must use HTTP or older TLS, add an ATS exception in your app Info.plist for the media domain.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>your-media-domain.com</key>
<dict>
<key>NSIncludesSubdomains</key><true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key><true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key><string>TLSv1.2</string>
</dict>
</dict>
<!-- Keep arbitrary loads off unless required -->
<key>NSAllowsArbitraryLoads</key><false/>
<key>NSAllowsArbitraryLoadsForMedia</key><false/>
<key>NSAllowsArbitraryLoadsInWebContent</key><false/>
<key>NSAllowsLocalNetworking</key><true/>
</dict>
This React Native framework is based on the iOS ToneListen framework version 19, maintaining compatibility with the same frequency tables and detection algorithms while adapting to React Native's cross-platform constraints and capabilities.
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
For issues and questions, please use the GitHub Issues page.
FAQs
ToneListen React Native Framework - Audio tone detection for React Native apps
The npm package tonelisten-react-native receives a total of 23 weekly downloads. As such, tonelisten-react-native popularity was classified as not popular.
We found that tonelisten-react-native demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.