# Audio Recorder

> A comprehensive audio recording component with real-time waveform visualization, quality settings, and built-in playback.

**BNA UI** — a React Native / Expo component library.
These components render through `react-native`, not the DOM: there are no HTML
elements, no Tailwind classes and no Radix primitives. Source is copied into your
project and imported through `@/components/ui/*`, `@/components/charts/*`,
`@/hooks/*` and `@/theme/*`. Colours come from the `useColor` hook rather than
hardcoded hex; sizing tokens (`HEIGHT`, `FONT_SIZE`, `BORDER_RADIUS`, `CORNERS`)
come from `@/theme/globals`.

- Docs: https://ui.ahmedbna.com/docs/components/audio-recorder
- Markdown: https://ui.ahmedbna.com/docs/components/audio-recorder.md
- Structured JSON (props, usage, source, examples): https://ui.ahmedbna.com/r/ai/audio-recorder.json
- Install payload (source plus every file it imports): https://ui.ahmedbna.com/r/audio-recorder.json
- Install: `npx bna-ui add audio-recorder`
- npm dependencies: `expo-asset`, `expo-audio`, `expo-haptics`, `lucide-react-native`, `react-native-gesture-handler`, `react-native-reanimated`, `react-native-svg`, `react-native-worklets`
- Registry dependencies: `mode-provider`, `useColorScheme`, `colors`, `useColor`, `globals`, `useHaptics`, `text`, `view`, `icon`, `spinner`, `button`, `progress`, `audio-waveform`, `audio-player`
- Preview recording: https://demo.ahmedbna.com/0031-audio-recorder-demo.MP4

---

**Example:** A full-featured audio recorder with real-time waveform and playback

```tsx
// components/demo/audio-recorder/audio-recorder-demo.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';

export function AudioRecorderDemo() {
  const handleRecordingComplete = (uri: string) => {
    console.log('Recording saved to:', uri);
  };

  const handleRecordingStart = () => {
    console.log('Recording started');
  };

  const handleRecordingStop = () => {
    console.log('Recording stopped');
  };

  return (
    <AudioRecorder
      quality='high'
      showWaveform={true}
      showTimer={true}
      maxDuration={300} // 5 minutes
      onRecordingComplete={handleRecordingComplete}
      onRecordingStart={handleRecordingStart}
      onRecordingStop={handleRecordingStop}
    />
  );
}
```

## Installation

### CLI

```bash
npx bna-ui add audio-recorder
```

### Manual

**1.** Install the following dependencies:

```bash
npx expo install expo-audio lucide-react-native react-native-reanimated
```

**2.** Copy and paste the following code into your project.

