Merge branch 'systemAudioEngineTest' into Integration
This commit is contained in:
@@ -185,11 +185,11 @@ public class MicHandler: NSObject {
|
||||
|
||||
private func configureSession() throws {
|
||||
let session = AVAudioSession.sharedInstance()
|
||||
try session.setCategory(.playAndRecord, mode: .videoRecording, options: [.mixWithOthers, .defaultToSpeaker, .allowBluetooth])
|
||||
let bluetoothAudioOption = self.useBuiltinMic ? AVAudioSession.CategoryOptions.allowBluetoothA2DP : AVAudioSession.CategoryOptions.allowBluetooth
|
||||
try session.setCategory(.playAndRecord, mode: .videoRecording, options: [.mixWithOthers, .defaultToSpeaker, bluetoothAudioOption])
|
||||
if #available(iOS 13.0, *) {
|
||||
try session.setAllowHapticsAndSystemSoundsDuringRecording(true)
|
||||
}
|
||||
try session.setActive(true)
|
||||
|
||||
// 列出所有可用输入
|
||||
if self.useBuiltinMic, let inputs = session.availableInputs {
|
||||
@@ -201,6 +201,7 @@ public class MicHandler: NSObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
try session.setActive(true)
|
||||
}
|
||||
|
||||
private func sendOpusFrameFromDequeBuffer() {
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
// Created by Diego Waxemberg on 1/19/14.
|
||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2025.9
|
||||
// Copyright © 2025 True砖家 on Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import "ConnectionCallbacks.h"
|
||||
#import "VideoDecoderRenderer.h"
|
||||
@@ -23,5 +27,6 @@
|
||||
-(BOOL) getVideoStats:(video_stats_t*)stats;
|
||||
-(NSString*) getActiveCodecName;
|
||||
+ (void)setVolume:(float)newVolume;
|
||||
+ (void)setUseSystemAudioEngine:(bool)useSysAudioEngine;
|
||||
|
||||
@end
|
||||
|
||||
+108
-16
@@ -5,6 +5,9 @@
|
||||
// Created by Diego Waxemberg on 1/19/14.
|
||||
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2025.9
|
||||
// Copyright © 2025 True砖家 on Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Connection.h"
|
||||
#import "Plot.h"
|
||||
@@ -47,6 +50,12 @@ static void* audioBuffer;
|
||||
static float volume = 1.0;
|
||||
static int audioFrameSize;
|
||||
|
||||
static bool useSystemAudioEngine;
|
||||
static AVAudioEngine *audioEngine;
|
||||
static AVAudioPlayerNode *audioPlayerNode;
|
||||
static AVAudioPCMBuffer *pcmBuffer;
|
||||
static AVAudioFormat *audioFormat;
|
||||
|
||||
static VideoDecoderRenderer* renderer;
|
||||
|
||||
static BandwidthTracker *bwTracker;
|
||||
@@ -276,10 +285,20 @@ int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, v
|
||||
SDL_PauseAudioDevice(audioDevice, 0);
|
||||
|
||||
// Disable lowering volume of other audio streams (SDL sets AVAudioSessionCategoryOptionDuckOthers by default)
|
||||
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
|
||||
|
||||
// AVAudioSessionCategoryOptionAllowBluetoothA2DP
|
||||
// AVAudioSessionCategoryOptionAllowBluetooth
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
TemporarySettings* tempSettings = [dataMan getSettings];
|
||||
bool useBluetoothD2P = tempSettings.useBuiltinMic || !tempSettings.redirectMic;
|
||||
AVAudioSessionCategoryOptions bluetoothAudioOption = useBluetoothD2P ? AVAudioSessionCategoryOptionAllowBluetoothA2DP : AVAudioSessionCategoryOptionAllowBluetooth;
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
[session setCategory:AVAudioSessionCategoryPlayAndRecord
|
||||
withOptions:AVAudioSessionCategoryOptionMixWithOthers|AVAudioSessionCategoryOptionDefaultToSpeaker|bluetoothAudioOption
|
||||
error:nil];
|
||||
[session setActive:YES error:nil];
|
||||
|
||||
AudioEngineInit(audioConfig.sampleRate, audioConfig.channelCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -310,6 +329,57 @@ void ArCleanup(void)
|
||||
volume = powf(linearVolume, exponent);
|
||||
}
|
||||
|
||||
+ (void)setUseSystemAudioEngine:(bool)useSysAudioEngine{
|
||||
useSystemAudioEngine = useSysAudioEngine;
|
||||
}
|
||||
|
||||
void AudioEngineInit(int sampleRate, int channelCount) {
|
||||
|
||||
audioEngine = [[AVAudioEngine alloc] init];
|
||||
audioPlayerNode = [[AVAudioPlayerNode alloc] init];
|
||||
|
||||
[audioEngine attachNode:audioPlayerNode];
|
||||
|
||||
AVAudioChannelLayout *layout;
|
||||
|
||||
switch (channelCount) {
|
||||
case 2:
|
||||
default:
|
||||
audioFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
|
||||
sampleRate:sampleRate
|
||||
channels:channelCount
|
||||
interleaved:NO];
|
||||
break;
|
||||
case 6:
|
||||
layout =
|
||||
[[AVAudioChannelLayout alloc] initWithLayoutTag:kAudioChannelLayoutTag_MPEG_5_1_A];
|
||||
audioFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
|
||||
sampleRate:sampleRate
|
||||
interleaved:NO
|
||||
channelLayout:layout];
|
||||
break;
|
||||
case 8:
|
||||
layout =
|
||||
[[AVAudioChannelLayout alloc] initWithLayoutTag:kAudioChannelLayoutTag_MPEG_7_1_A];
|
||||
audioFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
|
||||
sampleRate:sampleRate
|
||||
interleaved:NO
|
||||
channelLayout:layout];
|
||||
break;
|
||||
}
|
||||
|
||||
if(!audioFormat) return;
|
||||
|
||||
[audioEngine connect:audioPlayerNode to:audioEngine.mainMixerNode format:audioFormat];
|
||||
|
||||
NSError *err = nil;
|
||||
if (![audioEngine startAndReturnError:&err]) {
|
||||
NSLog(@"AudioEngine start error: %@", err);
|
||||
}
|
||||
|
||||
[audioPlayerNode play];
|
||||
}
|
||||
|
||||
void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
|
||||
{
|
||||
int decodeLen;
|
||||
@@ -333,21 +403,41 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
|
||||
|
||||
float* fbuf = (float*)audioBuffer;
|
||||
|
||||
if(volume != 1.0){
|
||||
int totalSamples = decodeLen * audioConfig.channelCount;
|
||||
for (int i = 0; i < totalSamples; i++) {
|
||||
fbuf[i] *= volume;
|
||||
// if(useSystemAudioEngine && false) {
|
||||
if(true){
|
||||
// 创建 AVAudioPCMBuffer
|
||||
AVAudioFrameCount frameCount = decodeLen;
|
||||
AVAudioPCMBuffer *buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:audioFormat frameCapacity:frameCount];
|
||||
buffer.frameLength = frameCount;
|
||||
|
||||
// 拷贝数据到 buffer
|
||||
for (int ch = 0; ch < audioConfig.channelCount; ch++) {
|
||||
float *dst = buffer.floatChannelData[ch];
|
||||
for (int i = 0; i < decodeLen; i++) {
|
||||
dst[i] = fbuf[i * audioConfig.channelCount + ch] * volume; // 非交错数据
|
||||
}
|
||||
}
|
||||
// 播放
|
||||
[audioPlayerNode scheduleBuffer:buffer completionHandler:nil];
|
||||
}
|
||||
|
||||
while (SDL_GetQueuedAudioSize(audioDevice) / audioFrameSize > 10) {
|
||||
[NSThread sleepForTimeInterval:0.001f];
|
||||
}
|
||||
|
||||
if (SDL_QueueAudio(audioDevice,
|
||||
audioBuffer,
|
||||
sizeof(float) * decodeLen * audioConfig.channelCount) < 0) {
|
||||
Log(LOG_E, @"Failed to queue audio sample: %s\n", SDL_GetError());
|
||||
else{
|
||||
if(volume != 1.0){
|
||||
int totalSamples = decodeLen * audioConfig.channelCount;
|
||||
for (int i = 0; i < totalSamples; i++) {
|
||||
fbuf[i] *= volume;
|
||||
}
|
||||
}
|
||||
|
||||
while (SDL_GetQueuedAudioSize(audioDevice) / audioFrameSize > 10) {
|
||||
[NSThread sleepForTimeInterval:0.001f];
|
||||
}
|
||||
|
||||
if (SDL_QueueAudio(audioDevice,
|
||||
audioBuffer,
|
||||
sizeof(float) * decodeLen * audioConfig.channelCount) < 0) {
|
||||
Log(LOG_E, @"Failed to queue audio sample: %s\n", SDL_GetError());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -423,7 +513,9 @@ void ClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t
|
||||
// won't be able to acquire it if LiStartConnection is in
|
||||
// progress.
|
||||
LiInterruptConnection();
|
||||
|
||||
[audioPlayerNode stop];
|
||||
[audioEngine stop];
|
||||
|
||||
// We dispatch this async to get out because this can be invoked
|
||||
// on a thread inside common and we don't want to deadlock. It also avoids
|
||||
// blocking on the caller's thread waiting to acquire initLock.
|
||||
|
||||
Reference in New Issue
Block a user