示例#1
0
 private static void CheckGraphError(AUGraphError error, string msg)
 {
     if (error != AUGraphError.OK)
     {
         throw new AudioSystemInternalException(msg + " [Error=" + error + "].");
     }
 }
示例#2
0
        void SetupAUGraph()
        {
            graph = new AUGraph();

            AudioComponentDescription mixerDescription = new AudioComponentDescription();

            mixerDescription.ComponentType         = AudioComponentType.Mixer;
            mixerDescription.ComponentSubType      = (int)AudioTypeMixer.MultiChannel;
            mixerDescription.ComponentFlags        = 0;
            mixerDescription.ComponentFlagsMask    = 0;
            mixerDescription.ComponentManufacturer = AudioComponentManufacturerType.Apple;

            AudioComponentDescription outputDesciption = new AudioComponentDescription();

            outputDesciption.ComponentType         = AudioComponentType.Output;
            outputDesciption.ComponentSubType      = (int)AudioTypeOutput.System;
            outputDesciption.ComponentFlags        = 0;
            outputDesciption.ComponentFlagsMask    = 0;
            outputDesciption.ComponentManufacturer = AudioComponentManufacturerType.Apple;

            int mixerNode  = graph.AddNode(mixerDescription);
            int outputNode = graph.AddNode(outputDesciption);

            AUGraphError error = graph.ConnnectNodeInput(mixerNode, 0, outputNode, 0);

            Assert.AreEqual(AUGraphError.OK, error);

            graph.Open();

            mMixer = graph.GetNodeInfo(mixerNode);

            AudioUnitStatus status = mMixer.SetElementCount(AudioUnitScopeType.Input, 0);

            Assert.AreEqual(AudioUnitStatus.OK, status);
        }
示例#3
0
        public AudioUnit?GetNodeInfo(int node, out AudioComponentDescription cd, out AUGraphError error)
        {
            error = AUGraphNodeInfo(GetCheckedHandle(), node, out cd, out var ptr);

            if (error != AUGraphError.OK || ptr == IntPtr.Zero)
            {
                return(null);
            }

            return(new AudioUnit(ptr, false));
        }
示例#4
0
        void restartAudioProcessingGraph()
        {
            AUGraphError result = AUGraphError.OK;

            if (processingGraph != null)
            {
                result = processingGraph.Start();
            }

            if (result != AUGraphError.OK)
            {
                throw new Exception("Unable to restart the audio processing graph.  Error code: " + result);
            }
        }
示例#5
0
        // AudioComponentDescription struct in only correctly fixed for unified
        // Following current Api behaviour of returning an AudioUnit instead of an error
        public AudioUnit GetNodeInfo(int node, out AudioComponentDescription cd, out AUGraphError error)
        {
            if (Handle == IntPtr.Zero)
            {
                throw new ObjectDisposedException("AUGraph");
            }

            IntPtr ptr;

            error = AUGraphNodeInfo(Handle, node, out cd, out ptr);

            if (error != AUGraphError.OK || ptr == IntPtr.Zero)
            {
                return(null);
            }

            return(new AudioUnit(ptr));
        }
示例#6
0
        bool createAUGraph()
        {
            AUGraphError result = 0;
            int          samplerNode, ioNode;

            var cd = new AudioComponentDescription()
            {
                ComponentManufacturer = AudioComponentManufacturerType.Apple,
                ComponentFlags        = 0,
                ComponentFlagsMask    = 0
            };

            processingGraph = new AUGraph();

            cd.ComponentType    = AudioComponentType.MusicDevice;
            cd.ComponentSubType = (int)AudioTypeMusicDevice.Sampler;             //0x73616d70;

            samplerNode = processingGraph.AddNode(cd);

            cd.ComponentType    = AudioComponentType.Output;
            cd.ComponentSubType = (int)AudioTypeOutput.Remote;             //0x72696f63;

            ioNode = processingGraph.AddNode(cd);

            processingGraph.Open();

            result = processingGraph.ConnnectNodeInput(samplerNode, 0, ioNode, 0);
            if (result != AUGraphError.OK)
            {
                throw new Exception("Unable to open the audio processing graph.  Error code: " + result);
            }
            samplerUnit = processingGraph.GetNodeInfo(samplerNode);
            ioUnit      = processingGraph.GetNodeInfo(ioNode);

            return(true);
        }
