Fixed the native audio playback
This commit is contained in:
parent
fe947ea83b
commit
0a6c68f940
|
@ -10,6 +10,7 @@ import {processArguments} from "../../shared/process-arguments";
|
||||||
|
|
||||||
import "./ExternalModal";
|
import "./ExternalModal";
|
||||||
import {showUpdateWindow} from "../windows/client-updater/controller/ClientUpdate";
|
import {showUpdateWindow} from "../windows/client-updater/controller/ClientUpdate";
|
||||||
|
import {getUiFilePath} from "../ui-loader/Loader";
|
||||||
|
|
||||||
ipcMain.on('basic-action', (event, action, ...args: any[]) => {
|
ipcMain.on('basic-action', (event, action, ...args: any[]) => {
|
||||||
const window = BrowserWindow.fromWebContents(event.sender);
|
const window = BrowserWindow.fromWebContents(event.sender);
|
||||||
|
@ -27,4 +28,6 @@ ipcMain.on('basic-action', (event, action, ...args: any[]) => {
|
||||||
} else if(action === "quit") {
|
} else if(action === "quit") {
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle("tc-get-ui-path", () => getUiFilePath());
|
|
@ -125,8 +125,14 @@ async function unpackLocalUiPack(version: CachedUIPack) : Promise<string> {
|
||||||
return targetDirectory;
|
return targetDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let uiFilePath: string;
|
||||||
|
export function getUiFilePath() : string | undefined {
|
||||||
|
return uiFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
function initializeFileSystemProtocol(directory: string) {
|
function initializeFileSystemProtocol(directory: string) {
|
||||||
directory = path.normalize(directory);
|
directory = path.normalize(directory);
|
||||||
|
uiFilePath = directory;
|
||||||
|
|
||||||
protocol.registerFileProtocol(kUiPackProtocol, (request, callback) => {
|
protocol.registerFileProtocol(kUiPackProtocol, (request, callback) => {
|
||||||
let targetPath;
|
let targetPath;
|
||||||
|
|
|
@ -1,27 +1,52 @@
|
||||||
import {audio as naudio} from "tc-native/connection";
|
import {audio as naudio} from "tc-native/connection";
|
||||||
import {SoundBackend, SoundFile} from "tc-shared/audio/Sounds";
|
import {SoundBackend, SoundFile} from "tc-shared/audio/Sounds";
|
||||||
import * as paths from "path";
|
import * as paths from "path";
|
||||||
|
import * as loader from "tc-loader";
|
||||||
|
import {Stage} from "tc-loader";
|
||||||
|
import {ipcRenderer} from "electron";
|
||||||
|
import {LogCategory, logDebug, logInfo} from "tc-shared/log";
|
||||||
|
|
||||||
|
let uiFilePath;
|
||||||
export class NativeSoundBackend implements SoundBackend {
|
export class NativeSoundBackend implements SoundBackend {
|
||||||
playSound(sound: SoundFile): Promise<void> {
|
playSound(sound: SoundFile): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let pathname = paths.dirname(decodeURIComponent(location.pathname));
|
if(!uiFilePath) {
|
||||||
if(pathname[0] === '/' && pathname[2] === ':') //e.g.: /C:/test...
|
reject("Mussing UI file path");
|
||||||
pathname = pathname.substr(1);
|
return;
|
||||||
const path = paths.join(pathname, sound.path);
|
}
|
||||||
|
|
||||||
console.log("replaying %s (volume: %f)", sound.path, sound.volume);
|
const path = paths.join(uiFilePath, sound.path);
|
||||||
|
console.log("replaying %s (volume: %f) from %s", sound.path, sound.volume, path);
|
||||||
naudio.sounds.playback_sound({
|
naudio.sounds.playback_sound({
|
||||||
callback: (result, message) => {
|
callback: (result, message) => {
|
||||||
if(result == naudio.sounds.PlaybackResult.SUCCEEDED)
|
if(result == naudio.sounds.PlaybackResult.SUCCEEDED) {
|
||||||
resolve();
|
resolve();
|
||||||
else
|
} else {
|
||||||
reject(naudio.sounds.PlaybackResult[result].toLowerCase() + ": " + message);
|
reject(naudio.sounds.PlaybackResult[result].toLowerCase() + ": " + message);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
file: path,
|
file: path,
|
||||||
volume: typeof sound.volume === "number" ? sound.volume : 1
|
volume: typeof sound.volume === "number" ? sound.volume : 1
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
//tc-get-ui-path
|
||||||
|
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
|
||||||
|
name: "sound initialize",
|
||||||
|
priority: 50,
|
||||||
|
function: async () => {
|
||||||
|
uiFilePath = await ipcRenderer.invoke("tc-get-ui-path");
|
||||||
|
if(!uiFilePath) {
|
||||||
|
logInfo(LogCategory.AUDIO, tr("Missing UI path. App sounds will not work."));
|
||||||
|
} else {
|
||||||
|
if(uiFilePath[0] === '/' && uiFilePath[2] === ':') {
|
||||||
|
//e.g.: /C:/test...
|
||||||
|
uiFilePath = uiFilePath.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
logDebug(LogCategory.AUDIO, tr("Received UI path: %s"), uiFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -270,7 +270,7 @@ ssize_t AudioOutputSource::enqueue_samples_no_interleave(const void *source_buff
|
||||||
bool AudioOutputSource::set_max_buffered_samples(size_t samples) {
|
bool AudioOutputSource::set_max_buffered_samples(size_t samples) {
|
||||||
samples = std::max(samples, (size_t) this->fadein_frame_samples_);
|
samples = std::max(samples, (size_t) this->fadein_frame_samples_);
|
||||||
if(samples > this->max_supported_buffering()) {
|
if(samples > this->max_supported_buffering()) {
|
||||||
return false;
|
samples = this->max_supported_buffering();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard buffer_lock{this->buffer_mutex};
|
std::lock_guard buffer_lock{this->buffer_mutex};
|
||||||
|
|
|
@ -87,8 +87,9 @@ namespace tc::audio::sounds {
|
||||||
this->file_handle = std::make_unique<file::WAVReader>(this->settings_.file);
|
this->file_handle = std::make_unique<file::WAVReader>(this->settings_.file);
|
||||||
std::string error{};
|
std::string error{};
|
||||||
if(auto err{this->file_handle->open_file(error)}; err != file::OPEN_RESULT_SUCCESS) {
|
if(auto err{this->file_handle->open_file(error)}; err != file::OPEN_RESULT_SUCCESS) {
|
||||||
if(auto callback{this->settings_.callback}; callback)
|
if(auto callback{this->settings_.callback}; callback) {
|
||||||
callback(PlaybackResult::FILE_OPEN_ERROR, error);
|
callback(PlaybackResult::FILE_OPEN_ERROR, error);
|
||||||
|
}
|
||||||
this->finalize(false);
|
this->finalize(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -175,21 +176,27 @@ namespace tc::audio::sounds {
|
||||||
auto weak_this = this->weak_from_this();
|
auto weak_this = this->weak_from_this();
|
||||||
this->output_source->on_underflow = [weak_this](size_t sample_count){
|
this->output_source->on_underflow = [weak_this](size_t sample_count){
|
||||||
auto self = weak_this.lock();
|
auto self = weak_this.lock();
|
||||||
if(!self) return false;
|
if(!self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(self->state_ == PLAYER_STATE_PLAYING)
|
if(self->state_ == PLAYER_STATE_PLAYING) {
|
||||||
log_warn(category::audio, tr("Having an audio underflow while playing a sound."));
|
log_warn(category::audio, tr("Having an audio underflow while playing a sound."));
|
||||||
else if(self->state_ == PLAYER_STATE_AWAIT_FINISH)
|
} else if(self->state_ == PLAYER_STATE_AWAIT_FINISH) {
|
||||||
self->state_ = PLAYER_STATE_FINISHED;
|
self->state_ = PLAYER_STATE_FINISHED;
|
||||||
|
}
|
||||||
audio::decode_event_loop->schedule(self);
|
audio::decode_event_loop->schedule(self);
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
this->output_source->on_read = [weak_this] {
|
this->output_source->on_read = [weak_this] {
|
||||||
auto self = weak_this.lock();
|
auto self = weak_this.lock();
|
||||||
if(!self) return;
|
if(!self) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(self->could_enqueue_next_buffer() && self->state_ == PLAYER_STATE_PLAYING)
|
if(self->could_enqueue_next_buffer() && self->state_ == PLAYER_STATE_PLAYING) {
|
||||||
audio::decode_event_loop->schedule(self);
|
audio::decode_event_loop->schedule(self);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this->output_source->on_overflow = [weak_this](size_t count) {
|
this->output_source->on_overflow = [weak_this](size_t count) {
|
||||||
|
@ -205,7 +212,9 @@ namespace tc::audio::sounds {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline bool could_enqueue_next_buffer() const {
|
[[nodiscard]] inline bool could_enqueue_next_buffer() const {
|
||||||
if(!this->output_source) return false;
|
if(!this->output_source) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const auto current_size = this->output_source->currently_buffered_samples();
|
const auto current_size = this->output_source->currently_buffered_samples();
|
||||||
const auto max_size = this->output_source->max_buffered_samples();
|
const auto max_size = this->output_source->max_buffered_samples();
|
||||||
|
@ -233,8 +242,9 @@ namespace tc::audio::sounds {
|
||||||
auto player = std::make_shared<FilePlayer>(settings);
|
auto player = std::make_shared<FilePlayer>(settings);
|
||||||
file_players.push_back(player);
|
file_players.push_back(player);
|
||||||
if(!player->play()) {
|
if(!player->play()) {
|
||||||
if(auto callback{settings.callback}; callback)
|
if(auto callback{settings.callback}; callback) {
|
||||||
callback(PlaybackResult::PLAYBACK_ERROR, "failed to start playback.");
|
callback(PlaybackResult::PLAYBACK_ERROR, "failed to start playback.");
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
fplock.unlock();
|
fplock.unlock();
|
||||||
|
@ -244,7 +254,9 @@ namespace tc::audio::sounds {
|
||||||
void cancel_playback(const sound_playback_id& id) {
|
void cancel_playback(const sound_playback_id& id) {
|
||||||
std::unique_lock fplock{file_player_mutex};
|
std::unique_lock fplock{file_player_mutex};
|
||||||
auto player_it = std::find_if(file_players.begin(), file_players.end(), [&](const auto& player) { return (sound_playback_id) &*player == id; });
|
auto player_it = std::find_if(file_players.begin(), file_players.end(), [&](const auto& player) { return (sound_playback_id) &*player == id; });
|
||||||
if(player_it == file_players.end()) return;
|
if(player_it == file_players.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto player = *player_it;
|
auto player = *player_it;
|
||||||
file_players.erase(player_it);
|
file_players.erase(player_it);
|
||||||
|
|
Loading…
Reference in New Issue