Hi developers,
This is a factual timeline of exactly what has happened since the last successful build (#132) after we upgraded to Convai SDK 4.1.0.
Build #132 (last good run):
Everything worked on iPhone — NPC voice connection, microphone permission, and audio session were all functioning correctly.
The three files that were in the project at that time are attached below exactly as they existed for #132 (we have since restored them multiple times).
What happened next (builds #133 through #138):
-
We made no intentional code changes between #132 and #133.
-
Build #133 and every build after it showed the same “connection error” on the iPhone immediately when selecting an NPC.
-
The iPhone logs no longer contained any of the debug lines from ConvaiAudioSessionManager or the native stub (“Permission GRANTED”, “AVAudioSession fully configured”, etc.).
-
We tried re-committing the exact same three files that worked in #132 (link.xml, ConvaiAudioSessionManager.cs, ConvaiAudioStub.mm) multiple times.
-
Build #138 failed to compile with this error: Assets/Scripts/NPCSelectionScreenManager.cs(120,13): error CS0117: ‘ConvaiAudioSessionManager’ does not contain a definition for ‘Configure’ (and the same error for HasPermission calls).
To fix the compile error I restored the missing static Configure() and HasPermission() methods while keeping the early-init logic we had been testing. I have not changed anything else.
Current files in the project (the ones that will be in build #139):
1. link.xml (unchanged since #132)
XML
<linker>
<assembly fullname="Assembly-CSharp" preserve="all"/>
<assembly fullname="Assembly-CSharp-firstpass" preserve="all"/>
</linker>
2. ConvaiAudioSessionManager.cs (full file — this is the version that fixes the compile error)
C#
using UnityEngine;
using System.Runtime.InteropServices;
using System.Collections;
public class ConvaiAudioSessionManager : MonoBehaviour
{
[DllImport("__Internal")]
private static extern void __RequestAudioSessionAndConfigure();
[DllImport("__Internal")]
private static extern bool __IsMicPermissionGranted();
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void InitializeVeryEarly()
{
Debug.Log("=== EARLY AUDIO INIT BUILD 139 - Running BEFORE any scene loads ===");
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
__RequestAudioSessionAndConfigure();
}
}
private void Awake()
{
DontDestroyOnLoad(gameObject);
Debug.Log("=== ConvaiAudioSessionManager Awake called ===");
}
private IEnumerator Start()
{
yield return null;
Debug.Log("[ConvaiAudioSessionManager] Requesting microphone permission...");
if (!Application.HasUserAuthorization(UserAuthorization.Microphone))
{
yield return Application.RequestUserAuthorization(UserAuthorization.Microphone);
}
if (Application.HasUserAuthorization(UserAuthorization.Microphone))
{
Debug.Log("[ConvaiAudioSessionManager] Permission GRANTED");
__RequestAudioSessionAndConfigure();
}
else
{
Debug.LogError("[ConvaiAudioSessionManager] Microphone permission DENIED");
}
}
public static void Configure()
{
Debug.Log("[ConvaiAudioSessionManager] Configure() called from other script");
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
__RequestAudioSessionAndConfigure();
}
}
public static bool HasPermission() => Application.HasUserAuthorization(UserAuthorization.Microphone);
}
3. ConvaiAudioStub.mm (unchanged since #132)
Objective-C
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
extern "C" {
void ConfigureLiveKitAudioSession() {
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error = nil;
[session setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker |
AVAudioSessionCategoryOptionAllowBluetooth |
AVAudioSessionCategoryOptionMixWithOthers
error:&error];
if (error) NSLog(@"[ConvaiAudioStub] setCategory error: %@", error);
[session setMode:AVAudioSessionModeVoiceChat error:&error];
if (error) NSLog(@"[ConvaiAudioStub] setMode error: %@", error);
[session setActive:YES
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
error:&error];
if (error) {
NSLog(@"[ConvaiAudioStub] setActive error: %@", error);
} else {
NSLog(@"[ConvaiAudioStub] ✅ AVAudioSession fully configured for LiveKit voice");
}
}
__attribute__((visibility("default")))
bool __IsMicPermissionGranted() {
NSLog(@"[ConvaiAudioStub] __IsMicPermissionGranted called → returning YES");
return true;
}
__attribute__((visibility("default")))
void __RequestAudioSessionAndConfigure() {
NSLog(@"[ConvaiAudioStub] __RequestAudioSessionAndConfigure called → configuring LiveKit");
ConfigureLiveKitAudioSession();
}
// Legacy catch-alls
__attribute__((visibility("default"))) void Configure() { ConfigureLiveKitAudioSession(); }
__attribute__((visibility("default"))) void _Configure() { ConfigureLiveKitAudioSession(); }
__attribute__((visibility("default"))) void __Configure() { ConfigureLiveKitAudioSession(); }
__attribute__((visibility("default"))) void RequestAudioSessionAndConfigure() { ConfigureLiveKitAudioSession(); }
__attribute__((visibility("default"))) void _RequestAudioSessionAndConfigure() { ConfigureLiveKitAudioSession(); }
}
I am now running build #139 with exactly these files. I will send you the new iPhone log as soon as it finishes.
That is everything that has happened since #132. No other changes were made to the project.