Skip to content

Commit 7d44ce4

Browse files
authored
Add audioSessionConfiguration to ElevenLabsProvider (#397)
feat: Add audioSessionConfiguration to ElevenLabsProvider - Add AudioSessionConfiguration interface to types - Add audioSessionConfiguration prop to ElevenLabsProvider - Configure LiveKit audio session based on allowMixingWithOthers setting - Update README with usage documentation - Add .pnpm-store to .gitignore
1 parent c294e6a commit 7d44ce4

File tree

6 files changed

+105
-11
lines changed

6 files changed

+105
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ __pycache__
1212

1313
# dependencies
1414
node_modules
15+
.pnpm-store
1516

1617
# IDEs and editors
1718
/.idea

packages/react-native/README.md

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,27 @@ function App() {
5151
</ElevenLabsProvider>
5252
);
5353
}
54+
```
55+
56+
### Audio Session Configuration
57+
58+
By default, ElevenLabs uses an exclusive audio session for optimal voice quality. To allow concurrent audio playback (e.g., sound effects, notifications, background music):
59+
60+
```typescript
61+
import React from 'react';
62+
import { ElevenLabsProvider, useConversation } from '@elevenlabs/react-native';
63+
64+
function App() {
65+
return (
66+
<ElevenLabsProvider
67+
audioSessionConfiguration={{
68+
allowMixingWithOthers: true,
69+
}}
70+
>
71+
<ConversationComponent />
72+
</ElevenLabsProvider>
73+
);
74+
}
5475

5576
function ConversationComponent() {
5677
const conversation = useConversation({
@@ -207,7 +228,39 @@ console.log(conversation.isSpeaking);
207228
console.log(conversation.canSendFeedback);
208229
```
209230

210-
### Configuration Options
231+
### ElevenLabsProvider Configuration
232+
233+
Configure the provider with optional settings:
234+
235+
#### Audio Session Configuration
236+
237+
Control how the SDK manages audio sessions with other audio sources:
238+
239+
```typescript
240+
<ElevenLabsProvider
241+
audioSessionConfiguration={{
242+
allowMixingWithOthers: true, // Default: false
243+
}}
244+
>
245+
{/* Your app */}
246+
</ElevenLabsProvider>
247+
```
248+
249+
**When to use `allowMixingWithOthers: true`:**
250+
- Playing connection/disconnection sound effects during conversations
251+
- Background music in your app
252+
- Notification sounds while agent is speaking
253+
- Multiple concurrent audio sources
254+
255+
**Default behavior (`false`):**
256+
- Exclusive audio session for best voice quality
257+
- Other audio sources will be paused during conversations
258+
259+
**Platform Notes:**
260+
- **iOS**: Adds `AVAudioSessionCategoryOptionMixWithOthers` to the audio session
261+
- **Android**: Uses `AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK` for audio focus
262+
263+
### Conversation Hook Options
211264

212265
Pass to `useConversation` hook to customize SDK behavior:
213266

packages/react-native/src/ElevenLabsProvider.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { createContext, useContext, useState } from 'react';
33
import { registerGlobals } from '@livekit/react-native';
44
import type { LocalParticipant } from 'livekit-client';
5-
import type { Callbacks, ConversationConfig, ConversationStatus, ClientToolsConfig } from './types';
5+
import type { Callbacks, ConversationConfig, ConversationStatus, ClientToolsConfig, AudioSessionConfiguration } from './types';
66
import { constructOverrides } from './utils/overrides';
77
import { DEFAULT_SERVER_URL } from './utils/constants';
88
import { useConversationCallbacks } from './hooks/useConversationCallbacks';
@@ -81,9 +81,10 @@ export const useConversation = (options: ConversationOptions = {}): Conversation
8181

8282
interface ElevenLabsProviderProps {
8383
children: React.ReactNode;
84+
audioSessionConfiguration?: AudioSessionConfiguration;
8485
}
8586

86-
export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children }) => {
87+
export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children, audioSessionConfiguration }) => {
8788
// Initialize globals on mount
8889
registerGlobals();
8990

@@ -319,6 +320,7 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
319320
clientTools={clientToolsRef.current}
320321
updateCurrentEventId={updateCurrentEventId}
321322
onEndSession={endSession}
323+
audioSessionConfiguration={audioSessionConfiguration}
322324
>
323325
{children}
324326
</LiveKitRoomWrapper>

packages/react-native/src/components/LiveKitRoomWrapper.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import React from 'react';
33
import { LiveKitRoom } from '@livekit/react-native';
44
import type { LocalParticipant } from 'livekit-client';
5-
import type { Callbacks, ClientToolsConfig } from '../types';
5+
import type { Callbacks, ClientToolsConfig, AudioSessionConfiguration } from '../types';
66
import { MessageHandler } from './MessageHandler';
77

88
interface LiveKitRoomWrapperProps {
@@ -20,6 +20,7 @@ interface LiveKitRoomWrapperProps {
2020
clientTools: ClientToolsConfig['clientTools'];
2121
onEndSession: (reason?: "user" | "agent") => void;
2222
updateCurrentEventId?: (eventId: number) => void;
23+
audioSessionConfiguration?: AudioSessionConfiguration;
2324
}
2425

2526
export const LiveKitRoomWrapper = ({
@@ -37,13 +38,32 @@ export const LiveKitRoomWrapper = ({
3738
clientTools,
3839
updateCurrentEventId,
3940
onEndSession,
41+
audioSessionConfiguration,
4042
}: LiveKitRoomWrapperProps) => {
43+
// Configure audio options based on audioSessionConfiguration
44+
const audioOptions = React.useMemo(() => {
45+
if (!audioSessionConfiguration?.allowMixingWithOthers) {
46+
return true;
47+
}
48+
49+
// When mixing is enabled, configure audio to allow concurrent playback
50+
return {
51+
audio: {
52+
noiseSuppression: true,
53+
echoCancellation: true,
54+
},
55+
audioSessionConfiguration: {
56+
allowMixingWithOthers: true,
57+
},
58+
};
59+
}, [audioSessionConfiguration]);
60+
4161
return (
4262
<LiveKitRoom
4363
serverUrl={serverUrl}
4464
token={token}
4565
connect={connect}
46-
audio={true}
66+
audio={audioOptions}
4767
video={false}
4868
options={{
4969
adaptiveStream: { pixelDensity: 'screen' },

packages/react-native/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ export type {
1212
ConversationOptions,
1313
ConversationConfig,
1414
ConversationEvent,
15+
AudioSessionConfiguration,
1516
} from "./types";

packages/react-native/src/types.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import type * as Types from "@elevenlabs/types";
22
import type {
3+
AsrInitiationMetadataEvent as AsrMetadataEvent,
4+
Callbacks,
5+
ConversationMetadata,
6+
Mode as ConversationMode,
37
Incoming,
4-
Outgoing,
58
Interruption,
6-
ConversationMetadata,
7-
Ping,
89
Role as MessageRole,
9-
Mode as ConversationMode,
10+
Outgoing,
11+
Ping,
1012
Status,
11-
Callbacks,
12-
AsrInitiationMetadataEvent as AsrMetadataEvent,
1313
} from "@elevenlabs/types";
1414
export type { Callbacks } from "@elevenlabs/types";
1515

@@ -139,3 +139,20 @@ export type ConversationEvent =
139139
| ConversationMetadataEvent
140140
| AsrInitiationMetadataEvent
141141
| AgentChatResponsePartEvent;
142+
143+
/**
144+
* Audio session configuration for controlling how the SDK handles audio
145+
*/
146+
export interface AudioSessionConfiguration {
147+
/**
148+
* Whether audio should mix with other audio sources.
149+
* When true, the SDK will configure the audio session to allow
150+
* concurrent audio playback with other audio sources.
151+
*
152+
* iOS: Adds AVAudioSessionCategoryOptionMixWithOthers
153+
* Android: Uses AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
154+
*
155+
* @default false (exclusive audio session)
156+
*/
157+
allowMixingWithOthers?: boolean;
158+
}

0 commit comments

Comments
 (0)