Library.java
com.mojang.blaze3d.audio.Library
信息
- 全限定名:com.mojang.blaze3d.audio.Library
- 类型:public class
- 包:com.mojang.blaze3d.audio
- 源码路径:src/main/java/com/mojang/blaze3d/audio/Library.java
- 起始行号:L26
- 职责:
TODO
字段/常量
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L27 - 说明:
TODO
- 类型:
-
NO_DEVICE- 类型:
int - 修饰符:
public static final - 源码定位:
L28 - 说明:
TODO
- 类型:
-
NO_DEVICE_NAME- 类型:
String - 修饰符:
private static final - 源码定位:
L29 - 说明:
TODO
- 类型:
-
DEFAULT_CHANNEL_COUNT- 类型:
int - 修饰符:
private static final - 源码定位:
L30 - 说明:
TODO
- 类型:
-
currentDevice- 类型:
long - 修饰符:
private - 源码定位:
L31 - 说明:
TODO
- 类型:
-
currentDeviceName- 类型:
String - 修饰符:
private - 源码定位:
L32 - 说明:
TODO
- 类型:
-
context- 类型:
long - 修饰符:
private - 源码定位:
L33 - 说明:
TODO
- 类型:
-
supportsDisconnections- 类型:
boolean - 修饰符:
private - 源码定位:
L34 - 说明:
TODO
- 类型:
-
EMPTY- 类型:
Library.ChannelPool - 修饰符:
private static final public public public public public - 源码定位:
L35 - 说明:
TODO
- 类型:
-
staticChannels- 类型:
Library.ChannelPool - 修饰符:
private - 源码定位:
L60 - 说明:
TODO
- 类型:
-
streamingChannels- 类型:
Library.ChannelPool - 修饰符:
private - 源码定位:
L61 - 说明:
TODO
- 类型:
-
listener- 类型:
Listener - 修饰符:
private final - 源码定位:
L62 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
com.mojang.blaze3d.audio.Library.ChannelPool- 类型:
interface - 修饰符:
private - 源码定位:
L244 - 说明:
TODO
- 类型:
-
com.mojang.blaze3d.audio.Library.CountingChannelPool- 类型:
class - 修饰符:
private static - 源码定位:
L257 - 说明:
TODO
- 类型:
-
com.mojang.blaze3d.audio.Library.Pool- 类型:
enum - 修饰符:
public static - 源码定位:
L311 - 说明:
TODO
- 类型:
构造器
- 无
方法
下面的方法块按源码顺序生成。
public void init(String preferredDevice, DeviceList currentDevices, boolean useHrtf) @ L64
- 方法名:init
- 源码定位:L64
- 返回类型:void
- 修饰符:public
参数:
- preferredDevice: String
- currentDevices: DeviceList
- useHrtf: boolean
说明:
TODO
private IntBuffer createAttributes(MemoryStack stack, boolean enableHrtf) @ L107
- 方法名:createAttributes
- 源码定位:L107
- 返回类型:IntBuffer
- 修饰符:private
参数:
- stack: MemoryStack
- enableHrtf: boolean
说明:
TODO
private int getChannelCount() @ L120
- 方法名:getChannelCount
- 源码定位:L120
- 返回类型:int
- 修饰符:private
参数:
- 无
说明:
TODO
public String currentDeviceName() @ L151
- 方法名:currentDeviceName
- 源码定位:L151
- 返回类型:String
- 修饰符:public
参数:
- 无
说明:
TODO
private static String queryDeviceName(long deviceId) @ L155
- 方法名:queryDeviceName
- 源码定位:L155
- 返回类型:String
- 修饰符:private static
参数:
- deviceId: long
说明:
TODO
private static long openDeviceOrFallback(String preferredDevice, String systemDefaultDevice) @ L168
- 方法名:openDeviceOrFallback
- 源码定位:L168
- 返回类型:long
- 修饰符:private static
参数:
- preferredDevice: String
- systemDefaultDevice: String
说明:
TODO
private static OptionalLong tryOpenDevice(String name) @ L189
- 方法名:tryOpenDevice
- 源码定位:L189
- 返回类型:OptionalLong
- 修饰符:private static
参数:
- name: String
说明:
TODO
public void cleanup() @ L194
- 方法名:cleanup
- 源码定位:L194
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public Listener getListener() @ L203
- 方法名:getListener
- 源码定位:L203
- 返回类型:Listener
- 修饰符:public
参数:
- 无
说明:
TODO
public Channel acquireChannel(Library.Pool pool) @ L207
- 方法名:acquireChannel
- 源码定位:L207
- 返回类型:Channel
- 修饰符:public
参数:
- pool: Library.Pool
说明:
TODO
public void releaseChannel(Channel channel) @ L211
- 方法名:releaseChannel
- 源码定位:L211
- 返回类型:void
- 修饰符:public
参数:
- channel: Channel
说明:
TODO
public String getChannelDebugString() @ L217
- 方法名:getChannelDebugString
- 源码定位:L217
- 返回类型:String
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isCurrentDeviceDisconnected() @ L228
- 方法名:isCurrentDeviceDisconnected
- 源码定位:L228
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public static DeviceTracker createDeviceTracker() @ L232
- 方法名:createDeviceTracker
- 源码定位:L232
- 返回类型:DeviceTracker
- 修饰符:public static
参数:
- 无
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class Library {
private static final Logger LOGGER = LogUtils.getLogger();
public static final int NO_DEVICE = 0;
private static final String NO_DEVICE_NAME = "(None)";
private static final int DEFAULT_CHANNEL_COUNT = 30;
private long currentDevice;
private String currentDeviceName = "(None)";
private long context;
private boolean supportsDisconnections;
private static final Library.ChannelPool EMPTY = new Library.ChannelPool() {
@Override
public @Nullable Channel acquire() {
return null;
}
@Override
public boolean release(Channel channel) {
return false;
}
@Override
public void cleanup() {
}
@Override
public int getMaxCount() {
return 0;
}
@Override
public int getUsedCount() {
return 0;
}
};
private Library.ChannelPool staticChannels = EMPTY;
private Library.ChannelPool streamingChannels = EMPTY;
private final Listener listener = new Listener();
public void init(@Nullable String preferredDevice, DeviceList currentDevices, boolean useHrtf) {
this.currentDeviceName = "(None)";
this.currentDevice = openDeviceOrFallback(preferredDevice, currentDevices.defaultDevice());
this.currentDeviceName = queryDeviceName(this.currentDevice);
this.supportsDisconnections = false;
ALCCapabilities alcCapabilities = ALC.createCapabilities(this.currentDevice);
if (OpenAlUtil.checkALCError(this.currentDevice, "Get capabilities")) {
throw new IllegalStateException("Failed to get OpenAL capabilities");
} else if (!alcCapabilities.OpenALC11) {
throw new IllegalStateException("OpenAL 1.1 not supported");
} else {
try (MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer attr = this.createAttributes(stack, alcCapabilities.ALC_SOFT_HRTF && useHrtf);
this.context = ALC10.alcCreateContext(this.currentDevice, attr);
}
if (OpenAlUtil.checkALCError(this.currentDevice, "Create context")) {
throw new IllegalStateException("Unable to create OpenAL context");
} else {
ALC10.alcMakeContextCurrent(this.context);
int totalChannelCount = this.getChannelCount();
int streamingChannelCount = Mth.clamp((int)Mth.sqrt(totalChannelCount), 2, 8);
int staticChannelCount = Mth.clamp(totalChannelCount - streamingChannelCount, 8, 255);
this.staticChannels = new Library.CountingChannelPool(staticChannelCount);
this.streamingChannels = new Library.CountingChannelPool(streamingChannelCount);
ALCapabilities alCapabilities = AL.createCapabilities(alcCapabilities);
OpenAlUtil.checkALError("Initialization");
if (!alCapabilities.AL_EXT_source_distance_model) {
throw new IllegalStateException("AL_EXT_source_distance_model is not supported");
} else {
AL10.alEnable(512);
if (!alCapabilities.AL_EXT_LINEAR_DISTANCE) {
throw new IllegalStateException("AL_EXT_LINEAR_DISTANCE is not supported");
} else {
OpenAlUtil.checkALError("Enable per-source distance models");
LOGGER.info("OpenAL initialized on device {}", this.currentDeviceName);
this.supportsDisconnections = ALC10.alcIsExtensionPresent(this.currentDevice, "ALC_EXT_disconnect");
}
}
}
}
}
private IntBuffer createAttributes(MemoryStack stack, boolean enableHrtf) {
int maxAttributes = 5;
IntBuffer attr = stack.callocInt(11);
int numHrtf = ALC10.alcGetInteger(this.currentDevice, 6548);
if (numHrtf > 0) {
attr.put(6546).put(enableHrtf ? 1 : 0);
attr.put(6550).put(0);
}
attr.put(6554).put(1);
return attr.put(0).flip();
}
private int getChannelCount() {
try (MemoryStack stack = MemoryStack.stackPush()) {
int size = ALC10.alcGetInteger(this.currentDevice, 4098);
if (OpenAlUtil.checkALCError(this.currentDevice, "Get attributes size")) {
throw new IllegalStateException("Failed to get OpenAL attributes");
}
IntBuffer attributes = stack.mallocInt(size);
ALC10.alcGetIntegerv(this.currentDevice, 4099, attributes);
if (OpenAlUtil.checkALCError(this.currentDevice, "Get attributes")) {
throw new IllegalStateException("Failed to get OpenAL attributes");
}
int pos = 0;
while (pos < size) {
int attribute = attributes.get(pos++);
if (attribute == 0) {
break;
}
int attributeValue = attributes.get(pos++);
if (attribute == 4112) {
return attributeValue;
}
}
}
return 30;
}
public @Nullable String currentDeviceName() {
return this.currentDeviceName;
}
private static String queryDeviceName(long deviceId) {
String name = ALC10.alcGetString(deviceId, 4115);
if (name == null) {
name = ALC10.alcGetString(deviceId, 4101);
}
if (name == null) {
name = "Unknown (0x" + HexFormat.of().toHexDigits(deviceId) + ")";
}
return name;
}
private static long openDeviceOrFallback(@Nullable String preferredDevice, @Nullable String systemDefaultDevice) {
OptionalLong device = OptionalLong.empty();
if (preferredDevice != null) {
device = tryOpenDevice(preferredDevice);
}
if (device.isEmpty() && systemDefaultDevice != null) {
device = tryOpenDevice(systemDefaultDevice);
}
if (device.isEmpty()) {
device = tryOpenDevice(null);
}
if (device.isEmpty()) {
throw new IllegalStateException("Failed to open OpenAL device");
} else {
return device.getAsLong();
}
}
private static OptionalLong tryOpenDevice(@Nullable String name) {
long device = ALC10.alcOpenDevice(name);
return device != 0L && !OpenAlUtil.checkALCError(device, "Open device") ? OptionalLong.of(device) : OptionalLong.empty();
}
public void cleanup() {
this.staticChannels.cleanup();
this.streamingChannels.cleanup();
ALC10.alcDestroyContext(this.context);
if (this.currentDevice != 0L) {
ALC10.alcCloseDevice(this.currentDevice);
}
}
public Listener getListener() {
return this.listener;
}
public @Nullable Channel acquireChannel(Library.Pool pool) {
return (pool == Library.Pool.STREAMING ? this.streamingChannels : this.staticChannels).acquire();
}
public void releaseChannel(Channel channel) {
if (!this.staticChannels.release(channel) && !this.streamingChannels.release(channel)) {
throw new IllegalStateException("Tried to release unknown channel");
}
}
public String getChannelDebugString() {
return String.format(
Locale.ROOT,
"Sounds: %d/%d + %d/%d",
this.staticChannels.getUsedCount(),
this.staticChannels.getMaxCount(),
this.streamingChannels.getUsedCount(),
this.streamingChannels.getMaxCount()
);
}
public boolean isCurrentDeviceDisconnected() {
return this.supportsDisconnections && ALC11.alcGetInteger(this.currentDevice, 787) == 0;
}
public static DeviceTracker createDeviceTracker() {
DeviceList deviceList = DeviceList.query();
if (CallbackDeviceTracker.isSupported()) {
LOGGER.debug("Using SOFT_system_events callback for tracking audio device changes");
return CallbackDeviceTracker.createAndInstall(deviceList);
} else {
LOGGER.debug("Using polling for tracking audio device changes");
return new PollingDeviceTracker(deviceList);
}
}
@OnlyIn(Dist.CLIENT)
private interface ChannelPool {
@Nullable Channel acquire();
boolean release(Channel channel);
void cleanup();
int getMaxCount();
int getUsedCount();
}
@OnlyIn(Dist.CLIENT)
private static class CountingChannelPool implements Library.ChannelPool {
private final int limit;
private final Set<Channel> activeChannels = Sets.newIdentityHashSet();
public CountingChannelPool(int limit) {
this.limit = limit;
}
@Override
public @Nullable Channel acquire() {
if (this.activeChannels.size() >= this.limit) {
if (SharedConstants.IS_RUNNING_IN_IDE) {
Library.LOGGER.warn("Maximum sound pool size {} reached", this.limit);
}
return null;
} else {
Channel channel = Channel.create();
if (channel != null) {
this.activeChannels.add(channel);
}
return channel;
}
}
@Override
public boolean release(Channel channel) {
if (!this.activeChannels.remove(channel)) {
return false;
} else {
channel.destroy();
return true;
}
}
@Override
public void cleanup() {
this.activeChannels.forEach(Channel::destroy);
this.activeChannels.clear();
}
@Override
public int getMaxCount() {
return this.limit;
}
@Override
public int getUsedCount() {
return this.activeChannels.size();
}
}
@OnlyIn(Dist.CLIENT)
public static enum Pool {
STATIC,
STREAMING;
}
}引用的其他类
-
- 引用位置:
方法调用 - 关联成员:
CallbackDeviceTracker.createAndInstall(), CallbackDeviceTracker.isSupported()
- 引用位置:
-
- 引用位置:
参数/方法调用/返回值 - 关联成员:
Channel.create()
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
DeviceList.query()
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
Listener()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
OpenAlUtil.checkALCError(), OpenAlUtil.checkALError()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
PollingDeviceTracker()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.clamp(), Mth.sqrt()
- 引用位置: