1/*
2 * Copyright (c) 2002, 2015, 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
26package com.sun.media.sound;
27
28import javax.sound.sampled.Mixer;
29import javax.sound.sampled.spi.MixerProvider;
30
31/**
32 * DirectAudioDevice provider.
33 *
34 * @author Florian Bomers
35 */
36public final class DirectAudioDeviceProvider extends MixerProvider {
37
38    /**
39     * Set of info objects for all port input devices on the system.
40     */
41    private static DirectAudioDeviceInfo[] infos;
42
43    /**
44     * Set of all port input devices on the system.
45     */
46    private static DirectAudioDevice[] devices;
47
48    static {
49        // initialize
50        Platform.initialize();
51    }
52
53    /**
54     * Required public no-arg constructor.
55     */
56    public DirectAudioDeviceProvider() {
57        synchronized (DirectAudioDeviceProvider.class) {
58            if (Platform.isDirectAudioEnabled()) {
59                init();
60            } else {
61                infos = new DirectAudioDeviceInfo[0];
62                devices = new DirectAudioDevice[0];
63            }
64        }
65    }
66
67    private static void init() {
68        // get the number of input devices
69        int numDevices = nGetNumDevices();
70
71        if (infos == null || infos.length != numDevices) {
72            if (Printer.trace) Printer.trace("DirectAudioDeviceProvider: init()");
73            // initialize the arrays
74            infos = new DirectAudioDeviceInfo[numDevices];
75            devices = new DirectAudioDevice[numDevices];
76
77            // fill in the info objects now.
78            for (int i = 0; i < infos.length; i++) {
79                infos[i] = nNewDirectAudioDeviceInfo(i);
80            }
81            if (Printer.trace) Printer.trace("DirectAudioDeviceProvider: init(): found numDevices: " + numDevices);
82        }
83    }
84
85    @Override
86    public Mixer.Info[] getMixerInfo() {
87        synchronized (DirectAudioDeviceProvider.class) {
88            Mixer.Info[] localArray = new Mixer.Info[infos.length];
89            System.arraycopy(infos, 0, localArray, 0, infos.length);
90            return localArray;
91        }
92    }
93
94    @Override
95    public Mixer getMixer(Mixer.Info info) {
96        synchronized (DirectAudioDeviceProvider.class) {
97            // if the default device is asked, we provide the mixer
98            // with SourceDataLine's
99            if (info == null) {
100                for (int i = 0; i < infos.length; i++) {
101                    Mixer mixer = getDevice(infos[i]);
102                    if (mixer.getSourceLineInfo().length > 0) {
103                        return mixer;
104                    }
105                }
106            }
107            // otherwise get the first mixer that matches
108            // the requested info object
109            for (int i = 0; i < infos.length; i++) {
110                if (infos[i].equals(info)) {
111                    return getDevice(infos[i]);
112                }
113            }
114        }
115        throw new IllegalArgumentException(
116                String.format("Mixer %s not supported by this provider", info));
117    }
118
119    private static Mixer getDevice(DirectAudioDeviceInfo info) {
120        int index = info.getIndex();
121        if (devices[index] == null) {
122            devices[index] = new DirectAudioDevice(info);
123        }
124        return devices[index];
125    }
126
127    /**
128     * Info class for DirectAudioDevices.  Adds an index value and a string for
129     * making native references to a particular device.
130     * This constructor is called from native.
131     */
132    static final class DirectAudioDeviceInfo extends Mixer.Info {
133        private final int index;
134        private final int maxSimulLines;
135
136        // For ALSA, the deviceID contains the encoded card index, device index, and sub-device-index
137        private final int deviceID;
138
139        private DirectAudioDeviceInfo(int index, int deviceID, int maxSimulLines,
140                                      String name, String vendor,
141                                      String description, String version) {
142            super(name, vendor, "Direct Audio Device: "+description, version);
143            this.index = index;
144            this.maxSimulLines = maxSimulLines;
145            this.deviceID = deviceID;
146        }
147
148        int getIndex() {
149            return index;
150        }
151
152        int getMaxSimulLines() {
153            return maxSimulLines;
154        }
155
156        int getDeviceID() {
157            return deviceID;
158        }
159    } // class DirectAudioDeviceInfo
160
161    private static native int nGetNumDevices();
162    // index: [0..nGetNumDevices()-1]
163    private static native DirectAudioDeviceInfo nNewDirectAudioDeviceInfo(int deviceIndex);
164}
165