// // KBAiMainVC.m // keyBoard // // Created by Mac on 2026/1/15. // #import "KBAiMainVC.h" #import "ConversationOrchestrator.h" #import "AiVM.h" #import "AudioSessionManager.h" #import "DeepgramStreamingManager.h" #import "KBAICommentView.h" #import "KBAiChatView.h" #import "KBAiRecordButton.h" #import "KBHUD.h" #import "LSTPopView.h" #import "VoiceChatStreamingManager.h" #import "KBUserSessionManager.h" #import @interface KBAiMainVC () @property(nonatomic, weak) LSTPopView *popView; // UI @property(nonatomic, strong) KBAiChatView *chatView; @property(nonatomic, strong) KBAiRecordButton *recordButton; @property(nonatomic, strong) UILabel *statusLabel; @property(nonatomic, strong) UILabel *transcriptLabel; @property(nonatomic, strong) UIButton *commentButton; @property(nonatomic, strong) KBAICommentView *commentView; @property(nonatomic, strong) UIView *tabbarBackgroundView; @property(nonatomic, strong) UIVisualEffectView *blurEffectView; @property(nonatomic, strong) CAGradientLayer *gradientLayer; @property(nonatomic, strong) UIImageView *personImageView; // 核心模块 @property(nonatomic, strong) ConversationOrchestrator *orchestrator; @property(nonatomic, strong) VoiceChatStreamingManager *streamingManager; @property(nonatomic, strong) DeepgramStreamingManager *deepgramManager; @property(nonatomic, strong) AiVM *aiVM; @property(nonatomic, strong) AVAudioPlayer *aiAudioPlayer; @property(nonatomic, strong) NSMutableData *voiceChatAudioBuffer; // 文本跟踪 @property(nonatomic, strong) NSMutableString *assistantVisibleText; @property(nonatomic, strong) NSMutableString *deepgramFullText; // 日志节流 @property(nonatomic, assign) NSTimeInterval lastRMSLogTime; @end @implementation KBAiMainVC #pragma mark - Lifecycle - (void)viewDidLoad { [super viewDidLoad]; // 让视图延伸到屏幕边缘(包括状态栏和导航栏下方) self.edgesForExtendedLayout = UIRectEdgeAll; self.extendedLayoutIncludesOpaqueBars = YES; [self setupUI]; [self setupOrchestrator]; [self setupStreamingManager]; // 切换到 websocket-api 方案,Deepgram 暂不初始化 // [self setupDeepgramManager]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // TabBar 背景色由 BaseTabBarController 统一管理,这里不需要设置 } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 页面消失时停止对话 [self.orchestrator stop]; [self.streamingManager disconnect]; [self.deepgramManager disconnect]; } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; // 只更新 mask 的 frame(mask 已在 setupUI 中创建) if (self.blurEffectView.layer.mask) { self.blurEffectView.layer.mask.frame = self.blurEffectView.bounds; } } #pragma mark - UI Setup - (void)setupUI { self.view.backgroundColor = [UIColor whiteColor]; self.title = @"AI 助手"; // 安全区域 UILayoutGuide *safeArea = self.view.safeAreaLayoutGuide; // PersonImageView(背景图,最底层) self.personImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"person_icon"]]; [self.view addSubview:self.personImageView]; [self.personImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.top.bottom.equalTo(self.view); }]; // TabBar 毛玻璃模糊背景(在 personImageView 之上) self.tabbarBackgroundView = [[UIView alloc] init]; self.tabbarBackgroundView.translatesAutoresizingMaskIntoConstraints = NO; self.tabbarBackgroundView.clipsToBounds = YES; [self.view addSubview:self.tabbarBackgroundView]; // 模糊效果 UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; self.blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; self.blurEffectView.translatesAutoresizingMaskIntoConstraints = NO; [self.tabbarBackgroundView addSubview:self.blurEffectView]; // 为 blurEffectView 创建透明度渐变 // mask(从底部到中间不透明,从中间到顶部透明) CAGradientLayer *maskLayer = [CAGradientLayer layer]; maskLayer.startPoint = CGPointMake(0.5, 1); // 底部 maskLayer.endPoint = CGPointMake(0.5, 0); // 顶部 // 底部到中间保持不透明,从中间到顶部过渡透明 maskLayer.colors = @[ (__bridge id)[UIColor whiteColor].CGColor, // 底部:完全不透明 (__bridge id)[UIColor whiteColor].CGColor, // 中间:完全不透明 (__bridge id)[UIColor clearColor].CGColor // 顶部:完全透明 ]; maskLayer.locations = @[ @(0.0), @(0.5), @(1.0) ]; self.blurEffectView.layer.mask = maskLayer; // 状态标签 self.statusLabel = [[UILabel alloc] init]; self.statusLabel.text = @"按住按钮开始对话"; self.statusLabel.font = [UIFont systemFontOfSize:14]; self.statusLabel.textColor = [UIColor secondaryLabelColor]; self.statusLabel.textAlignment = NSTextAlignmentCenter; self.statusLabel.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:self.statusLabel]; // 转写文本标签 self.transcriptLabel = [[UILabel alloc] init]; self.transcriptLabel.text = @""; self.transcriptLabel.font = [UIFont systemFontOfSize:16]; self.transcriptLabel.textColor = [UIColor labelColor]; self.transcriptLabel.numberOfLines = 0; self.transcriptLabel.textAlignment = NSTextAlignmentRight; self.transcriptLabel.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:self.transcriptLabel]; // 聊天视图 self.chatView = [[KBAiChatView alloc] init]; self.chatView.backgroundColor = [UIColor clearColor]; self.chatView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:self.chatView]; // 录音按钮 self.recordButton = [[KBAiRecordButton alloc] init]; self.recordButton.delegate = self; self.recordButton.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:self.recordButton]; // 评论按钮(聊天视图右侧居中) self.commentButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.commentButton setImage:[UIImage systemImageNamed:@"bubble.right.fill"] forState:UIControlStateNormal]; self.commentButton.tintColor = [UIColor whiteColor]; self.commentButton.backgroundColor = [UIColor systemBlueColor]; self.commentButton.layer.cornerRadius = 25; self.commentButton.layer.shadowColor = [UIColor blackColor].CGColor; self.commentButton.layer.shadowOffset = CGSizeMake(0, 2); self.commentButton.layer.shadowOpacity = 0.3; self.commentButton.layer.shadowRadius = 4; self.commentButton.translatesAutoresizingMaskIntoConstraints = NO; [self.commentButton addTarget:self action:@selector(showComment) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.commentButton]; // 布局约束 - 使用 Masonry [self.tabbarBackgroundView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.bottom.equalTo(self.view); make.height.mas_equalTo(KBFit(238)); }]; [self.blurEffectView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.tabbarBackgroundView); }]; [self.statusLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop).offset(8); make.left.equalTo(self.view).offset(16); make.right.equalTo(self.view).offset(-16); }]; [self.transcriptLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.statusLabel.mas_bottom).offset(8); make.left.equalTo(self.view).offset(16); make.right.equalTo(self.view).offset(-16); }]; [self.chatView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.transcriptLabel.mas_bottom).offset(8); make.left.equalTo(self.view).offset(16); make.right.equalTo(self.view).offset(-16); make.bottom.lessThanOrEqualTo(self.recordButton.mas_top).offset(-16); }]; [self.recordButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view.mas_safeAreaLayoutGuideLeft).offset(20); make.right.equalTo(self.view.mas_safeAreaLayoutGuideRight).offset(-20); make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-16); make.height.mas_equalTo(50); }]; [self.commentButton mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self.view.mas_safeAreaLayoutGuideRight).offset(-16); make.centerY.equalTo(self.view); make.width.height.mas_equalTo(50); }]; } #pragma mark - Orchestrator Setup - (void)setupOrchestrator { self.orchestrator = [[ConversationOrchestrator alloc] init]; // 配置服务器地址 // 1. ASR 语音识别服务(WebSocket) self.orchestrator.asrServerURL = @"ws://192.168.2.21:7529/ws/asr"; // 2. LLM 大语言模型服务(HTTP Stream) self.orchestrator.llmServerURL = @"http://192.168.2.21:7529/api/chat/stream"; // 3. TTS 语音合成服务(HTTP) self.orchestrator.ttsServerURL = @"http://192.168.2.21:7529/api/tts/stream"; __weak typeof(self) weakSelf = self; // 状态变化回调 self.orchestrator.onStateChange = ^(ConversationState state) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; [strongSelf updateStatusForState:state]; }; // 实时识别文本回调 self.orchestrator.onPartialText = ^(NSString *text) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; strongSelf.statusLabel.text = text.length > 0 ? text : @"正在识别..."; }; // 用户最终文本回调 self.orchestrator.onUserFinalText = ^(NSString *text) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; if (text.length > 0) { [strongSelf.chatView addUserMessage:text]; } }; // AI 可见文本回调(打字机效果) self.orchestrator.onAssistantVisibleText = ^(NSString *text) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; [strongSelf.chatView updateLastAssistantMessage:text]; }; // AI 完整回复回调 self.orchestrator.onAssistantFullText = ^(NSString *text) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; [strongSelf.chatView updateLastAssistantMessage:text]; [strongSelf.chatView markLastAssistantMessageComplete]; }; // 音量更新回调 self.orchestrator.onVolumeUpdate = ^(float rms) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; [strongSelf.recordButton updateVolumeRMS:rms]; }; // AI 开始说话 self.orchestrator.onSpeakingStart = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; // 添加空的 AI 消息占位 [strongSelf.chatView addAssistantMessage:@""]; }; // AI 说话结束 self.orchestrator.onSpeakingEnd = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; [strongSelf.chatView markLastAssistantMessageComplete]; }; // 错误回调 self.orchestrator.onError = ^(NSError *error) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; [strongSelf showError:error]; }; } #pragma mark - Streaming Manager - (void)setupStreamingManager { self.streamingManager = [[VoiceChatStreamingManager alloc] init]; self.streamingManager.delegate = self; self.streamingManager.serverURL = @"ws://192.168.2.21:7529/api/ws/chat"; self.assistantVisibleText = [[NSMutableString alloc] init]; self.voiceChatAudioBuffer = [[NSMutableData alloc] init]; self.lastRMSLogTime = 0; } #pragma mark - Deepgram Manager - (void)setupDeepgramManager { self.deepgramManager = [[DeepgramStreamingManager alloc] init]; self.deepgramManager.delegate = self; self.deepgramManager.serverURL = @"wss://api.deepgram.com/v1/listen"; self.deepgramManager.apiKey = @"9c792eb63a65d644cbc95785155754cd1e84f8cf"; self.deepgramManager.language = @"en"; self.deepgramManager.model = @"nova-3"; self.deepgramManager.punctuate = YES; self.deepgramManager.smartFormat = YES; self.deepgramManager.interimResults = YES; self.deepgramManager.encoding = @"linear16"; self.deepgramManager.sampleRate = 16000.0; self.deepgramManager.channels = 1; [self.deepgramManager prepareConnection]; self.deepgramFullText = [[NSMutableString alloc] init]; self.aiVM = [[AiVM alloc] init]; } #pragma mark - 事件 - (void)showComment { CGFloat customViewHeight = KB_SCREEN_HEIGHT * (0.8); KBAICommentView *customView = [[KBAICommentView alloc] initWithFrame:CGRectMake(0, 0, KB_SCREEN_WIDTH, customViewHeight)]; LSTPopView *popView = [LSTPopView initWithCustomView:customView parentView:nil popStyle:LSTPopStyleSmoothFromBottom dismissStyle:LSTDismissStyleSmoothToBottom]; self.popView = popView; popView.priority = 1000; popView.isAvoidKeyboard = false; popView.hemStyle = LSTHemStyleBottom; popView.dragStyle = LSTDragStyleY_Positive; popView.dragDistance = customViewHeight * 0.5; popView.sweepStyle = LSTSweepStyleY_Positive; popView.swipeVelocity = 1600; popView.sweepDismissStyle = LSTSweepDismissStyleSmooth; [popView pop]; } - (void)showCommentDirectly { if (self.commentView.superview) { [self.view bringSubviewToFront:self.commentView]; return; } CGFloat customViewHeight = KB_SCREEN_HEIGHT * (0.8); KBAICommentView *customView = [[KBAICommentView alloc] initWithFrame:CGRectZero]; customView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:customView]; [NSLayoutConstraint activateConstraints:@[ [customView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [customView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [customView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], [customView.heightAnchor constraintEqualToConstant:customViewHeight], ]]; self.commentView = customView; } #pragma mark - UI Updates - (void)updateStatusForState:(ConversationState)state { switch (state) { case ConversationStateIdle: self.statusLabel.text = @"按住按钮开始对话"; self.recordButton.state = KBAiRecordButtonStateNormal; break; case ConversationStateListening: self.statusLabel.text = @"正在聆听..."; self.recordButton.state = KBAiRecordButtonStateRecording; break; case ConversationStateRecognizing: self.statusLabel.text = @"正在识别..."; self.recordButton.state = KBAiRecordButtonStateNormal; break; case ConversationStateThinking: self.statusLabel.text = @"AI 正在思考..."; self.recordButton.state = KBAiRecordButtonStateNormal; break; case ConversationStateSpeaking: self.statusLabel.text = @"AI 正在回复..."; self.recordButton.state = KBAiRecordButtonStateNormal; break; } } - (void)showError:(NSError *)error { UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"错误" message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alert animated:YES completion:nil]; } #pragma mark - KBAiRecordButtonDelegate - (void)recordButtonDidBeginPress:(KBAiRecordButton *)button { NSLog(@"[KBAiMainVC] Record button began press"); NSString *token = [[KBUserSessionManager shared] accessToken] ?: @""; if (token.length == 0) { [[KBUserSessionManager shared] goLoginVC]; return; } self.statusLabel.text = @"正在连接..."; self.recordButton.state = KBAiRecordButtonStateRecording; self.transcriptLabel.text = @""; [self.voiceChatAudioBuffer setLength:0]; [self.streamingManager startWithToken:token language:@"en" voiceId:nil]; } - (void)recordButtonDidEndPress:(KBAiRecordButton *)button { NSLog(@"[KBAiMainVC] Record button end press"); [self.streamingManager stopAndFinalize]; } - (void)recordButtonDidCancelPress:(KBAiRecordButton *)button { NSLog(@"[KBAiMainVC] Record button cancel press"); [self.voiceChatAudioBuffer setLength:0]; [self.streamingManager cancel]; } #pragma mark - VoiceChatStreamingManagerDelegate - (void)voiceChatStreamingManagerDidConnect { self.statusLabel.text = @"已连接,准备中..."; } - (void)voiceChatStreamingManagerDidDisconnect:(NSError *_Nullable)error { self.recordButton.state = KBAiRecordButtonStateNormal; if (error) { [self showError:error]; } } - (void)voiceChatStreamingManagerDidStartSession:(NSString *)sessionId { self.statusLabel.text = @"正在聆听..."; self.recordButton.state = KBAiRecordButtonStateRecording; } - (void)voiceChatStreamingManagerDidStartTurn:(NSInteger)turnIndex { self.statusLabel.text = @"正在聆听..."; self.recordButton.state = KBAiRecordButtonStateRecording; } - (void)voiceChatStreamingManagerDidReceiveEagerEndOfTurnWithTranscript:(NSString *)text confidence:(double)confidence { self.statusLabel.text = @"准备响应..."; } - (void)voiceChatStreamingManagerDidResumeTurn { self.statusLabel.text = @"正在聆听..."; } - (void)voiceChatStreamingManagerDidUpdateRMS:(float)rms { [self.recordButton updateVolumeRMS:rms]; NSTimeInterval now = [[NSDate date] timeIntervalSince1970]; if (now - self.lastRMSLogTime >= 1.0) { self.lastRMSLogTime = now; NSLog(@"[KBAiMainVC] RMS: %.3f", rms); } } - (void)voiceChatStreamingManagerDidReceiveInterimTranscript:(NSString *)text { self.statusLabel.text = @"正在识别..."; if (text.length > 0) { self.transcriptLabel.text = text; } } - (void)voiceChatStreamingManagerDidReceiveFinalTranscript:(NSString *)text { if (text.length > 0) { self.transcriptLabel.text = @""; [self.chatView addUserMessage:text]; } } - (void)voiceChatStreamingManagerDidReceiveLLMStart { self.statusLabel.text = @"AI 正在思考..."; [self.assistantVisibleText setString:@""]; [self.chatView addAssistantMessage:@""]; [self.voiceChatAudioBuffer setLength:0]; } - (void)voiceChatStreamingManagerDidReceiveLLMToken:(NSString *)token { if (token.length == 0) { return; } [self.assistantVisibleText appendString:token]; [self.chatView updateLastAssistantMessage:self.assistantVisibleText]; } - (void)voiceChatStreamingManagerDidReceiveAudioChunk:(NSData *)audioData { if (audioData.length == 0) { return; } [self.voiceChatAudioBuffer appendData:audioData]; } - (void)voiceChatStreamingManagerDidCompleteWithTranscript:(NSString *)transcript aiResponse:(NSString *)aiResponse { NSString *finalText = aiResponse.length > 0 ? aiResponse : self.assistantVisibleText; if (aiResponse.length > 0) { [self.assistantVisibleText setString:aiResponse]; } if (finalText.length > 0) { [self.chatView updateLastAssistantMessage:finalText]; [self.chatView markLastAssistantMessageComplete]; } else if (transcript.length > 0) { [self.chatView addAssistantMessage:transcript]; [self.chatView markLastAssistantMessageComplete]; } if (self.voiceChatAudioBuffer.length > 0) { [self playAiAudioData:self.voiceChatAudioBuffer]; [self.voiceChatAudioBuffer setLength:0]; } self.recordButton.state = KBAiRecordButtonStateNormal; self.statusLabel.text = @"完成"; } - (void)voiceChatStreamingManagerDidFail:(NSError *)error { self.recordButton.state = KBAiRecordButtonStateNormal; [self showError:error]; } #pragma mark - DeepgramStreamingManagerDelegate - (void)deepgramStreamingManagerDidConnect { self.statusLabel.text = @"已连接,准备中..."; } - (void)deepgramStreamingManagerDidDisconnect:(NSError *_Nullable)error { self.recordButton.state = KBAiRecordButtonStateNormal; if (error) { [self showError:error]; } } - (void)deepgramStreamingManagerDidUpdateRMS:(float)rms { [self.recordButton updateVolumeRMS:rms]; NSTimeInterval now = [[NSDate date] timeIntervalSince1970]; if (now - self.lastRMSLogTime >= 1.0) { self.lastRMSLogTime = now; NSLog(@"[KBAiMainVC] RMS: %.3f", rms); } } - (void)deepgramStreamingManagerDidReceiveInterimTranscript:(NSString *)text { self.statusLabel.text = @"正在识别..."; NSString *displayText = text ?: @""; if (self.deepgramFullText.length > 0 && displayText.length > 0) { displayText = [NSString stringWithFormat:@"%@ %@", self.deepgramFullText, displayText]; } else if (self.deepgramFullText.length > 0) { displayText = [self.deepgramFullText copy]; } self.transcriptLabel.text = displayText; } - (void)deepgramStreamingManagerDidReceiveFinalTranscript:(NSString *)text { if (text.length > 0) { if (self.deepgramFullText.length > 0) { [self.deepgramFullText appendString:@" "]; } [self.deepgramFullText appendString:text]; } self.transcriptLabel.text = self.deepgramFullText; self.statusLabel.text = @"识别完成"; self.recordButton.state = KBAiRecordButtonStateNormal; // NSString *finalText = [self.deepgramFullText copy]; // if (finalText.length > 0) { // __weak typeof(self) weakSelf = self; // [KBHUD show]; // [self.aiVM syncChatWithTranscript:finalText // completion:^(KBAiSyncResponse *_Nullable response, // NSError *_Nullable error) { // __strong typeof(weakSelf) strongSelf = weakSelf; // if (!strongSelf) { // return; // } // dispatch_async(dispatch_get_main_queue(), ^{ // [KBHUD dismiss]; // if (error) { // [KBHUD showError:error.localizedDescription ?: @"请求失败"]; // return; // } // // NSString *aiResponse = response.data.aiResponse ?: @""; // if (aiResponse.length > 0) { // NSLog(@"[KBAiMainVC] /chat/sync aiResponse: %@", aiResponse); // } // // NSData *audioData = response.data.audioData; // if (audioData.length > 0) { // NSLog(@"[KBAiMainVC] /chat/sync audio ready, start play"); // [strongSelf playAiAudioData:audioData]; // } else { // NSLog(@"[KBAiMainVC] /chat/sync audioData empty"); // } // }); // }]; // } } - (void)deepgramStreamingManagerDidFail:(NSError *)error { self.recordButton.state = KBAiRecordButtonStateNormal; [self showError:error]; } #pragma mark - Audio Playback - (void)playAiAudioData:(NSData *)audioData { if (audioData.length == 0) { return; } NSError *sessionError = nil; AudioSessionManager *audioSession = [AudioSessionManager sharedManager]; if (![audioSession configureForPlayback:&sessionError]) { NSLog(@"[KBAiMainVC] Configure playback failed: %@", sessionError.localizedDescription ?: @""); } if (![audioSession activateSession:&sessionError]) { NSLog(@"[KBAiMainVC] Activate playback session failed: %@", sessionError.localizedDescription ?: @""); } NSError *error = nil; self.aiAudioPlayer = [[AVAudioPlayer alloc] initWithData:audioData error:&error]; if (error || !self.aiAudioPlayer) { NSLog(@"[KBAiMainVC] Audio player init failed: %@", error.localizedDescription ?: @""); return; } self.aiAudioPlayer.delegate = self; [self.aiAudioPlayer prepareToPlay]; [self.aiAudioPlayer play]; } #pragma mark - AVAudioPlayerDelegate - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { [[AudioSessionManager sharedManager] deactivateSession]; } @end