示例#7
0
 private static void CheckGraphError(AUGraphError error, string msg)
 {
     if (error != AUGraphError.OK)
         throw new AudioSystemInternalException(msg + " [Error=" + error + "].");
 }
        void StreamPropertyListenerProc(object sender, PropertyFoundEventArgs args)
        {
            if (args.Property == AudioFileStreamProperty.DataFormat)
            {
                dataFormat = audioFileStream.DataFormat;
                return;
            }

            if (args.Property != AudioFileStreamProperty.ReadyToProducePackets)
            {
                return;
            }

            if (audioQueue != null)
            {
                // TODO: dispose old queue and its tap
                throw new NotImplementedException();
            }

            audioQueue = new OutputAudioQueue(dataFormat);
            audioQueue.BufferCompleted += HandleBufferCompleted;

            AudioQueueStatus status;

            aqTap = audioQueue.CreateProcessingTap(TapProc, AudioQueueProcessingTapFlags.PreEffects, out status);
            if (status != AudioQueueStatus.Ok)
            {
                throw new ApplicationException("Could not create AQ tap");
            }

            // create an augraph to process in the tap. needs to convert from tapFormat to effect format and back

            /* note: this is invalidname's recipe to do an in-place effect when a format conversion is needed
             * before and after the effect, usually because effects want floats, and everything else in iOS
             * core audio works with ints (or, in rare cases, fixed-point).
             * the graph looks like this:
             * [render-callback] -> [converter] -> [effect] -> [converter] -> [generic-output]
             * prior to calling AudioUnitRender() on generic-output the ioData to a pointer that render-callback
             * knows about, and NULLs the ioData provided to AudioUnitRender(). the NULL tells generic-output to
             * pull from its upstream units (ie, the augraph), and copying off the ioData pointer allows the
             * render-callback	to provide it to the front of the stream. in some locales, this kind of shell game
             * is described as "batshit crazy", but it seems to work pretty well in practice.
             */

            auGraph = new AUGraph();
            auGraph.Open();
            int effectNode = auGraph.AddNode(AudioComponentDescription.CreateConverter(AudioTypeConverter.NewTimePitch));

            effectUnit = auGraph.GetNodeInfo(effectNode);

            int convertToEffectNode = auGraph.AddNode(AudioComponentDescription.CreateConverter(AudioTypeConverter.AU));

            convertToEffectUnit = auGraph.GetNodeInfo(convertToEffectNode);

            int convertFromEffectNode = auGraph.AddNode(AudioComponentDescription.CreateConverter(AudioTypeConverter.AU));

            convertFromEffectUnit = auGraph.GetNodeInfo(convertFromEffectNode);

            int genericOutputNode = auGraph.AddNode(AudioComponentDescription.CreateOutput(AudioTypeOutput.Generic));

            genericOutputUnit = auGraph.GetNodeInfo(genericOutputNode);

            // set the format conversions throughout the graph
            AudioStreamBasicDescription effectFormat = effectUnit.GetAudioFormat(AudioUnitScopeType.Output);
            var tapFormat = aqTap.ProcessingFormat;

            convertToEffectUnit.SetAudioFormat(tapFormat, AudioUnitScopeType.Input);
            convertToEffectUnit.SetAudioFormat(effectFormat, AudioUnitScopeType.Output);

            convertFromEffectUnit.SetAudioFormat(effectFormat, AudioUnitScopeType.Input);
            convertFromEffectUnit.SetAudioFormat(tapFormat, AudioUnitScopeType.Output);

            genericOutputUnit.SetAudioFormat(tapFormat, AudioUnitScopeType.Input);
            genericOutputUnit.SetAudioFormat(tapFormat, AudioUnitScopeType.Output);

            // set maximum fames per slice higher (4096) so we don't get kAudioUnitErr_TooManyFramesToProcess
            const uint maxFramesPerSlice = 4096;

            if (convertToEffectUnit.SetMaximumFramesPerSlice(maxFramesPerSlice, AudioUnitScopeType.Global) != AudioUnitStatus.OK)
            {
                throw new ApplicationException();
            }
            if (effectUnit.SetMaximumFramesPerSlice(maxFramesPerSlice, AudioUnitScopeType.Global) != AudioUnitStatus.OK)
            {
                throw new ApplicationException();
            }
            if (convertFromEffectUnit.SetMaximumFramesPerSlice(maxFramesPerSlice, AudioUnitScopeType.Global) != AudioUnitStatus.OK)
            {
                throw new ApplicationException();
            }
            if (genericOutputUnit.SetMaximumFramesPerSlice(maxFramesPerSlice, AudioUnitScopeType.Global) != AudioUnitStatus.OK)
            {
                throw new ApplicationException();
            }

            // connect the nodes
            AUGraphError err = auGraph.ConnnectNodeInput(convertToEffectNode, 0, effectNode, 0);

            if (err != AUGraphError.OK)
            {
                throw new InvalidOperationException();
            }

            err = auGraph.ConnnectNodeInput(effectNode, 0, convertFromEffectNode, 0);
            if (err != AUGraphError.OK)
            {
                throw new InvalidOperationException();
            }

            err = auGraph.ConnnectNodeInput(convertFromEffectNode, 0, genericOutputNode, 0);
            if (err != AUGraphError.OK)
            {
                throw new InvalidOperationException();
            }

            renderTimeStamp.SampleTime = 0;
            renderTimeStamp.Flags      = AudioTimeStamp.AtsFlags.SampleTimeValid;

            // set up the callback into the first convert unit
            if (convertToEffectUnit.SetRenderCallback(ConvertInputRenderCallback, AudioUnitScopeType.Global) != AudioUnitStatus.NoError)
            {
                throw new ApplicationException();
            }

            var res = auGraph.Initialize();

            if (res != AUGraphError.OK)
            {
                throw new ApplicationException();
            }
        }
示例#9
0
		// AudioComponentDescription struct in only correctly fixed for unified
		// Following current Api behaviour of returning an AudioUnit instead of an error
		public AudioUnit GetNodeInfo (int node, out AudioComponentDescription cd, out AUGraphError error)
		{
			if (Handle == IntPtr.Zero)
				throw new ObjectDisposedException ("AUGraph");

			IntPtr ptr;
			error = AUGraphNodeInfo (Handle, node, out cd, out ptr);

			if (error != AUGraphError.OK || ptr == IntPtr.Zero)
				return null;

			return new AudioUnit (ptr);
		}