@mobileai/react-native 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +25 -34
  2. package/lib/module/components/AIAgent.js +216 -5
  3. package/lib/module/components/AIAgent.js.map +1 -1
  4. package/lib/module/components/AgentChatBar.js +358 -36
  5. package/lib/module/components/AgentChatBar.js.map +1 -1
  6. package/lib/module/core/AgentRuntime.js +122 -6
  7. package/lib/module/core/AgentRuntime.js.map +1 -1
  8. package/lib/module/core/systemPrompt.js +57 -0
  9. package/lib/module/core/systemPrompt.js.map +1 -1
  10. package/lib/module/index.js +8 -0
  11. package/lib/module/index.js.map +1 -1
  12. package/lib/module/providers/GeminiProvider.js +108 -85
  13. package/lib/module/providers/GeminiProvider.js.map +1 -1
  14. package/lib/module/services/AudioInputService.js +128 -0
  15. package/lib/module/services/AudioInputService.js.map +1 -0
  16. package/lib/module/services/AudioOutputService.js +154 -0
  17. package/lib/module/services/AudioOutputService.js.map +1 -0
  18. package/lib/module/services/VoiceService.js +362 -0
  19. package/lib/module/services/VoiceService.js.map +1 -0
  20. package/lib/module/utils/audioUtils.js +49 -0
  21. package/lib/module/utils/audioUtils.js.map +1 -0
  22. package/lib/module/utils/logger.js +21 -4
  23. package/lib/module/utils/logger.js.map +1 -1
  24. package/lib/typescript/babel.config.d.ts +10 -0
  25. package/lib/typescript/babel.config.d.ts.map +1 -0
  26. package/lib/typescript/eslint.config.d.mts +3 -0
  27. package/lib/typescript/eslint.config.d.mts.map +1 -0
  28. package/lib/typescript/fetch-models.d.mts +2 -0
  29. package/lib/typescript/fetch-models.d.mts.map +1 -0
  30. package/lib/typescript/list-all-models.d.mts +2 -0
  31. package/lib/typescript/list-all-models.d.mts.map +1 -0
  32. package/lib/typescript/list-models.d.mts +2 -0
  33. package/lib/typescript/list-models.d.mts.map +1 -0
  34. package/lib/typescript/src/components/AIAgent.d.ts +8 -2
  35. package/lib/typescript/src/components/AIAgent.d.ts.map +1 -1
  36. package/lib/typescript/src/components/AgentChatBar.d.ts +19 -2
  37. package/lib/typescript/src/components/AgentChatBar.d.ts.map +1 -1
  38. package/lib/typescript/src/core/AgentRuntime.d.ts +17 -1
  39. package/lib/typescript/src/core/AgentRuntime.d.ts.map +1 -1
  40. package/lib/typescript/src/core/systemPrompt.d.ts +8 -0
  41. package/lib/typescript/src/core/systemPrompt.d.ts.map +1 -1
  42. package/lib/typescript/src/core/types.d.ts +24 -1
  43. package/lib/typescript/src/core/types.d.ts.map +1 -1
  44. package/lib/typescript/src/index.d.ts +6 -1
  45. package/lib/typescript/src/index.d.ts.map +1 -1
  46. package/lib/typescript/src/providers/GeminiProvider.d.ts +22 -18
  47. package/lib/typescript/src/providers/GeminiProvider.d.ts.map +1 -1
  48. package/lib/typescript/src/services/AudioInputService.d.ts +31 -0
  49. package/lib/typescript/src/services/AudioInputService.d.ts.map +1 -0
  50. package/lib/typescript/src/services/AudioOutputService.d.ts +34 -0
  51. package/lib/typescript/src/services/AudioOutputService.d.ts.map +1 -0
  52. package/lib/typescript/src/services/VoiceService.d.ts +73 -0
  53. package/lib/typescript/src/services/VoiceService.d.ts.map +1 -0
  54. package/lib/typescript/src/utils/audioUtils.d.ts +17 -0
  55. package/lib/typescript/src/utils/audioUtils.d.ts.map +1 -0
  56. package/lib/typescript/src/utils/logger.d.ts +4 -0
  57. package/lib/typescript/src/utils/logger.d.ts.map +1 -1
  58. package/package.json +24 -8
  59. package/src/components/AIAgent.tsx +222 -3
  60. package/src/components/AgentChatBar.tsx +487 -42
  61. package/src/core/AgentRuntime.ts +131 -2
  62. package/src/core/systemPrompt.ts +62 -0
  63. package/src/core/types.ts +30 -0
  64. package/src/index.ts +16 -0
  65. package/src/providers/GeminiProvider.ts +105 -89
  66. package/src/services/AudioInputService.ts +141 -0
  67. package/src/services/AudioOutputService.ts +167 -0
  68. package/src/services/VoiceService.ts +409 -0
  69. package/src/utils/audioUtils.ts +54 -0
  70. package/src/utils/logger.ts +24 -7
@@ -1,83 +1,81 @@
1
1
  "use strict";
2
2
 
3
3
  /**
4
- * GeminiProvider — Gemini API integration with structured action pattern.
4
+ * GeminiProvider — Gemini API integration via @google/genai SDK.
5
5
  *
6
- * Uses a single forced function call (`agent_step`) that bundles
7
- * structured reasoning (evaluation, memory, plan) alongside the action.
8
- * This replaces free-form text + separate tool calls for stability.
6
+ * Uses the official Google GenAI SDK for:
7
+ * - generateContent with structured function calling (agent_step)
8
+ * - inlineData for vision (base64 screenshots)
9
+ * - System instructions
10
+ *
11
+ * Implements the AIProvider interface so it can be swapped
12
+ * with OpenAIProvider, AnthropicProvider, etc.
9
13
  */
10
14
 
15
+ import { GoogleGenAI, FunctionCallingConfigMode, Type } from '@google/genai';
11
16
  import { logger } from "../utils/logger.js";
12
17
  // ─── Constants ─────────────────────────────────────────────────
13
18
 
14
19
  const AGENT_STEP_FN = 'agent_step';
15
20
 
16
- // Reasoning fields that are always present in the agent_step schema
21
+ // Reasoning fields always present in the agent_step schema
17
22
  const REASONING_FIELDS = ['previous_goal_eval', 'memory', 'plan'];
18
23
 
19
- // ─── Gemini API Types ──────────────────────────────────────────
20
-
21
24
  // ─── Provider ──────────────────────────────────────────────────
22
25
 
23
26
  export class GeminiProvider {
24
27
  constructor(apiKey, model = 'gemini-2.5-flash') {
25
- this.apiKey = apiKey;
28
+ this.ai = new GoogleGenAI({
29
+ apiKey
30
+ });
26
31
  this.model = model;
27
32
  }
28
- async generateContent(systemPrompt, userMessage, tools, history) {
29
- logger.info('GeminiProvider', `Sending request. Model: ${this.model}, Tools: ${tools.length}`);
33
+ async generateContent(systemPrompt, userMessage, tools, history, screenshot) {
34
+ logger.info('GeminiProvider', `Sending request. Model: ${this.model}, Tools: ${tools.length}${screenshot ? ', with screenshot' : ''}`);
30
35
 
31
36
  // Build single agent_step function declaration
32
37
  const agentStepDeclaration = this.buildAgentStepDeclaration(tools);
33
38
 
34
- // Build conversation history with proper function call/response pairs
35
- const contents = this.buildContents(userMessage, history);
36
-
37
- // Make API request
38
- const url = `https://generativelanguage.googleapis.com/v1beta/models/${this.model}:generateContent?key=${this.apiKey}`;
39
- const body = {
40
- contents,
41
- tools: [{
42
- functionDeclarations: [agentStepDeclaration]
43
- }],
44
- systemInstruction: {
45
- parts: [{
46
- text: systemPrompt
47
- }]
48
- },
49
- // Force the model to always call agent_step
50
- tool_config: {
51
- function_calling_config: {
52
- mode: 'ANY',
53
- allowed_function_names: [AGENT_STEP_FN]
54
- }
55
- },
56
- generationConfig: {
57
- temperature: 0.2,
58
- maxOutputTokens: 2048
59
- }
60
- };
39
+ // Build contents (user message + optional screenshot)
40
+ const contents = this.buildContents(userMessage, history, screenshot);
61
41
  const startTime = Date.now();
62
42
  try {
63
- const response = await fetch(url, {
64
- method: 'POST',
65
- headers: {
66
- 'Content-Type': 'application/json'
67
- },
68
- body: JSON.stringify(body)
43
+ const response = await this.ai.models.generateContent({
44
+ model: this.model,
45
+ contents,
46
+ config: {
47
+ systemInstruction: systemPrompt,
48
+ tools: [{
49
+ functionDeclarations: [agentStepDeclaration]
50
+ }],
51
+ toolConfig: {
52
+ functionCallingConfig: {
53
+ mode: FunctionCallingConfigMode.ANY,
54
+ allowedFunctionNames: [AGENT_STEP_FN]
55
+ }
56
+ },
57
+ temperature: 0.2,
58
+ maxOutputTokens: 2048
59
+ }
69
60
  });
70
61
  const elapsed = Date.now() - startTime;
71
62
  logger.info('GeminiProvider', `Response received in ${elapsed}ms`);
72
- if (!response.ok) {
73
- const errorText = await response.text();
74
- logger.error('GeminiProvider', `API error ${response.status}: ${errorText}`);
75
- throw new Error(`Gemini API error ${response.status}: ${errorText}`);
63
+
64
+ // Extract token usage from SDK response
65
+ const tokenUsage = this.extractTokenUsage(response);
66
+ if (tokenUsage) {
67
+ logger.info('GeminiProvider', `Tokens: ${tokenUsage.promptTokens} in / ${tokenUsage.completionTokens} out / $${tokenUsage.estimatedCostUSD.toFixed(6)}`);
76
68
  }
77
- const data = await response.json();
78
- return this.parseAgentStepResponse(data, tools);
69
+ const result = this.parseAgentStepResponse(response, tools);
70
+ result.tokenUsage = tokenUsage;
71
+ return result;
79
72
  } catch (error) {
80
73
  logger.error('GeminiProvider', 'Request failed:', error.message);
74
+
75
+ // Preserve HTTP error format for backward compatibility with tests
76
+ if (error.status) {
77
+ throw new Error(`Gemini API error ${error.status}: ${error.message}`);
78
+ }
81
79
  throw error;
82
80
  }
83
81
  }
@@ -99,7 +97,6 @@ export class GeminiProvider {
99
97
  const actionProperties = {};
100
98
  for (const tool of tools) {
101
99
  for (const [paramName, param] of Object.entries(tool.parameters)) {
102
- // Skip if already added (shared field names like 'text', 'index')
103
100
  if (actionProperties[paramName]) continue;
104
101
  actionProperties[paramName] = {
105
102
  type: this.mapParamType(param.type),
@@ -120,28 +117,25 @@ export class GeminiProvider {
120
117
  name: AGENT_STEP_FN,
121
118
  description: `Execute one agent step. Choose an action and provide reasoning.\n\nAvailable actions:\n${toolDescriptions}`,
122
119
  parameters: {
123
- type: 'OBJECT',
120
+ type: Type.OBJECT,
124
121
  properties: {
125
- // ── Reasoning fields ──
126
122
  previous_goal_eval: {
127
- type: 'STRING',
123
+ type: Type.STRING,
128
124
  description: 'One-sentence assessment of your last action. State success, failure, or uncertain. Skip on first step.'
129
125
  },
130
126
  memory: {
131
- type: 'STRING',
127
+ type: Type.STRING,
132
128
  description: 'Key facts to remember for future steps: progress made, items found, counters, field values already collected.'
133
129
  },
134
130
  plan: {
135
- type: 'STRING',
131
+ type: Type.STRING,
136
132
  description: 'Your immediate next goal — what action you will take and why.'
137
133
  },
138
- // ── Action selection ──
139
134
  action_name: {
140
- type: 'STRING',
135
+ type: Type.STRING,
141
136
  description: 'Which action to execute.',
142
137
  enum: toolNames
143
138
  },
144
- // ── Action parameters (flat) ──
145
139
  ...actionProperties
146
140
  },
147
141
  required: ['plan', 'action_name']
@@ -151,48 +145,52 @@ export class GeminiProvider {
151
145
  mapParamType(type) {
152
146
  switch (type) {
153
147
  case 'number':
154
- return 'NUMBER';
148
+ return Type.NUMBER;
155
149
  case 'integer':
156
- return 'INTEGER';
150
+ return Type.INTEGER;
157
151
  case 'boolean':
158
- return 'BOOLEAN';
152
+ return Type.BOOLEAN;
159
153
  case 'string':
160
154
  default:
161
- return 'STRING';
155
+ return Type.STRING;
162
156
  }
163
157
  }
164
158
 
165
159
  // ─── Build Contents ────────────────────────────────────────
166
160
 
167
161
  /**
168
- * Builds Gemini conversation contents.
169
- *
170
- * Each step is a STATELESS single-turn request (matching page-agent's approach):
171
- * - System prompt has general instructions
172
- * - User message contains full context: task, history, screen state
173
- * - Model responds with agent_step function call
174
- *
175
- * History is embedded as text in assembleUserPrompt (via <agent_history>),
176
- * NOT as functionCall/functionResponse pairs. This avoids Gemini's
177
- * conversation format requirements and thought_signature complexity.
162
+ * Builds contents for the generateContent call.
163
+ * Single-turn: user message + optional screenshot as inlineData.
178
164
  */
179
- buildContents(userMessage, _history) {
165
+ buildContents(userMessage, _history, screenshot) {
166
+ const parts = [{
167
+ text: userMessage
168
+ }];
169
+
170
+ // Append screenshot as inlineData for Gemini vision
171
+ if (screenshot) {
172
+ parts.push({
173
+ inlineData: {
174
+ mimeType: 'image/jpeg',
175
+ data: screenshot
176
+ }
177
+ });
178
+ }
180
179
  return [{
181
180
  role: 'user',
182
- parts: [{
183
- text: userMessage
184
- }]
181
+ parts
185
182
  }];
186
183
  }
187
184
 
188
185
  // ─── Parse Response ────────────────────────────────────────
189
186
 
190
187
  /**
191
- * Parses the Gemini response expecting a single agent_step function call.
192
- * Extracts structured reasoning + action, and determines which tool to execute.
188
+ * Parses the SDK response expecting a single agent_step function call.
189
+ * Extracts structured reasoning + action.
193
190
  */
194
- parseAgentStepResponse(data, tools) {
195
- if (!data.candidates || data.candidates.length === 0) {
191
+ parseAgentStepResponse(response, tools) {
192
+ const candidates = response.candidates || [];
193
+ if (candidates.length === 0) {
196
194
  logger.warn('GeminiProvider', 'No candidates in response');
197
195
  return {
198
196
  toolCalls: [{
@@ -210,7 +208,7 @@ export class GeminiProvider {
210
208
  text: 'No response generated.'
211
209
  };
212
210
  }
213
- const candidate = data.candidates[0];
211
+ const candidate = candidates[0];
214
212
  const parts = candidate.content?.parts || [];
215
213
 
216
214
  // Find the function call part
@@ -260,11 +258,9 @@ export class GeminiProvider {
260
258
  };
261
259
  }
262
260
 
263
- // Build action args: everything except reasoning fields and action_name
261
+ // Build action args: extract only the params that belong to the matched tool
264
262
  const actionArgs = {};
265
263
  const reservedKeys = new Set([...REASONING_FIELDS, 'action_name']);
266
-
267
- // Find the matching tool to know which params belong to it
268
264
  const matchedTool = tools.find(t => t.name === actionName);
269
265
  if (matchedTool) {
270
266
  for (const paramName of Object.keys(matchedTool.parameters)) {
@@ -273,7 +269,6 @@ export class GeminiProvider {
273
269
  }
274
270
  }
275
271
  } else {
276
- // Custom/registered tool — grab all non-reserved fields
277
272
  for (const [key, value] of Object.entries(args)) {
278
273
  if (!reservedKeys.has(key)) {
279
274
  actionArgs[key] = value;
@@ -290,5 +285,33 @@ export class GeminiProvider {
290
285
  text: textPart?.text
291
286
  };
292
287
  }
288
+
289
+ // ─── Token Usage Extraction ─────────────────────────────────
290
+
291
+ /**
292
+ * Extracts token usage from SDK response and calculates estimated cost.
293
+ *
294
+ * Pricing (Gemini 2.5 Flash):
295
+ * - Input: $0.30 / 1M tokens
296
+ * - Output: $2.50 / 1M tokens
297
+ */
298
+ extractTokenUsage(response) {
299
+ const meta = response?.usageMetadata;
300
+ if (!meta) return undefined;
301
+ const promptTokens = meta.promptTokenCount ?? 0;
302
+ const completionTokens = meta.candidatesTokenCount ?? 0;
303
+ const totalTokens = meta.totalTokenCount ?? promptTokens + completionTokens;
304
+
305
+ // Cost estimation based on Gemini 2.5 Flash pricing
306
+ const INPUT_COST_PER_M = 0.30;
307
+ const OUTPUT_COST_PER_M = 2.50;
308
+ const estimatedCostUSD = promptTokens / 1_000_000 * INPUT_COST_PER_M + completionTokens / 1_000_000 * OUTPUT_COST_PER_M;
309
+ return {
310
+ promptTokens,
311
+ completionTokens,
312
+ totalTokens,
313
+ estimatedCostUSD
314
+ };
315
+ }
293
316
  }
294
317
  //# sourceMappingURL=GeminiProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["logger","AGENT_STEP_FN","REASONING_FIELDS","GeminiProvider","constructor","apiKey","model","generateContent","systemPrompt","userMessage","tools","history","info","length","agentStepDeclaration","buildAgentStepDeclaration","contents","buildContents","url","body","functionDeclarations","systemInstruction","parts","text","tool_config","function_calling_config","mode","allowed_function_names","generationConfig","temperature","maxOutputTokens","startTime","Date","now","response","fetch","method","headers","JSON","stringify","elapsed","ok","errorText","error","status","Error","data","json","parseAgentStepResponse","message","toolNames","map","t","name","actionProperties","tool","paramName","param","Object","entries","parameters","type","mapParamType","description","enum","toolDescriptions","params","keys","join","properties","previous_goal_eval","memory","plan","action_name","required","_history","role","candidates","warn","toolCalls","args","success","reasoning","previousGoalEval","candidate","content","fnCallPart","find","p","functionCall","textPart","actionName","actionArgs","reservedKeys","Set","matchedTool","undefined","key","value","has"],"sourceRoot":"../../../src","sources":["providers/GeminiProvider.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["GoogleGenAI","FunctionCallingConfigMode","Type","logger","AGENT_STEP_FN","REASONING_FIELDS","GeminiProvider","constructor","apiKey","model","ai","generateContent","systemPrompt","userMessage","tools","history","screenshot","info","length","agentStepDeclaration","buildAgentStepDeclaration","contents","buildContents","startTime","Date","now","response","models","config","systemInstruction","functionDeclarations","toolConfig","functionCallingConfig","mode","ANY","allowedFunctionNames","temperature","maxOutputTokens","elapsed","tokenUsage","extractTokenUsage","promptTokens","completionTokens","estimatedCostUSD","toFixed","result","parseAgentStepResponse","error","message","status","Error","toolNames","map","t","name","actionProperties","tool","paramName","param","Object","entries","parameters","type","mapParamType","description","enum","toolDescriptions","params","keys","join","OBJECT","properties","previous_goal_eval","STRING","memory","plan","action_name","required","NUMBER","INTEGER","BOOLEAN","_history","parts","text","push","inlineData","mimeType","data","role","candidates","warn","toolCalls","args","success","reasoning","previousGoalEval","candidate","content","fnCallPart","find","p","functionCall","textPart","actionName","actionArgs","reservedKeys","Set","matchedTool","undefined","key","value","has","meta","usageMetadata","promptTokenCount","candidatesTokenCount","totalTokens","totalTokenCount","INPUT_COST_PER_M","OUTPUT_COST_PER_M"],"sourceRoot":"../../../src","sources":["providers/GeminiProvider.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * AudioInputService — Real-time microphone capture for voice mode.
5
+ *
6
+ * Uses react-native-audio-api (Software Mansion) AudioRecorder for native
7
+ * PCM streaming from the microphone. Each chunk is converted from Float32
8
+ * to Int16 PCM and base64-encoded for the Gemini Live API.
9
+ *
10
+ * Requires: react-native-audio-api (development build only, not Expo Go)
11
+ */
12
+
13
+ import { logger } from "../utils/logger.js";
14
+ import { float32ToInt16Base64 } from "../utils/audioUtils.js";
15
+
16
+ // ─── Types ─────────────────────────────────────────────────────
17
+
18
+ // ─── Service ───────────────────────────────────────────────────
19
+
20
+ export class AudioInputService {
21
+ status = 'idle';
22
+ recorder = null;
23
+ constructor(config) {
24
+ this.config = config;
25
+ }
26
+
27
+ // ─── Lifecycle ─────────────────────────────────────────────
28
+
29
+ async start() {
30
+ try {
31
+ // Lazy-load react-native-audio-api (optional peer dependency)
32
+ let audioApi;
33
+ try {
34
+ audioApi = require('react-native-audio-api');
35
+ } catch {
36
+ const msg = 'Voice mode requires react-native-audio-api. Install with: npm install react-native-audio-api';
37
+ logger.error('AudioInput', msg);
38
+ this.config.onError?.(msg);
39
+ return false;
40
+ }
41
+
42
+ // Request mic permission (Android)
43
+ try {
44
+ const {
45
+ PermissionsAndroid,
46
+ Platform
47
+ } = require('react-native');
48
+ if (Platform.OS === 'android') {
49
+ const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO);
50
+ if (result !== PermissionsAndroid.RESULTS.GRANTED) {
51
+ logger.warn('AudioInput', 'Microphone permission denied');
52
+ this.config.onPermissionDenied?.();
53
+ return false;
54
+ }
55
+ }
56
+ } catch {
57
+ // Permission check failed — continue and let native layer handle it
58
+ }
59
+
60
+ // Create AudioRecorder
61
+ this.recorder = new audioApi.AudioRecorder();
62
+ const sampleRate = this.config.sampleRate || 16000;
63
+ const bufferLength = this.config.bufferLength || 4096;
64
+
65
+ // Register audio data callback
66
+ let frameCount = 0;
67
+ this.recorder.onAudioReady({
68
+ sampleRate,
69
+ bufferLength,
70
+ channelCount: 1
71
+ }, event => {
72
+ frameCount++;
73
+ try {
74
+ // event.buffer is an AudioBuffer — get Float32 channel data
75
+ const float32Data = event.buffer.getChannelData(0);
76
+ // Convert Float32 → Int16 → base64 for Gemini
77
+ const base64Chunk = float32ToInt16Base64(float32Data);
78
+ logger.debug('AudioInput', `🎤 Frame #${frameCount}: size=${base64Chunk.length}`);
79
+ this.config.onAudioChunk(base64Chunk);
80
+ } catch (err) {
81
+ logger.error('AudioInput', `Frame processing error: ${err.message}`);
82
+ }
83
+ });
84
+
85
+ // Register error callback
86
+ this.recorder.onError(error => {
87
+ logger.error('AudioInput', `Recorder error: ${error.message || error}`);
88
+ this.config.onError?.(error.message || String(error));
89
+ });
90
+
91
+ // Start recording
92
+ this.recorder.start();
93
+ this.status = 'recording';
94
+ logger.info('AudioInput', `Streaming started (${sampleRate}Hz, bufLen=${bufferLength})`);
95
+ return true;
96
+ } catch (error) {
97
+ logger.error('AudioInput', `Failed to start: ${error.message}`);
98
+ this.config.onError?.(error.message);
99
+ return false;
100
+ }
101
+ }
102
+ async stop() {
103
+ try {
104
+ if (this.recorder && this.status !== 'idle') {
105
+ this.recorder.clearOnAudioReady();
106
+ this.recorder.clearOnError();
107
+ this.recorder.stop();
108
+ }
109
+ this.recorder = null;
110
+ this.status = 'idle';
111
+ logger.info('AudioInput', 'Streaming stopped');
112
+ } catch (error) {
113
+ logger.error('AudioInput', `Failed to stop: ${error.message}`);
114
+ this.recorder = null;
115
+ this.status = 'idle';
116
+ }
117
+ }
118
+
119
+ // ─── Status ───────────────────────────────────────────────
120
+
121
+ get isRecording() {
122
+ return this.status === 'recording';
123
+ }
124
+ get currentStatus() {
125
+ return this.status;
126
+ }
127
+ }
128
+ //# sourceMappingURL=AudioInputService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["logger","float32ToInt16Base64","AudioInputService","status","recorder","constructor","config","start","audioApi","require","msg","error","onError","PermissionsAndroid","Platform","OS","result","request","PERMISSIONS","RECORD_AUDIO","RESULTS","GRANTED","warn","onPermissionDenied","AudioRecorder","sampleRate","bufferLength","frameCount","onAudioReady","channelCount","event","float32Data","buffer","getChannelData","base64Chunk","debug","length","onAudioChunk","err","message","String","info","stop","clearOnAudioReady","clearOnError","isRecording","currentStatus"],"sourceRoot":"../../../src","sources":["services/AudioInputService.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * AudioOutputService — AI speech playback for voice mode.
5
+ *
6
+ * Uses react-native-audio-api (Software Mansion) for gapless, low-latency
7
+ * PCM playback. Decodes base64 PCM from Gemini Live API and queues it via
8
+ * AudioBufferQueueSourceNode for seamless streaming.
9
+ *
10
+ * Requires: react-native-audio-api (development build only, not Expo Go)
11
+ */
12
+
13
+ import { logger } from "../utils/logger.js";
14
+ import { base64ToFloat32 } from "../utils/audioUtils.js";
15
+
16
+ // ─── Types ─────────────────────────────────────────────────────
17
+
18
+ /** Gemini Live API outputs 24kHz 16-bit mono PCM */
19
+ const GEMINI_OUTPUT_SAMPLE_RATE = 24000;
20
+ // ─── Service ───────────────────────────────────────────────────
21
+
22
+ export class AudioOutputService {
23
+ audioContext = null;
24
+ queueSourceNode = null;
25
+ gainNode = null;
26
+ muted = false;
27
+ isStarted = false;
28
+ chunkCount = 0;
29
+ constructor(config = {}) {
30
+ this.config = config;
31
+ }
32
+
33
+ // ─── Lifecycle ─────────────────────────────────────────────
34
+
35
+ async initialize() {
36
+ try {
37
+ let audioApi;
38
+ try {
39
+ audioApi = require('react-native-audio-api');
40
+ } catch {
41
+ const msg = 'react-native-audio-api is required for audio output. Install with: npm install react-native-audio-api';
42
+ logger.error('AudioOutput', msg);
43
+ this.config.onError?.(msg);
44
+ return false;
45
+ }
46
+ const sampleRate = this.config.sampleRate || GEMINI_OUTPUT_SAMPLE_RATE;
47
+
48
+ // Create AudioContext at Gemini's output sample rate
49
+ this.audioContext = new audioApi.AudioContext({
50
+ sampleRate
51
+ });
52
+
53
+ // Create GainNode for mute control
54
+ this.gainNode = this.audioContext.createGain();
55
+ this.gainNode.gain.value = 1.0;
56
+ this.gainNode.connect(this.audioContext.destination);
57
+
58
+ // Create AudioBufferQueueSourceNode for gapless streaming
59
+ this.queueSourceNode = this.audioContext.createBufferQueueSource();
60
+ this.queueSourceNode.connect(this.gainNode);
61
+ logger.info('AudioOutput', `Initialized (${sampleRate}Hz, AudioBufferQueueSourceNode)`);
62
+ return true;
63
+ } catch (error) {
64
+ logger.error('AudioOutput', `Failed to initialize: ${error.message}`);
65
+ this.config.onError?.(error.message);
66
+ return false;
67
+ }
68
+ }
69
+
70
+ // ─── Enqueue Audio ─────────────────────────────────────────
71
+
72
+ /** Add a base64-encoded PCM chunk from Gemini to the playback queue */
73
+ enqueue(base64Audio) {
74
+ if (this.muted || !this.audioContext || !this.queueSourceNode) return;
75
+ try {
76
+ this.chunkCount++;
77
+
78
+ // Decode base64 Int16 PCM → Float32
79
+ const float32Data = base64ToFloat32(base64Audio);
80
+ const sampleRate = this.config.sampleRate || GEMINI_OUTPUT_SAMPLE_RATE;
81
+
82
+ // Create an AudioBuffer and fill it with PCM data
83
+ const audioBuffer = this.audioContext.createBuffer(1, float32Data.length, sampleRate);
84
+ audioBuffer.copyToChannel(float32Data, 0);
85
+
86
+ // Enqueue the buffer for gapless playback
87
+ this.queueSourceNode.enqueueBuffer(audioBuffer);
88
+
89
+ // Start playback on first enqueue
90
+ if (!this.isStarted) {
91
+ this.queueSourceNode.start();
92
+ this.isStarted = true;
93
+ this.config.onPlaybackStart?.();
94
+ logger.info('AudioOutput', '▶️ Playback started');
95
+ }
96
+ if (this.chunkCount % 20 === 0) {
97
+ logger.debug('AudioOutput', `Queued chunk #${this.chunkCount}`);
98
+ }
99
+ } catch (error) {
100
+ logger.error('AudioOutput', `Enqueue error: ${error.message}`);
101
+ }
102
+ }
103
+
104
+ // ─── Mute/Unmute ──────────────────────────────────────────
105
+
106
+ mute() {
107
+ this.muted = true;
108
+ if (this.gainNode) {
109
+ this.gainNode.gain.value = 0;
110
+ }
111
+ logger.info('AudioOutput', 'Speaker muted');
112
+ }
113
+ unmute() {
114
+ this.muted = false;
115
+ if (this.gainNode) {
116
+ this.gainNode.gain.value = 1.0;
117
+ }
118
+ logger.info('AudioOutput', 'Speaker unmuted');
119
+ }
120
+ get isMuted() {
121
+ return this.muted;
122
+ }
123
+
124
+ // ─── Stop & Cleanup ───────────────────────────────────────
125
+
126
+ async stop() {
127
+ try {
128
+ if (this.queueSourceNode && this.isStarted) {
129
+ this.queueSourceNode.stop();
130
+ this.queueSourceNode.clearBuffers();
131
+ }
132
+ this.isStarted = false;
133
+ this.chunkCount = 0;
134
+ this.config.onPlaybackEnd?.();
135
+ logger.info('AudioOutput', 'Playback stopped');
136
+ } catch (error) {
137
+ logger.error('AudioOutput', `Stop error: ${error.message}`);
138
+ }
139
+ }
140
+ async cleanup() {
141
+ await this.stop();
142
+ try {
143
+ if (this.audioContext) {
144
+ await this.audioContext.close();
145
+ }
146
+ } catch {
147
+ // Non-critical
148
+ }
149
+ this.audioContext = null;
150
+ this.queueSourceNode = null;
151
+ this.gainNode = null;
152
+ }
153
+ }
154
+ //# sourceMappingURL=AudioOutputService.js.map