1 /*
   2  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "AVFKernelProcessor.h"
  27 
  28 #include <pthread.h>
  29 
  30 // Apple reserves 0-1024 for their own properties
  31 #define kAVFProperty_KernelProcessor 2099
  32 
  33 class AVFKernelComponent : AUEffectBase {
  34 public:
  35     AVFKernelComponent(AudioComponentInstance audioUnit, bool inProcessesInPlace = true)
  36         : AUEffectBase(audioUnit, inProcessesInPlace),
  37         mUsesKernel(false),
  38         mProcessor(nullptr)
  39     {}
  40 
  41     virtual ~AVFKernelComponent() {
  42         mProcessor = nullptr;
  43     }
  44 
  45     virtual AUKernelBase *NewKernel() {
  46         if (mProcessor != nullptr) {
  47             AUKernelBase *kernel = mProcessor->NewKernel();
  48             mUsesKernel = (kernel != NULL);
  49             return kernel;
  50         }
  51         mUsesKernel = false;
  52         return NULL;
  53     }
  54 
  55     virtual OSStatus ChangeStreamFormat(AudioUnitScope inScope,
  56                                         AudioUnitElement inElement,
  57                                         const CAStreamBasicDescription &inPrevFormat,
  58                                         const CAStreamBasicDescription &inNewFormat) {
  59         OSStatus status = this->AUEffectBase::ChangeStreamFormat(inScope,
  60                                                                  inElement,
  61                                                                  inPrevFormat,
  62                                                                  inNewFormat);
  63         if (mProcessor != nullptr && inScope == kAudioUnitScope_Input && inElement == 0) {
  64             mProcessor->StreamFormatChanged(inNewFormat);
  65         }
  66         return status;
  67     }
  68 
  69     virtual OSStatus ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,
  70                                         const AudioBufferList& inBuffer,
  71                                         AudioBufferList& outBuffer,
  72                                         UInt32 inFramesToProcess) {
  73         // Call our base class if we have kernels
  74         if (mUsesKernel) {
  75             return this->AUEffectBase::ProcessBufferLists(ioActionFlags,
  76                                                           inBuffer,
  77                                                           outBuffer,
  78                                                           inFramesToProcess);
  79         }
  80         // Otherwise call ProcessBufferLists
  81         if (mProcessor != nullptr) {
  82             return mProcessor->ProcessBufferLists(ioActionFlags,
  83                                                   inBuffer,
  84                                                   outBuffer,
  85                                                   inFramesToProcess);
  86         }
  87         return noErr; // ??? just in case
  88     }
  89 
  90     virtual OSStatus SetProperty(AudioUnitPropertyID inID,
  91                                  AudioUnitScope inScope,
  92                                  AudioUnitElement inElement,
  93                                  const void *inData,
  94                                  UInt32 inDataSize) {
  95         if (inID == kAVFProperty_KernelProcessor &&
  96             inScope == kAudioUnitScope_Global &&
  97             inElement == 0) {
  98             if (inDataSize == sizeof(AVFKernelProcessor*)) {
  99                 AVFKernelProcessorPtr processor = *((AVFKernelProcessorPtr*)inData);
 100                 // this compares the raw pointers, not the shared_ptr itself
 101                 if (mProcessor != processor) {
 102                     if (mProcessor != nullptr) {
 103                         mProcessor->SetAudioUnit(NULL);
 104                         mProcessor = nullptr;
 105                     }
 106 
 107                     mProcessor = processor;
 108                     if (mProcessor != nullptr) {
 109                         mProcessor->SetAudioUnit(this);
 110                         const AudioStreamBasicDescription& format =
 111                                 GetStreamFormat(kAudioUnitScope_Input, 0);
 112                         mProcessor->StreamFormatChanged(format);
 113                     }
 114                 }
 115                 return noErr;
 116             }
 117             return kAudioUnitErr_InvalidPropertyValue;
 118         }
 119         return this->AUEffectBase::SetProperty(inID, inScope, inElement, inData, inDataSize);
 120     }
 121 private:
 122     bool mUsesKernel;
 123     AVFKernelProcessorPtr mProcessor;
 124 };
 125 
 126 // Synchronize registration of the component
 127 volatile AudioComponent gAVFComponent = NULL;
 128 pthread_mutex_t gAVFComponentLock = PTHREAD_MUTEX_INITIALIZER;
 129 
 130 static inline AudioComponent GetAVFComponent() {
 131     AudioComponent component = NULL;
 132     pthread_mutex_lock(&gAVFComponentLock);
 133 
 134     if (!gAVFComponent) {
 135         gAVFComponent = AUBaseFactory<AVFKernelComponent>::Register(kAudioUnitType_Effect,
 136                                                                     'Krnl',
 137                                                                     'JAVA',
 138                                                                     CFSTR("JavaFX Kernel Processor"),
 139                                                                     0x00010000);
 140     }
 141     component = gAVFComponent;
 142 
 143     pthread_mutex_unlock(&gAVFComponentLock);
 144     return component;
 145 }
 146 
 147 
 148 AudioUnit NewKernelProcessorUnit(AVFKernelProcessorPtr kernel) {
 149     OSStatus status = noErr;
 150     AudioUnit unit = NULL;
 151     AudioComponent ac = GetAVFComponent();
 152 
 153     if (!ac) {
 154         return NULL;
 155     }
 156 
 157     status = AudioComponentInstanceNew(ac, &unit);
 158     if (noErr == status) {
 159         status = AudioUnitSetProperty(unit,
 160                                       kAVFProperty_KernelProcessor,
 161                                       kAudioUnitScope_Global,
 162                                       0,
 163                                       &kernel,
 164                                       sizeof(AVFKernelProcessorPtr*));
 165     }
 166 
 167     if (noErr != status) {
 168         if (unit) {
 169             AudioComponentInstanceDispose(unit);
 170         }
 171     }
 172     return unit;
 173 }