I have an Electron app (with Angular).
I am new to Electron and all this inter-process event handling.
My problem is that I have this ipcMain handler(main process) (that I 'Invoke' from an Angular service) :
ipcMain.handle('video-audio-merge', (event, filename) => {
return new Promise((resolve) => {
new FFmpeg(filename+'.mp4').addInput(filename+'.mp3')
.on('progress', progress => resolve(progress.percent)) // The problem is in this line
.save('merged_'+filename+'.mp4')
.on('end', () => resolve(100));
});
})
What I am trying to achieve is to follow the progress of a merge of a video and an audio (which may take several seconds to several minutes). But the problem here is that once the Promise is resolved, it does not send the next progress values (I end up receiving 3% and then never receive any other value even if 'merge' is still in progress).
Then I tried the following (main process) (which I am not able to compile):
const Observable = require('rxjs');
...
ipcMain.handle('video-audio-merge', (event, filename) => {
return new Promise((resolve) => {
resolve( // Will resolve to an Observable that will be able to provide progress values
new Observable<number>(subscriber => {
new FFmpeg(filename+'.mp4').addInput(filename+'.mp3')
.on('progress', progress => subscriber.next(progress.percent)) // Streaming progress values
.save('merged_'+filename+'.mp4')
.on('end', () => subscriber.completed());
}) // End Observable
); // End Resolve
}); // End Promise
}) // End ipcMain.handle
I added comments to explain what I am trying to achieve. And in my Angular service I am invoking this handler as follows :
const electron = (<any>window).require('electron');
import { Observable } from 'rxjs';
...
electron.ipcRenderer.invoke('video-audio-merge', filename).then((subscriber: Observable<number>) => { // This should resolve to my Observable
subscriber.subscribe((progress: number) => { // I subscribe to the Observable to get progress values
console.log(progress); // here I should be using my progress value
});
});
On compilation I get the following error :
A JavaScript error occurred in the main process
Uncaught Exception:
Error: Cannot find module 'rxjs-compat'
I am convinced that there is some other 'elegant' way to achieve this behavior between Main and Renderer processes, if you can lead me to any I would be thankful.
Otherwise, can you please help me out to solve this error ? or share with me what can I read to learn how to use 'Observables' in Electron.
This is the best way I could find.
Let's start with my ipcMain (see code's comments):
ipcMain.on('video-audio-merge', (event, filename) => {
new FFmpeg(filename+'.mp4').addInput(filename+'.mp3')
.on('progress', (progress) => {
event.reply(filename, { progress: progress.percent }); /* 'event.reply' as its name indicates sends a response through channel <filename>,
which I use on the renderer process side to listen to progress value */
})
.save('./merged_'+filename+'.mp4');
}) // end ipcMain.on
This is how I construct my Observable in Angular (see code's comments):
VideoAudioMerge(filename: string) {
return new Observable<any>(observer => {
electron.ipcRenderer.on(filename, (event: any, data: any) => { /* Creates an ipcRenderer listener on channel named <filename>,
so when multiple files are progressing at the same time each will send it's
progress value on a different channel */
observer.next(data.progress);
if(data.progress >= 100) observer.complete();
});
electron.ipcRenderer.send('video-audio-merge', filename);
});
} // end VideoAudioMerge
And finally this is how I use the Observable (see code's comments):
this.VideoAudioMerge(filename).subscribe( progress => {
this.progress = progress
},
(error) => {/*Error handling */},
() => {
electron.ipcRenderer.removeAllListeners(filename); // At the end of video merge remove each <filename> listener.
})
Please feel free if you have any comments :)