1 /*
   2  * Copyright (c) 2002, 2014, 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 //#define USE_TRACE
  27 #define USE_ERROR
  28 
  29 
  30 #include <jni.h>
  31 #include <jni_util.h>
  32 #include "SoundDefs.h"
  33 #include "Ports.h"
  34 #include "Utilities.h"
  35 #include "com_sun_media_sound_PortMixer.h"
  36 
  37 
  38 //////////////////////////////////////////// PortMixer ////////////////////////////////////////////
  39 
  40 JNIEXPORT jlong JNICALL Java_com_sun_media_sound_PortMixer_nOpen
  41   (JNIEnv *env, jclass cls, jint mixerIndex) {
  42 
  43     jlong ret = 0;
  44 #if USE_PORTS == TRUE
  45     ret = (jlong) (INT_PTR) PORT_Open(mixerIndex);
  46 #endif
  47     return ret;
  48 }
  49 
  50 JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nClose
  51   (JNIEnv *env, jclass cls, jlong id) {
  52 
  53 #if USE_PORTS == TRUE
  54     if (id != 0) {
  55         PORT_Close((void*) (INT_PTR) id);
  56     }
  57 #endif
  58 }
  59 
  60 JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nGetPortCount
  61   (JNIEnv *env, jclass cls, jlong id) {
  62 
  63     jint ret = 0;
  64 #if USE_PORTS == TRUE
  65     if (id != 0) {
  66         ret = (jint) PORT_GetPortCount((void*) (INT_PTR) id);
  67     }
  68 #endif
  69     return ret;
  70 }
  71 
  72 
  73 JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nGetPortType
  74   (JNIEnv *env, jclass cls, jlong id, jint portIndex) {
  75 
  76     jint ret = 0;
  77     TRACE1("Java_com_sun_media_sound_PortMixer_nGetPortType(%d).\n", portIndex);
  78 
  79 #if USE_PORTS == TRUE
  80     if (id != 0) {
  81         ret = (jint) PORT_GetPortType((void*) (INT_PTR) id, portIndex);
  82     }
  83 #endif
  84 
  85     TRACE1("Java_com_sun_media_sound_PortMixerProvider_nGetPortType returning %d.\n", ret);
  86     return ret;
  87 }
  88 
  89 JNIEXPORT jstring JNICALL Java_com_sun_media_sound_PortMixer_nGetPortName
  90   (JNIEnv *env, jclass cls, jlong id, jint portIndex) {
  91 
  92     char str[PORT_STRING_LENGTH];
  93     jstring jString = NULL;
  94     TRACE1("Java_com_sun_media_sound_PortMixer_nGetPortName(%d).\n", portIndex);
  95 
  96     str[0] = 0;
  97 #if USE_PORTS == TRUE
  98     if (id != 0) {
  99         PORT_GetPortName((void*) (INT_PTR) id, portIndex, str, PORT_STRING_LENGTH);
 100     }
 101 #endif
 102     jString = (*env)->NewStringUTF(env, str);
 103 
 104     TRACE1("Java_com_sun_media_sound_PortMixerProvider_nGetName returning \"%s\".\n", str);
 105     return jString;
 106 }
 107 
 108 JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nControlSetIntValue
 109   (JNIEnv *env, jclass cls, jlong controlID, jint value) {
 110 #if USE_PORTS == TRUE
 111     if (controlID != 0) {
 112         PORT_SetIntValue((void*) (UINT_PTR) controlID, (INT32) value);
 113     }
 114 #endif
 115 }
 116 
 117 JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nControlGetIntValue
 118   (JNIEnv *env, jclass cls, jlong controlID) {
 119     INT32 ret = 0;
 120 #if USE_PORTS == TRUE
 121     if (controlID != 0) {
 122         ret = PORT_GetIntValue((void*) (UINT_PTR) controlID);
 123     }
 124 #endif
 125     return (jint) ret;
 126 }
 127 
 128 JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nControlSetFloatValue
 129   (JNIEnv *env, jclass cls, jlong controlID, jfloat value) {
 130 #if USE_PORTS == TRUE
 131     if (controlID != 0) {
 132         PORT_SetFloatValue((void*) (UINT_PTR) controlID, (float) value);
 133     }
 134 #endif
 135 }
 136 
 137 JNIEXPORT jfloat JNICALL Java_com_sun_media_sound_PortMixer_nControlGetFloatValue
 138   (JNIEnv *env, jclass cls, jlong controlID) {
 139     float ret = 0;
 140 #if USE_PORTS == TRUE
 141     if (controlID != 0) {
 142         ret = PORT_GetFloatValue((void*) (UINT_PTR) controlID);
 143     }
 144 #endif
 145     return (jfloat) ret;
 146 }
 147 
 148 /* ************************************** native control creation support ********************* */
 149 
 150 // contains all the needed references so that the platform dependent code can call JNI wrapper functions
 151 typedef struct tag_ControlCreatorJNI {
 152     // this member is seen by the platform dependent code
 153     PortControlCreator creator;
 154     // general JNI variables
 155     JNIEnv *env;
 156     // the vector to be filled with controls (initialized before usage)
 157     jobject vector;
 158     jmethodID vectorAddElement;
 159     // control specific constructors (initialized on demand)
 160     jclass boolCtrlClass;
 161     jmethodID boolCtrlConstructor;   // signature (JLjava/lang/String;)V
 162     jclass controlClass;             // class of javax.sound.sampled.Control
 163     jclass compCtrlClass;
 164     jmethodID compCtrlConstructor;   // signature (Ljava/lang/String;[Ljavax/sound/sampled/Control;)V
 165     jclass floatCtrlClass;
 166     jmethodID floatCtrlConstructor1; // signature (JLjava/lang/String;FFFLjava/lang/String;)V
 167     jmethodID floatCtrlConstructor2; // signature (JIFFFLjava/lang/String;)V
 168 } ControlCreatorJNI;
 169 
 170 
 171 void* PORT_NewBooleanControl(void* creatorV, void* controlID, char* type) {
 172     ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV;
 173     jobject ctrl = NULL;
 174     jstring typeString;
 175 
 176 #ifdef USE_TRACE
 177     if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) {
 178         TRACE1("PORT_NewBooleanControl: creating '%d'\n", (int) (UINT_PTR) type);
 179     } else {
 180         TRACE1("PORT_NewBooleanControl: creating '%s'\n", type);
 181     }
 182 #endif
 183     if (!creator->boolCtrlClass) {
 184         // retrieve class and constructor of PortMixer.BoolCtrl
 185         creator->boolCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$BoolCtrl");
 186         if (!creator->boolCtrlClass) {
 187             ERROR0("PORT_NewBooleanControl: boolCtrlClass is NULL\n");
 188             return NULL;
 189         }
 190         creator->boolCtrlConstructor = (*creator->env)->GetMethodID(creator->env, creator->boolCtrlClass,
 191                  "<init>", "(JLjava/lang/String;)V");
 192         if (!creator->boolCtrlConstructor) {
 193             ERROR0("PORT_NewBooleanControl: boolCtrlConstructor is NULL\n");
 194             return NULL;
 195         }
 196     }
 197     if (type == CONTROL_TYPE_MUTE) {
 198         type = "Mute";
 199     }
 200     else if (type == CONTROL_TYPE_SELECT) {
 201         type = "Select";
 202     }
 203 
 204     typeString = (*creator->env)->NewStringUTF(creator->env, type);
 205     CHECK_NULL_RETURN(typeString, (void*) ctrl);
 206     ctrl = (*creator->env)->NewObject(creator->env, creator->boolCtrlClass,
 207                                       creator->boolCtrlConstructor,
 208                                       (jlong) (UINT_PTR) controlID, typeString);
 209     if (!ctrl) {
 210         ERROR0("PORT_NewBooleanControl: ctrl is NULL\n");
 211     }
 212     if ((*creator->env)->ExceptionOccurred(creator->env)) {
 213         ERROR0("PORT_NewBooleanControl: ExceptionOccurred!\n");
 214     }
 215     TRACE0("PORT_NewBooleanControl succeeded\n");
 216     return (void*) ctrl;
 217 }
 218 
 219 void* PORT_NewCompoundControl(void* creatorV, char* type, void** controls, int controlCount) {
 220     ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV;
 221     jobject ctrl = NULL;
 222     jobjectArray controlArray;
 223     int i;
 224     jstring typeString;
 225 
 226     TRACE2("PORT_NewCompoundControl: creating '%s' with %d controls\n", type, controlCount);
 227     if (!creator->compCtrlClass) {
 228         TRACE0("PORT_NewCompoundControl: retrieve method ids\n");
 229         // retrieve class and constructor of PortMixer.BoolCtrl
 230         creator->compCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$CompCtrl");
 231         if (!creator->compCtrlClass) {
 232             ERROR0("PORT_NewCompoundControl: compCtrlClass is NULL\n");
 233             return NULL;
 234         }
 235         creator->compCtrlConstructor = (*creator->env)->GetMethodID(creator->env, creator->compCtrlClass,
 236                  "<init>", "(Ljava/lang/String;[Ljavax/sound/sampled/Control;)V");
 237         if (!creator->compCtrlConstructor) {
 238             ERROR0("PORT_NewCompoundControl: compCtrlConstructor is NULL\n");
 239             return NULL;
 240         }
 241         creator->controlClass = (*creator->env)->FindClass(creator->env, JAVA_SAMPLED_PACKAGE_NAME"/Control");
 242         if (!creator->controlClass) {
 243             ERROR0("PORT_NewCompoundControl: controlClass is NULL\n");
 244             return NULL;
 245         }
 246     }
 247     TRACE0("PORT_NewCompoundControl: creating array\n");
 248     // create new array for the controls
 249     controlArray = (*creator->env)->NewObjectArray(creator->env, controlCount, creator->controlClass, (jobject) NULL);
 250     if (!controlArray) {
 251         ERROR0("PORT_NewCompoundControl: controlArray is NULL\n");
 252         return NULL;
 253     }
 254     TRACE0("PORT_NewCompoundControl: setting array values\n");
 255     for (i = 0; i < controlCount; i++) {
 256         (*creator->env)->SetObjectArrayElement(creator->env, controlArray, i, (jobject) controls[i]);
 257     }
 258     TRACE0("PORT_NewCompoundControl: creating compound control\n");
 259     typeString = (*creator->env)->NewStringUTF(creator->env, type);
 260     CHECK_NULL_RETURN(typeString, (void*) ctrl);
 261     ctrl = (*creator->env)->NewObject(creator->env, creator->compCtrlClass,
 262                                       creator->compCtrlConstructor,
 263                                       typeString, controlArray);
 264     if (!ctrl) {
 265         ERROR0("PORT_NewCompoundControl: ctrl is NULL\n");
 266     }
 267     if ((*creator->env)->ExceptionOccurred(creator->env)) {
 268         ERROR0("PORT_NewCompoundControl: ExceptionOccurred!\n");
 269     }
 270     TRACE0("PORT_NewCompoundControl succeeded\n");
 271     return (void*) ctrl;
 272 }
 273 
 274 void* PORT_NewFloatControl(void* creatorV, void* controlID, char* type,
 275                            float min, float max, float precision, const char* units) {
 276     ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV;
 277     jobject ctrl = NULL;
 278     jstring unitsString;
 279     jstring typeString;
 280 
 281 #ifdef USE_TRACE
 282     if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) {
 283         TRACE1("PORT_NewFloatControl: creating '%d'\n", (int) (UINT_PTR) type);
 284     } else {
 285         TRACE1("PORT_NewFloatControl: creating '%s'\n", type);
 286     }
 287 #endif
 288     if (!creator->floatCtrlClass) {
 289         // retrieve class and constructor of PortMixer.BoolCtrl
 290         creator->floatCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$FloatCtrl");
 291         if (!creator->floatCtrlClass) {
 292             ERROR0("PORT_NewFloatControl: floatCtrlClass is NULL\n");
 293             return NULL;
 294         }
 295         creator->floatCtrlConstructor1 = (*creator->env)->GetMethodID(creator->env, creator->floatCtrlClass,
 296                  "<init>", "(JLjava/lang/String;FFFLjava/lang/String;)V");
 297         if (!creator->floatCtrlConstructor1) {
 298             ERROR0("PORT_NewFloatControl: floatCtrlConstructor1 is NULL\n");
 299             return NULL;
 300         }
 301         creator->floatCtrlConstructor2 = (*creator->env)->GetMethodID(creator->env, creator->floatCtrlClass,
 302                  "<init>", "(JIFFFLjava/lang/String;)V");
 303         if (!creator->floatCtrlConstructor2) {
 304             ERROR0("PORT_NewFloatControl: floatCtrlConstructor2 is NULL\n");
 305             return NULL;
 306         }
 307     }
 308     unitsString = (*creator->env)->NewStringUTF(creator->env, units);
 309     CHECK_NULL_RETURN(unitsString, (void*) ctrl);
 310     if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) {
 311         // constructor with int parameter
 312         TRACE1("PORT_NewFloatControl: calling constructor2 with type %d\n", (int) (UINT_PTR) type);
 313         ctrl = (*creator->env)->NewObject(creator->env, creator->floatCtrlClass,
 314                                           creator->floatCtrlConstructor2,
 315                                           (jlong) (UINT_PTR) controlID, (jint) (UINT_PTR) type,
 316                                           min, max, precision, unitsString);
 317     } else {
 318         TRACE0("PORT_NewFloatControl: calling constructor1\n");
 319         // constructor with string parameter
 320         typeString = (*creator->env)->NewStringUTF(creator->env, type);
 321         CHECK_NULL_RETURN(typeString, (void*) ctrl);
 322         ctrl = (*creator->env)->NewObject(creator->env, creator->floatCtrlClass,
 323                                           creator->floatCtrlConstructor1,
 324                                           (jlong) (UINT_PTR) controlID, typeString,
 325                                           min, max, precision, unitsString);
 326     }
 327     if (!ctrl) {
 328         ERROR0("PORT_NewFloatControl: ctrl is NULL!\n");
 329     }
 330     if ((*creator->env)->ExceptionOccurred(creator->env)) {
 331         ERROR0("PORT_NewFloatControl: ExceptionOccurred!\n");
 332     }
 333     TRACE1("PORT_NewFloatControl succeeded %p\n", (void*) ctrl);
 334     return (void*) ctrl;
 335 }
 336 
 337 int PORT_AddControl(void* creatorV, void* control) {
 338     ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV;
 339 
 340     TRACE1("PORT_AddControl %p\n", (void*) control);
 341     (*creator->env)->CallVoidMethod(creator->env, creator->vector, creator->vectorAddElement, (jobject) control);
 342     if ((*creator->env)->ExceptionOccurred(creator->env)) {
 343         ERROR0("PORT_AddControl: ExceptionOccurred!\n");
 344     }
 345     TRACE0("PORT_AddControl succeeded\n");
 346     return TRUE;
 347 }
 348 
 349 JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nGetControls
 350   (JNIEnv *env, jclass cls, jlong id, jint portIndex, jobject vector) {
 351 
 352     ControlCreatorJNI creator;
 353     jclass vectorClass;
 354 
 355 #if USE_PORTS == TRUE
 356     if (id != 0) {
 357         memset(&creator, 0, sizeof(ControlCreatorJNI));
 358         creator.creator.newBooleanControl  = &PORT_NewBooleanControl;
 359         creator.creator.newCompoundControl = &PORT_NewCompoundControl;
 360         creator.creator.newFloatControl    = &PORT_NewFloatControl;
 361         creator.creator.addControl         = &PORT_AddControl;
 362         creator.env = env;
 363         vectorClass = (*env)->GetObjectClass(env, vector);
 364         if (vectorClass == NULL) {
 365             ERROR0("Java_com_sun_media_sound_PortMixer_nGetControls: vectorClass is NULL\n");
 366             return;
 367         }
 368         creator.vector = vector;
 369         creator.vectorAddElement = (*env)->GetMethodID(env, vectorClass, "addElement", "(Ljava/lang/Object;)V");
 370         if (creator.vectorAddElement == NULL) {
 371             ERROR0("Java_com_sun_media_sound_PortMixer_nGetControls: addElementMethodID is NULL\n");
 372             return;
 373         }
 374         PORT_GetControls((void*) (UINT_PTR) id, (INT32) portIndex, (PortControlCreator*) &creator);
 375     }
 376 #endif
 377 }