#import "ViewController.h" #import // 导入AVKit框架 #import // 导入AVFoundation框架 @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self printAVAudioSessionConfiguration]; [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; [[AVAudioSession sharedInstance] setActive: YES error:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:) name:AVAudioSessionRouteChangeNotification object:nil]; NSLog(@"Current Audio Route: %@", [AVAudioSession sharedInstance].currentRoute); [self printAVAudioSessionConfiguration]; self.view.backgroundColor = [UIColor whiteColor]; // 1. 创建AVPlayerViewController实例 AVPlayerViewController *playerVC = [[AVPlayerViewController alloc] init]; // 2. 创建AVPlayer // 示例HLS URL。请替换为您的实际HLS流地址。 NSURL *hlsURL = [NSURL URLWithString:@"https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8"]; AVPlayer *player = [AVPlayer playerWithURL:hlsURL]; // 3. 将AVPlayer赋值给AVPlayerViewController playerVC.player = player; // 4. 将AVPlayerViewController作为子视图控制器添加 // 在tvOS上,AVPlayerViewController通常作为唯一的或主要内容视图控制器 playerVC.view.frame = self.view.bounds; // 通常全屏显示 [self addChildViewController:playerVC]; [self.view addSubview:playerVC.view]; [playerVC didMoveToParentViewController:self]; // 5. 自动播放 (可选) [player play]; // 您可以通过playerVC访问其player属性来控制播放,例如: // [playerVC.player pause]; // [playerVC.player seekToTime:CMTimeMakeWithSeconds(60, NSEC_PER_SEC)]; } - (void)audioRouteChangeListenerCallback:(NSNotification *)notification { NSDictionary *interruptionDict = notification.userInfo; NSInteger routeChangeReason = [[interruptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; switch (routeChangeReason) { case AVAudioSessionRouteChangeReasonNewDeviceAvailable: NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable"); // 新设备可用,检查是否包含 HomePod break; case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable"); break; case AVAudioSessionRouteChangeReasonCategoryChange: NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange"); break; // ... 其他原因 } NSLog(@"routeChangeReason: %ld, Change Audio Route: %@", routeChangeReason, [AVAudioSession sharedInstance].currentRoute); [self printAVAudioSessionConfiguration]; } // 这是一个示例方法,您可以在 viewDidLoad 或任何需要检查配置的地方调用它 - (void)printAVAudioSessionConfiguration { AVAudioSession *audioSession = [AVAudioSession sharedInstance]; NSLog(@"--- AVAudioSession 配置信息 ---"); // 1. 类别 (Category) // 用于定义音频会话的基本行为(例如,播放、录音、混合等) NSLog(@"Category: %@", audioSession.category); // 2. 模式 (Mode) // 用于优化特定用例的音频行为(例如,视频聊天、语音聊天、测量等) NSLog(@"Mode: %@", audioSession.mode); // 3. 选项 (Category Options) // 类别相关的额外选项,例如是否允许后台播放、是否混音等 AVAudioSessionCategoryOptions options = audioSession.categoryOptions; NSMutableString *optionsString = [NSMutableString string]; if (options & AVAudioSessionCategoryOptionMixWithOthers) { [optionsString appendString:@"MixWithOthers | "]; } if (options & AVAudioSessionCategoryOptionDuckOthers) { [optionsString appendString:@"DuckOthers | "]; } if (options & AVAudioSessionCategoryOptionAllowBluetooth) { [optionsString appendString:@"AllowBluetooth | "]; } if (options & AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers) { [optionsString appendString:@"InterruptSpokenAudioAndMixWithOthers | "]; } if (options & AVAudioSessionCategoryOptionAllowBluetoothA2DP) { [optionsString appendString:@"AllowBluetoothA2DP | "]; } if (options & AVAudioSessionCategoryOptionAllowAirPlay ) { [optionsString appendString:@"AllowAirPlay | "]; } if (optionsString.length > 0) { [optionsString deleteCharactersInRange:NSMakeRange(optionsString.length - 3, 3)]; // 移除末尾的 " | " NSLog(@"Category Options: %@", optionsString); } else { NSLog(@"Category Options: None"); } // 4. 当前是否激活 (Active) // 会话是否已被系统激活并用于音频处理 //NSLog(@"Active: %@", audioSession active ? @"YES" : @"NO"); // 5. 采样率 (Sample Rate) // 音频数据的采样率,单位赫兹 (Hz) NSLog(@"Sample Rate: %f Hz", audioSession.sampleRate); // 6. IO 缓冲区时长 (IO Buffer Duration) // 音频硬件的输入/输出缓冲区大小,影响延迟 NSLog(@"IO Buffer Duration: %f seconds", audioSession.IOBufferDuration); // 7. 通道数 (Channel Count) // 设备支持的输入/输出通道数 NSLog(@"Input Channel Count: %ld", (long)audioSession.inputNumberOfChannels); NSLog(@"Output Channel Count: %ld", (long)audioSession.outputNumberOfChannels); // 8. 硬件输入/输出增益 (Hardware IO Gain) - iOS 10.0+ // 硬件提供的输入/输出增益,通常用于调节麦克风或扬声器音量 if (@available(iOS 10.0, tvOS 10.0, *)) { if (audioSession.isInputGainSettable) { NSLog(@"Input Gain Settable: YES"); NSLog(@"Input Gain: %f dB", audioSession.inputGain); } else { NSLog(@"Input Gain Settable: NO"); } } // 9. 当前路由 (Current Route) // 最重要的部分之一,显示当前音频的输入和输出设备 AVAudioSessionRouteDescription *currentRoute = audioSession.currentRoute; NSLog(@"Current Route:"); for (AVAudioSessionPortDescription *inputPort in currentRoute.inputs) { NSLog(@" Input Port: Type=%@ Name=%@ UID=%@", inputPort.portType, inputPort.portName, inputPort.UID); } for (AVAudioSessionPortDescription *outputPort in currentRoute.outputs) { NSLog(@" Output Port: Type=%@ Name=%@ UID=%@", outputPort.portType, outputPort.portName, outputPort.UID); // 如果是 AirPlay 设备,portType 会是 AVAudioSessionPortAirPlay // portName 会是设备名称(如 "HomePod mini") } // 10. 可用输入 (Available Inputs) // 设备当前可用的所有输入端口 NSLog(@"Available Inputs:"); for (AVAudioSessionPortDescription *inputPort in audioSession.availableInputs) { NSLog(@" Input Port: Type=%@ Name=%@ UID=%@", inputPort.portType, inputPort.portName, inputPort.UID); } NSLog(@"--- 配置信息结束 ---"); } - (void)dealloc { // 在视图控制器销毁时,确保停止播放并释放player资源 for (UIViewController *vc in self.childViewControllers) { if ([vc isKindOfClass:[AVPlayerViewController class]]) { AVPlayerViewController *playerVC = (AVPlayerViewController *)vc; [playerVC.player pause]; // 停止播放 playerVC.player = nil; // 释放player break; } } } @end