mirror of
https://github.com/zakk4223/CocoaSplit.git
synced 2026-05-15 14:15:50 -06:00
Initial work on clean/modernization of the audio engine.
Audio Graph now keeps track of connections via connection objects. Connecting nodes now requires an AudioFormat, and the format is set on both ends of the connection. No more explicit setting of stream formats. CAMultAudioPCM is now based on AVAudioPCMBuffer Most instances of AudioStreamBasicDescription are replaced with AVAudioFormat
This commit is contained in:
parent
4226e7facc
commit
51e4356993
47 changed files with 652 additions and 1122 deletions
|
|
@ -42,7 +42,7 @@
|
|||
dispatch_queue_t _video_decoder_queue;
|
||||
dispatch_queue_t _media_reader_queue;
|
||||
CAMultiAudioPCM *_bufferPCM;
|
||||
AudioStreamBasicDescription _asbd;
|
||||
AVAudioFormat * _audioFormat;
|
||||
CFTimeInterval _lastTimeUpdate;
|
||||
double _savedTime;
|
||||
NSSize _lastSize;
|
||||
|
|
|
|||
|
|
@ -96,18 +96,11 @@
|
|||
|
||||
//Inputs resample to floating point non-interleaved 48k for now.
|
||||
|
||||
_asbd.mSampleRate = 48000;
|
||||
_asbd.mFormatID = kAudioFormatLinearPCM;
|
||||
_asbd.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved;
|
||||
_asbd.mChannelsPerFrame = 2;
|
||||
_asbd.mBitsPerChannel = 32;
|
||||
_asbd.mBytesPerFrame = 4;
|
||||
_asbd.mBytesPerPacket = 4;
|
||||
_asbd.mFramesPerPacket = 1;
|
||||
|
||||
_audioFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:48000.0f channels:2];
|
||||
self.player = [[CSFFMpegPlayer alloc] init];
|
||||
|
||||
self.player.asbd = &_asbd;
|
||||
self.player.audioFormat = _audioFormat;
|
||||
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
|
|
@ -504,11 +497,11 @@
|
|||
|
||||
if (!self.pcmPlayer)
|
||||
{
|
||||
self.pcmPlayer = [self createAttachedAudioInputForUUID:self.uuid withName:withName withFormat:&_asbd];
|
||||
self.pcmPlayer = [self createAttachedAudioInputForUUID:self.uuid withName:withName withFormat:_audioFormat];
|
||||
|
||||
if (self.pcmPlayer && self.player)
|
||||
{
|
||||
self.player.asbd = &_asbd;
|
||||
self.player.audioFormat = _audioFormat;
|
||||
self.player.pcmPlayer = self.pcmPlayer;
|
||||
if (self.player.currentlyPlaying)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@
|
|||
|
||||
|
||||
|
||||
-(CAMultiAudioPCM *)consumeAudioFrame:(AudioStreamBasicDescription *)asbd error_out:(int *)error_out
|
||||
-(CAMultiAudioPCM *)consumeAudioFrame:(AVAudioFormat *)audioFormat error_out:(int *)error_out
|
||||
{
|
||||
struct frame_message msg;
|
||||
uint8_t *arrBuf[2] = {0};
|
||||
|
|
@ -234,10 +234,11 @@
|
|||
{
|
||||
//flush PCM player
|
||||
av_frame_free(&recv_frame);
|
||||
CAMultiAudioPCM *flushPCM = [[CAMultiAudioPCM alloc] init];
|
||||
flushPCM.frameCount = -1;
|
||||
flushPCM.bufferCount = -1;
|
||||
return flushPCM;
|
||||
*error_out = AVERROR_PATCHWELCOME;
|
||||
|
||||
//flushPCM.frameCount = -1;
|
||||
//flushPCM.bufferCount = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dst_linesize;
|
||||
|
|
@ -249,14 +250,14 @@
|
|||
{
|
||||
channel_layout = av_get_default_channel_layout(_audio_codec_ctx->channels);
|
||||
}
|
||||
_swr_ctx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_FLTP, asbd->mSampleRate, channel_layout, _audio_codec_ctx->sample_fmt, _audio_codec_ctx->sample_rate, 0, NULL);
|
||||
_swr_ctx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_FLTP, audioFormat.sampleRate, channel_layout, _audio_codec_ctx->sample_fmt, _audio_codec_ctx->sample_rate, 0, NULL);
|
||||
swr_init(_swr_ctx);
|
||||
}
|
||||
int64_t dst_nb_samples = av_rescale_rnd(recv_frame->nb_samples, asbd->mSampleRate, _audio_codec_ctx->sample_rate, AV_ROUND_UP);
|
||||
int64_t dst_nb_samples = av_rescale_rnd(recv_frame->nb_samples, audioFormat.sampleRate, _audio_codec_ctx->sample_rate, AV_ROUND_UP);
|
||||
|
||||
CAMultiAudioPCM *retPCM = [[CAMultiAudioPCM alloc] initWithDescription:asbd forFrameCount:(int)dst_nb_samples];
|
||||
|
||||
uint8_t *dBuf = retPCM.dataBuffer;
|
||||
CAMultiAudioPCM *retPCM = [[CAMultiAudioPCM alloc] initWithPCMFormat:audioFormat frameCapacity:(int)dst_nb_samples];
|
||||
retPCM.frameLength = (int)dst_nb_samples;
|
||||
uint8_t *dBuf = retPCM.audioBufferList->mBuffers->mData;
|
||||
|
||||
|
||||
if (dBuf) //Just in case
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ typedef enum ff_movie_repeat_t {
|
|||
@property (assign) bool playing;
|
||||
|
||||
@property (strong) CSFFMpegInput *currentlyPlaying;
|
||||
@property (assign) AudioStreamBasicDescription *asbd;
|
||||
@property (strong) AVAudioFormat *audioFormat;
|
||||
|
||||
@property (copy, nonatomic) void (^itemStarted)(CSFFMpegInput *);
|
||||
@property (copy, nonatomic) void (^pauseStateChanged)(void);
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@
|
|||
|
||||
}
|
||||
|
||||
-(void)registerPCMOutput:(const AudioStreamBasicDescription *)audioFormat
|
||||
-(void)registerPCMOutput:(AVAudioFormat *)audioFormat
|
||||
{
|
||||
|
||||
if (_pcmPlayer)
|
||||
|
|
@ -189,8 +189,7 @@
|
|||
{
|
||||
CSNDISource *ndiSource = self.activeVideoDevice.captureDevice;
|
||||
|
||||
AudioStreamBasicDescription useFormat = pcmData.pcmFormat;
|
||||
_pcmPlayer = [self createAttachedAudioInputForUUID:ndiSource.name withName:ndiSource.name withFormat:&useFormat];
|
||||
_pcmPlayer = [self createAttachedAudioInputForUUID:ndiSource.name withName:ndiSource.name withFormat:pcmData.format];
|
||||
[_pcmPlayer play];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@
|
|||
{
|
||||
|
||||
CAMultiAudioPCM *retPCM = [[CAMultiAudioPCM alloc] initWithDescription:_asbd forFrameCount:audio_frame.no_samples];
|
||||
uint8_t *dBuf = retPCM.dataBuffer;
|
||||
uint8_t *dBuf = retPCM.audioBufferList->mBuffers->mData;
|
||||
if (dBuf)
|
||||
{
|
||||
memcpy(dBuf, audio_frame.p_data, 4*audio_frame.no_samples*audio_frame.no_channels);
|
||||
|
|
|
|||
|
|
@ -413,8 +413,8 @@
|
|||
if (self.isLive && !_pcmPlayer)
|
||||
{
|
||||
CMFormatDescriptionRef sDescr = CMSampleBufferGetFormatDescription(sampleBuffer);
|
||||
const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(sDescr);
|
||||
_pcmPlayer = [[CSPluginServices sharedPluginServices] createPCMInput:self.activeVideoDevice.uniqueID withFormat:asbd];
|
||||
AVAudioFormat *avFmt = [[AVAudioFormat alloc] initWithCMAudioFormatDescription:sDescr];
|
||||
_pcmPlayer = [[CSPluginServices sharedPluginServices] createPCMInput:self.activeVideoDevice.uniqueID withFormat:avFmt];
|
||||
_pcmPlayer.name = _selectedVideoCaptureDevice.localizedName;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@
|
|||
if (!pcmPlayer)
|
||||
{
|
||||
CMFormatDescriptionRef sDescr = CMSampleBufferGetFormatDescription(sampleBuffer);
|
||||
const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(sDescr);
|
||||
AVAudioFormat *avFmt = [[AVAudioFormat alloc] initWithCMAudioFormatDescription:sDescr];
|
||||
NSString *trackName = [[CSPluginServices sharedPluginServices] nameForAudioTrackUUID:audioTrackkey];
|
||||
if (!trackName)
|
||||
{
|
||||
|
|
@ -369,7 +369,7 @@
|
|||
|
||||
NSString *pcmName = [NSString stringWithFormat:@"%@ - %@", self.activeVideoDevice.captureName, trackName];
|
||||
|
||||
pcmPlayer = [self createAttachedAudioInputForUUID:audioTrackkey withName:pcmName withFormat:asbd];
|
||||
pcmPlayer = [self createAttachedAudioInputForUUID:audioTrackkey withName:pcmName withFormat:avFmt];
|
||||
_pcmPlayers[audioTrackkey] = pcmPlayer;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@
|
|||
348585B4201C998200C30A08 /* CSPassthroughCompressorViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 348585B2201C998200C30A08 /* CSPassthroughCompressorViewController.xib */; };
|
||||
348585DE201E65F900C30A08 /* CSLayerFiltersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 348585DC201E65F900C30A08 /* CSLayerFiltersViewController.m */; };
|
||||
348585DF201E65F900C30A08 /* CSLayerFiltersViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 348585DD201E65F900C30A08 /* CSLayerFiltersViewController.xib */; };
|
||||
3488161A23FE9BBF00FF4E1B /* CAMultiAudioConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 3488161923FE9BBF00FF4E1B /* CAMultiAudioConnection.m */; };
|
||||
348AC06B19B406910064F02D /* SourceLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 348AC06A19B406910064F02D /* SourceLayout.m */; };
|
||||
348CDBC923D6671C004131AD /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 348CDBC723D665DF004131AD /* Sparkle.framework */; };
|
||||
348CDBCA23D6671C004131AD /* Sparkle.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 348CDBC723D665DF004131AD /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
|
|
@ -258,7 +259,6 @@
|
|||
34DA1D3F1BF823E700132486 /* CSNewOutputWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 34DA1D3D1BF823E700132486 /* CSNewOutputWindowController.xib */; };
|
||||
34DC2FB01B512362008F12A2 /* CSCaptureBase+TimerDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DC2FAF1B512362008F12A2 /* CSCaptureBase+TimerDelegate.m */; };
|
||||
34DF75581AA272F100DA9FDE /* LayoutRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DF75571AA272F100DA9FDE /* LayoutRenderer.m */; };
|
||||
34E26DD91FF6ED7B00ACE58B /* CAMultiAudioSubgraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E26DD81FF6ED7B00ACE58B /* CAMultiAudioSubgraph.m */; };
|
||||
34E26DDC1FF702BD00ACE58B /* CAMultiAudioSilence.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E26DDB1FF702BD00ACE58B /* CAMultiAudioSilence.m */; };
|
||||
34E26DDF1FF70E0E00ACE58B /* CAMultiAudioGenericOutput.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E26DDE1FF70E0E00ACE58B /* CAMultiAudioGenericOutput.m */; };
|
||||
34E88C9E218DB0A90053913B /* CSAppleWebViewCapturePlugin.bundle in Copy Files */ = {isa = PBXBuildFile; fileRef = 34E88C97218DACE40053913B /* CSAppleWebViewCapturePlugin.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
|
|
@ -941,6 +941,8 @@
|
|||
348585DB201E65F900C30A08 /* CSLayerFiltersViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSLayerFiltersViewController.h; sourceTree = "<group>"; };
|
||||
348585DC201E65F900C30A08 /* CSLayerFiltersViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CSLayerFiltersViewController.m; sourceTree = "<group>"; };
|
||||
348585DD201E65F900C30A08 /* CSLayerFiltersViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CSLayerFiltersViewController.xib; sourceTree = "<group>"; };
|
||||
3488161823FE9BBF00FF4E1B /* CAMultiAudioConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAMultiAudioConnection.h; path = CAMultiAudio/CAMultiAudioConnection.h; sourceTree = "<group>"; };
|
||||
3488161923FE9BBF00FF4E1B /* CAMultiAudioConnection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CAMultiAudioConnection.m; path = CAMultiAudio/CAMultiAudioConnection.m; sourceTree = "<group>"; };
|
||||
348AC06919B406910064F02D /* SourceLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceLayout.h; sourceTree = "<group>"; };
|
||||
348AC06A19B406910064F02D /* SourceLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SourceLayout.m; sourceTree = "<group>"; };
|
||||
348CDBC723D665DF004131AD /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = "<group>"; };
|
||||
|
|
@ -1080,8 +1082,6 @@
|
|||
34DC2FAF1B512362008F12A2 /* CSCaptureBase+TimerDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CSCaptureBase+TimerDelegate.m"; sourceTree = "<group>"; };
|
||||
34DF75561AA272F100DA9FDE /* LayoutRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutRenderer.h; sourceTree = "<group>"; };
|
||||
34DF75571AA272F100DA9FDE /* LayoutRenderer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LayoutRenderer.m; sourceTree = "<group>"; };
|
||||
34E26DD71FF6ED7B00ACE58B /* CAMultiAudioSubgraph.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAMultiAudioSubgraph.h; path = CAMultiAudio/CAMultiAudioSubgraph.h; sourceTree = "<group>"; };
|
||||
34E26DD81FF6ED7B00ACE58B /* CAMultiAudioSubgraph.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CAMultiAudioSubgraph.m; path = CAMultiAudio/CAMultiAudioSubgraph.m; sourceTree = "<group>"; };
|
||||
34E26DDA1FF702BD00ACE58B /* CAMultiAudioSilence.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAMultiAudioSilence.h; path = CAMultiAudio/CAMultiAudioSilence.h; sourceTree = "<group>"; };
|
||||
34E26DDB1FF702BD00ACE58B /* CAMultiAudioSilence.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CAMultiAudioSilence.m; path = CAMultiAudio/CAMultiAudioSilence.m; sourceTree = "<group>"; };
|
||||
34E26DDD1FF70E0E00ACE58B /* CAMultiAudioGenericOutput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAMultiAudioGenericOutput.h; path = CAMultiAudio/CAMultiAudioGenericOutput.h; sourceTree = "<group>"; };
|
||||
|
|
@ -1928,8 +1928,6 @@
|
|||
34EB705A1F24F65900F61E6A /* CAMultiAudioFile.m */,
|
||||
340620741F2E2BFE0016D997 /* CAMultiAudioInput.h */,
|
||||
340620751F2E2BFE0016D997 /* CAMultiAudioInput.m */,
|
||||
34E26DD71FF6ED7B00ACE58B /* CAMultiAudioSubgraph.h */,
|
||||
34E26DD81FF6ED7B00ACE58B /* CAMultiAudioSubgraph.m */,
|
||||
34E26DDA1FF702BD00ACE58B /* CAMultiAudioSilence.h */,
|
||||
34E26DDB1FF702BD00ACE58B /* CAMultiAudioSilence.m */,
|
||||
34E26DDD1FF70E0E00ACE58B /* CAMultiAudioGenericOutput.h */,
|
||||
|
|
@ -1940,6 +1938,8 @@
|
|||
34342203222A76220060F43E /* CAMultiAudioSplitter.m */,
|
||||
3434E169224F2E1A0091A149 /* CAMultiAudioOutputTrack.h */,
|
||||
3434E16A224F2E1A0091A149 /* CAMultiAudioOutputTrack.m */,
|
||||
3488161823FE9BBF00FF4E1B /* CAMultiAudioConnection.h */,
|
||||
3488161923FE9BBF00FF4E1B /* CAMultiAudioConnection.m */,
|
||||
);
|
||||
name = CAMultiAudio;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -3085,7 +3085,6 @@
|
|||
3470CD2E1D57D2AA006404D9 /* CSStreamOutputWindowController.m in Sources */,
|
||||
3400A0621BD44DF0003E1828 /* CSInputLibraryItem.m in Sources */,
|
||||
34ED8C831B07371C002C0674 /* MIKMIDIMetaSequenceEvent.m in Sources */,
|
||||
34E26DD91FF6ED7B00ACE58B /* CAMultiAudioSubgraph.m in Sources */,
|
||||
3434CB2D1CA90D28001B3DF9 /* CSx264CompressorViewController.m in Sources */,
|
||||
34788E291F0D166C00C3C9C5 /* CSAudioInputSource.m in Sources */,
|
||||
34ED8C6D1B07371C002C0674 /* MIKMIDIMapping.m in Sources */,
|
||||
|
|
@ -3138,6 +3137,7 @@
|
|||
34348C2A19BDBDC000A122C2 /* PluginManagerWindowController.m in Sources */,
|
||||
34CFE4A018F154DD00092C6A /* AVFChannelManager.m in Sources */,
|
||||
34ED8C6B1B07371C002C0674 /* MIKMIDIMacDebugQuickLookSupport.m in Sources */,
|
||||
3488161A23FE9BBF00FF4E1B /* CAMultiAudioConnection.m in Sources */,
|
||||
34BE2B092014845200E37382 /* CSPassthroughCompressor.m in Sources */,
|
||||
34A2722C205D99D000135A5D /* CSTransitionCollectionItem.m in Sources */,
|
||||
34ED8C511B07371C002C0674 /* MIKMIDICommand.m in Sources */,
|
||||
|
|
@ -3330,7 +3330,7 @@
|
|||
PRODUCT_NAME = CocoaSplit;
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx;
|
||||
SDKROOT = macosx10.14;
|
||||
STRIP_STYLE = debugging;
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
|
|
@ -3383,7 +3383,7 @@
|
|||
PRODUCT_NAME = CocoaSplit;
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx;
|
||||
SDKROOT = macosx10.14;
|
||||
STRIP_STYLE = debugging;
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -239,13 +239,13 @@
|
|||
|
||||
|
||||
_audio_capture_output.audioSettings = @{
|
||||
AVFormatIDKey: [NSNumber numberWithInt:kAudioFormatLinearPCM],
|
||||
AVLinearPCMBitDepthKey: @32,
|
||||
AVLinearPCMIsFloatKey: @YES,
|
||||
AVLinearPCMIsNonInterleaved: @YES,
|
||||
//AVNumberOfChannelsKey: @2,
|
||||
AVSampleRateKey: @(self.audioSamplerate),
|
||||
};
|
||||
AVFormatIDKey: [NSNumber numberWithInt:kAudioFormatLinearPCM],
|
||||
AVLinearPCMBitDepthKey: @32,
|
||||
AVLinearPCMIsFloatKey: @YES,
|
||||
AVLinearPCMIsNonInterleaved: @YES,
|
||||
//AVNumberOfChannelsKey: @2,
|
||||
//AVSampleRateKey: @(self.audioSamplerate),
|
||||
};;
|
||||
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
@property (strong) AVFAudioCapture *avfCapture;
|
||||
@property (assign) int sampleRate;
|
||||
|
||||
-(instancetype)initWithDevice:(AVCaptureDevice *)avDevice withFormat:(AudioStreamBasicDescription *)withFormat;
|
||||
|
||||
-(void)resetFormat:(AudioStreamBasicDescription *)format;
|
||||
-(instancetype)initWithDevice:(AVCaptureDevice *)avDevice;
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -8,20 +8,22 @@
|
|||
#import "CAMultiAudioAVCapturePlayer.h"
|
||||
#import "CAMultiAudioMatrixMixerWindowController.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation CAMultiAudioAVCapturePlayer
|
||||
|
||||
|
||||
|
||||
-(instancetype)initWithDevice:(AVCaptureDevice *)avDevice withFormat:(AudioStreamBasicDescription *)withFormat
|
||||
-(instancetype)initWithDevice:(AVCaptureDevice *)avDevice
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
||||
self.captureDevice = avDevice;
|
||||
self.sampleRate = withFormat->mSampleRate;
|
||||
self.name = avDevice.localizedName;
|
||||
//self.nodeUID = avDevice.uniqueID;
|
||||
self.inputFormat = withFormat;
|
||||
self.systemDevice = YES;
|
||||
self.deviceUID = avDevice.uniqueID;
|
||||
|
||||
|
|
@ -49,14 +51,6 @@
|
|||
-(bool)createNode:(CAMultiAudioGraph *)forGraph
|
||||
{
|
||||
[super createNode:forGraph];
|
||||
AudioStreamBasicDescription asbd;
|
||||
UInt32 asbdSize = sizeof(asbd);
|
||||
|
||||
|
||||
AudioUnitGetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &asbd, &asbdSize);
|
||||
asbd.mChannelsPerFrame = self.channelCount;
|
||||
AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &asbd, asbdSize);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
|
@ -85,89 +79,27 @@
|
|||
}
|
||||
|
||||
|
||||
-(void)resetFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
self.inputFormat = format;
|
||||
self.sampleRate = format->mSampleRate;
|
||||
AudioStreamBasicDescription asbd;
|
||||
UInt32 asbdSize = sizeof(asbd);
|
||||
memcpy(&asbd, format, sizeof(asbd));
|
||||
|
||||
asbd.mChannelsPerFrame = self.channelCount;
|
||||
|
||||
AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &asbd, asbdSize);
|
||||
if (self.avfCapture)
|
||||
{
|
||||
self.avfCapture.audioSamplerate = self.sampleRate;
|
||||
|
||||
[self.avfCapture stopAudioCompression];
|
||||
[self.avfCapture setupAudioCompression];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(void)resetSamplerate:(UInt32)sampleRate
|
||||
{
|
||||
if (self.avfCapture)
|
||||
{
|
||||
self.avfCapture.audioSamplerate = sampleRate;
|
||||
|
||||
[self.avfCapture stopAudioCompression];
|
||||
[self.avfCapture setupAudioCompression];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(void)setChannelCount:(int)channelCount
|
||||
{
|
||||
super.channelCount = channelCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
-(AudioStreamBasicDescription *)inputFormat
|
||||
-(AVAudioFormat *)inputFormat
|
||||
{
|
||||
if (self.captureDevice)
|
||||
{
|
||||
CMFormatDescriptionRef sDescr = self.captureDevice.activeFormat.formatDescription;
|
||||
|
||||
|
||||
const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(sDescr);
|
||||
return (AudioStreamBasicDescription *)asbd;
|
||||
AVAudioFormat *tmpFmt = [[AVAudioFormat alloc] initWithCMAudioFormatDescription:sDescr];
|
||||
AVAudioFormat *retFmt = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:tmpFmt.sampleRate channelLayout:tmpFmt.channelLayout];
|
||||
return retFmt;
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nil;
|
||||
|
||||
}
|
||||
|
||||
-(void)setInputFormat:(AudioStreamBasicDescription *)inputFormat
|
||||
{
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
-(int)channelCount
|
||||
{
|
||||
if (self.captureDevice)
|
||||
{
|
||||
CMFormatDescriptionRef sDescr = self.captureDevice.activeFormat.formatDescription;
|
||||
|
||||
|
||||
const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(sDescr);
|
||||
|
||||
|
||||
|
||||
if (asbd)
|
||||
{
|
||||
return asbd->mChannelsPerFrame;
|
||||
}
|
||||
}
|
||||
|
||||
return super.channelCount;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
23
CocoaSplit/CAMultiAudio/CAMultiAudioConnection.h
Normal file
23
CocoaSplit/CAMultiAudio/CAMultiAudioConnection.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// CAMultiAudioConnection.h
|
||||
// CocoaSplit
|
||||
//
|
||||
// Created by Zakk on 2/20/20.
|
||||
// Copyright © 2020 Zakk. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CAMultiAudioNode.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CAMultiAudioConnection : NSObject
|
||||
|
||||
@property (readonly, weak) CAMultiAudioNode *node;
|
||||
@property (readonly) UInt32 bus;
|
||||
|
||||
-(instancetype)initWithNode:(CAMultiAudioNode *)node bus:(UInt32)bus;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
24
CocoaSplit/CAMultiAudio/CAMultiAudioConnection.m
Normal file
24
CocoaSplit/CAMultiAudio/CAMultiAudioConnection.m
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// CAMultiAudioConnection.m
|
||||
// CocoaSplit
|
||||
//
|
||||
// Created by Zakk on 2/20/20.
|
||||
|
||||
#import "CAMultiAudioConnection.h"
|
||||
|
||||
@implementation CAMultiAudioConnection
|
||||
|
||||
|
||||
-(instancetype)initWithNode:(CAMultiAudioNode *)node bus:(UInt32)bus
|
||||
{
|
||||
if (self = [self init])
|
||||
{
|
||||
_node = node;
|
||||
_bus = bus;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
@ -21,6 +21,5 @@
|
|||
@property (weak) CAMultiAudioNode *sourceNode;
|
||||
|
||||
|
||||
-(instancetype)initWithInputFormat:(const AudioStreamBasicDescription *)format;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -21,57 +21,18 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
-(instancetype)initWithInputFormat:(const AudioStreamBasicDescription *)format
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-(bool)setInputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus
|
||||
{
|
||||
if (self = [self init])
|
||||
{
|
||||
memcpy(&_inputFormat, format, sizeof(AudioStreamBasicDescription));
|
||||
self.channelCount = format->mChannelsPerFrame;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
|
||||
/*
|
||||
bool ret = NO;
|
||||
if (&_inputFormat)
|
||||
{
|
||||
ret = [super setInputStreamFormat:&_inputFormat];
|
||||
} else {
|
||||
ret = [super setInputStreamFormat:format];
|
||||
}
|
||||
|
||||
return ret;
|
||||
*/
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
//ignore if we have our own
|
||||
|
||||
return YES;
|
||||
|
||||
bool ret = NO;
|
||||
if (self.outputFormat)
|
||||
{
|
||||
|
||||
ret = [super setOutputStreamFormat:self.outputFormat];
|
||||
} else {
|
||||
ret = [super setOutputStreamFormat:format];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
-(float)volume
|
||||
{
|
||||
if (self.sourceNode)
|
||||
|
|
|
|||
|
|
@ -37,41 +37,6 @@
|
|||
}
|
||||
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
AudioStreamBasicDescription casbd;
|
||||
|
||||
memcpy(&casbd, format, sizeof(casbd));
|
||||
casbd.mChannelsPerFrame = self.channelCount;
|
||||
OSStatus err = AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &casbd, sizeof(AudioStreamBasicDescription));
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"Failed to set StreamFormat for input %@ in willInitializeNode: %d", self, err);
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
AudioStreamBasicDescription casbd;
|
||||
|
||||
memcpy(&casbd, format, sizeof(casbd));
|
||||
casbd.mChannelsPerFrame = self.channelCount;
|
||||
OSStatus err = AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &casbd, sizeof(AudioStreamBasicDescription));
|
||||
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"Failed to set StreamFormat for output on node %@ with %d", self, err);
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
|
||||
}
|
||||
|
||||
-(void)willInitializeNode
|
||||
{
|
||||
AudioUnitSetParameter(self.audioUnit, kDelayParam_Feedback, kAudioUnitScope_Global, 0, 0, 0);
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@
|
|||
@property (assign) bool hasOutput;
|
||||
|
||||
|
||||
|
||||
-(instancetype)initWithDeviceUID:(NSString *)uid;
|
||||
-(instancetype)initWithDeviceID:(AudioDeviceID)devid;
|
||||
|
||||
-(void)setInputForDevice;
|
||||
-(void)setOutputForDevice;
|
||||
-(AudioStreamBasicDescription *)getOutputFormat;
|
||||
|
||||
+(NSMutableArray *)allDevices;
|
||||
+(AudioDeviceID)defaultOutputDeviceID;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
|
||||
|
||||
|
||||
-(instancetype)initWithDeviceID:(AudioDeviceID)devid
|
||||
{
|
||||
if (self = [super initWithSubType:kAudioUnitSubType_HALOutput unitType:kAudioUnitType_Output])
|
||||
|
|
@ -61,31 +62,6 @@
|
|||
|
||||
}
|
||||
|
||||
-(AudioStreamBasicDescription *)getOutputFormat
|
||||
{
|
||||
AudioStreamBasicDescription *outfmt = malloc(sizeof(AudioStreamBasicDescription));
|
||||
UInt32 outsize = sizeof(AudioStreamBasicDescription);
|
||||
|
||||
AudioUnitGetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, outfmt, &outsize);
|
||||
|
||||
|
||||
return outfmt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
return [super setInputStreamFormat:[self getOutputFormat]];
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
-(void)setOutputForDevice
|
||||
{
|
||||
|
|
@ -301,3 +277,5 @@
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
{
|
||||
_inputChannels = channels;
|
||||
self.inputChannelCount = channels;
|
||||
self.outputChannelCount = 2;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -235,8 +236,6 @@
|
|||
elementCount += 64;
|
||||
NSDictionary *saveData = [self saveDataForPrivateRestore];
|
||||
AudioUnitUninitialize(self.audioUnit);
|
||||
[self setInputStreamFormat:self.graph.graphAsbd];
|
||||
[self setOutputStreamFormat:self.graph.graphAsbd];
|
||||
[self willInitializeNode];
|
||||
AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &elementCount, sizeof(elementCount));
|
||||
AudioUnitInitialize(self.audioUnit);
|
||||
|
|
@ -293,8 +292,6 @@
|
|||
elementCount += 64;
|
||||
NSDictionary *saveData = [self saveDataForPrivateRestore];
|
||||
AudioUnitUninitialize(self.audioUnit);
|
||||
[self setInputStreamFormat:self.graph.graphAsbd];
|
||||
[self setOutputStreamFormat:self.graph.graphAsbd];
|
||||
[self willInitializeNode];
|
||||
AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Output, 0, &elementCount, sizeof(elementCount));
|
||||
AudioUnitInitialize(self.audioUnit);
|
||||
|
|
@ -347,31 +344,9 @@
|
|||
}
|
||||
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
bool ret = [super setOutputStreamFormat:format];
|
||||
|
||||
self.outputChannelCount = format->mChannelsPerFrame;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
|
||||
|
||||
AudioStreamBasicDescription fCopy;
|
||||
|
||||
|
||||
memcpy(&fCopy, format, sizeof(fCopy));
|
||||
|
||||
|
||||
fCopy.mChannelsPerFrame = _inputChannels;
|
||||
|
||||
|
||||
return [super setInputStreamFormat:&fCopy];
|
||||
}
|
||||
|
||||
|
||||
-(void)setEnabled:(bool)enabled
|
||||
{
|
||||
|
|
@ -419,14 +394,14 @@
|
|||
|
||||
|
||||
//Set output volume for all channels
|
||||
for (UInt32 chan = 0; chan < self.graph.graphAsbd->mChannelsPerFrame; chan++) {
|
||||
for (UInt32 chan = 0; chan < self.graph.audioFormat.channelCount; chan++) {
|
||||
err = AudioUnitSetParameter(self.audioUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Output, chan, 1.0, 0);
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"Failed to set output volume for channel %d on %@ with status %d", chan, self, err);
|
||||
}
|
||||
|
||||
if (_inputChannels < self.graph.graphAsbd->mChannelsPerFrame)
|
||||
if (_inputChannels < self.graph.audioFormat.channelCount)
|
||||
{
|
||||
UInt32 inChan = chan % _inputChannels;
|
||||
[self setVolume:1.0f forChannel:inChan outChannel:chan];
|
||||
|
|
@ -442,9 +417,9 @@
|
|||
}
|
||||
|
||||
//also set crosspoint volumes.
|
||||
if (_inputChannels >= self.graph.graphAsbd->mChannelsPerFrame)
|
||||
if (_inputChannels >= self.graph.audioFormat.channelCount)
|
||||
{
|
||||
UInt32 outChan = chan % self.graph.graphAsbd->mChannelsPerFrame;
|
||||
UInt32 outChan = chan % self.graph.audioFormat.channelCount;
|
||||
|
||||
[self setVolume:1.0 forChannel:chan outChannel:outChan];
|
||||
}
|
||||
|
|
@ -502,16 +477,18 @@
|
|||
|
||||
-(void)disconnectOutput:(CAMultiAudioNode *)outNode
|
||||
{
|
||||
NSDictionary *outInfo = self.outputMap[outNode.nodeUID];
|
||||
if (outInfo)
|
||||
|
||||
CAMultiAudioConnection *conn = [self.graph inputConnection:outNode forBus:0];
|
||||
|
||||
|
||||
if (conn && (conn.node == self))
|
||||
{
|
||||
NSNumber *outBus = outInfo[@"outBus"];
|
||||
for(NSString *inpUUID in self.inputMap)
|
||||
UInt32 outBus = conn.bus;
|
||||
NSArray *allInputBusses = [self.graph connectedInputBusses:self];
|
||||
for (NSNumber *inpBus in allInputBusses)
|
||||
{
|
||||
NSDictionary *inpInfo = self.inputMap[inpUUID];
|
||||
NSNumber *inpBus = inpInfo[@"inBus"];
|
||||
[self disconnectInputBus:inpBus.unsignedIntValue fromOutputBus:outBus.unsignedIntValue];
|
||||
[self disableOutputBus:outBus.unsignedIntValue];
|
||||
[self disconnectInputBus:inpBus.unsignedIntValue fromOutputBus:outBus];
|
||||
[self disableOutputBus:outBus];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
@property (strong) CAMultiAudioEffect *renderNode;
|
||||
@property (strong) NSString *defaultTrackUUID;
|
||||
|
||||
-(CAMultiAudioPCMPlayer *)createPCMInput:(NSString *)uniqueID withFormat:(const AudioStreamBasicDescription *)withFormat;
|
||||
-(CAMultiAudioPCMPlayer *)createPCMInput:(NSString *)uniqueID withFormat:(AVAudioFormat *)withFormat;
|
||||
-(CAMultiAudioFile *)createFileInput:(NSString *)filePath;
|
||||
-(void)addFileInput:(CAMultiAudioFile *)fileInput;
|
||||
|
||||
|
|
|
|||
|
|
@ -195,9 +195,9 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
AVCaptureDevice *dev = [AVCaptureDevice deviceWithUniqueID:devUID];
|
||||
if (dev)
|
||||
{
|
||||
CAMultiAudioAVCapturePlayer *avplayer = [[CAMultiAudioAVCapturePlayer alloc] initWithDevice:dev withFormat:self.graph.graphAsbd];
|
||||
CAMultiAudioAVCapturePlayer *avplayer = [[CAMultiAudioAVCapturePlayer alloc] initWithDevice:dev];
|
||||
avplayer.nodeUID = nodeUID;
|
||||
[self attachInput:avplayer];
|
||||
//[self attachInput:avplayer];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -350,28 +350,6 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
-(CSAacEncoder *)encoder
|
||||
{
|
||||
return _encoder;
|
||||
}
|
||||
|
||||
-(void)setEncoder:(CSAacEncoder *)encoder
|
||||
{
|
||||
CSAacEncoder *oldEncoder = _encoder;
|
||||
|
||||
_encoder = encoder;
|
||||
|
||||
if (oldEncoder)
|
||||
{
|
||||
AudioUnitRemoveRenderNotify(self.renderNode.audioUnit, encoderRenderCallback, [oldEncoder inputBufferPtr]);
|
||||
}
|
||||
|
||||
AudioUnitAddRenderNotify(self.renderNode.audioUnit, encoderRenderCallback, [_encoder inputBufferPtr]);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
-(void) disableAllInputs
|
||||
{
|
||||
for (CAMultiAudioInput *input in self.audioInputs)
|
||||
|
|
@ -492,6 +470,8 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
|
||||
|
||||
NSNumber *trackOutBus = outputTrack.outputBus;
|
||||
NSLog(@"EFFECT HEAD %@ ON BUS %d -> BUS %d", input.effectsHead, input.effectsHead.connectedToBus, trackOutBus.unsignedIntValue);
|
||||
|
||||
[self.encodeMixer connectInputBus:input.effectsHead.connectedToBus toOutputBus:trackOutBus.unsignedIntValue];
|
||||
[input.outputTracks setObject:outputTrack forKey:outputTrack.uuid];
|
||||
return YES;
|
||||
|
|
@ -527,7 +507,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
CSAacEncoder *encoder = [[CSAacEncoder alloc] init];
|
||||
encoder.sampleRate = self.sampleRate;
|
||||
encoder.bitRate = self.audioBitrate*1000;
|
||||
encoder.inputASBD = self.graph.graphAsbd;
|
||||
encoder.inputASBD = self.graph.audioFormat.streamDescription;
|
||||
encoder.trackName = defaultTrack.uuid;
|
||||
[encoder setupEncoderBuffer];
|
||||
defaultTrack.encoder = encoder;
|
||||
|
|
@ -554,20 +534,21 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
encoder.sampleRate = self.sampleRate;
|
||||
encoder.bitRate = self.audioBitrate*1000;
|
||||
encoder.trackName = outputTrack.uuid;
|
||||
encoder.inputASBD = self.graph.graphAsbd;
|
||||
encoder.inputASBD = self.graph.audioFormat.streamDescription;
|
||||
[encoder setupEncoderBuffer];
|
||||
encNode.bypass = YES;
|
||||
[self.graph addNode:encNode];
|
||||
[self.graph connectNode:self.encodeMixer toNode:encNode];
|
||||
[self.graph connectNode:encNode toNode:self.previewMixer];
|
||||
[self.previewMixer setVolumeOnInputBus:encNode.connectedToBus volume:0.0f];
|
||||
NSDictionary *connInfo = encNode.inputMap[self.encodeMixer.nodeUID];
|
||||
NSNumber *outBus = connInfo[@"outBus"];
|
||||
[self.encodeMixer setVolumeOnOutputBus:outBus.unsignedIntValue volume:1.0f];
|
||||
[self.encodeMixer connectInputBus:self.silentNode.connectedToBus toOutputBus:outBus.unsignedIntValue];
|
||||
CAMultiAudioConnection *eConn = [self.graph inputConnection:encNode forBus:0];
|
||||
CAMultiAudioConnection *silenceConn = [self.graph findOutputConnection:self.silentNode forNode:self.encodeMixer onBus:0];
|
||||
[self.encodeMixer setVolumeOnOutputBus:eConn.bus volume:1.0f];
|
||||
|
||||
[self.encodeMixer connectInputBus:silenceConn.bus toOutputBus:eConn.bus];
|
||||
outputTrack.encoderNode = encNode;
|
||||
outputTrack.encoder = encoder;
|
||||
outputTrack.outputBus = outBus;
|
||||
outputTrack.outputBus = @(eConn.bus);
|
||||
}
|
||||
|
||||
-(bool)createOutputTrack:(NSString *)withName
|
||||
|
|
@ -652,7 +633,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
|
||||
-(bool)buildGraph
|
||||
{
|
||||
self.graph = [[CAMultiAudioGraph alloc] initWithSamplerate:self.sampleRate];
|
||||
self.graph = [[CAMultiAudioGraph alloc] initWithFormat:nil];
|
||||
self.graph.engine = self;
|
||||
|
||||
|
||||
|
|
@ -714,6 +695,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
[self.graph connectNode:self.encodeMixer toNode:self.renderNode];
|
||||
[self.graph connectNode:self.silentNode toNode:self.encodeMixer];
|
||||
|
||||
|
||||
/*
|
||||
if (!self.encoder)
|
||||
{
|
||||
|
|
@ -779,7 +761,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
_defaultInput = nil;
|
||||
}
|
||||
}
|
||||
CAMultiAudioAVCapturePlayer *avplayer = [[CAMultiAudioAVCapturePlayer alloc] initWithDevice:defaultAV withFormat:self.graph.graphAsbd];
|
||||
CAMultiAudioAVCapturePlayer *avplayer = [[CAMultiAudioAVCapturePlayer alloc] initWithDevice:defaultAV];
|
||||
|
||||
|
||||
avplayer.name = @"System Input";
|
||||
|
|
@ -839,7 +821,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
return nil;
|
||||
}
|
||||
|
||||
CAMultiAudioAVCapturePlayer *avplayer = [[CAMultiAudioAVCapturePlayer alloc] initWithDevice:dev withFormat:self.graph.graphAsbd];
|
||||
CAMultiAudioAVCapturePlayer *avplayer = [[CAMultiAudioAVCapturePlayer alloc] initWithDevice:dev];
|
||||
if (avplayer)
|
||||
{
|
||||
[self attachInput:avplayer];
|
||||
|
|
@ -870,7 +852,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
bool isGlobal = [settings[@"isGlobal"] boolValue];
|
||||
if (isEnabled || isGlobal)
|
||||
{
|
||||
CAMultiAudioAVCapturePlayer *avplayer = [[CAMultiAudioAVCapturePlayer alloc] initWithDevice:dev withFormat:self.graph.graphAsbd];
|
||||
CAMultiAudioAVCapturePlayer *avplayer = [[CAMultiAudioAVCapturePlayer alloc] initWithDevice:dev];
|
||||
NSString *realUID = avplayer.nodeUID;
|
||||
avplayer.nodeUID = dev.uniqueID;
|
||||
[self attachInput:avplayer];
|
||||
|
|
@ -1002,21 +984,10 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
|
||||
for (CAMultiAudioInput *node in self.audioInputs)
|
||||
{
|
||||
[node resetFormat:self.graph.graphAsbd];
|
||||
[self reattachInput:node];
|
||||
|
||||
}
|
||||
/*
|
||||
for (CAMultiAudioPCMPlayer *node in self.pcmInputs)
|
||||
{
|
||||
[self attachPCMInput:node];
|
||||
}
|
||||
|
||||
for (CAMultiAudioFile *node in self.fileInputs)
|
||||
{
|
||||
[self attachFileInput:node];
|
||||
}
|
||||
*/
|
||||
|
||||
[self.encodeMixer restoreDataFromDict:encodeEffectChain];
|
||||
[self.graph graphUpdate];
|
||||
[self.graph startGraph];
|
||||
|
|
@ -1100,7 +1071,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
|
||||
-(void)addFileInput:(CAMultiAudioFile *)fileInput
|
||||
{
|
||||
[self attachFileInput:fileInput];
|
||||
[self attachInput:fileInput];
|
||||
|
||||
[self.fileInputs addObject:fileInput];
|
||||
}
|
||||
|
|
@ -1118,16 +1089,16 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
}
|
||||
|
||||
|
||||
-(CAMultiAudioPCMPlayer *)createPCMInput:(NSString *)uniqueID withFormat:(const AudioStreamBasicDescription *)withFormat
|
||||
-(CAMultiAudioPCMPlayer *)createPCMInput:(NSString *)uniqueID withFormat:(AVAudioFormat *)withFormat
|
||||
{
|
||||
CAMultiAudioPCMPlayer *newInput = nil;
|
||||
|
||||
|
||||
newInput = [[CAMultiAudioPCMPlayer alloc] init];
|
||||
newInput.inputFormat = (AudioStreamBasicDescription *)withFormat;
|
||||
newInput.inputFormat = withFormat;
|
||||
newInput.nodeUID = uniqueID;
|
||||
|
||||
[self attachPCMInput:newInput];
|
||||
[self attachInput:newInput];
|
||||
|
||||
//[newInput play];
|
||||
[self.pcmInputs addObject:newInput];
|
||||
|
|
@ -1145,48 +1116,12 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
-(void)attachDeviceInput:(CAMultiAudioAVCapturePlayer *)device
|
||||
{
|
||||
if (!device)
|
||||
{
|
||||
return; //what?
|
||||
}
|
||||
|
||||
AudioStreamBasicDescription *devFormat = device.inputFormat;
|
||||
|
||||
if (devFormat)
|
||||
{
|
||||
CAMultiAudioConverter *newConverter = [[CAMultiAudioConverter alloc] initWithInputFormat:devFormat];
|
||||
newConverter.nodeUID = device.nodeUID;
|
||||
|
||||
newConverter.sourceNode = device;
|
||||
device.converterNode = newConverter;
|
||||
}
|
||||
[self attachInput:device];
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(void)attachFileInput:(CAMultiAudioFile *)input
|
||||
{
|
||||
CAMultiAudioConverter *newConverter = [[CAMultiAudioConverter alloc] initWithInputFormat:input.outputFormat];
|
||||
newConverter.nodeUID = input.nodeUID; //Not so unique, lol
|
||||
|
||||
newConverter.sourceNode = input;
|
||||
input.converterNode = newConverter;
|
||||
[self attachInput:input];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(bool)attachInputCommon:(CAMultiAudioInput *)input
|
||||
{
|
||||
if (input)
|
||||
{
|
||||
[self.graph addNode:input];
|
||||
[self.graph connectNode:input toNode:self.encodeMixer];
|
||||
[self.graph connectNode:input.headNode toNode:self.encodeMixer];
|
||||
if (_defaultOutputTrack)
|
||||
{
|
||||
[self addInput:input toTrack:_defaultOutputTrack];
|
||||
|
|
@ -1197,22 +1132,6 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
}
|
||||
|
||||
|
||||
-(void)attachPCMInput:(CAMultiAudioPCMPlayer *)input
|
||||
{
|
||||
|
||||
|
||||
CAMultiAudioConverter *newConverter = [[CAMultiAudioConverter alloc] initWithInputFormat:input.inputFormat];
|
||||
newConverter.nodeUID = input.nodeUID; //Not so unique, lol
|
||||
|
||||
newConverter.sourceNode = input;
|
||||
input.converterNode = newConverter;
|
||||
input.enabled = YES;
|
||||
[self attachInput:input];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(bool)reattachInput:(CAMultiAudioInput *)input
|
||||
{
|
||||
|
||||
|
|
@ -1245,6 +1164,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
return NO;
|
||||
}
|
||||
|
||||
input.enabled = YES;
|
||||
|
||||
if (input.nodeUID && !input.noSettings)
|
||||
{
|
||||
|
|
@ -1272,10 +1192,8 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
|
||||
-(bool)disconnectInputNode:(CAMultiAudioInput *)disconnectNode
|
||||
{
|
||||
|
||||
|
||||
|
||||
CAMultiAudioGraph *inputGraph = (CAMultiAudioSubgraph *)disconnectNode.graph;
|
||||
CAMultiAudioGraph *inputGraph = disconnectNode.graph;
|
||||
|
||||
|
||||
[inputGraph removeNode:disconnectNode];
|
||||
|
|
@ -1413,6 +1331,7 @@ OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
OSStatus encoderRenderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData )
|
||||
{
|
||||
|
||||
|
||||
|
||||
if ((*ioActionFlags) & kAudioUnitRenderAction_PostRenderError)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
}
|
||||
|
||||
@property (strong) NSString *filePath;
|
||||
@property (assign) AudioStreamBasicDescription *outputFormat;
|
||||
@property (strong) AVAudioFormat *outputFormat;
|
||||
@property (assign) Float64 duration;
|
||||
@property (assign) Float64 currentTime;
|
||||
@property (assign) bool playing;
|
||||
|
|
|
|||
|
|
@ -174,11 +174,7 @@
|
|||
UInt32 absdSize = sizeof(AudioStreamBasicDescription);
|
||||
UInt32 durationSize = sizeof(Float64);
|
||||
Float64 fileDuration;
|
||||
|
||||
if (!_outputFormat)
|
||||
{
|
||||
_outputFormat = malloc(sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
err = AudioFileOpenURL(audioURL, kAudioFileReadPermission, 0, &_audioFile);
|
||||
CFRelease(audioURL);
|
||||
|
||||
|
|
@ -186,9 +182,14 @@
|
|||
{
|
||||
return NO;
|
||||
}
|
||||
err = AudioFileGetProperty(_audioFile, kAudioFilePropertyDataFormat, &absdSize, _outputFormat);
|
||||
AudioStreamBasicDescription fileasbd;
|
||||
|
||||
err = AudioFileGetProperty(_audioFile, kAudioFilePropertyDataFormat, &absdSize, &fileasbd);
|
||||
|
||||
AudioFileGetProperty(_audioFile, kAudioFilePropertyEstimatedDuration, &durationSize, &fileDuration);
|
||||
|
||||
AVAudioChannelLayout *chanLayout = [AVAudioChannelLayout layoutWithLayoutTag:kAudioChannelLayoutTag_DiscreteInOrder | fileasbd.mChannelsPerFrame];
|
||||
_outputFormat = [[AVAudioFormat alloc] initWithStreamDescription:&fileasbd channelLayout:chanLayout];
|
||||
Float64 realEnd = fileDuration;
|
||||
|
||||
if (self.endTime)
|
||||
|
|
@ -245,15 +246,15 @@
|
|||
}
|
||||
|
||||
|
||||
Float64 adjustedFrame = _lastStartFrame * (_outputFormat->mSampleRate/_outputSampleRate);
|
||||
Float64 calculatedStart = self.startTime * _outputFormat->mSampleRate;
|
||||
Float64 adjustedFrame = _lastStartFrame * (_outputFormat.sampleRate/_outputSampleRate);
|
||||
Float64 calculatedStart = self.startTime * _outputFormat.sampleRate;
|
||||
|
||||
fileRegion.mStartFrame = calculatedStart + adjustedFrame;
|
||||
|
||||
if (self.endTime > 0 && self.endTime > self.startTime)
|
||||
{
|
||||
|
||||
Float64 endFrame = self.endTime * _outputFormat->mSampleRate;
|
||||
Float64 endFrame = self.endTime * _outputFormat.sampleRate;
|
||||
fileRegion.mFramesToPlay = endFrame - fileRegion.mStartFrame;
|
||||
} else {
|
||||
fileRegion.mFramesToPlay = -1;
|
||||
|
|
@ -281,7 +282,7 @@
|
|||
fileRegion.mStartFrame = calculatedStart;
|
||||
if (self.endTime > 0 && self.endTime > self.startTime)
|
||||
{
|
||||
fileRegion.mFramesToPlay = (self.endTime * _outputFormat->mSampleRate) - fileRegion.mStartFrame;
|
||||
fileRegion.mFramesToPlay = (self.endTime * _outputFormat.sampleRate) - fileRegion.mStartFrame;
|
||||
} else {
|
||||
fileRegion.mFramesToPlay = -1;
|
||||
}
|
||||
|
|
@ -306,7 +307,6 @@
|
|||
|
||||
}
|
||||
|
||||
|
||||
-(void)play
|
||||
{
|
||||
AudioTimeStamp startTime;
|
||||
|
|
@ -314,7 +314,11 @@
|
|||
startTime.mSampleTime = -1;
|
||||
AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_ScheduleStartTimeStamp,
|
||||
kAudioUnitScope_Global, 0, &startTime, sizeof(startTime));
|
||||
self.playing = YES;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.playing = YES;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -334,6 +338,18 @@
|
|||
}
|
||||
|
||||
|
||||
-(bool)setOutputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus
|
||||
{
|
||||
bool ret = [super setOutputStreamFormat:format bus:bus];
|
||||
_outputSampleRate = format.sampleRate;
|
||||
return ret;
|
||||
}
|
||||
|
||||
-(bool)setInputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)setEnabled:(bool)enabled
|
||||
{
|
||||
super.enabled = enabled;
|
||||
|
|
@ -346,28 +362,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
|
||||
|
||||
bool ret = [super setOutputStreamFormat:format];
|
||||
|
||||
_outputSampleRate = format->mSampleRate;
|
||||
return ret;
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
AudioFileClose(_audioFile);
|
||||
if (_outputFormat)
|
||||
{
|
||||
free(_outputFormat);
|
||||
}
|
||||
_outputFormat = nil;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,32 +8,43 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AudioUnit/AudioUnit.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#import "CAMultiAudioNode.h"
|
||||
|
||||
#import "CAMultiAudioConnection.h"
|
||||
|
||||
@interface CAMultiAudioGraph : NSObject
|
||||
{
|
||||
AUGraph _graphInst;
|
||||
AudioStreamBasicDescription *_graphAsbd;
|
||||
|
||||
}
|
||||
|
||||
//We need to hold references to all the nodes so this isn't a pain to use for clients
|
||||
|
||||
@property (assign) AUGraph graphInst;
|
||||
@property (strong) NSMutableArray *nodeList;
|
||||
@property (assign) int sampleRate;
|
||||
@property (assign) AudioStreamBasicDescription *graphAsbd;
|
||||
@property (strong) NSMutableDictionary *nodeMap;
|
||||
@property (strong) AVAudioFormat *audioFormat;
|
||||
@property (weak) CAMultiAudioEngine *engine;
|
||||
@property (assign) bool running;
|
||||
|
||||
-(instancetype)initWithFormat:(AVAudioFormat *)format;
|
||||
|
||||
-(instancetype)initWithSamplerate:(int)samplerate;
|
||||
|
||||
-(bool)addNode:(CAMultiAudioNode *)newNode;
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode;
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode sampleRate:(int)sampleRate;
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode sampleRate:(int)sampleRate inBus:(UInt32)inBus outBus:(UInt32)outBus;
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode format:(AVAudioFormat *)format;
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode format:(AVAudioFormat *)format inBus:(UInt32)inBus outBus:(UInt32)outBus;
|
||||
-(bool)disconnectNode:(CAMultiAudioNode *)node;
|
||||
-(bool)disconnectNode:(CAMultiAudioNode *)node inputBus:(UInt32)inputBus;
|
||||
-(bool)disconnectNode:(CAMultiAudioNode *)node outputBus:(UInt32)outputBus;
|
||||
-(bool)disconnectNodeOutput:(CAMultiAudioNode *)node;
|
||||
-(bool)disconnectNodeInput:(CAMultiAudioNode *)node;
|
||||
-(CAMultiAudioConnection *)inputConnection:(CAMultiAudioNode *)node forBus:(UInt32)forBus;
|
||||
-(NSArray *)outputConnections:(CAMultiAudioNode *)node forBus:(UInt32)forBus;
|
||||
-(NSArray *)connectedInputBusses:(CAMultiAudioNode *)node;
|
||||
-(NSArray *)connectedOutputBusses:(CAMultiAudioNode *)node;
|
||||
-(CAMultiAudioConnection *)findOutputConnection:(CAMultiAudioNode *)node forNode:(CAMultiAudioNode *)forNode onBus:(UInt32)outBus;
|
||||
|
||||
|
||||
|
||||
-(bool)startGraph;
|
||||
|
|
|
|||
|
|
@ -11,32 +11,22 @@
|
|||
|
||||
|
||||
|
||||
|
||||
@implementation CAMultiAudioGraph
|
||||
@synthesize graphAsbd = _graphAsbd;
|
||||
|
||||
-(instancetype)initWithSamplerate:(int)samplerate
|
||||
-(instancetype)initWithFormat:(AVAudioFormat *)format
|
||||
{
|
||||
if (self = [self init])
|
||||
{
|
||||
//default to something reasonable
|
||||
|
||||
_sampleRate = samplerate;
|
||||
//set to canonical, 2 channel
|
||||
self.graphAsbd = malloc(sizeof(AudioStreamBasicDescription));
|
||||
|
||||
_graphAsbd->mSampleRate = self.sampleRate;
|
||||
_graphAsbd->mFormatID = kAudioFormatLinearPCM;
|
||||
_graphAsbd->mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved;
|
||||
_graphAsbd->mFramesPerPacket = 1;
|
||||
_graphAsbd->mChannelsPerFrame = 2;
|
||||
_graphAsbd->mReserved = 0;
|
||||
_graphAsbd->mBytesPerPacket = 1 * sizeof(Float32);
|
||||
_graphAsbd->mBytesPerFrame = 1 * sizeof(Float32);
|
||||
_graphAsbd->mBitsPerChannel = 8 * sizeof(Float32);
|
||||
|
||||
_audioFormat = format;
|
||||
if (!_audioFormat)
|
||||
{
|
||||
_audioFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100.0f channels:2];
|
||||
}
|
||||
|
||||
self.nodeList = [NSMutableArray array];
|
||||
self.nodeMap = [NSMutableDictionary dictionary];
|
||||
OSStatus err;
|
||||
err = NewAUGraph(&_graphInst);
|
||||
if (err)
|
||||
|
|
@ -122,15 +112,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if ([newNode createNode:self])
|
||||
{
|
||||
|
||||
|
||||
|
||||
[newNode setInputStreamFormat:self.graphAsbd];
|
||||
[newNode setOutputStreamFormat:self.graphAsbd];
|
||||
|
||||
[newNode willInitializeNode];
|
||||
|
||||
OSStatus err = AudioUnitInitialize(newNode.audioUnit);
|
||||
|
|
@ -139,7 +122,6 @@
|
|||
NSLog(@"AudioUnitInitialize failed for node %@ with status %d", newNode, err);
|
||||
return NO;
|
||||
}
|
||||
|
||||
[newNode didInitializeNode];
|
||||
|
||||
@synchronized (self.nodeList) {
|
||||
|
|
@ -158,25 +140,14 @@
|
|||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
[node willRemoveNode];
|
||||
|
||||
|
||||
|
||||
|
||||
OSStatus err;
|
||||
if (![self disconnectNode:node])
|
||||
{
|
||||
NSLog(@"Remove node %@: disconnected failed", node);
|
||||
return NO;
|
||||
}
|
||||
for (NSString *inpUUID in node.inputMap)
|
||||
{
|
||||
NSDictionary *inpInfo = node.inputMap[inpUUID];
|
||||
CAMultiAudioNode *inpNode = inpInfo[@"node"];
|
||||
[inpNode.outputMap removeObjectForKey:node.nodeUID];
|
||||
}
|
||||
|
||||
|
||||
|
||||
err = AUGraphRemoveNode(_graphInst, node.node);
|
||||
if (err)
|
||||
{
|
||||
|
|
@ -236,12 +207,12 @@
|
|||
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode
|
||||
{
|
||||
return [self connectNode:node toNode:toNode sampleRate:self.sampleRate];
|
||||
return [self connectNode:node toNode:toNode format:self.audioFormat];
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode sampleRate:(int)sampleRate
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode format:(AVAudioFormat *)format
|
||||
{
|
||||
if (!_graphInst)
|
||||
{
|
||||
|
|
@ -258,11 +229,11 @@
|
|||
UInt32 inBus = toNode.inputElement;
|
||||
UInt32 outBus = node.outputElement;
|
||||
|
||||
return [self connectNode:node toNode:toNode sampleRate:self.sampleRate inBus:inBus outBus:outBus];
|
||||
return [self connectNode:node toNode:toNode format:format inBus:inBus outBus:outBus];
|
||||
}
|
||||
|
||||
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode sampleRate:(int)sampleRate inBus:(UInt32)inBus outBus:(UInt32)outBus
|
||||
-(bool)connectNode:(CAMultiAudioNode *)node toNode:(CAMultiAudioNode *)toNode format:(AVAudioFormat *)format inBus:(UInt32)inBus outBus:(UInt32)outBus
|
||||
{
|
||||
|
||||
if (!_graphInst)
|
||||
|
|
@ -278,6 +249,7 @@
|
|||
}
|
||||
|
||||
|
||||
NSLog(@"CONNECT %@:%d TO %@:%d FORMAT %@", node, outBus, toNode, inBus, format);
|
||||
AUNode inNode;
|
||||
AUNode connectTo;
|
||||
|
||||
|
|
@ -285,30 +257,29 @@
|
|||
|
||||
UInt32 bus = inBus;
|
||||
|
||||
|
||||
|
||||
[node willConnectToNode:toNode inBus:bus outBus:outBus];
|
||||
|
||||
[toNode willConnectNode:node inBus:bus outBus:outBus];
|
||||
|
||||
CAMultiAudioNode *useNode = node;
|
||||
if (node.headNode)
|
||||
{
|
||||
useNode = node.headNode;
|
||||
}
|
||||
|
||||
inNode = useNode.node;
|
||||
inNode = node.node;
|
||||
connectTo = toNode.node;
|
||||
//aUnit = node.audioUnit;
|
||||
|
||||
[toNode setInputStreamFormat:format bus:inBus];
|
||||
[node setOutputStreamFormat:format bus:outBus];
|
||||
|
||||
err = AUGraphConnectNodeInput(_graphInst, inNode, outBus, connectTo, bus);
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"AUGraphConnectNodeInput failed for %@ -> %@, err: %d", node, toNode, err);
|
||||
return NO;
|
||||
}
|
||||
|
||||
[useNode nodeConnected:toNode inBus:bus outBus:outBus];
|
||||
|
||||
[toNode connectedToNode:useNode inBus:bus outBus:outBus];
|
||||
[node nodeConnected:toNode inBus:bus outBus:outBus];
|
||||
|
||||
[toNode connectedToNode:node inBus:bus outBus:outBus];
|
||||
|
||||
if (![self graphUpdate])
|
||||
{
|
||||
|
|
@ -323,10 +294,171 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
|
||||
NSMutableArray *outputsForBus = node.outputConnections[@(outBus)];
|
||||
if (!outputsForBus)
|
||||
{
|
||||
outputsForBus = [NSMutableArray array];
|
||||
node.outputConnections[@(outBus)] = outputsForBus;
|
||||
}
|
||||
[outputsForBus addObject:[[CAMultiAudioConnection alloc] initWithNode:toNode bus:inBus]];
|
||||
toNode.inputConnections[@(inBus)] = [[CAMultiAudioConnection alloc] initWithNode:node bus:outBus];
|
||||
NSLog(@"%@ OUTPUT %@", node, [node outputFormatForBus:outBus]);
|
||||
NSLog(@"%@ INPUT %@", toNode, [toNode inputFormatForBus:inBus]);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
-(NSArray *)connectedInputBusses:(CAMultiAudioNode *)node
|
||||
{
|
||||
return node.inputConnections.allKeys;
|
||||
}
|
||||
|
||||
-(NSArray *)connectedOutputBusses:(CAMultiAudioNode *)node
|
||||
{
|
||||
return node.outputConnections.allKeys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(CAMultiAudioConnection *)findOutputConnection:(CAMultiAudioNode *)node forNode:(CAMultiAudioNode *)forNode onBus:(UInt32)outBus
|
||||
{
|
||||
|
||||
CAMultiAudioConnection *retConn = nil;
|
||||
NSArray *outConns = [self outputConnections:node forBus:outBus];
|
||||
for(CAMultiAudioConnection *conn in outConns)
|
||||
{
|
||||
if (conn.node == forNode)
|
||||
{
|
||||
retConn = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retConn;
|
||||
}
|
||||
|
||||
|
||||
-(CAMultiAudioConnection *)inputConnection:(CAMultiAudioNode *)node forBus:(UInt32)forBus
|
||||
{
|
||||
return node.inputConnections[@(forBus)];
|
||||
}
|
||||
|
||||
|
||||
-(NSArray *)outputConnections:(CAMultiAudioNode *)node forBus:(UInt32)forBus
|
||||
{
|
||||
NSMutableArray *conns = node.outputConnections[@(forBus)];
|
||||
|
||||
if (conns)
|
||||
{
|
||||
return [conns copy];
|
||||
}
|
||||
|
||||
return @[];
|
||||
}
|
||||
|
||||
|
||||
-(bool)disconnectNode:(CAMultiAudioNode *)node inputBus:(UInt32)inputBus
|
||||
{
|
||||
return [self disconnectNode:node inputBus:inputBus updateOutputs:YES];
|
||||
}
|
||||
|
||||
|
||||
-(bool)disconnectNode:(CAMultiAudioNode *)node inputBus:(UInt32)inputBus updateOutputs:(bool)updateOutputs
|
||||
{
|
||||
if (!_graphInst || !node)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
CAMultiAudioConnection *inputConnection = node.inputConnections[@(inputBus)];
|
||||
|
||||
if (inputConnection)
|
||||
{
|
||||
OSErr err = AUGraphDisconnectNodeInput(_graphInst, node.node, inputBus);
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"AUGraphDisconnectNodeInput failed for node %@:%d, err %d", node, inputBus, err);
|
||||
}
|
||||
|
||||
if (updateOutputs)
|
||||
{
|
||||
CAMultiAudioNode *srcNode = inputConnection.node;
|
||||
if (srcNode)
|
||||
{
|
||||
NSMutableArray *newConns = [NSMutableArray array];
|
||||
NSArray *conns = [self outputConnections:srcNode forBus:inputConnection.bus];
|
||||
for(CAMultiAudioConnection *nConn in conns)
|
||||
{
|
||||
if (nConn.node != node)
|
||||
{
|
||||
[newConns addObject:nConn];
|
||||
}
|
||||
}
|
||||
|
||||
srcNode.outputConnections[@(inputConnection.bus)] = newConns;
|
||||
}
|
||||
}
|
||||
[node.inputConnections removeObjectForKey:@(inputBus)];
|
||||
}
|
||||
[self graphUpdate];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
-(bool)disconnectNodeOutput:(CAMultiAudioNode *)node
|
||||
{
|
||||
|
||||
if (!_graphInst || !node)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSArray *outbusses = node.outputConnections.allKeys;
|
||||
|
||||
for(NSNumber *busNum in outbusses)
|
||||
{
|
||||
[self disconnectNode:node outputBus:busNum.unsignedIntValue];
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(bool)disconnectNodeInput:(CAMultiAudioNode *)node
|
||||
{
|
||||
if (!_graphInst || !node)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSArray *inbusses = node.inputConnections.allKeys;
|
||||
for(NSNumber *busNum in inbusses)
|
||||
{
|
||||
[self disconnectNode:node inputBus:busNum.unsignedIntValue updateOutputs:YES];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
-(bool)disconnectNode:(CAMultiAudioNode *)node outputBus:(UInt32)outputBus
|
||||
{
|
||||
if (!_graphInst || !node)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSArray *outputConnections = [self outputConnections:node forBus:outputBus];
|
||||
|
||||
for(CAMultiAudioConnection *conn in outputConnections)
|
||||
{
|
||||
[self disconnectNode:conn.node inputBus:conn.bus updateOutputs:NO];
|
||||
}
|
||||
|
||||
[node.outputConnections removeObjectForKey:@(outputBus)];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
-(bool)disconnectNode:(CAMultiAudioNode *)node
|
||||
{
|
||||
if (!_graphInst || !node)
|
||||
|
|
@ -334,35 +466,9 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
if (!node.outputMap || node.outputMap.count == 0)
|
||||
{
|
||||
// NSLog(@"Node %@ is not connected to anything", node);
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (!node.audioUnit)
|
||||
{
|
||||
NSLog(@"Node %@ has no audio unit", node);
|
||||
return NO;
|
||||
}
|
||||
OSStatus err;
|
||||
for(NSString *uuid in node.outputMap)
|
||||
{
|
||||
NSDictionary *outDict = node.outputMap[uuid];
|
||||
CAMultiAudioNode *outNode = outDict[@"node"];
|
||||
NSNumber *inBus = outDict[@"inBus"];
|
||||
err = AUGraphDisconnectNodeInput(_graphInst, outNode.node, inBus.unsignedIntValue);
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"AUGraphDisconnectNodeInput failed for source node %@ dest node %@, err %d", node, outNode, err);
|
||||
}
|
||||
[outNode.inputMap removeObjectForKey:node.nodeUID];
|
||||
}
|
||||
|
||||
[node.outputMap removeAllObjects];
|
||||
[self disconnectNodeInput:node];
|
||||
[self disconnectNodeOutput:node];
|
||||
|
||||
[self graphUpdate];
|
||||
|
||||
return YES;
|
||||
|
||||
}
|
||||
|
|
@ -370,10 +476,7 @@
|
|||
-(void)dealloc
|
||||
{
|
||||
self.nodeList = nil;
|
||||
if (self.graphAsbd)
|
||||
{
|
||||
free(self.graphAsbd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (_graphInst)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#import "CAMultiAudioNode.h"
|
||||
#import "CAMultiAudioConverter.h"
|
||||
#import "CAMultiAudioSubgraph.h"
|
||||
#import "CAMultiAudioOutputTrack.h"
|
||||
|
||||
@protocol CAMultiAudioInputJSExport <JSExport>
|
||||
|
|
@ -44,7 +43,6 @@
|
|||
@property (assign) Float32 delay;
|
||||
@property (assign) bool noSettings;
|
||||
@property (assign) bool systemDevice;
|
||||
@property (strong) CAMultiAudioSubgraph *subGraph;
|
||||
@property (assign) float powerLevel;
|
||||
@property (strong) NSMutableDictionary *powerLevels;
|
||||
|
||||
|
|
@ -52,6 +50,9 @@
|
|||
@property (assign) bool isGlobal;
|
||||
@property (strong) NSMutableDictionary *outputTracks;
|
||||
@property (strong) NSString *deviceUID;
|
||||
@property (strong) AVAudioFormat *inputFormat;
|
||||
|
||||
@property (strong) CAMultiAudioDelay *wtfNode;
|
||||
|
||||
|
||||
-(void)didRemoveInput;
|
||||
|
|
|
|||
|
|
@ -26,12 +26,17 @@
|
|||
[self.powerLevels setObject:[NSMutableArray array] forKey:@"input"];
|
||||
[self.powerLevels setObject:[NSMutableArray array] forKey:@"output"];
|
||||
self.outputTracks = [NSMutableDictionary dictionary];
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
-(AVAudioFormat *)inputFormat
|
||||
{
|
||||
return self.graph.audioFormat;
|
||||
}
|
||||
|
||||
-(void)updatePowerlevel
|
||||
{
|
||||
|
|
@ -150,27 +155,28 @@
|
|||
{
|
||||
|
||||
|
||||
if (self.converterNode)
|
||||
if (!self.converterNode)
|
||||
{
|
||||
if (![self.graph addNode:self.converterNode])
|
||||
{
|
||||
[self teardownGraph];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
self.converterNode = [[CAMultiAudioConverter alloc] init];
|
||||
}
|
||||
|
||||
if (![self.graph addNode:self.converterNode])
|
||||
{
|
||||
[self teardownGraph];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
self.downMixer = [[CAMultiAudioDownmixer alloc] initWithInputChannels:self.channelCount];
|
||||
|
||||
|
||||
if (![self.graph addNode:self.downMixer])
|
||||
{
|
||||
|
||||
[self teardownGraph];
|
||||
return NO;
|
||||
}
|
||||
|
||||
self.downMixer.muted = NO;
|
||||
self.downMixer.volume = 1.0f;
|
||||
CAMultiAudioNode *connectTo = self.converterNode;
|
||||
if (!connectTo)
|
||||
{
|
||||
|
|
@ -179,25 +185,27 @@
|
|||
|
||||
|
||||
|
||||
if(![self.graph connectNode:self toNode:connectTo])
|
||||
|
||||
if(![self.graph connectNode:self toNode:connectTo format:self.inputFormat])
|
||||
{
|
||||
[self teardownGraph];
|
||||
return NO;
|
||||
}
|
||||
if (self.converterNode)
|
||||
{
|
||||
|
||||
|
||||
if(![self.graph connectNode:self.converterNode toNode:self.downMixer])
|
||||
{
|
||||
[self teardownGraph];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
CAMultiAudioDelay *delayNode;
|
||||
CAMultiAudioNode *connectNode = self.downMixer;
|
||||
|
||||
for(int i=0; i < 5; i++)
|
||||
{
|
||||
|
||||
bool ret;
|
||||
|
||||
delayNode = [[CAMultiAudioDelay alloc] init];
|
||||
|
|
@ -216,24 +224,37 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
|
||||
connectNode = delayNode;
|
||||
delayNode.bypass = YES;
|
||||
[self.delayNodes addObject:delayNode];
|
||||
}
|
||||
|
||||
|
||||
|
||||
self.effectsHead = delayNode;
|
||||
|
||||
self.effectsHead = connectNode;
|
||||
[self.downMixer connectInputBus:0 toOutputBus:0];
|
||||
|
||||
|
||||
return YES;
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(void)rebuildEffectChain
|
||||
{
|
||||
[super rebuildEffectChain];
|
||||
[self.graph connectNode:self.effectsHead toNode:self.downMixer];
|
||||
self.headNode = self.downMixer;
|
||||
}
|
||||
|
||||
-(void)setupEffectsChain
|
||||
{
|
||||
[self setupGraph];
|
||||
[super setupEffectsChain];
|
||||
//self.effectsHead = self;
|
||||
// [super setupEffectsChain];
|
||||
self.headNode = self.effectsHead;
|
||||
//[self.converterNode generateTone];
|
||||
|
||||
}
|
||||
|
||||
-(void)removeEffectsChain
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
@property (assign) float volume;
|
||||
@property (assign) bool muted;
|
||||
@property (assign) bool enabled;
|
||||
@property (strong) NSMutableDictionary *inputMap;
|
||||
@property (strong) NSMutableDictionary *outputMap;
|
||||
@property (readonly) CAMultiAudioNode *connectedTo;
|
||||
@property (readonly) UInt32 connectedToBus;
|
||||
|
||||
|
|
@ -57,11 +55,11 @@
|
|||
|
||||
-(void)willInitializeNode;
|
||||
-(void)didInitializeNode;
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format;
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format;
|
||||
|
||||
-(void)resetSamplerate:(UInt32)sampleRate;
|
||||
-(void)resetFormat:(AudioStreamBasicDescription *)format;
|
||||
-(bool)setInputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus;
|
||||
-(bool)setOutputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus;
|
||||
-(AVAudioFormat *)outputFormatForBus:(UInt32)bus;
|
||||
-(AVAudioFormat *)inputFormatForBus:(UInt32)bus;
|
||||
-(void)rebuildEffectChain;
|
||||
|
||||
-(void)setVolumeAnimated:(float)volume withDuration:(float)duration;
|
||||
-(NSView *)audioUnitNSView;
|
||||
|
|
@ -95,8 +93,9 @@
|
|||
@property (strong) NSMutableArray *effectChain;
|
||||
@property (assign) bool deleteNode;
|
||||
@property (readonly) NSString *uuid;
|
||||
@property (strong) NSMutableDictionary *inputMap;
|
||||
@property (strong) NSMutableDictionary *outputMap;
|
||||
@property (strong) NSMutableDictionary *inputConnections;
|
||||
@property (strong) NSMutableDictionary *outputConnections;
|
||||
|
||||
@property (readonly) CAMultiAudioNode *connectedTo;
|
||||
@property (readonly) UInt32 connectedToBus;
|
||||
|
||||
|
|
@ -105,6 +104,7 @@
|
|||
@property (assign) bool muted;
|
||||
|
||||
@property (assign) bool enabled;
|
||||
@property (assign) double theta;
|
||||
|
||||
|
||||
-(instancetype)initWithSubType:(OSType)subType unitType:(OSType)unitType;
|
||||
|
|
@ -113,14 +113,11 @@
|
|||
-(void)connectedToNode:(CAMultiAudioNode *)node inBus:(UInt32)inBus outBus:(UInt32)outBus;
|
||||
-(void)nodeConnected:(CAMultiAudioNode *)toNode inBus:(UInt32)inBus outBus:(UInt32)outBus;
|
||||
-(void)willConnectNode:(CAMultiAudioNode *)node inBus:(UInt32)inBus outBus:(UInt32)outBus;
|
||||
-(void)willRemoveNode;
|
||||
-(void)setupEffectsChain;
|
||||
-(void)removeEffectsChain;
|
||||
-(void)addEffect:(CAMultiAudioNode *)effect;
|
||||
-(void)addEffect:(CAMultiAudioNode *)effect atIndex:(NSUInteger)idx;
|
||||
-(bool)busForOutput:(CAMultiAudioNode *)inputNode busOut:(UInt32 *)busOut;
|
||||
-(bool)busForInput:(CAMultiAudioNode *)inputNode busOut:(UInt32 *)busOut;
|
||||
-(void) remakeNode;
|
||||
-(void)generateTone;
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,14 @@
|
|||
#include "CaptureController.h"
|
||||
|
||||
|
||||
OSStatus RenderTone(
|
||||
void *inRefCon,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList *ioData);
|
||||
|
||||
@implementation CAMultiAudioVolumeAnimation
|
||||
|
||||
@end
|
||||
|
|
@ -52,10 +60,9 @@
|
|||
self.channelCount = 2;
|
||||
_volume = 1.0;
|
||||
self.effectChain = [NSMutableArray array];
|
||||
self.inputMap = [NSMutableDictionary dictionary];
|
||||
self.outputMap = [NSMutableDictionary dictionary];
|
||||
self.nodeUID = [[NSUUID UUID] UUIDString];
|
||||
|
||||
self.inputConnections = [NSMutableDictionary dictionary];
|
||||
self.outputConnections = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
|
@ -118,7 +125,7 @@
|
|||
|
||||
}
|
||||
|
||||
[self rebuildEffectChain];
|
||||
//[self rebuildEffectChain];
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -197,6 +204,8 @@
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(bool)createNode:(CAMultiAudioGraph *)forGraph
|
||||
{
|
||||
if (!forGraph)
|
||||
|
|
@ -223,34 +232,63 @@
|
|||
self.effectsHead = self;
|
||||
self.headNode = self;
|
||||
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
|
||||
-(AVAudioFormat *)inputFormatForBus:(UInt32)bus
|
||||
{
|
||||
|
||||
AVAudioFormat *ret = nil;
|
||||
AudioStreamBasicDescription asbd;
|
||||
UInt32 asbdSize = sizeof(asbd);
|
||||
|
||||
AudioUnitGetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, bus, &asbd, &asbdSize);
|
||||
|
||||
AVAudioChannelLayout *chanLayout = [AVAudioChannelLayout layoutWithLayoutTag:kAudioChannelLayoutTag_DiscreteInOrder | asbd.mChannelsPerFrame];
|
||||
ret = [[AVAudioFormat alloc] initWithStreamDescription:&asbd channelLayout:chanLayout];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
-(AVAudioFormat *)outputFormatForBus:(UInt32)bus
|
||||
{
|
||||
|
||||
AVAudioFormat *ret = nil;
|
||||
AudioStreamBasicDescription asbd;
|
||||
UInt32 asbdSize = sizeof(asbd);
|
||||
|
||||
AudioUnitGetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, bus, &asbd, &asbdSize);
|
||||
|
||||
AVAudioChannelLayout *chanLayout = [AVAudioChannelLayout layoutWithLayoutTag:kAudioChannelLayoutTag_DiscreteInOrder | asbd.mChannelsPerFrame];
|
||||
ret = [[AVAudioFormat alloc] initWithStreamDescription:&asbd channelLayout:chanLayout];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
-(bool)setInputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus
|
||||
{
|
||||
|
||||
OSStatus err = AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, format, sizeof(AudioStreamBasicDescription));
|
||||
OSStatus err = AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, bus, format.streamDescription, sizeof(AudioStreamBasicDescription));
|
||||
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"Failed to set StreamFormat for input %@ in willInitializeNode: %d", self, err);
|
||||
NSLog(@"Failed to set StreamFormat for input on node %@ with %d", self, err);
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
-(bool)setOutputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus
|
||||
{
|
||||
AudioStreamBasicDescription casbd;
|
||||
|
||||
memcpy(&casbd, format, sizeof(casbd));
|
||||
casbd.mChannelsPerFrame = self.channelCount;
|
||||
|
||||
OSStatus err = AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &casbd, sizeof(AudioStreamBasicDescription));
|
||||
|
||||
OSStatus err = AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, bus, format.streamDescription, sizeof(AudioStreamBasicDescription));
|
||||
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"Failed to set StreamFormat for output on node %@ with %d", self, err);
|
||||
|
|
@ -273,76 +311,30 @@
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
-(void)setVolumeOnConnectedNode
|
||||
-(void)generateTone
|
||||
{
|
||||
|
||||
CAMultiAudioNode *volNode = self.connectedTo;
|
||||
|
||||
|
||||
while (volNode)
|
||||
{
|
||||
if ([volNode.class conformsToProtocol:@protocol(CAMultiAudioMixingProtocol)])
|
||||
{
|
||||
id<CAMultiAudioMixingProtocol>mixerNode = (id<CAMultiAudioMixingProtocol>)volNode;
|
||||
[mixerNode setVolumeOnInputBus:self.downMixer volume:self.volume];
|
||||
break;
|
||||
} else {
|
||||
volNode = volNode.connectedTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
-(bool)busForOutput:(CAMultiAudioNode *)inputNode busOut:(UInt32 *)busOut
|
||||
{
|
||||
NSString *nodeUUID = inputNode.nodeUID;
|
||||
NSDictionary *outputInfo = self.inputMap[nodeUUID];
|
||||
if (outputInfo)
|
||||
{
|
||||
NSNumber *oBus = outputInfo[@"outBus"];
|
||||
if (oBus)
|
||||
{
|
||||
*busOut = oBus.unsignedIntValue;
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return NO;
|
||||
OSErr err;
|
||||
AURenderCallbackStruct input;
|
||||
input.inputProc = RenderTone;
|
||||
input.inputProcRefCon = (__bridge void * _Nullable)(self);
|
||||
err = AudioUnitSetProperty(self.audioUnit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&input,
|
||||
sizeof(input));
|
||||
}
|
||||
|
||||
|
||||
-(bool)busForInput:(CAMultiAudioNode *)inputNode busOut:(UInt32 *)busOut
|
||||
{
|
||||
NSString *nodeUUID = inputNode.nodeUID;
|
||||
NSDictionary *inputInfo = self.inputMap[nodeUUID];
|
||||
if (inputInfo)
|
||||
{
|
||||
NSNumber *inBus = inputInfo[@"inBus"];
|
||||
if (inBus)
|
||||
{
|
||||
*busOut = inBus.unsignedIntValue;
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-(void)nodeConnected:(CAMultiAudioNode *)toNode inBus:(UInt32)inBus outBus:(UInt32)outBus
|
||||
{
|
||||
[self.outputMap setObject:@{@"inBus": @(inBus), @"outBus": @(outBus), @"node": toNode} forKey:toNode.nodeUID];
|
||||
if (outBus == 0)
|
||||
{
|
||||
_connectedTo = toNode;
|
||||
|
|
@ -356,10 +348,6 @@
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-(void)setMuted:(bool)muted
|
||||
{
|
||||
if (_muted == muted)
|
||||
|
|
@ -386,17 +374,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
-(void)resetSamplerate:(UInt32)sampleRate
|
||||
{
|
||||
//only certain node types need to react to this
|
||||
return;
|
||||
}
|
||||
|
||||
-(void)resetFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
-(bool)muted
|
||||
{
|
||||
|
|
@ -459,50 +436,11 @@
|
|||
}
|
||||
|
||||
-(void) connectedToNode:(CAMultiAudioNode *)node inBus:(UInt32)inBus outBus:(UInt32)outBus
|
||||
{
|
||||
|
||||
|
||||
[self.inputMap setObject:@{@"inBus": @(inBus), @"outBus": @(outBus), @"node": node} forKey:node.nodeUID];
|
||||
|
||||
}
|
||||
|
||||
-(void)willRemoveNode
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(void) remakeNode
|
||||
{
|
||||
NSMutableDictionary *inputMap = self.inputMap.copy;
|
||||
NSMutableDictionary *outputMap = self.outputMap.copy;
|
||||
CAMultiAudioGraph *saveGraph = self.graph;
|
||||
|
||||
[saveGraph removeNode:self];
|
||||
|
||||
[saveGraph addNode:self];
|
||||
|
||||
for (NSString *uuid in inputMap)
|
||||
{
|
||||
NSDictionary *inpInfo = inputMap[uuid];
|
||||
CAMultiAudioNode *inputNode = inpInfo[@"node"];
|
||||
NSNumber *inBus = inpInfo[@"inBus"];
|
||||
NSNumber *outBus = inpInfo[@"outBus"];
|
||||
|
||||
[saveGraph connectNode:inputNode toNode:self sampleRate:self.graph.sampleRate inBus:inBus.unsignedIntValue outBus:outBus.unsignedIntValue];
|
||||
}
|
||||
|
||||
for (NSString *uuid in outputMap)
|
||||
{
|
||||
NSDictionary *outInfo = outputMap[uuid];
|
||||
CAMultiAudioNode *outputNode = outInfo[@"node"];
|
||||
NSNumber *inBus = outInfo[@"inBus"];
|
||||
NSNumber *outBus = outInfo[@"outBus"];
|
||||
[saveGraph connectNode:self toNode:outputNode sampleRate:self.graph.sampleRate inBus:inBus.unsignedIntValue outBus:outBus.unsignedIntValue];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)rebuildEffectChain
|
||||
{
|
||||
//Disconnect every node from effectsHead -> headNode (including headNode) and then reconnect everything in effectchain array
|
||||
|
|
@ -608,7 +546,7 @@
|
|||
|
||||
-(void)setupEffectsChain
|
||||
{
|
||||
[self rebuildEffectChain];
|
||||
//[self rebuildEffectChain];
|
||||
//Do restore here
|
||||
}
|
||||
|
||||
|
|
@ -642,3 +580,45 @@
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
OSStatus RenderTone(
|
||||
void *inRefCon,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList *ioData)
|
||||
|
||||
{
|
||||
// Fixed amplitude is good enough for our purposes
|
||||
const double amplitude = 0.25;
|
||||
|
||||
// Get the tone parameters out of the view controller
|
||||
CAMultiAudioDevice *viewController =
|
||||
(__bridge CAMultiAudioDevice *)inRefCon;
|
||||
double theta = viewController.theta;
|
||||
double theta_increment =
|
||||
2.0 * M_PI * 600 / 44100;
|
||||
|
||||
// This is a mono tone generator so we only need the first buffer
|
||||
const int channel = 0;
|
||||
Float32 *buffer = (Float32 *)ioData->mBuffers[channel].mData;
|
||||
|
||||
// Generate the samples
|
||||
for (UInt32 frame = 0; frame < inNumberFrames; frame++)
|
||||
{
|
||||
buffer[frame] = sin(theta) * amplitude;
|
||||
|
||||
theta += theta_increment;
|
||||
if (theta > 2.0 * M_PI)
|
||||
{
|
||||
theta -= 2.0 * M_PI;
|
||||
}
|
||||
}
|
||||
|
||||
// Store the updated theta back in the view controller
|
||||
viewController.theta = theta;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
//
|
||||
|
||||
#import "CAMultiAudioPCM.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
@implementation CAMultiAudioPCM
|
||||
|
||||
|
|
@ -14,53 +15,21 @@
|
|||
|
||||
-(instancetype) copyWithZone:(NSZone *)zone
|
||||
{
|
||||
|
||||
CAMultiAudioPCM *newCopy = [[CAMultiAudioPCM allocWithZone:zone] initWithDescription:&_pcmFormat forFrameCount:self.frameCount];
|
||||
|
||||
[newCopy copyFromAudioBufferList:_pcmData];
|
||||
|
||||
CAMultiAudioPCM *newCopy = [super copyWithZone:zone];
|
||||
newCopy.audioSlice = self.audioSlice;
|
||||
return newCopy;
|
||||
}
|
||||
|
||||
|
||||
-(instancetype)initWithAudioBufferList:(AudioBufferList *)bufferList streamFormat:(const AudioStreamBasicDescription *)streamFormat
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
||||
_audioSlice = calloc(1, sizeof(ScheduledAudioSlice));
|
||||
|
||||
_audioSlice->mBufferList = bufferList;
|
||||
_audioSlice->mNumberFrames = bufferList->mBuffers[0].mDataByteSize / streamFormat->mBytesPerFrame;
|
||||
self.frameCount = _audioSlice->mNumberFrames;
|
||||
|
||||
self.bufferCount = streamFormat->mChannelsPerFrame;
|
||||
_alloced_buffers = NO;
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(void)silenceBuffer
|
||||
{
|
||||
|
||||
|
||||
for (int i=0; i < _audioSlice->mBufferList->mNumberBuffers; i++)
|
||||
{
|
||||
memset(_audioSlice->mBufferList->mBuffers[i].mData, 0, _audioSlice->mBufferList->mBuffers[i].mDataByteSize);
|
||||
}
|
||||
|
||||
}
|
||||
-(void)copyFromAudioBufferList:(AudioBufferList *)copyFrom
|
||||
{
|
||||
//Just copy the data, we already allocated the List.
|
||||
|
||||
for (int i=0; i < _pcmData->mNumberBuffers; i++)
|
||||
const AudioBufferList *myData = self.audioBufferList;
|
||||
for (int i=0; i < myData->mNumberBuffers; i++)
|
||||
{
|
||||
memcpy(_pcmData->mBuffers[i].mData, copyFrom->mBuffers[i].mData, _audioBufferDataSize);
|
||||
memcpy(myData->mBuffers[i].mData, copyFrom->mBuffers[i].mData, myData->mBuffers[i].mDataByteSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,73 +37,31 @@
|
|||
-(instancetype)initWithDescription:(const AudioStreamBasicDescription *)streamFormat forFrameCount:(int)forFrameCount
|
||||
{
|
||||
|
||||
if (self = [super init])
|
||||
AVAudioChannelLayout *chanLayout = [AVAudioChannelLayout layoutWithLayoutTag:kAudioChannelLayoutTag_DiscreteInOrder | streamFormat->mChannelsPerFrame];
|
||||
AVAudioFormat *avFmt = [[AVAudioFormat alloc] initWithStreamDescription:streamFormat channelLayout:chanLayout];
|
||||
if (self = [super initWithPCMFormat:avFmt frameCapacity:forFrameCount])
|
||||
{
|
||||
_audioSlice = calloc(1, sizeof(ScheduledAudioSlice));
|
||||
_audioSlice->mNumberFrames = forFrameCount;
|
||||
_audioSlice->mBufferList = NULL;
|
||||
|
||||
|
||||
int bufferCnt = streamFormat->mFormatFlags & kAudioFormatFlagIsNonInterleaved ? streamFormat->mChannelsPerFrame : 1;
|
||||
int channelCnt = streamFormat->mFormatFlags & kAudioFormatFlagIsNonInterleaved ? 1 : streamFormat->mChannelsPerFrame;
|
||||
|
||||
self.bufferCount = bufferCnt;
|
||||
self.frameCount = forFrameCount;
|
||||
|
||||
long byteCnt = streamFormat->mBytesPerFrame * forFrameCount;
|
||||
|
||||
_audioBufferDataSize = byteCnt;
|
||||
|
||||
_audioBufferListSize = sizeof(AudioBufferList) + (bufferCnt-1)*sizeof(AudioBuffer);
|
||||
|
||||
_pcmData = malloc(_audioBufferListSize);
|
||||
|
||||
|
||||
_dataBuffer = malloc(_audioBufferDataSize*bufferCnt);
|
||||
|
||||
_pcmData->mNumberBuffers = bufferCnt;
|
||||
|
||||
|
||||
for (int i=0; i<bufferCnt; i++)
|
||||
{
|
||||
/*
|
||||
if (byteCnt > 0)
|
||||
{
|
||||
_pcmData->mBuffers[i].mData = malloc(_audioBufferDataSize);
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
_pcmData->mBuffers[i].mData = _dataBuffer+(_audioBufferDataSize*i);
|
||||
|
||||
_pcmData->mBuffers[i].mDataByteSize = (UInt32)_audioBufferDataSize;
|
||||
_pcmData->mBuffers[i].mNumberChannels = channelCnt;
|
||||
}
|
||||
_audioSlice->mBufferList = _pcmData;
|
||||
memcpy(&_pcmFormat, streamFormat, sizeof(AudioStreamBasicDescription));
|
||||
_alloced_buffers = YES;
|
||||
self.frameLength = forFrameCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
-(void)createAudioSlice
|
||||
{
|
||||
_audioSlice = calloc(1, sizeof(ScheduledAudioSlice));
|
||||
_audioSlice->mNumberFrames = self.frameLength;
|
||||
_audioSlice->mBufferList = self.mutableAudioBufferList;
|
||||
}
|
||||
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
if (_alloced_buffers || self.handleFreeBuffer)
|
||||
|
||||
if (_audioSlice)
|
||||
{
|
||||
/*
|
||||
for (int i=0; i < self.bufferCount; i++)
|
||||
{
|
||||
free(_audioSlice->mBufferList->mBuffers[i].mData);
|
||||
}*/
|
||||
free(_audioSlice->mBufferList);
|
||||
free(_dataBuffer);
|
||||
|
||||
free(_audioSlice);
|
||||
}
|
||||
free(_audioSlice);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ struct cspcm_buffer_msg {
|
|||
NSMutableArray *_pendingBuffers;
|
||||
dispatch_queue_t _pendingQueue;
|
||||
bool _playing;
|
||||
int _bufcnt;
|
||||
bool _exitPending;
|
||||
|
||||
TPCircularBuffer _completedBuffer;
|
||||
|
|
@ -38,8 +37,6 @@ struct cspcm_buffer_msg {
|
|||
}
|
||||
|
||||
@property (strong) NSString *inputUID;
|
||||
@property (assign) Float64 latestScheduledTime;
|
||||
@property (assign) AudioStreamBasicDescription *inputFormat;
|
||||
@property (readonly) NSUInteger pendingFrames;
|
||||
@property (nonatomic, copy) void (^completedBlock)(CAMultiAudioPCM *pcmBuffer);
|
||||
@property (strong) NSMutableArray *pauseBuffer;
|
||||
|
|
@ -47,7 +44,6 @@ struct cspcm_buffer_msg {
|
|||
|
||||
-(void)releasePCM:(CAMultiAudioPCM *)buffer;
|
||||
-(void)scheduleBuffer:(CMSampleBufferRef)sampleBuffer;
|
||||
-(void)scheduleAudioBuffer:(AudioBufferList *)bufferList bufferFormat:(AudioStreamBasicDescription)bufferFormat;
|
||||
-(bool)playPcmBuffer:(CAMultiAudioPCM *)pcmBuffer;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,23 +10,18 @@
|
|||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
@interface CAMultiAudioPCM()
|
||||
-(void)createAudioSlice;
|
||||
@end
|
||||
|
||||
|
||||
@implementation CAMultiAudioPCMPlayer
|
||||
|
||||
@synthesize inputFormat = _inputFormat;
|
||||
|
||||
|
||||
|
||||
-(instancetype)init
|
||||
{
|
||||
if (self = [super initWithSubType:kAudioUnitSubType_ScheduledSoundPlayer unitType:kAudioUnitType_Generator])
|
||||
{
|
||||
_pendingBuffers = [NSMutableArray array];
|
||||
//_pendingQueue = dispatch_queue_create("PCM Player pending queue", NULL);
|
||||
_bufcnt = 0;
|
||||
_inputFormat = NULL;
|
||||
self.latestScheduledTime = 0;
|
||||
_pauseBuffer = [[NSMutableArray alloc] init];
|
||||
self.enabled = YES;
|
||||
_exitPending = NO;
|
||||
|
|
@ -35,15 +30,6 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
-(void)scheduleAudioBuffer:(AudioBufferList *)bufferList bufferFormat:(AudioStreamBasicDescription)bufferFormat
|
||||
{
|
||||
//Assuming 32 bit non-interleaved float.
|
||||
|
||||
CAMultiAudioPCM *pcmBuffer = [[CAMultiAudioPCM alloc] initWithAudioBufferList:bufferList streamFormat:&bufferFormat];
|
||||
|
||||
[self playPcmBuffer:pcmBuffer];
|
||||
}
|
||||
|
||||
-(NSUInteger)pendingFrames
|
||||
{
|
||||
return _pendingBuffers.count;
|
||||
|
|
@ -133,49 +119,14 @@
|
|||
[self startPendingProcessor];
|
||||
}
|
||||
|
||||
|
||||
OSStatus err;
|
||||
//Under 10.10 this means PLAY NEXT. Need to figure out everything that's not 10.10 :(
|
||||
|
||||
|
||||
AudioTimeStamp currentTimeStamp = {0};
|
||||
UInt32 ctsSize = sizeof(currentTimeStamp);
|
||||
|
||||
Float64 playAtTime = 0;
|
||||
|
||||
[pcmBuffer createAudioSlice];
|
||||
pcmBuffer.audioSlice->mFlags = 0;
|
||||
|
||||
pcmBuffer.player = self;
|
||||
|
||||
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9)
|
||||
{
|
||||
//Before 10.10 this was a bit more involved...
|
||||
AudioUnitGetProperty(self.audioUnit, kAudioUnitProperty_CurrentPlayTime, kAudioUnitScope_Global, 0, ¤tTimeStamp, &ctsSize);
|
||||
|
||||
if (self.latestScheduledTime == 0)
|
||||
{
|
||||
playAtTime = 0;
|
||||
} else {
|
||||
playAtTime = self.latestScheduledTime;
|
||||
}
|
||||
|
||||
if (currentTimeStamp.mSampleTime > self.latestScheduledTime)
|
||||
{
|
||||
|
||||
self.latestScheduledTime = playAtTime = 0;
|
||||
}
|
||||
pcmBuffer.audioSlice->mTimeStamp.mSampleTime = playAtTime;
|
||||
pcmBuffer.audioSlice->mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
|
||||
|
||||
if (playAtTime == 0)
|
||||
{
|
||||
[self play];
|
||||
}
|
||||
self.latestScheduledTime += pcmBuffer.frameCount;
|
||||
} else {
|
||||
//In 10.10 mFlags = 0 says 'play as soon as you can, but don't interrupt anything currently playing'
|
||||
pcmBuffer.audioSlice->mTimeStamp.mSampleTime = 0;
|
||||
pcmBuffer.audioSlice->mTimeStamp.mFlags = 0;
|
||||
}
|
||||
pcmBuffer.audioSlice->mTimeStamp.mSampleTime = 0;
|
||||
pcmBuffer.audioSlice->mTimeStamp.mFlags = 0;
|
||||
|
||||
|
||||
err = AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_ScheduleAudioSlice, kAudioUnitScope_Global, 0, pcmBuffer.audioSlice, sizeof(ScheduledAudioSlice));
|
||||
|
|
@ -186,70 +137,21 @@
|
|||
[self->_pendingBuffers addObject:pcmBuffer];
|
||||
}
|
||||
|
||||
// });
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-(void)scheduleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||
{
|
||||
|
||||
|
||||
//credit to TheAmazingAudioEngine for an illustration of proper audiobufferlist allocation. Google leads to some really really bad allocation code...
|
||||
|
||||
AudioBufferList *sampleABL;
|
||||
|
||||
|
||||
CMFormatDescriptionRef sDescr = CMSampleBufferGetFormatDescription(sampleBuffer);
|
||||
const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(sDescr);
|
||||
|
||||
|
||||
int bufferCnt = asbd->mFormatFlags & kAudioFormatFlagIsNonInterleaved ? asbd->mChannelsPerFrame : 1;
|
||||
int channelCnt = asbd->mFormatFlags & kAudioFormatFlagIsNonInterleaved ? 1 : asbd->mChannelsPerFrame;
|
||||
CMItemCount numSamples = CMSampleBufferGetNumSamples(sampleBuffer);
|
||||
|
||||
AVAudioFormat *avFmt = [[AVAudioFormat alloc] initWithCMAudioFormatDescription:sDescr];
|
||||
|
||||
|
||||
CAMultiAudioPCM *pcmBuffer = [[CAMultiAudioPCM alloc] initWithPCMFormat:avFmt frameCapacity:(unsigned int)numSamples];
|
||||
pcmBuffer.frameLength = (unsigned int)numSamples;
|
||||
|
||||
long byteCnt = asbd->mBytesPerFrame * numSamples;
|
||||
|
||||
sampleABL = malloc(sizeof(AudioBufferList) + (bufferCnt-1)*sizeof(AudioBuffer));
|
||||
|
||||
sampleABL->mNumberBuffers = bufferCnt;
|
||||
uint8_t *dataBuf = malloc(bufferCnt*byteCnt);
|
||||
|
||||
for (int i=0; i<bufferCnt; i++)
|
||||
{
|
||||
/*
|
||||
if (byteCnt > 0)
|
||||
{
|
||||
sampleABL->mBuffers[i].mData = malloc(byteCnt);
|
||||
|
||||
}*/
|
||||
|
||||
sampleABL->mBuffers[i].mData = dataBuf+(byteCnt*i);
|
||||
|
||||
sampleABL->mBuffers[i].mDataByteSize = (UInt32)byteCnt;
|
||||
sampleABL->mBuffers[i].mNumberChannels = channelCnt;
|
||||
}
|
||||
|
||||
|
||||
CMSampleBufferCopyPCMDataIntoAudioBufferList(sampleBuffer, 0, (int32_t)numSamples, sampleABL);
|
||||
CAMultiAudioPCM *pcmBuffer = [[CAMultiAudioPCM alloc] initWithAudioBufferList:sampleABL streamFormat:asbd];
|
||||
pcmBuffer.dataBuffer = dataBuf;
|
||||
|
||||
|
||||
pcmBuffer.handleFreeBuffer = YES;
|
||||
|
||||
|
||||
|
||||
|
||||
CMSampleBufferCopyPCMDataIntoAudioBufferList(sampleBuffer, 0, (int32_t)numSamples, pcmBuffer.mutableAudioBufferList);
|
||||
[self playPcmBuffer:pcmBuffer];
|
||||
}
|
||||
|
||||
|
|
@ -257,67 +159,31 @@
|
|||
{
|
||||
@autoreleasepool {
|
||||
|
||||
//dispatch_async(_pendingQueue, ^{
|
||||
@synchronized(self)
|
||||
{
|
||||
[self->_pendingBuffers removeObject:buffer];
|
||||
}
|
||||
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(bool)createNode:(CAMultiAudioGraph *)forGraph
|
||||
-(bool)setInputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus
|
||||
{
|
||||
bool ret = [super createNode:forGraph];
|
||||
if (floor(NSAppKitVersionNumber > NSAppKitVersionNumber10_9))
|
||||
{
|
||||
|
||||
//We can start whenever on 10.10. Anything not 10.10 we have to start/restart at specific times in the schedule function.
|
||||
[self play];
|
||||
return YES;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-(bool)setOutputStreamFormat:(AVAudioFormat *)format bus:(UInt32)bus
|
||||
{
|
||||
AudioUnitUninitialize(self.audioUnit);
|
||||
bool ret = [super setOutputStreamFormat:format bus:bus];
|
||||
AudioUnitInitialize(self.audioUnit);
|
||||
[self play];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
-(void)setInputFormat:(AudioStreamBasicDescription *)inputFormat
|
||||
{
|
||||
if (inputFormat)
|
||||
{
|
||||
if (!_inputFormat)
|
||||
{
|
||||
_inputFormat = malloc(sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
memcpy(_inputFormat, inputFormat, sizeof(AudioStreamBasicDescription));
|
||||
} else {
|
||||
inputFormat = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
-(AudioStreamBasicDescription *)inputFormat
|
||||
{
|
||||
return _inputFormat;
|
||||
}
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
if (self.inputFormat)
|
||||
{
|
||||
return [super setOutputStreamFormat:self.inputFormat];
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)pause
|
||||
{
|
||||
|
|
@ -363,10 +229,7 @@
|
|||
|
||||
[self flush];
|
||||
_pendingBuffers = nil;
|
||||
if (_inputFormat)
|
||||
{
|
||||
free(_inputFormat);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,15 +39,4 @@
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -20,33 +20,5 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
-(bool)setInputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
|
||||
/*
|
||||
bool ret = NO;
|
||||
if (&_inputFormat)
|
||||
{
|
||||
ret = [super setInputStreamFormat:&_inputFormat];
|
||||
} else {
|
||||
ret = [super setInputStreamFormat:format];
|
||||
}
|
||||
|
||||
return ret;
|
||||
*/
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(bool)setOutputStreamFormat:(AudioStreamBasicDescription *)format
|
||||
{
|
||||
//ignore if we have our own
|
||||
|
||||
return YES;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
// CAMultiAudioSubgraph.h
|
||||
// CocoaSplit
|
||||
//
|
||||
// Created by Zakk on 12/29/17.
|
||||
//
|
||||
|
||||
#import "CAMultiAudioGraph.h"
|
||||
#import "CAMultiAudioGenericOutput.h"
|
||||
|
||||
@interface CAMultiAudioSubgraph : CAMultiAudioGraph
|
||||
|
||||
@property (assign) AUNode subgraphNode;
|
||||
@property (strong) CAMultiAudioGenericOutput *outputNode;
|
||||
@property (strong) CAMultiAudioGraph *parentGraph;
|
||||
|
||||
-(instancetype) initWithParent:(CAMultiAudioGraph *)parent;
|
||||
|
||||
|
||||
@end
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
//
|
||||
// CAMultiAudioSubgraph.m
|
||||
// CocoaSplit
|
||||
//
|
||||
// Created by Zakk on 12/29/17.
|
||||
//
|
||||
|
||||
#import "CAMultiAudioSubgraph.h"
|
||||
|
||||
@implementation CAMultiAudioSubgraph
|
||||
|
||||
|
||||
-(instancetype) initWithParent:(CAMultiAudioGraph *)parent
|
||||
{
|
||||
if (self = [self init])
|
||||
{
|
||||
AUGraphNewNodeSubGraph(parent.graphInst, &_subgraphNode);
|
||||
AUGraphGetNodeInfoSubGraph(parent.graphInst, _subgraphNode, &_graphInst);
|
||||
self.parentGraph = parent;
|
||||
self.sampleRate = parent.sampleRate;
|
||||
self.graphAsbd = malloc(sizeof(AudioStreamBasicDescription));
|
||||
memcpy(_graphAsbd, parent.graphAsbd, sizeof(AudioStreamBasicDescription));
|
||||
//AUGraphOpen(_graphInst);
|
||||
AUGraphInitialize(_graphInst);
|
||||
self.outputNode = [[CAMultiAudioGenericOutput alloc] init];
|
||||
|
||||
[self addNode:self.outputNode];
|
||||
|
||||
[self graphUpdate];
|
||||
[self startGraph];
|
||||
//AUGraphConnectNodeInput(self.graphInst, self.outputNode.node, 0, _subgraphNode, 0);
|
||||
//[self graphUpdate];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
if (self.graphAsbd)
|
||||
{
|
||||
free(self.graphAsbd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
@ -131,8 +131,8 @@ typedef enum frame_render_behavior_t {
|
|||
-(NSSize)captureSize;
|
||||
|
||||
/* Create a PCM audio input. Use this and not the service plugin version. This version properly finds the appropriate audio engine and creates the PCM input there */
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(const AudioStreamBasicDescription *)withFormat;
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID named:(NSString *)withName withFormat:(const AudioStreamBasicDescription *)withFormat;
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(AVAudioFormat *)withFormat;
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID named:(NSString *)withName withFormat:(AVAudioFormat *)withFormat;
|
||||
|
||||
//Don't ever call this, it's not for you.
|
||||
-(CALayer *)createNewLayerForInput:(id)inputsrc;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
@interface CSPcmPlayer ()
|
||||
{
|
||||
NSMapTable *_realPlayers;
|
||||
AudioStreamBasicDescription *_asbd;
|
||||
AVAudioFormat *_audioDescription;
|
||||
|
||||
//NSPointerArray *_realPlayers;
|
||||
}
|
||||
|
|
@ -28,28 +28,14 @@
|
|||
@synthesize name = _name;
|
||||
|
||||
|
||||
-(void)setAudioFormat:(AudioStreamBasicDescription *)asbd
|
||||
-(void)setAudioFormat:(AVAudioFormat *)avFmt
|
||||
{
|
||||
if (!asbd)
|
||||
{
|
||||
if (_asbd)
|
||||
{
|
||||
free(_asbd);
|
||||
}
|
||||
_asbd = NULL;
|
||||
} else {
|
||||
if (!_asbd)
|
||||
{
|
||||
_asbd = malloc(sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
memcpy(_asbd, asbd, sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
|
||||
_audioDescription = avFmt;
|
||||
[self runBlockForPlayers:^(CAMultiAudioPCMPlayer *player) {
|
||||
CAMultiAudioEngine *useEngine = player.engine;
|
||||
[player removeFromEngine];
|
||||
player.inputFormat = asbd;
|
||||
player.inputFormat = avFmt;
|
||||
[useEngine attachInput:player];
|
||||
}];
|
||||
|
||||
|
|
@ -109,12 +95,7 @@
|
|||
}
|
||||
|
||||
|
||||
if (!_asbd)
|
||||
{
|
||||
CAMultiAudioPCMPlayer *caPlayer = player;
|
||||
_asbd = malloc(sizeof(AudioStreamBasicDescription));
|
||||
memcpy(_asbd, caPlayer.inputFormat, sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@synchronized(self)
|
||||
|
|
@ -123,9 +104,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
-(AudioStreamBasicDescription *)audioDescription
|
||||
-(AVAudioFormat *)audioDescription
|
||||
{
|
||||
return _asbd;
|
||||
return _audioDescription;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -179,10 +160,6 @@
|
|||
[self runBlockForPlayers:^(CAMultiAudioPCMPlayer *player) {
|
||||
[player removeFromEngine];
|
||||
}];
|
||||
if (_asbd)
|
||||
{
|
||||
free(_asbd);
|
||||
}
|
||||
}
|
||||
|
||||
-(void)runBlockForPlayers:(void (^)(CAMultiAudioPCMPlayer *player))useBlock
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@
|
|||
slider.tag = ((row+1)*100) + columnIndex-1;
|
||||
|
||||
Float32 volume = [self.downMixer getVolumeforChannel:(UInt32)row outChannel:(UInt32)columnIndex-1];
|
||||
NSLog(@"VOLUME %f", volume);
|
||||
slider.doubleValue = volume;
|
||||
|
||||
|
||||
|
|
@ -185,6 +186,7 @@
|
|||
|
||||
[self.matrixTable registerNib:cellNib forIdentifier:@"MatrixMixerCell"];
|
||||
|
||||
NSLog(@"OUTPUT CHANNELS %d", self.downMixer.outputChannelCount);
|
||||
if (self.matrixTable.numberOfColumns < self.downMixer.outputChannelCount)
|
||||
{
|
||||
for (int i = 0; i < self.downMixer.outputChannelCount; i++)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15505"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -26,15 +26,15 @@
|
|||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6qE-t2-zqe">
|
||||
<rect key="frame" x="19" y="476" width="84" height="14"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Stream Volume" id="clH-Fr-TJ1">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wwP-vq-QJZ">
|
||||
<rect key="frame" x="18" y="529" width="65" height="14"/>
|
||||
<rect key="frame" x="18" y="528" width="65" height="14"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Samplerate" id="qPp-Ym-izV">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ssR-h6-svZ">
|
||||
<rect key="frame" x="91" y="548" width="59" height="19"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="lBZ-LI-XH0">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
|
@ -51,10 +51,10 @@
|
|||
</connections>
|
||||
</textField>
|
||||
<popUpButton horizontalHuggingPriority="249" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="67k-Zi-Ko9">
|
||||
<rect key="frame" x="88" y="524" width="70" height="22"/>
|
||||
<rect key="frame" x="88" y="523" width="70" height="22"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="FJb-Og-tdf" id="uSC-7v-E4B">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<menu key="menu" id="6Ra-rI-plD">
|
||||
<items>
|
||||
<menuItem title="Item 1" state="on" id="FJb-Og-tdf"/>
|
||||
|
|
@ -69,20 +69,20 @@
|
|||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ycu-9s-oiz">
|
||||
<rect key="frame" x="155" y="551" width="62" height="14"/>
|
||||
<rect key="frame" x="155" y="550" width="62" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="58" id="q2p-hX-TR0"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="kbits/sec" id="S8r-Xg-ebh">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="zuo-gj-1Pr">
|
||||
<rect key="frame" x="18" y="507" width="63" height="14"/>
|
||||
<rect key="frame" x="18" y="506" width="63" height="14"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Audio Shift" id="6Pl-mK-60G">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
|
@ -90,7 +90,7 @@
|
|||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I72-n8-A7m">
|
||||
<rect key="frame" x="91" y="504" width="59" height="19"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="Utr-K4-fTZ">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
|
@ -99,20 +99,20 @@
|
|||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3S3-NA-Pfr">
|
||||
<rect key="frame" x="157" y="507" width="49" height="14"/>
|
||||
<rect key="frame" x="157" y="506" width="49" height="14"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="seconds" id="ktg-pa-9dP">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nao-kV-Rtm">
|
||||
<rect key="frame" x="19" y="551" width="40" height="14"/>
|
||||
<rect key="frame" x="19" y="550" width="40" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="36" id="8wR-h0-BoG"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Bitrate" id="FVz-ie-6Zt">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
|
@ -120,7 +120,7 @@
|
|||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="GNm-og-wRf">
|
||||
<rect key="frame" x="19" y="372" width="101" height="14"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Monitor volume" id="IAm-lt-PXz">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5HX-Gi-83X">
|
||||
<rect key="frame" x="19" y="420" width="84" height="14"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Monitor Output" id="41g-2s-fF7">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
</constraints>
|
||||
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="KN8-OL-txf" id="SEL-4J-m1s">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<menu key="menu" id="sce-bW-EMX">
|
||||
<items>
|
||||
<menuItem title="Item 1" state="on" id="KN8-OL-txf"/>
|
||||
|
|
@ -192,9 +192,6 @@
|
|||
<binding destination="dRe-6o-71e" name="audioLevels" keyPath="selection.streamAudioPowerLevels.output" id="cxT-di-4rA"/>
|
||||
</connections>
|
||||
</customView>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="3Xs-zj-OzR">
|
||||
<rect key="frame" x="212" y="-102" width="277" height="669"/>
|
||||
</customView>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="NeC-nP-8fw">
|
||||
<rect key="frame" x="135" y="435" width="25" height="27"/>
|
||||
<constraints>
|
||||
|
|
@ -202,7 +199,7 @@
|
|||
</constraints>
|
||||
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="Mute_Icon" imagePosition="only" alignment="center" alternateImage="Speaker_Icon" controlSize="small" imageScaling="proportionallyUpOrDown" inset="2" id="HFf-ty-SwM" customClass="CSNSButtonCellThemed">
|
||||
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<binding destination="dRe-6o-71e" name="value" keyPath="selection.encodeMixer.enabled" id="gtc-5g-Cnh"/>
|
||||
|
|
@ -229,7 +226,7 @@
|
|||
</constraints>
|
||||
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="Mute_Icon" imagePosition="only" alignment="center" alternateImage="Speaker_Icon" controlSize="small" imageScaling="proportionallyUpOrDown" inset="2" id="6fp-6X-2wk" customClass="CSNSButtonCellThemed">
|
||||
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<binding destination="dRe-6o-71e" name="value" keyPath="selection.previewMixer.enabled" id="GY9-T8-HVd"/>
|
||||
|
|
@ -243,14 +240,14 @@
|
|||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnSelection="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" id="YfJ-xY-GcZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="138" height="133"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="135" minWidth="40" maxWidth="1000" id="Gka-Lc-OMt">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
|
|
@ -304,7 +301,7 @@
|
|||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8BQ-Ld-p55">
|
||||
<rect key="frame" x="19" y="282" width="72" height="14"/>
|
||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Audio Tracks" id="szd-Om-2xO">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
|
@ -317,7 +314,7 @@
|
|||
</constraints>
|
||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="caC-7M-URI">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="addAudioTrack:" target="-2" id="Kp6-Qm-Mq6"/>
|
||||
|
|
@ -331,19 +328,22 @@
|
|||
</constraints>
|
||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="EQD-RZ-rXn">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="removeAudioTrack:" target="-2" id="Vpk-YM-Bjv"/>
|
||||
</connections>
|
||||
</button>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="3Xs-zj-OzR">
|
||||
<rect key="frame" x="212" y="20" width="277" height="547"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="ssR-h6-svZ" firstAttribute="leading" secondItem="67k-Zi-Ko9" secondAttribute="leading" id="0rd-we-8mU"/>
|
||||
<constraint firstItem="wwP-vq-QJZ" firstAttribute="baseline" secondItem="67k-Zi-Ko9" secondAttribute="baseline" id="1ZV-jK-xHF"/>
|
||||
<constraint firstItem="3Xs-zj-OzR" firstAttribute="leading" secondItem="67k-Zi-Ko9" secondAttribute="trailing" constant="57" id="41R-jK-RRC"/>
|
||||
<constraint firstItem="3Xs-zj-OzR" firstAttribute="leading" secondItem="tVX-Ff-Ma1" secondAttribute="trailing" constant="52" id="44N-8o-cIp"/>
|
||||
<constraint firstAttribute="bottom" secondItem="3Xs-zj-OzR" secondAttribute="bottom" constant="-102" id="4AL-iV-4YT"/>
|
||||
<constraint firstAttribute="bottom" secondItem="3Xs-zj-OzR" secondAttribute="bottom" constant="20" id="4AL-iV-4YT"/>
|
||||
<constraint firstItem="tVX-Ff-Ma1" firstAttribute="top" secondItem="YVY-IW-xNH" secondAttribute="bottom" constant="67" id="4i9-j4-rgS"/>
|
||||
<constraint firstItem="3Xs-zj-OzR" firstAttribute="leading" secondItem="NeC-nP-8fw" secondAttribute="trailing" constant="52" id="58h-KA-Osu"/>
|
||||
<constraint firstItem="zwp-mN-H4b" firstAttribute="top" secondItem="6qE-t2-zqe" secondAttribute="bottom" constant="3" id="5OV-Of-H0C"/>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
-(void) addPlayer:(id)player forUUID:(NSString *)uuid;
|
||||
-(void)removePlayerForUUID:(NSString *)uuid;
|
||||
-(AudioStreamBasicDescription *)audioDescription;
|
||||
-(AVAudioFormat *)audioDescription;
|
||||
|
||||
@end
|
||||
|
||||
|
|
@ -529,12 +529,12 @@
|
|||
}
|
||||
|
||||
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(const AudioStreamBasicDescription *)withFormat
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(AVAudioFormat *)withFormat
|
||||
{
|
||||
return [self createPCMInput:forUID named:forUID withFormat:withFormat];
|
||||
}
|
||||
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID named:(NSString *)withName withFormat:(const AudioStreamBasicDescription *)withFormat
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID named:(NSString *)withName withFormat:(AVAudioFormat *)withFormat
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
|
|
@ -729,7 +729,7 @@
|
|||
if (!realPlayer)
|
||||
{
|
||||
|
||||
AudioStreamBasicDescription *useDesc = [pPlayer audioDescription];
|
||||
AVAudioFormat *useDesc = [pPlayer audioDescription];
|
||||
|
||||
if (useDesc)
|
||||
{
|
||||
|
|
@ -890,7 +890,7 @@
|
|||
|
||||
//[self createPCMInput:self.captureName withFormat:audioFormat];
|
||||
|
||||
-(CSPcmPlayer *)createAttachedAudioInputForUUID:(NSString *)uuid withName:(NSString *)withName withFormat:(const AudioStreamBasicDescription *)withFormat
|
||||
-(CSPcmPlayer *)createAttachedAudioInputForUUID:(NSString *)uuid withName:(NSString *)withName withFormat:(AVAudioFormat *)withFormat
|
||||
{
|
||||
if (!uuid)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@
|
|||
}
|
||||
|
||||
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(const AudioStreamBasicDescription *)withFormat
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(AVAudioFormat *)withFormat
|
||||
{
|
||||
AppDelegate *myAppDelegate = [[NSApplication sharedApplication] delegate];
|
||||
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreAudio/CoreAudio.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <AudioUnit/AudioUnit.h>
|
||||
|
||||
|
||||
|
||||
//This class is used by the CAMultiAudioPCMPlayer class to store some submitted buffers for later free-ing.
|
||||
|
||||
@interface CAMultiAudioPCM : NSObject <NSCopying>
|
||||
@interface CAMultiAudioPCM : AVAudioPCMBuffer
|
||||
{
|
||||
size_t _audioBufferListSize;
|
||||
size_t _audioBufferDataSize;
|
||||
|
|
@ -22,20 +23,11 @@
|
|||
|
||||
}
|
||||
@property (assign) ScheduledAudioSlice *audioSlice;
|
||||
@property (assign) int bufferCount;
|
||||
@property (assign) int frameCount;
|
||||
@property (weak) id player;
|
||||
@property (assign) AudioStreamBasicDescription pcmFormat;
|
||||
@property (assign) AudioBufferList *pcmData;
|
||||
@property (assign) bool handleFreeBuffer;
|
||||
@property (assign) uint8_t *dataBuffer;
|
||||
|
||||
|
||||
|
||||
-(instancetype)initWithAudioBufferList:(AudioBufferList *)bufferList streamFormat:(const AudioStreamBasicDescription *)streamFormat;
|
||||
-(instancetype)initWithDescription:(const AudioStreamBasicDescription *)streamFormat forFrameCount:(int)forFrameCount;
|
||||
-(void)copyFromAudioBufferList:(AudioBufferList *)copyFrom;
|
||||
-(void)silenceBuffer;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -131,12 +131,12 @@ typedef enum frame_render_behavior_t {
|
|||
-(NSSize)captureSize;
|
||||
|
||||
/* Create a PCM audio input. Use this and not the service plugin version. This version properly finds the appropriate audio engine and creates the PCM input there */
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(const AudioStreamBasicDescription *)withFormat;
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID named:(NSString *)withName withFormat:(const AudioStreamBasicDescription *)withFormat;
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(AVAudioFormat *)withFormat;
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID named:(NSString *)withName withFormat:(AVAudioFormat *)withFormat;
|
||||
|
||||
-(void)createAttachedAudioInputForUUID:(NSString *)uuid withName:(NSString *)withName;
|
||||
-(void)changeAttachedAudioInputName:(NSString *)uuid withName:(NSString *)withName;
|
||||
-(CSPcmPlayer *)createAttachedAudioInputForUUID:(NSString *)uuid withName:(NSString *)withName withFormat:(const AudioStreamBasicDescription *)withFormat;
|
||||
-(CSPcmPlayer *)createAttachedAudioInputForUUID:(NSString *)uuid withName:(NSString *)withName withFormat:(AVAudioFormat *)withFormat;
|
||||
-(void)removeAttachedAudioInput:(NSString *)uuid;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
-(void)play;
|
||||
-(void)pause;
|
||||
-(void)flush;
|
||||
-(void)setAudioFormat:(AudioStreamBasicDescription *)asbd;
|
||||
-(void)setAudioFormat:(AVAudioFormat *)asbd;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
|
||||
+(CSPluginServices *)sharedPluginServices;
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(const AudioStreamBasicDescription *)withFormat;
|
||||
-(CSPcmPlayer *)createPCMInput:(NSString *)forUID withFormat:(AVAudioFormat *)withFormat;
|
||||
|
||||
-(void)removePCMInput:(CSPcmPlayer *)toRemove;
|
||||
-(void)loadPythonClass:(NSString *)pyClass fromFile:(NSString *)fromFile withBlock:(void(^)(Class))withBlock;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue