2020-04-01 21:56:23 +02:00
|
|
|
import * as native from "tc-native/connection";
|
2021-03-20 16:18:05 +01:00
|
|
|
import {AudioBackend, OutputDevice} from "tc-shared/audio/Player";
|
2019-10-26 01:51:40 +02:00
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
//FIXME: Native audio initialize handle!
|
|
|
|
export interface Device {
|
|
|
|
device_id: string;
|
|
|
|
name: string;
|
|
|
|
}
|
2020-02-08 16:50:48 +01:00
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
let _initialized_callbacks: (() => any)[] = [];
|
|
|
|
export let _initialized = false;
|
|
|
|
export let _initializing = false;
|
|
|
|
export let _current_device: native.audio.AudioDevice;
|
2020-02-08 16:50:48 +01:00
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
export function initialized() : boolean {
|
|
|
|
return _initialized;
|
|
|
|
}
|
|
|
|
export function on_ready(cb: () => any) {
|
|
|
|
if(_initialized)
|
|
|
|
cb();
|
|
|
|
else
|
|
|
|
_initialized_callbacks.push(cb);
|
|
|
|
}
|
2020-02-08 16:50:48 +01:00
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
export function initialize() {
|
|
|
|
if(_initializing) return;
|
|
|
|
_initializing = true;
|
|
|
|
|
|
|
|
native.audio.initialize(() => {
|
|
|
|
_initialized = true;
|
|
|
|
for(const callback of _initialized_callbacks)
|
|
|
|
callback();
|
|
|
|
_initialized_callbacks = [];
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
2020-02-08 16:50:48 +01:00
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
export async function available_devices() : Promise<Device[]> {
|
|
|
|
return native.audio.available_devices().filter(e => e.output_supported || e.output_default);
|
|
|
|
}
|
2019-10-26 01:51:40 +02:00
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
export async function set_device(device_id?: string) : Promise<void> {
|
|
|
|
const dev = native.audio.available_devices().filter(e => e.device_id == device_id);
|
|
|
|
if(dev.length == 0) {
|
|
|
|
console.warn("Missing audio device with is %s", device_id);
|
|
|
|
throw "invalid device id";
|
2019-10-26 01:51:40 +02:00
|
|
|
}
|
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
try {
|
|
|
|
native.audio.playback.set_device(dev[0].device_id);
|
|
|
|
} catch(error) {
|
|
|
|
if(error instanceof Error)
|
|
|
|
throw error.message;
|
|
|
|
throw error;
|
2019-10-26 01:51:40 +02:00
|
|
|
}
|
2020-04-01 21:56:23 +02:00
|
|
|
_current_device = dev[0];
|
|
|
|
}
|
2019-10-26 01:51:40 +02:00
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
export function current_device() : Device {
|
|
|
|
if(_current_device)
|
|
|
|
return _current_device;
|
2019-10-26 01:51:40 +02:00
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
const dev = native.audio.available_devices().filter(e => e.output_default);
|
|
|
|
if(dev.length > 0)
|
|
|
|
return dev[0];
|
|
|
|
return {device_id: "default", name: "default"} as Device;
|
2019-10-26 01:51:40 +02:00
|
|
|
}
|
|
|
|
|
2020-04-01 21:56:23 +02:00
|
|
|
export function get_master_volume() : number {
|
|
|
|
return native.audio.playback.get_master_volume();
|
|
|
|
}
|
|
|
|
export function set_master_volume(volume: number) {
|
|
|
|
native.audio.playback.set_master_volume(volume);
|
2021-03-20 16:18:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export class NativeAudioPlayer implements AudioBackend {
|
|
|
|
private readonly audioContext: AudioContext;
|
|
|
|
private initializedPromises: (() => void)[];
|
|
|
|
|
|
|
|
private currentDevice: native.audio.AudioDevice;
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
this.audioContext = new AudioContext();
|
|
|
|
this.initializedPromises = [];
|
|
|
|
|
|
|
|
native.audio.initialize(() => {
|
|
|
|
const promises = this.initializedPromises;
|
|
|
|
this.initializedPromises = undefined;
|
|
|
|
|
|
|
|
promises.forEach(callback => callback());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
executeWhenInitialized(callback: () => void): any {
|
|
|
|
if(this.initializedPromises) {
|
|
|
|
this.initializedPromises.push(callback);
|
|
|
|
} else {
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getMasterVolume(): number {
|
|
|
|
return native.audio.playback.get_master_volume();
|
|
|
|
}
|
|
|
|
|
|
|
|
setMasterVolume(volume: number): any {
|
|
|
|
native.audio.playback.set_master_volume(volume);
|
|
|
|
}
|
|
|
|
|
|
|
|
getAudioContext(): AudioContext | undefined {
|
|
|
|
return this.audioContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
async getAvailableDevices(): Promise<OutputDevice[]> {
|
|
|
|
return native.audio.available_devices().filter(e => e.output_supported || e.output_default).map(entry => ({
|
|
|
|
device_id: entry.device_id,
|
|
|
|
driver: entry.driver,
|
|
|
|
name: entry.name
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
getCurrentDevice(): OutputDevice {
|
|
|
|
if(this.currentDevice) {
|
|
|
|
return this.currentDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
const defaultDevice = native.audio.available_devices().find(entry => entry.output_default);
|
|
|
|
if(defaultDevice) {
|
|
|
|
return {
|
|
|
|
name: defaultDevice.name,
|
|
|
|
driver: defaultDevice.driver,
|
|
|
|
device_id: defaultDevice.device_id
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
name: "Default device",
|
|
|
|
device_id: "default",
|
|
|
|
driver: "default driver"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
async setCurrentDevice(targetId: string | undefined): Promise<void> {
|
|
|
|
const device = native.audio.available_devices().find(e => e.device_id == targetId);
|
|
|
|
if(!device) {
|
|
|
|
console.warn("Missing audio device with is %s", targetId);
|
|
|
|
throw "invalid device id";
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
native.audio.playback.set_device(device.device_id);
|
|
|
|
} catch(error) {
|
|
|
|
if(error instanceof Error) {
|
|
|
|
throw error.message;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.currentDevice = device;
|
|
|
|
}
|
|
|
|
|
|
|
|
getDefaultDeviceId(): string {
|
|
|
|
return native.audio.available_devices().find(entry => entry.output_default).device_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
isDeviceRefreshAvailable(): boolean {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
isInitialized(): boolean {
|
|
|
|
return !this.initializedPromises;
|
|
|
|
}
|
|
|
|
|
|
|
|
refreshDevices(): Promise<void> {
|
|
|
|
return Promise.resolve(undefined);
|
|
|
|
}
|
2020-04-01 21:56:23 +02:00
|
|
|
}
|