Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ Usecases are numerous - OMI Mentor is one of them. Friend/Omi/pendants are a sma

Regardless - this repo will try to do the minimal of this - multiple OMI-like audio devices feeding audio data - and from it:
- Memories
- Action items
- Action items
- Home automation

## Golden Goals (Not Yet Achieved)
Expand All @@ -179,4 +179,3 @@ Regardless - this repo will try to do the minimal of this - multiple OMI-like au
- **Home automation integration** (planned)
- **Multi-device coordination** (planned)
- **Visual context capture** (smart glasses integration planned)

10 changes: 5 additions & 5 deletions app/src/components/StatusIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ const StatusIndicator: React.FC<StatusIndicatorProps> = ({
inactiveColor = '#FF3B30', // Red
}) => {
return (
<View
<View
style={[
styles.dot,
{
width: size,
height: size,
{
width: size,
height: size,
borderRadius: size / 2,
backgroundColor: isActive ? activeColor : inactiveColor,
}
Expand All @@ -40,4 +40,4 @@ const styles = StyleSheet.create({
},
});

export default StatusIndicator;
export default StatusIndicator;
1 change: 0 additions & 1 deletion app/src/hooks/.gitkeep
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@

24 changes: 12 additions & 12 deletions app/src/hooks/useAudioListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,38 @@ export const useAudioListener = (
const [isRetrying, setIsRetrying] = useState<boolean>(false);
const [retryAttempts, setRetryAttempts] = useState<number>(0);
const { addEvent } = useConnectionLog();

const audioSubscriptionRef = useRef<Subscription | null>(null);
const uiUpdateIntervalRef = useRef<NodeJS.Timeout | null>(null);
const localPacketCounterRef = useRef<number>(0);
const retryTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const shouldRetryRef = useRef<boolean>(false);
const currentOnAudioDataRef = useRef<((bytes: Uint8Array) => void) | null>(null);

// Retry configuration
const MAX_RETRY_ATTEMPTS = 10;
const INITIAL_RETRY_DELAY = 1000; // 1 second
const MAX_RETRY_DELAY = 60000; // 60 seconds

const stopAudioListener = useCallback(async () => {
console.log('Attempting to stop audio listener...');

// Stop retry mechanism
shouldRetryRef.current = false;
setIsRetrying(false);
setRetryAttempts(0);
currentOnAudioDataRef.current = null;

if (retryTimeoutRef.current) {
clearTimeout(retryTimeoutRef.current);
retryTimeoutRef.current = null;
}

if (uiUpdateIntervalRef.current) {
clearInterval(uiUpdateIntervalRef.current);
uiUpdateIntervalRef.current = null;
}

if (audioSubscriptionRef.current) {
try {
await omiConnection.stopAudioBytesListener(audioSubscriptionRef.current);
Expand Down Expand Up @@ -147,7 +147,7 @@ export const useAudioListener = (
setIsRetrying(true);

const success = await attemptStartAudioListener(currentOnAudioDataRef.current);

if (success) {
console.log('[AudioListener] Retry successful');
return;
Expand All @@ -157,7 +157,7 @@ export const useAudioListener = (
if (shouldRetryRef.current) {
const delay = getRetryDelay(currentAttempt);
console.log(`[AudioListener] Scheduling retry in ${Math.round(delay)}ms`);

retryTimeoutRef.current = setTimeout(() => {
if (shouldRetryRef.current) {
retryStartAudioListener();
Expand All @@ -171,7 +171,7 @@ export const useAudioListener = (
Alert.alert('Not Connected', 'Please connect to a device first to start audio listener.');
return;
}

if (isListeningAudio) {
console.log('[AudioListener] Audio listener is already active. Stopping first.');
await stopAudioListener();
Expand All @@ -180,7 +180,7 @@ export const useAudioListener = (
// Store the callback for retry attempts
currentOnAudioDataRef.current = onAudioData;
shouldRetryRef.current = true;

setAudioPacketsReceived(0); // Reset counter on start
localPacketCounterRef.current = 0;
setRetryAttempts(0);
Expand All @@ -197,7 +197,7 @@ export const useAudioListener = (

// Try to start audio listener
const success = await attemptStartAudioListener(onAudioData);

if (!success && shouldRetryRef.current) {
console.log('[AudioListener] Initial attempt failed, starting retry mechanism');
setIsRetrying(true);
Expand Down Expand Up @@ -227,4 +227,4 @@ export const useAudioListener = (
isRetrying,
retryAttempts,
};
};
};
6 changes: 3 additions & 3 deletions app/src/hooks/useBluetoothManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const useBluetoothManager = () => {
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
];
}

console.log('[BTManager] Android permissions to request:', permissionsToRequest);
const statuses = await PermissionsAndroid.requestMultiple(permissionsToRequest);
console.log('[BTManager] Android permission statuses:', statuses);
Expand Down Expand Up @@ -100,12 +100,12 @@ export const useBluetoothManager = () => {
checkAndRequestPermissions();
}
}, [bluetoothState, checkAndRequestPermissions]); // Rerun if BT state changes or on initial mount

return {
bleManager,
bluetoothState,
permissionGranted,
requestBluetoothPermission: checkAndRequestPermissions,
isPermissionsLoading,
};
};
};
2 changes: 1 addition & 1 deletion app/src/hooks/useDeviceConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,4 @@ export const useDeviceConnection = (
getRawBatteryLevel,
connectedDeviceId
};
};
};
6 changes: 3 additions & 3 deletions app/src/hooks/useDeviceScanning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const useDeviceScanning = (
const startScan = useCallback(async () => {
console.log('[Scanner] startScan called');
setError(null);
setDevices([]);
setDevices([]);

if (scanning) {
console.log('[Scanner] Scan already in progress. Stopping previous scan first.');
Expand Down Expand Up @@ -80,7 +80,7 @@ export const useDeviceScanning = (
setError('Bluetooth is not enabled. Please turn on Bluetooth.');
return;
}

const currentState = await bleManager.state();
if (currentState !== BluetoothState.PoweredOn) {
console.warn(`[Scanner] Bluetooth state is ${currentState}, not PoweredOn. Cannot scan.`);
Expand Down Expand Up @@ -143,4 +143,4 @@ export const useDeviceScanning = (
}, [handleStopScan]);

return { devices, scanning, startScan, stopScan: handleStopScan, error };
};
};
24 changes: 12 additions & 12 deletions app/src/hooks/usePhoneAudioRecorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const usePhoneAudioRecorder = (): UsePhoneAudioRecorder => {
const [isInitializing, setIsInitializing] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const [audioLevel, setAudioLevel] = useState<number>(0);

const onAudioDataRef = useRef<((pcmBuffer: Uint8Array) => void) | null>(null);
const mountedRef = useRef<boolean>(true);

Expand All @@ -53,13 +53,13 @@ export const usePhoneAudioRecorder = (): UsePhoneAudioRecorder => {
try {
const audioData = event.data;
console.log('[PhoneAudioRecorder] processAudioDataEvent called, data type:', typeof audioData);

if (typeof audioData === 'string') {
// Base64 encoded data (native platforms) - decode using react-native-base64
console.log('[PhoneAudioRecorder] Decoding Base64 string, length:', audioData.length);
const binaryString = base64.decode(audioData);
console.log('[PhoneAudioRecorder] Decoded to binary string, length:', binaryString.length);

const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
Expand Down Expand Up @@ -148,10 +148,10 @@ export const usePhoneAudioRecorder = (): UsePhoneAudioRecorder => {
intervalAnalysis: 500, // Analysis every 500ms
onAudioStream: async (event: AudioDataEvent) => {
// EXACT payload handling from guide
const payload = typeof event.data === "string"
? event.data
const payload = typeof event.data === "string"
? event.data
: Buffer.from(event.data as unknown as ArrayBuffer).toString("base64");

// Convert to our expected format
if (onAudioDataRef.current && mountedRef.current) {
const pcmBuffer = processAudioDataEvent(event);
Expand All @@ -163,7 +163,7 @@ export const usePhoneAudioRecorder = (): UsePhoneAudioRecorder => {
};

const result = await startRecorderInternal(config);

if (!result) {
throw new Error('Failed to start recording');
}
Expand All @@ -185,7 +185,7 @@ export const usePhoneAudioRecorder = (): UsePhoneAudioRecorder => {
// Stop recording
const stopRecording = useCallback(async (): Promise<void> => {
console.log('[PhoneAudioRecorder] Stopping recording...');

// Early return if not recording
if (!isRecording) {
console.log('[PhoneAudioRecorder] Not recording, nothing to stop');
Expand All @@ -194,7 +194,7 @@ export const usePhoneAudioRecorder = (): UsePhoneAudioRecorder => {
setStateSafe(setIsInitializing, false);
return;
}

onAudioDataRef.current = null;
setStateSafe(setAudioLevel, 0);

Expand Down Expand Up @@ -231,13 +231,13 @@ export const usePhoneAudioRecorder = (): UsePhoneAudioRecorder => {
console.log('[PhoneAudioRecorder] Component unmounting, setting mountedRef to false');
};
}, []); // Empty dependency array - only runs on mount/unmount

// Separate effect for stopping recording when needed
useEffect(() => {
return () => {
// Stop recording if active when dependencies change
if (isRecording) {
stopRecorderInternal().catch(err =>
stopRecorderInternal().catch(err =>
console.error('[PhoneAudioRecorder] Cleanup stop error:', err)
);
}
Expand All @@ -252,4 +252,4 @@ export const usePhoneAudioRecorder = (): UsePhoneAudioRecorder => {
startRecording,
stopRecording,
};
};
};
2 changes: 1 addition & 1 deletion app/src/utils/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,4 @@ export const clearAuthData = async (): Promise<void> => {
} catch (error) {
console.error('[Storage] Error clearing auth data:', error);
}
};
};
Loading
Loading