diff --git a/cpp/AudioContext/ios/AudioContextWrapper.cpp b/cpp/AudioContext/ios/AudioContextWrapper.cpp index 063ba6d6..1eb0500e 100644 --- a/cpp/AudioContext/ios/AudioContextWrapper.cpp +++ b/cpp/AudioContext/ios/AudioContextWrapper.cpp @@ -7,9 +7,8 @@ namespace audiocontext return std::make_shared(audiocontext_); } - std::shared_ptr AudioContextWrapper::getDestination() const { - // TODO: Add AudioDestinationNode implementation - return std::make_shared(); + std::shared_ptr AudioContextWrapper::getDestination() { + return std::make_shared(audiocontext_); } std::shared_ptr AudioContextWrapper::createGain() { @@ -36,5 +35,9 @@ namespace audiocontext int AudioContextWrapper::getSampleRate() const { return audiocontext_->getSampleRate(); } + + void AudioContextWrapper::close() { + //TODO + } } // namespace audiocontext #endif diff --git a/cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h b/cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h index 11c14cf4..73981d7f 100644 --- a/cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h +++ b/cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h @@ -5,6 +5,9 @@ #ifdef ANDROID #include "AudioDestinationNode.h" #include "AudioNodeWrapper.h" +#else +#include "IOSAudioDestinationNode.h" +#include "IOSAudioContext.h" #endif namespace audiocontext { @@ -18,8 +21,12 @@ namespace audiocontext { public: explicit AudioDestinationNodeWrapper(AudioDestinationNode *destinationNode) : AudioNodeWrapper(destinationNode) {} #else - public: - explicit AudioDestinationNodeWrapper() {} + private: + std::shared_ptr destination_; + public: + explicit AudioDestinationNodeWrapper(std::shared_ptr context) : AudioNodeWrapper() { + node_ = destination_ = std::make_shared(context); + } #endif }; } // namespace audiocontext diff --git a/example/src/App.tsx b/example/src/App.tsx index 7e2cf28a..7544c05d 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Button, Platform, StyleSheet, Text, View } from 'react-native'; +import { Button, StyleSheet, Text, View } from 'react-native'; import { useRef, useState, useEffect } from 'react'; import { Slider } from '@miblanchard/react-native-slider'; import { Kick } from './sound-engines/Kick'; @@ -48,11 +48,7 @@ const App: React.FC = () => { oscillatorRef.current.connect(gainRef.current); gainRef.current.connect(panRef.current); - - if (Platform.OS === 'android') { - const destination = audioContextRef.current.destination; - panRef.current.connect(destination!); - } + panRef.current.connect(audioContextRef.current.destination); } return () => { diff --git a/example/src/sound-engines/Kick.ts b/example/src/sound-engines/Kick.ts index c8099880..5a993835 100644 --- a/example/src/sound-engines/Kick.ts +++ b/example/src/sound-engines/Kick.ts @@ -3,7 +3,6 @@ import { type GainNode, type OscillatorNode, } from 'react-native-audio-context'; -import { Platform } from 'react-native'; import type { SoundEngine } from './SoundEngine'; export class Kick implements SoundEngine { @@ -24,11 +23,9 @@ export class Kick implements SoundEngine { setup() { this.gain = this.audioContext.createGain(); this.oscillator = this.audioContext.createOscillator(); - this.oscillator.connect(this.gain); - if (Platform.OS === 'android') { - this.gain.connect(this.audioContext.destination!); - } + this.oscillator.connect(this.gain); + this.gain.connect(this.audioContext.destination!); } play(time: number) { diff --git a/ios/nodes/AudioDestinationNode/AudioDestinationNode.h b/ios/nodes/AudioDestinationNode/AudioDestinationNode.h new file mode 100644 index 00000000..aa93c577 --- /dev/null +++ b/ios/nodes/AudioDestinationNode/AudioDestinationNode.h @@ -0,0 +1,12 @@ +#pragma once + +#import "AudioNode.h" + +#import + +@interface AudioDestinationNode : AudioNode + +- (instancetype)initWithContext:(AudioContext *)context; +- (void)clean; + +@end diff --git a/ios/nodes/AudioDestinationNode/AudioDestinationNode.m b/ios/nodes/AudioDestinationNode/AudioDestinationNode.m new file mode 100644 index 00000000..a0a57136 --- /dev/null +++ b/ios/nodes/AudioDestinationNode/AudioDestinationNode.m @@ -0,0 +1,23 @@ +#import +#import "AudioContext.h" + +@implementation AudioDestinationNode + +- (instancetype)initWithContext:(AudioContext *)context { + if (self = [super initWithContext:context]) { + self.numberOfInputs = INT_MAX; + self.numberOfOutputs = 0; + } + + return self; +} + +- (void)clean { + // Do nothing +} + +- (void)process:(float *)buffer frameCount:(AVAudioFrameCount)frameCount { + // Do nothing +} + +@end diff --git a/ios/nodes/AudioDestinationNode/IOSAudioDestinationNode.h b/ios/nodes/AudioDestinationNode/IOSAudioDestinationNode.h new file mode 100644 index 00000000..67625344 --- /dev/null +++ b/ios/nodes/AudioDestinationNode/IOSAudioDestinationNode.h @@ -0,0 +1,24 @@ +#pragma once + +#ifdef __OBJC__ // when compiled as Objective-C++ +#import +#else // when compiled as C++ +typedef struct objc_object AudioDestinationNode; +#endif // __OBJC__ + +#include "IOSAudioNode.h" +#include "IOSAudioContext.h" + +#import + +namespace audiocontext { + class IOSAudioDestinationNode : public IOSAudioNode { + public: + explicit IOSAudioDestinationNode(std::shared_ptr context); + ~IOSAudioDestinationNode(); + + protected: + AudioDestinationNode *destination_; + }; +} // namespace audiocontext + diff --git a/ios/nodes/AudioDestinationNode/IOSAudioDestinationNode.mm b/ios/nodes/AudioDestinationNode/IOSAudioDestinationNode.mm new file mode 100644 index 00000000..bee3fcf9 --- /dev/null +++ b/ios/nodes/AudioDestinationNode/IOSAudioDestinationNode.mm @@ -0,0 +1,13 @@ +#include + +namespace audiocontext { + + IOSAudioDestinationNode::IOSAudioDestinationNode(std::shared_ptr context) { + audioNode_ = destination_ = [[AudioDestinationNode alloc] initWithContext:context->audioContext_]; + } + + IOSAudioDestinationNode::~IOSAudioDestinationNode() { + [destination_ clean]; + audioNode_ = destination_ = nil; + } +} // namespace audiocontext diff --git a/src/index.ts b/src/index.ts index 0c1c1343..3f46b643 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,19 +10,15 @@ import type { import { installACModule } from './utils/install'; export class AudioContext implements BaseAudioContext { - readonly destination: AudioDestinationNode | null; + readonly destination: AudioDestinationNode; readonly sampleRate: number; constructor() { - this.destination = null; - if (global.__AudioContext == null) { installACModule(); } - if (Platform.OS === 'android') { - this.destination = global.__AudioContext.destination; - } + this.destination = global.__AudioContext.destination; this.sampleRate = global.__AudioContext.sampleRate; } diff --git a/src/modules/global.d.ts b/src/modules/global.d.ts index fb180d83..24de18af 100644 --- a/src/modules/global.d.ts +++ b/src/modules/global.d.ts @@ -8,7 +8,7 @@ import type { } from '../types'; type AudioContext = { - destination: AudioDestinationNode | null; + destination: AudioDestinationNode; state: ContextState; sampleRate: number; currentTime: number; diff --git a/src/types.ts b/src/types.ts index a3839c52..33f4a6c0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,5 @@ export interface BaseAudioContext { - readonly destination: AudioDestinationNode | null; + readonly destination: AudioDestinationNode; readonly state: ContextState; readonly sampleRate: number; readonly currentTime: number;