```tsx
// components/ui/audio-recorder.tsx
import { AudioPlayer } from '@/components/ui/audio-player';
import { AudioWaveform } from '@/components/ui/audio-waveform';
import { Button } from '@/components/ui/button';
import { Text } from '@/components/ui/text';
import { useColor } from '@/hooks/useColor';
import { BORDER_RADIUS } from '@/theme/globals';
import {
  AudioModule,
  RecordingOptions,
  RecordingPresets,
  useAudioRecorder,
} from 'expo-audio';
import { Circle, Download, Mic, Square, Trash2 } from 'lucide-react-native';
import React, { useEffect, useRef, useState } from 'react';
import { Alert, Platform, StyleSheet, View, ViewStyle } from 'react-native';
import Animated, {
  cancelAnimation,
  Easing,
  useAnimatedStyle,
  useSharedValue,
  withRepeat,
  withTiming,
} from 'react-native-reanimated';

export interface AudioRecorderProps {
  style?: ViewStyle;
  quality?: 'high' | 'low';
  showWaveform?: boolean;
  showTimer?: boolean;
  maxDuration?: number; // in seconds
  onRecordingComplete?: (uri: string) => void;
  onRecordingStart?: () => void;
  onRecordingStop?: () => void;
  customRecordingOptions?: RecordingOptions;
}

export function AudioRecorder({
  style,
  quality = 'high',
  showWaveform = true,
  showTimer = true,
  maxDuration,
  onRecordingComplete,
  onRecordingStart,
  onRecordingStop,
  customRecordingOptions,
}: AudioRecorderProps) {
  const recordingOptions =
    customRecordingOptions ||
    (quality === 'high'
      ? RecordingPresets.HIGH_QUALITY
      : RecordingPresets.LOW_QUALITY);

  const recorder = useAudioRecorder(recordingOptions);
  const [permissionGranted, setPermissionGranted] = useState(false);
  const [duration, setDuration] = useState(0);
  const [recordingUri, setRecordingUri] = useState<string | null>(null);
  const [isRecording, setIsRecording] = useState(false);

  // Waveform data for real-time visualization
  const [waveformData, setWaveformData] = useState<number[]>(
    Array.from({ length: 30 }, () => 0.2)
  );

  // Theme colors
  const primaryColor = useColor('primary');
  const secondaryColor = useColor('secondary');
  const textColor = useColor('text');
  const mutedColor = useColor('textMuted');
  const redColor = useColor('red');
  const greenColor = useColor('green');

  // Animation values using react-native-reanimated
  const recordingPulse = useSharedValue(1);
  const durationInterval = useRef<ReturnType<typeof setTimeout> | null>(null);
  const meteringInterval = useRef<ReturnType<typeof setTimeout> | null>(null);

  // Request permissions on mount
  useEffect(() => {
    (async () => {
      try {
        const status = await AudioModule.requestRecordingPermissionsAsync();
        setPermissionGranted(status.granted);

        if (!status.granted) {
          Alert.alert(
            'Permission Required',
            'Please grant microphone permission to record audio.',
            [{ text: 'OK' }]
          );
        }
      } catch (error) {
        console.error('Error requesting permissions:', error);
        setPermissionGranted(false);
      }
    })();
  }, []);

  // Recording pulse animation using react-native-reanimated
  useEffect(() => {
    if (isRecording) {
      // Start the pulse animation
      recordingPulse.value = withRepeat(
        withTiming(1.2, { duration: 600, easing: Easing.inOut(Easing.ease) }),
        -1, // Infinite loop
        true // Reverse the animation (yoyo effect)
      );
    } else {
      // Stop the animation and reset the scale
      cancelAnimation(recordingPulse);
      recordingPulse.value = withTiming(1, { duration: 300 });
    }

    return () => {
      // Ensure animation is cancelled on unmount
      cancelAnimation(recordingPulse);
    };
  }, [isRecording, recordingPulse]);

  // Create animated style for the record button
  const animatedRecordButtonStyle = useAnimatedStyle(() => {
    return {
      transform: [{ scale: recordingPulse.value }],
    };
  });

  // Real-time waveform updates during recording
  useEffect(() => {
    if (isRecording) {
      meteringInterval.current = setInterval(async () => {
        try {
          // Try to get metering data from recorder
          const status = recorder.getStatus();
          let level = 0.3; // Default fallback level

          if (status && typeof status.metering === 'number') {
            // Convert dB to normalized value (typical range -160 to 0 dB)
            const dbLevel = status.metering;
            level = Math.max(0.1, Math.min(1.0, (dbLevel + 50) / 50));
          } else {
            // Generate more realistic simulated audio levels
            const time = Date.now() / 1000;
            const baseLevel = 0.3 + Math.sin(time * 2) * 0.2; // Sine wave base
            const variation = (Math.random() - 0.5) * 0.4; // Random variation
            const spike = Math.random() < 0.1 ? Math.random() * 0.3 : 0; // Occasional spikes
            level = Math.max(0.1, Math.min(0.9, baseLevel + variation + spike));
          }

          // Update waveform data by shifting array and adding new value
          setWaveformData((prevData) => {
            const newData = [...prevData.slice(1), level];
            return newData;
          });
        } catch (error) {
          console.log('Using simulated audio data');
          // Fallback to realistic simulated data
          const time = Date.now() / 1000;
          const baseLevel = 0.4 + Math.sin(time * 3) * 0.2;
          const noise = (Math.random() - 0.5) * 0.3;
          const level = Math.max(0.15, Math.min(0.85, baseLevel + noise));

          setWaveformData((prevData) => [...prevData.slice(1), level]);
        }
      }, 80); // Update every 80ms for smooth animation

      return () => {
        if (meteringInterval.current) {
          clearInterval(meteringInterval.current);
          meteringInterval.current = null;
        }
      };
    } else {
      // Reset to quiet state when not recording
      setWaveformData(Array.from({ length: 30 }, () => 0.2));

      if (meteringInterval.current) {
        clearInterval(meteringInterval.current);
        meteringInterval.current = null;
      }
    }
  }, [isRecording, recorder]);

  // Auto-stop recording when max duration is reached
  useEffect(() => {
    if (maxDuration && duration >= maxDuration && isRecording) {
      handleStopRecording();
    }
  }, [duration, maxDuration, isRecording]);

  const startDurationTimer = () => {
    setDuration(0);
    durationInterval.current = setInterval(() => {
      setDuration((prev) => prev + 0.1);
    }, 100);
  };

  const stopDurationTimer = () => {
    if (durationInterval.current) {
      clearInterval(durationInterval.current);
      durationInterval.current = null;
    }
  };

  const handleStartRecording = async () => {
    if (!permissionGranted) {
      Alert.alert(
        'Permission Required',
        'Microphone permission is required to record audio.'
      );
      return;
    }

    try {
      console.log('Starting recording...');
      setRecordingUri(null);
      setIsRecording(true);
      startDurationTimer();

      // Enable metering in recording options
      const meteringOptions = {
        ...recordingOptions,
        isMeteringEnabled: true,
      };

      await recorder.prepareToRecordAsync(meteringOptions);
      await recorder.record();

      onRecordingStart?.();
      console.log('Recording started successfully');
    } catch (error) {
      console.error('Error starting recording:', error);
      setIsRecording(false);
      stopDurationTimer();
      Alert.alert('Error', 'Failed to start recording. Please try again.');
    }
  };

  const handleStopRecording = async () => {
    try {
      console.log('Stopping recording...');
      setIsRecording(false);
      stopDurationTimer();

      await recorder.stop();
      const uri = recorder.uri;
      console.log('Recording stopped, URI:', uri);

      if (uri) {
        setRecordingUri(uri);
        onRecordingComplete?.(uri);
      }

      onRecordingStop?.();
    } catch (error) {
      console.error('Error stopping recording:', error);
      Alert.alert('Error', 'Failed to stop recording. Please try again.');
    }
  };

  const handleDeleteRecording = () => {
    Alert.alert(
      'Delete Recording',
      'Are you sure you want to delete this recording?',
      [
        { text: 'Cancel', style: 'cancel' },
        {
          text: 'Delete',
          style: 'destructive',
          onPress: () => {
            setRecordingUri(null);
            setDuration(0);
          },
        },
      ]
    );
  };

  const handleSaveRecording = () => {
    if (recordingUri && onRecordingComplete) {
      onRecordingComplete(recordingUri);
    }
  };

  const formatTime = (seconds: number) => {
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    const centisecs = Math.floor((seconds % 1) * 100);
    return `${mins}:${secs.toString().padStart(2, '0')}.${centisecs
      .toString()
      .padStart(2, '0')}`;
  };

  if (!permissionGranted) {
    return (
      <View
        style={[styles.container, { backgroundColor: secondaryColor }, style]}
      >
        <Text variant='body' style={{ color: textColor, textAlign: 'center' }}>
          Microphone permission is required to record audio.
        </Text>
      </View>
    );
  }

  return (
    <View
      style={[styles.container, { backgroundColor: secondaryColor }, style]}
    >
      {recordingUri && !isRecording ? (
        <View style={{ alignItems: 'center' }}>
          <AudioPlayer
            source={{ uri: recordingUri }}
            showControls={true}
            showWaveform={true}
            showTimer={true}
            autoPlay={false}
          />
          <View style={styles.playbackControls}>
            <Button
              variant='outline'
              size='icon'
              onPress={handleDeleteRecording}
              style={styles.controlButton}
              accessibilityLabel='Delete recording'
            >
              <Trash2 size={20} color={redColor} />
            </Button>

            <Button
              variant='default'
              onPress={handleSaveRecording}
              style={[styles.saveButton, { backgroundColor: greenColor }]}
              accessibilityLabel='Save recording'
            >
              <Download size={20} color='white' />
              <Text style={{ color: 'white', marginLeft: 8 }}>Save</Text>
            </Button>
          </View>
        </View>
      ) : (
        <View>
          {/* Recording Status */}
          {isRecording ? (
            <View style={styles.recordingStatus}>
              <View style={styles.recordingIndicator}>
                <Circle size={8} color={redColor} fill={redColor} />
                <Text
                  variant='caption'
                  style={{ color: redColor, marginLeft: 8 }}
                >
                  Recording
                </Text>
              </View>
            </View>
          ) : (
            <View style={{ height: 36 }} />
          )}
          {/* Waveform Visualization */}
          {showWaveform && (
            <View style={styles.waveformContainer}>
              <AudioWaveform
                data={waveformData}
                isPlaying={false} // Disable built-in animation
                progress={0}
                height={60}
                barCount={30}
                barWidth={4}
                barGap={2}
                activeColor={isRecording ? redColor : primaryColor}
                inactiveColor={mutedColor}
                animated={false} // Disable built-in animation to use real-time data
              />
            </View>
          )}
          {/* Timer */}
          {showTimer && (
            <View style={styles.timerContainer}>
              <Text
                variant='title'
                style={{
                  color: isRecording ? redColor : textColor,
                  fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
                }}
              >
                {formatTime(duration)}
              </Text>
              {maxDuration && (
                <Text variant='caption' style={{ color: mutedColor }}>
                  Max: {formatTime(maxDuration)}
                </Text>
              )}
            </View>
          )}

          {/* Controls */}
          <View style={styles.controlsContainer}>
            {!isRecording && !recordingUri && (
              <Animated.View style={animatedRecordButtonStyle}>
                <Button
                  variant='default'
                  size='lg'
                  onPress={handleStartRecording}
                  style={[styles.recordButton, { backgroundColor: redColor }]}
                  accessibilityLabel='Start recording'
                >
                  <Mic size={32} color='white' />
                </Button>
              </Animated.View>
            )}

            {isRecording && (
              <Button
                variant='default'
                size='lg'
                onPress={handleStopRecording}
                style={[styles.stopButton, { backgroundColor: redColor }]}
                accessibilityLabel='Stop recording'
              >
                <Square size={32} fill='white' color='white' />
              </Button>
            )}
          </View>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    borderRadius: BORDER_RADIUS,
    padding: 20,
    alignItems: 'center',
  },
  recordingStatus: {
    height: 36,
  },
  recordingIndicator: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  waveformContainer: {
    alignItems: 'center',
    marginBottom: 16,
  },
  timerContainer: {
    alignItems: 'center',
    marginBottom: 20,
  },
  controlsContainer: {
    alignItems: 'center',
    marginBottom: 12,
  },
  recordButton: {
    width: 80,
    height: 80,
    borderRadius: 40,
  },
  stopButton: {
    width: 80,
    height: 80,
    borderRadius: 40,
  },
  playbackControls: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 16,
    marginTop: 16,
  },
  controlButton: {
    width: 48,
    height: 48,
  },
  saveButton: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 24,
  },
});
```

**3.** Update the import paths to match your project setup.

## Usage

```tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';
```

### Basic Usage

```tsx
function MyComponent() {
  return (
    <AudioRecorder
      quality='high'
      showWaveform={true}
      showTimer={true}
      onRecordingComplete={(uri) => {
        console.log('Recording saved to:', uri);
      }}
    />
  );
}
```

### With Custom Settings

```tsx
<AudioRecorder
  quality='high'
  maxDuration={300} // 5 minutes
  showWaveform={true}
  showTimer={true}
  onRecordingStart={() => console.log('Recording started')}
  onRecordingStop={() => console.log('Recording stopped')}
  onRecordingComplete={(uri) => {
    // Handle the recorded audio file
    handleAudioFile(uri);
  }}
/>
```

### Low Quality for Voice Notes

```tsx
<AudioRecorder
  quality='low'
  maxDuration={60} // 1 minute limit
  showWaveform={false}
  customRecordingOptions={{
    ...RecordingPresets.LOW_QUALITY,
    bitRate: 32000, // Very low bitrate for voice
  }}
/>
```

## Examples

#### Default

**Example:** A complete audio recorder with all features enabled

```tsx
// components/demo/audio-recorder/audio-recorder-demo.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';

export function AudioRecorderDemo() {
  const handleRecordingComplete = (uri: string) => {
    console.log('Recording saved to:', uri);
  };

  const handleRecordingStart = () => {
    console.log('Recording started');
  };

  const handleRecordingStop = () => {
    console.log('Recording stopped');
  };

  return (
    <AudioRecorder
      quality='high'
      showWaveform={true}
      showTimer={true}
      maxDuration={300} // 5 minutes
      onRecordingComplete={handleRecordingComplete}
      onRecordingStart={handleRecordingStart}
      onRecordingStop={handleRecordingStop}
    />
  );
}
```

#### Voice Notes

**Example:** Optimized recorder for quick voice notes with time limit

```tsx
// components/demo/audio-recorder/audio-recorder-voice.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';

export function AudioRecorderVoice() {
  const handleRecordingComplete = (uri: string) => {
    // Here you could add the voice note to a list or send it
    console.log('Voice note saved:', uri);
  };

  return (
    <AudioRecorder
      quality='low'
      showWaveform={true}
      showTimer={true}
      maxDuration={120} // 2 minutes for voice notes
      onRecordingComplete={handleRecordingComplete}
    />
  );
}
```

#### High Quality

**Example:** High-quality recorder for music or professional audio

```tsx
// components/demo/audio-recorder/audio-recorder-hq.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';
import { RecordingPresets } from 'expo-audio';

export function AudioRecorderHQ() {
  const handleRecordingComplete = (uri: string) => {
    console.log('HQ recording saved:', uri);
  };

  return (
    <AudioRecorder
      quality='high'
      showWaveform={true}
      showTimer={true}
      maxDuration={1800} // 30 minutes
      customRecordingOptions={{
        ...RecordingPresets.HIGH_QUALITY,
        sampleRate: 48000,
        bitRate: 192000,
        numberOfChannels: 2,
      }}
      onRecordingComplete={handleRecordingComplete}
    />
  );
}
```

#### Minimal

**Example:** Minimal recorder without waveform visualization

```tsx
// components/demo/audio-recorder/audio-recorder-minimal.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';

export function AudioRecorderMinimal() {
  const handleRecordingComplete = (uri: string) => {
    console.log('Your audio has been recorded.', uri);
  };

  return (
    <AudioRecorder
      quality='low'
      showWaveform={false}
      showTimer={true}
      maxDuration={60} // 1 minute
      onRecordingComplete={handleRecordingComplete}
    />
  );
}
```

#### Custom Styled

**Example:** Audio recorder with custom styling and branding

```tsx
// components/demo/audio-recorder/audio-recorder-styled.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';

export function AudioRecorderStyled() {
  const handleRecordingComplete = (uri: string) => {
    console.log('🎵 Recording Complete', uri);
  };

  return (
    <AudioRecorder
      quality='high'
      showWaveform={true}
      showTimer={true}
      maxDuration={300}
      style={{
        backgroundColor: 'transparent',
        borderWidth: 2,
        borderColor: 'red',
        borderRadius: 20,
        padding: 24,
        shadowColor: 'red',
        shadowOffset: { width: 0, height: 4 },
        shadowOpacity: 0.1,
        shadowRadius: 12,
        elevation: 8,
      }}
      onRecordingComplete={handleRecordingComplete}
    />
  );
}
```

#### Callbacks Recorder

**Example:** Recorder with comprehensive callback handling

```tsx
// components/demo/audio-recorder/audio-recorder-callbacks.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useState } from 'react';

export function AudioRecorderCallbacks() {
  const [status, setStatus] = useState('Ready to record');
  const [recordingCount, setRecordingCount] = useState(0);

  const handleRecordingStart = () => {
    setStatus('🔴 Recording in progress...');
    console.log('Recording started');
  };

  const handleRecordingStop = () => {
    setStatus('✅ Recording stopped');
    console.log('Recording stopped');
  };

  const handleRecordingComplete = (uri: string) => {
    setRecordingCount((prev) => prev + 1);
    setStatus(`📁 Recording #${recordingCount + 1} saved`);

    // Reset status after 3 seconds
    setTimeout(() => setStatus('Ready to record'), 3000);
  };

  const getOrdinalSuffix = (num: number) => {
    const lastDigit = num % 10;
    const lastTwoDigits = num % 100;

    if (lastTwoDigits >= 11 && lastTwoDigits <= 13) return 'th';
    if (lastDigit === 1) return 'st';
    if (lastDigit === 2) return 'nd';
    if (lastDigit === 3) return 'rd';
    return 'th';
  };

  return (
    <View style={{ width: '100%' }}>
      <Text
        variant='body'
        style={{ marginBottom: 16, textAlign: 'center', fontWeight: '500' }}
      >
        Status: {status}
      </Text>

      <AudioRecorder
        quality='high'
        showWaveform={true}
        showTimer={true}
        maxDuration={180} // 3 minutes
        onRecordingStart={handleRecordingStart}
        onRecordingStop={handleRecordingStop}
        onRecordingComplete={handleRecordingComplete}
      />

      {recordingCount > 0 && (
        <Text variant='caption' style={{ marginTop: 12, textAlign: 'center' }}>
          Total recordings: {recordingCount}
        </Text>
      )}
    </View>
  );
}
```

#### Cloud Integration Recorder

**Example:** Recorder with cloud storage integration for saving recordings

```tsx
// components/demo/audio-recorder/audio-recorder-cloud.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
import { ActivityIndicator } from 'react-native';

export function AudioRecorderCloud() {
  const [uploading, setUploading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState(0);

  const simulateCloudUpload = async (uri: string): Promise<string> => {
    return new Promise((resolve) => {
      setUploading(true);
      setUploadProgress(0);

      const interval = setInterval(() => {
        setUploadProgress((prev) => {
          if (prev >= 100) {
            clearInterval(interval);
            setUploading(false);
            resolve(
              `https://cloud-storage.example.com/audio/${Date.now()}.m4a`
            );
            return 100;
          }
          return prev + 10;
        });
      }, 200);
    });
  };

  const handleRecordingComplete = async (uri: string) => {
    try {
      const cloudUrl = await simulateCloudUpload(uri);

      console.log(`Recording uploaded to cloud storage!\n\nURL: ${cloudUrl}`);

      setUploadProgress(0);
    } catch (error) {
      console.log('Failed to upload recording to cloud storage.');

      setUploading(false);
      setUploadProgress(0);
    }
  };

  return (
    <View style={{ width: '100%' }}>
      <AudioRecorder
        quality='high'
        showWaveform={true}
        showTimer={true}
        maxDuration={600} // 10 minutes
        onRecordingComplete={handleRecordingComplete}
      />

      {uploading && (
        <View style={{ marginTop: 16, alignItems: 'center' }}>
          <ActivityIndicator size='small' />
          <Text variant='caption' style={{ marginTop: 8 }}>
            Uploading... {uploadProgress}%
          </Text>
        </View>
      )}
    </View>
  );
}
```

#### Interview Mode Recorder

**Example:** Interview mode recorder

```tsx
// components/demo/audio-recorder/audio-recorder-interview.tsx
import { AudioRecorder } from '@/components/ui/audio-recorder';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { RecordingPresets } from 'expo-audio';
import React, { useState } from 'react';
import { Alert, StyleSheet } from 'react-native';

export function AudioRecorderInterview() {
  const [interviewTitle, setInterviewTitle] = useState('');
  const [isRecording, setIsRecording] = useState(false);

  const handleRecordingStart = () => {
    setIsRecording(true);
    const title = `Interview ${new Date().toLocaleDateString()}`;
    setInterviewTitle(title);
  };

  const handleRecordingStop = () => {
    setIsRecording(false);
  };

  const handleRecordingComplete = (uri: string) => {
    Alert.alert(
      '🎤 Interview Complete',
      `"${interviewTitle}" has been recorded and saved.\n\nDuration: Available in file metadata\nQuality: High (48kHz, Stereo)`,
      [{ text: 'Save & Exit' }]
    );
  };

  return (
    <View style={{ width: '100%' }}>
      <View style={styles.interviewHeader}>
        <Text variant='title' style={styles.interviewTitle}>
          {interviewTitle || 'Ready for Interview'}
        </Text>

        <View
          style={[styles.statusBadge, isRecording && styles.recordingBadge]}
        >
          <Text
            style={[styles.statusText, isRecording && styles.recordingText]}
          >
            {isRecording ? '🔴 LIVE' : '⏸️ READY'}
          </Text>
        </View>
      </View>

      <AudioRecorder
        quality='high'
        showWaveform={true}
        showTimer={true}
        maxDuration={7200} // 2 hours for long interviews
        customRecordingOptions={{
          ...RecordingPresets.HIGH_QUALITY,
          sampleRate: 48000,
          bitRate: 128000,
          numberOfChannels: 2,
          isMeteringEnabled: true,
        }}
        onRecordingStart={handleRecordingStart}
        onRecordingStop={handleRecordingStop}
        onRecordingComplete={handleRecordingComplete}
      />

      <Text variant='caption' style={{ marginTop: 12, textAlign: 'center' }}>
        Maximum duration: 2 hours • High quality stereo recording
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  interviewHeader: {
    marginBottom: 16,
    alignItems: 'center',
  },
  interviewTitle: {
    marginBottom: 8,
    textAlign: 'center',
  },
  statusBadge: {
    paddingHorizontal: 12,
    paddingVertical: 4,
    borderRadius: 12,
    backgroundColor: '#f3f4f6',
  },
  recordingBadge: {
    backgroundColor: '#fef2f2',
  },
  statusText: {
    fontSize: 12,
    fontWeight: '600',
    color: '#6b7280',
  },
  recordingText: {
    color: '#dc2626',
  },
});
```

## API Reference

### AudioRecorder

The main AudioRecorder component.

| Prop                     | Type                    | Default  | Description                                           |
| ------------------------ | ----------------------- | -------- | ----------------------------------------------------- |
| `style`                  | `ViewStyle`             | -        | Additional styles for the recorder container.         |
| `quality`                | `'high' \| 'low'`       | `'high'` | Recording quality preset.                             |
| `showWaveform`           | `boolean`               | `true`   | Whether to show real-time waveform visualization.     |
| `showTimer`              | `boolean`               | `true`   | Whether to show the recording timer.                  |
| `maxDuration`            | `number`                | -        | Maximum recording duration in seconds.                |
| `onRecordingComplete`    | `(uri: string) => void` | -        | Callback fired when recording is completed and saved. |
| `onRecordingStart`       | `() => void`            | -        | Callback fired when recording starts.                 |
| `onRecordingStop`        | `() => void`            | -        | Callback fired when recording stops.                  |
| `customRecordingOptions` | `RecordingOptions`      | -        | Custom recording options to override presets.         |

### Recording Quality Presets

The component includes two built-in quality presets:

#### High Quality

- Sample Rate: 44,100 Hz
- Bit Rate: 128,000 bps
- Channels: 2 (Stereo)
- Format: AAC
- Best for: Music, professional recordings

#### Low Quality

- Sample Rate: 22,050 Hz
- Bit Rate: 64,000 bps
- Channels: 1 (Mono)
- Format: AAC
- Best for: Voice notes, quick recordings

### Custom Recording Options

```tsx
type RecordingOptions = {
  sampleRate?: number;
  bitRate?: number;
  numberOfChannels?: number;
  format?: string;
  isMeteringEnabled?: boolean;
};
```

## Features

### Real-time Waveform Visualization

The recorder shows live audio levels:

- 30 bars representing real-time audio amplitude
- Smooth animation updates every 80ms
- Uses actual microphone input when available
- Falls back to realistic simulated data
- Color changes based on recording state

### Recording Controls

Intuitive recording interface:

- **Record Button**: Large, prominent button to start recording
- **Stop Button**: Clear square icon to stop recording
- **Animated Feedback**: Pulsing animation during recording
- **Visual Indicators**: Recording status with red dot

### Built-in Playback

After recording, users can:

- **Play/Pause**: Review the recorded audio
- **Seek**: Navigate through the recording using waveform or progress bar
- **Save**: Confirm and save the recording
- **Delete**: Discard the recording and start over

### Timer Display

Precision timing information:

- Real-time recording duration
- Centisecond accuracy (MM:SS.CC format)
- Maximum duration indicator when set
- Monospace font for consistent display

## Permissions

The AudioRecorder automatically handles microphone permissions:

- Requests permission on first use
- Shows helpful error messages if denied
- Provides clear instructions for enabling permissions
- Gracefully handles permission changes

### iOS Permissions

Add to your `Info.plist`:

```xml
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to the microphone to record audio.</string>
```

### Android Permissions

Add to your `AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.RECORD_AUDIO" />
```

## Platform Support

### iOS

- Native audio recording with hardware integration
- Automatic audio session management
- Background recording support
- Hardware control integration

### Android

- Optimized audio capture
- Proper lifecycle management
- Background recording with proper permissions
- Audio focus handling

### Web

- MediaRecorder API integration
- Browser compatibility fallbacks
- Microphone access handling

## Accessibility

The AudioRecorder follows accessibility standards:

- Screen reader announcements for recording state
- Clear button labels and roles
- Keyboard navigation support
- High contrast mode support
- Proper focus management

## Performance Optimization

The component is optimized for:

- **Memory Efficiency**: Proper cleanup of audio resources
- **Battery Life**: Efficient audio processing and minimal background activity
- **Storage**: Compressed audio formats to minimize file size
- **Responsiveness**: Non-blocking UI during recording operations

## Theming

Automatic theme integration:

- Recording button uses destructive/red theme color
- Background adapts to secondary theme color
- Text colors follow theme hierarchy
- Supports light and dark modes
- Waveform colors match theme accent

## Advanced Usage

### Custom Recording Configuration

```tsx
<AudioRecorder
  customRecordingOptions={{
    sampleRate: 48000,
    bitRate: 192000,
    numberOfChannels: 2,
    format: 'wav',
    isMeteringEnabled: true,
  }}
  onRecordingComplete={(uri) => {
    // Handle high-quality WAV file
    uploadAudioFile(uri);
  }}
/>
```

### Integration with Cloud Storage

```tsx
function CloudRecorder() {
  const handleRecordingComplete = async (uri: string) => {
    try {
      // Upload to cloud storage
      const downloadUrl = await uploadToFirebase(uri);

      // Save reference in database
      await saveAudioRecord({
        url: downloadUrl,
        timestamp: new Date(),
        duration: recordingDuration,
      });

      Alert.alert('Success', 'Recording saved to cloud!');
    } catch (error) {
      Alert.alert('Error', 'Failed to save recording');
    }
  };

  return (
    <AudioRecorder
      quality='high'
      maxDuration={600} // 10 minutes
      onRecordingComplete={handleRecordingComplete}
    />
  );
}
```

### Voice Note Integration

```tsx
<AudioRecorder
  quality='low'
  maxDuration={120} // 2 minutes for voice notes
  showWaveform={false} // Simplified UI
  onRecordingComplete={(uri) => {
    // Add to voice notes collection
    addVoiceNote({
      audioUri: uri,
      createdAt: new Date(),
      transcription: null, // Add speech-to-text later
    });
  }}
/>
```

## Troubleshooting

### Permission Issues

- Check that microphone permissions are granted
- Verify Info.plist/AndroidManifest.xml configuration
- Test on physical device (simulator may have limitations)

### Audio Quality Problems

- Ensure device microphone is working
- Check for background noise interference
- Try different quality presets
- Verify adequate storage space

### Recording Interruptions

- Handle phone calls and other audio interruptions
- Implement proper audio session management
- Save partial recordings when interrupted

### Performance Issues

- Reduce waveform update frequency on older devices
- Use lower quality settings for better performance
- Disable real-time waveform on low-end devices
