[gnome-sound-recorder/bilelmoussaoui/refresh] Add a player
- From: Bilal Elmoussaoui <bilelmoussaoui src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-sound-recorder/bilelmoussaoui/refresh] Add a player
- Date: Mon, 17 Jun 2019 12:58:09 +0000 (UTC)
commit 001e15b6cbd2bcaeb671bb77554e65771bf48d30
Author: Bilal Elmoussaoui <bil elmoussaoui gmail com>
Date: Sun Jun 16 21:47:55 2019 +0200
Add a player
data/org.gnome.SoundRecorder.data.gresource.xml | 1 +
data/ui/main_window.ui | 213 +++++++++++++++++-------
data/ui/player.ui | 200 ++++++++++++++++++++++
data/ui/recording_row.ui | 57 +++++--
src/application.js | 9 -
src/main.js | 3 +
src/mainWindow.js | 100 +++++++----
src/player.js | 201 +++++++++++++---------
src/recorder.js | 22 +--
src/recording.js | 94 ++++-------
src/utils.js | 4 +-
src/waveform.js | 74 ++++----
12 files changed, 668 insertions(+), 310 deletions(-)
---
diff --git a/data/org.gnome.SoundRecorder.data.gresource.xml b/data/org.gnome.SoundRecorder.data.gresource.xml
index be02925..bb16711 100644
--- a/data/org.gnome.SoundRecorder.data.gresource.xml
+++ b/data/org.gnome.SoundRecorder.data.gresource.xml
@@ -2,6 +2,7 @@
<gresources>
<gresource prefix="/org/gnome/SoundRecorder">
<file>application.css</file>
+ <file compressed="true" preprocess="xml-stripblanks" alias="player.ui">ui/player.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="main_window.ui">ui/main_window.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="recording_row.ui">ui/recording_row.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="recording_waveform_row.ui">ui/recording_waveform_row.ui</file>
diff --git a/data/ui/main_window.ui b/data/ui/main_window.ui
index 6c9c651..98abb5f 100644
--- a/data/ui/main_window.ui
+++ b/data/ui/main_window.ui
@@ -4,8 +4,8 @@
<requires lib="gtk+" version="3.20"/>
<requires lib="libhandy" version="0.0"/>
<template class="Gjs_MainWindow" parent="GtkApplicationWindow">
- <property name="width_request">480</property>
- <property name="height_request">640</property>
+ <property name="width_request">360</property>
+ <property name="height_request">600</property>
<property name="can_focus">False</property>
<property name="default_width">480</property>
<property name="default_height">780</property>
@@ -17,44 +17,98 @@
<property name="title" translatable="yes">SoundRecorder</property>
<property name="show_close_button">True</property>
<child>
- <object class="GtkButton" id="record_button">
+ <object class="GtkStack" id="record_stack">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkBox">
+ <object class="GtkButton" id="record_button">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
<child>
- <object class="GtkImage">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="icon_name">media-record-symbolic</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-record-symbolic</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Record</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
</child>
+ <style>
+ <class name="suggested-action"/>
+ <class name="record-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">record</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="stop_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
<child>
- <object class="GtkLabel" id="record_label">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Record</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-playback-stop-symbolic</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Stop</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
</child>
+ <style>
+ <class name="destructive-action"/>
+ <class name="record-button"/>
+ </style>
</object>
+ <packing>
+ <property name="name">stop</property>
+ <property name="position">1</property>
+ </packing>
</child>
- <style>
- <class name="suggested-action"/>
- <class name="record-button"/>
- </style>
</object>
</child>
<child>
@@ -144,66 +198,101 @@
</packing>
</child>
<child>
- <object class="GtkScrolledWindow">
+ <object class="GtkBox">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="shadow_type">in</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkViewport">
+ <object class="GtkScrolledWindow">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="can_focus">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
<child>
- <object class="HdyColumn">
+ <object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="maximum_width">760</property>
- <property name="linear_growth_width">760</property>
+ <property name="vexpand">True</property>
<child>
- <object class="GtkBox">
+ <object class="HdyColumn">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="valign">start</property>
<property name="vexpand">True</property>
- <property name="border_width">18</property>
- <property name="orientation">vertical</property>
+ <property name="maximum_width">760</property>
+ <property name="linear_growth_width">760</property>
<child>
- <object class="GtkRevealer" id="new_recording_revealer">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
- <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">18</property>
+ <property name="orientation">vertical</property>
<child>
- <placeholder/>
+ <object class="GtkRevealer" id="new_recording_revealer">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkListBox" id="records_listbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="vexpand">True</property>
+ <property name="selection_mode">none</property>
+ <style>
+ <class name="frame"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkListBox" id="records_listbox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">start</property>
- <property name="vexpand">True</property>
- <property name="selection_mode">none</property>
- <style>
- <class name="frame"/>
- </style>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
</child>
</object>
</child>
</object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRevealer" id="player_revealer">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ <property name="transition_type">slide-up</property>
+ <property name="reveal_child">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
<packing>
diff --git a/data/ui/player.ui b/data/ui/player.ui
new file mode 100644
index 0000000..89ea964
--- /dev/null
+++ b/data/ui/player.ui
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <requires lib="libhandy" version="0.0"/>
+ <template class="Gjs_PlayerWidget" parent="GtkBox">
+ <property name="height_request">60</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="clip_name_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="clip_duration_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">12</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="HdyColumn">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="maximum_width">760</property>
+ <property name="linear_growth_width">760</property>
+ <child>
+ <object class="GtkScale" id="player_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">player_adjustement</property>
+ <property name="fill_level">0</property>
+ <property name="draw_value">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">False</property>
+ <child>
+ <object class="GtkButton" id="backward_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-seek-backward-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="pause_stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="pause_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-playback-pause-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">pause</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="play_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-playback-start-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">play</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="forward_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-seek-forward-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <style>
+ <class name="linked"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">12</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </template>
+ <object class="GtkAdjustment" id="player_adjustement">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+</interface>
diff --git a/data/ui/recording_row.ui b/data/ui/recording_row.ui
index 91dcf2f..0167893 100644
--- a/data/ui/recording_row.ui
+++ b/data/ui/recording_row.ui
@@ -36,7 +36,7 @@
</packing>
</child>
<child>
- <object class="GtkButton" id="pause_button">
+ <object class="GtkButton" id="stop_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -48,12 +48,12 @@
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
- <property name="icon_name">media-playback-pause-symbolic</property>
+ <property name="icon_name">media-playback-stop-symbolic</property>
</object>
</child>
</object>
<packing>
- <property name="name">pause</property>
+ <property name="name">stop</property>
<property name="position">1</property>
</packing>
</child>
@@ -119,18 +119,50 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkLabel" id="time_label">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
- <property name="valign">start</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <style>
- <class name="dim-label"/>
- </style>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="time_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <property name="margin_top">6</property>
+ <property name="margin_bottom">6</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="duration_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="index">-1</property>
@@ -140,6 +172,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
+ <property name="padding">6</property>
<property name="position">2</property>
</packing>
</child>
diff --git a/src/application.js b/src/application.js
index 6062c6c..912562e 100644
--- a/src/application.js
+++ b/src/application.js
@@ -90,15 +90,6 @@ var Application = GObject.registerClass(class Application extends Gtk.Applicatio
this.window.get_style_context().add_class("devel");
}
- onWindowDestroy() {
- if (MainWindow.wave.pipeline)
- MainWindow.wave.pipeline.set_state(Gst.State.NULL);
- if (MainWindow._record.pipeline)
- MainWindow._record.pipeline.set_state(Gst.State.NULL);
-
- if (MainWindow.play.play)
- MainWindow.play.play.set_state(Gst.State.NULL);
- }
_showPreferences() {
let preferencesDialog = new Preferences.Preferences();
diff --git a/src/main.js b/src/main.js
index 854a38d..cc88bbd 100644
--- a/src/main.js
+++ b/src/main.js
@@ -38,7 +38,10 @@ pkg.require({ 'Gdk': '3.0',
'Handy': '0.0' });
const Handy = imports.gi.Handy;
+const GstPbutils = imports.gi.GstPbutils;
+
Handy.init(null);
+GstPbutils.pb_utils_init()
const Application = imports.application;
diff --git a/src/mainWindow.js b/src/mainWindow.js
index abc7409..3458efd 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -40,7 +40,8 @@ const NewRecording = imports.recording.NewRecording;
const RecordingRow = imports.recording.RecordingRow;
const Preferences = imports.preferences;
-
+const Player = imports.player.Player;
+const PlayerWidget = imports.player.PlayerWidget;
const Waveform = imports.waveform;
let activeProfile = null;
@@ -111,9 +112,11 @@ var MainWindow = GObject.registerClass({
'menu_button',
'main_stack',
'record_button',
- 'record_label',
+ 'stop_button',
+ 'record_stack',
'records_listbox',
'new_recording_revealer',
+ 'player_revealer',
]
},
class MainWindow extends Gtk.ApplicationWindow {
@@ -121,14 +124,16 @@ var MainWindow = GObject.registerClass({
super._init();
this._addAppMenu();
this._recordingsManager = new RecordingsManager();
+ this._player = new Player();
this._initWidgets();
-
+ this.connect("destroy", () => this._onWindowDestroy)
this.show_all();
}
_initWidgets() {
this._record_button.connect('clicked', () => this._onRecordClicked())
+ this._stop_button.connect('clicked', () => this._onStopRecordingClicked())
this._recordingsManager.connect('recording-added', (obj, recording) => {
this._onRecordingAdded(recording);
});
@@ -143,6 +148,26 @@ var MainWindow = GObject.registerClass({
this._newRecordingWidget.updateRecordTime(recordTime);
});
this._new_recording_revealer.add(this._newRecordingWidget);
+
+
+ this._playerWidget = new PlayerWidget();
+ this._playerWidget.connect("pause", () => {
+ if(this._player.isPlaying()){
+ this._player.pausePlaying();
+ }
+ });
+ this._playerWidget.connect("play", () => {
+ this._player.resumePlaying();
+ });
+ this._player_revealer.add(this._playerWidget);
+ this._player_revealer.set_reveal_child(false);
+
+ this._player.connect("time-updated", (obj, time) => {
+ this._playerWidget.updateTime(time);
+ });
+ this._player.connect("stream-ended", () => {
+ this._playerWidget.reset();
+ })
}
@@ -156,43 +181,49 @@ var MainWindow = GObject.registerClass({
}
_onRecordClicked() {
- if(this.recording_state === RecordingState.STOPPED) {
- this._main_stack.set_visible_child_name('records_view');
- this._main_stack.show_all();
- this._record_button.get_style_context().remove_class('suggeted-action');
- this._record_button.get_style_context().add_class('destructive-action');
-
- this._record_label.set_text('Stop');
+ this._main_stack.set_visible_child_name('records_view');
+ this._record_stack.set_visible_child_name('stop')
+ this._main_stack.show_all();
- let wave = this._recordingsManager.startNewRecording();
- this._newRecordingWidget.setWave(wave);
- this._newRecordingWidget.show_all();
+ let wave = this._recordingsManager.startNewRecording();
+ this._newRecordingWidget.setWave(wave);
+ this._newRecordingWidget.show_all();
- this._new_recording_revealer.set_reveal_child(true);
+ this._new_recording_revealer.set_reveal_child(true);
- this.set_property('recording-state', RecordingState.RECORDING);
- } else {
+ this.set_property('recording-state', RecordingState.RECORDING);
+ this._records_listbox.set_sensitive(false);
+ this._playerWidget.set_sensitive(false);
+ }
- this._recordingsManager.saveRecording();
- this._newRecordingWidget.reset();
+ _onStopRecordingClicked() {
+ this._recordingsManager.saveRecording();
+ this._newRecordingWidget.reset();
- this._record_button.get_style_context().add_class('suggested-action');
- this._record_button.get_style_context().remove_class('destructive-action');
- this._record_label.set_text('Record');
- this.set_property('recording-state', RecordingState.STOPPED);
+ this._new_recording_revealer.set_reveal_child(false);
+ this._record_stack.set_visible_child_name('record')
- this._new_recording_revealer.set_reveal_child(false);
- }
+ this.set_property('recording-state', RecordingState.STOPPED);
+ this._records_listbox.set_sensitive(true);
+ this._playerWidget.set_sensitive(true);
}
_onRecordingAdded(recording) {
this._main_stack.set_visible_child_name('records_view');
let recordingRow = new RecordingRow(recording);
+ recordingRow.connect("play", (obj, recording) => {
+ this._playerWidget.setPlaying(recording);
+ this._player.play(recording);
+ this._player_revealer.set_reveal_child(true);
+ });
+ recordingRow.connect("stop", () => {
+ this._player.stopPlaying();
+ this._player_revealer.set_reveal_child(false);
+ });
this._records_listbox.add(recordingRow);
this._records_listbox.show_all();
}
-
_updateHeaderFunc(row, before) {
if (before) {
let separator = new Gtk.Separator();
@@ -203,15 +234,22 @@ var MainWindow = GObject.registerClass({
separator.show()
}
}
+
_sortRecordings(row1, row2) {
- if (row2.recording) {
- if(row1.recording.fileName < row2.recording.fileName) {
- return -1;
- } else {
- return 1;
- }
+ if (row1.recording && row1.recording.dateCreated) {
+ if (row2.recording.dateCreated.difference(row1.recording.dateCreated) > 0)
+ return 1
+ else
+ return -1
}
}
+
+ _onWindowDestory() {
+ this._player.stopPlaying();
+ this._recordingsManager._recorder.stopRecording()
+
+
+ }
});
const MainView = GObject.registerClass(class MainView extends Gtk.Stack {
diff --git a/src/player.js b/src/player.js
index c6606d2..8907926 100644
--- a/src/player.js
+++ b/src/player.js
@@ -31,7 +31,8 @@ const Mainloop = imports.mainloop;
const Application = imports.application;
const MainWindow = imports.mainWindow;
-const Waveform = imports.waveform;
+
+const utils = imports.utils;
const PipelineStates = {
PLAYING: 0,
@@ -51,9 +52,12 @@ const _TENTH_SEC = 100000000;
var Player = GObject.registerClass({
Signals: {
- 'timer-updated': {
+ 'time-updated': {
flags: GObject.SignalFlags.RUN_FIRST,
param_types: [ GObject.TYPE_INT ]
+ },
+ 'stream-ended': {
+ flags: GObject.SignalFlags.RUN_FIRST
}
}
@@ -62,11 +66,11 @@ var Player = GObject.registerClass({
_init() {
super._init();
this.playState = PipelineStates.STOPPED;
- this.play = Gst.ElementFactory.make("playbin", "play");
+ this.playbin = Gst.ElementFactory.make("playbin", "play");
this.sink = Gst.ElementFactory.make("pulsesink", "sink");
- this.play.set_property("audio-sink", this.sink);
- this.clock = this.play.get_clock();
- this.playBus = this.play.get_bus();
+ this.playbin.set_property("audio-sink", this.sink);
+ this.clock = this.playbin.get_clock();
+ this.playBus = this.playbin.get_bus();
this._asset = null;
}
_playPipeline() {
@@ -80,12 +84,17 @@ var Player = GObject.registerClass({
}
get duration() {
- return this.play.query_duration(Gst.Format.TIME)
+ return this.playbin.query_duration(Gst.Format.TIME)
+
+ }
+ play(recording) {
+ this.playbin.set_property("uri", recording.uri);
+ this.startPlaying();
}
- setUri(uri) {
- this.play.set_property("uri", uri);
+ isPlaying() {
+ return this.playState == PipelineStates.PLAYING
}
@@ -98,11 +107,11 @@ var Player = GObject.registerClass({
if (this.playState == PipelineStates.PAUSED) {
this.updatePosition();
- this.play.set_base_time(this.clock.get_time());
- this.baseTime = this.play.get_base_time() - this.runTime;
+ this.playbin.set_base_time(this.clock.get_time());
+ this.baseTime = this.playbin.get_base_time() - this.runTime;
}
- this.ret = this.play.set_state(Gst.State.PLAYING);
+ this.ret = this.playbin.set_state(Gst.State.PLAYING);
this.playState = PipelineStates.PLAYING;
if (this.ret == Gst.StateChangeReturn.FAILURE) {
@@ -111,12 +120,10 @@ var Player = GObject.registerClass({
} else if (this.ret == Gst.StateChangeReturn.SUCCESS) {
/*MainWindow.view.setVolume();*/
}
- GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGINT,
Application.application.onWindowDestroy);
- GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGTERM,
Application.application.onWindowDestroy);
}
pausePlaying() {
- this.play.set_state(Gst.State.PAUSED);
+ this.playbin.set_state(Gst.State.PAUSED);
this.playState = PipelineStates.PAUSED;
if (this.timeout) {
@@ -125,6 +132,12 @@ var Player = GObject.registerClass({
}
}
+ resumePlaying () {
+ this.playbin.set_state(Gst.State.PLAYING);
+ this.playState = PipelineStates.PLAYING;
+ }
+
+
stopPlaying() {
if (this.playState != PipelineStates.STOPPED) {
this.onEnd();
@@ -132,7 +145,7 @@ var Player = GObject.registerClass({
}
onEnd() {
- this.play.set_state(Gst.State.NULL);
+ this.playbin.set_state(Gst.State.NULL);
this.playState = PipelineStates.STOPPED;
this.playBus.remove_signal_watch();
this._updateTime();
@@ -141,56 +154,46 @@ var Player = GObject.registerClass({
GLib.source_remove(this.timeout);
this.timeout = null;
}
- /*
- if (MainWindow.wave != null)
- MainWindow.wave.endDrawing();
- */
- errorDialogState = ErrState.OFF;
+ this.emit("stream-ended")
}
- onEndOfStream() {
- /*
- MainWindow.view.onPlayStopClicked();
- */
- }
_onMessageReceived(message) {
this.localMsg = message;
- let msg = message.type;
- switch(msg) {
+ switch(message.type) {
- case Gst.MessageType.EOS:
- this.onEndOfStream();
+ case Gst.MessageType.EOS:
+ this.emit("stream-ended")
break;
- case Gst.MessageType.WARNING:
- let warningMessage = message.parse_warning()[0];
- log(warningMessage.toString());
+ case Gst.MessageType.WARNING:
+ let warningMessage = message.parse_warning()[0];
+ log(warningMessage.toString());
break;
- case Gst.MessageType.ERROR:
- let errorMessage = message.parse_error()[0];
- this._showErrorDialog(errorMessage.toString());
- errorDialogState = ErrState.ON;
+ case Gst.MessageType.ERROR:
+ let errorMessage = message.parse_error()[0];
+ this._showErrorDialog(errorMessage.toString());
+ errorDialogState = ErrState.ON;
break;
- case Gst.MessageType.ASYNC_DONE:
- if (this.sought) {
- this.play.set_state(this._lastState);
- MainWindow.view.setProgressScaleSensitive();
- }
- this.updatePosition();
+ case Gst.MessageType.ASYNC_DONE:
+ if (this.sought) {
+ this.playbin.set_state(this._lastState);
+ MainWindow.view.setProgressScaleSensitive();
+ }
+ this.updatePosition();
break;
- case Gst.MessageType.CLOCK_LOST:
- this.pausePlaying();
+ case Gst.MessageType.CLOCK_LOST:
+ this.pausePlaying();
break;
- case Gst.MessageType.NEW_CLOCK:
- if (this.playState == PipelineStates.PAUSED) {
- this.clock = this.play.get_clock();
- this.startPlaying();
- }
+ case Gst.MessageType.NEW_CLOCK:
+ if (this.playState == PipelineStates.PAUSED) {
+ this.clock = this.playbin.get_clock();
+ this.startPlaying();
+ }
break;
}
}
@@ -200,44 +203,26 @@ var Player = GObject.registerClass({
}
_updateTime() {
- let time = this.play.query_position(Gst.Format.TIME)[1]/Gst.SECOND;
- this.trackDuration = this.play.query_duration(Gst.Format.TIME)[1];
- this.trackDurationSecs = this.trackDuration/Gst.SECOND;
-
- if (time >= 0 && this.playState != PipelineStates.STOPPED) {
- this.emit("timer-updated", time);
- } else if (time >= 0 && this.playState == PipelineStates.STOPPED) {
- this.emit("timer-updated", 0);
- }
+ let time = this.playbin.query_position(Gst.Format.TIME)[1];
+ let trackDuration = this.playbin.query_duration(Gst.Format.TIME)[1];
- let absoluteTime = 0;
-
- if (this.clock == null) {
- this.clock = this.play.get_clock();
- }
- try {
- absoluteTime = this.clock.get_time();
- } catch(error) {
- // no-op
- }
+ this.emit("time-updated", time);
- if (this.baseTime == 0)
- this.baseTime = absoluteTime;
+ if(this.wave)
+ this.wave._drawEvent(time);
- this.runTime = absoluteTime- this.baseTime;
- let approxTime = Math.round(this.runTime/_TENTH_SEC);
- if (MainWindow.wave != null) {
- MainWindow.wave._drawEvent(approxTime);
- }
return true;
}
+
+
+
queryPosition() {
let position = 0;
while (position == 0) {
- position = this.play.query_position(Gst.Format.TIME)[1]/Gst.SECOND;
+ position = this.playbin.query_position(Gst.Format.TIME)[1]/Gst.SECOND;
}
return position;
@@ -251,7 +236,7 @@ var Player = GObject.registerClass({
}
setVolume(value) {
- this.play.set_volume(GstAudio.StreamVolumeFormat.CUBIC, value);
+ this.playbin.set_volume(GstAudio.StreamVolumeFormat.CUBIC, value);
}
passSelected(selected) {
@@ -281,3 +266,63 @@ var Player = GObject.registerClass({
}
}
);
+
+
+var PlayerWidget = GObject.registerClass({
+ Template: 'resource:///org/gnome/SoundRecorder/player.ui',
+ Signals: {
+ 'pause': {
+ flags: GObject.SignalFlags.RUN_FIRST
+ },
+ 'play': {
+ flags: GObject.SignalFlags.RUN_FIRST
+ }
+ },
+ InternalChildren: [
+ 'clip_name_label',
+ 'clip_duration_label',
+ 'player_scale',
+ 'player_adjustement',
+ 'pause_button',
+ 'play_button',
+ 'pause_stack'
+ ],
+ },
+ class PlayerWidget extends Gtk.Box {
+ _init() {
+ super._init();
+
+
+ this._pause_button.connect('clicked', () => {
+ this._pause_stack.set_visible_child_name('play');
+ this.emit('pause');
+ });
+
+ this._play_button.connect('clicked', () => {
+ this._pause_stack.set_visible_child_name('pause');
+ this.emit('play');
+ });
+
+ this.show_all();
+ }
+
+ setPlaying(recording) {
+ this._player_adjustement.set_upper(recording.duration);
+ this._player_adjustement.set_value(0);
+ this._clip_name_label.set_text(recording.fileName);
+ this._pause_stack.set_visible_child_name('pause');
+ }
+
+ updateTime(time) {
+ log(time);
+ this._clip_duration_label.set_text(utils.getDisplayDuration(time));
+ this._player_adjustement.set_value(time);
+ }
+
+ reset() {
+ this._player_adjustement.set_value(this._player_adjustement.upper);
+ this._pause_stack.set_visible_child_name('play');
+ }
+
+ }
+);
diff --git a/src/recorder.js b/src/recorder.js
index 5ab1586..46ee73d 100644
--- a/src/recorder.js
+++ b/src/recorder.js
@@ -124,17 +124,15 @@ var Recorder = GObject.registerClass({
this.ebin = Gst.ElementFactory.make("encodebin", "ebin");
this.ebin.connect("element-added", (ebin, element) => {
let factory = element.get_factory();
-
if (factory != null) {
- this.hasTagSetter = factory.has_interface("GstTagSetter");
- if (this.hasTagSetter == true) {
- this.taglist = Gst.TagList.new_empty();
- this.taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_APPLICATION_NAME, _("Sound
Recorder"));
- element.merge_tags(this.taglist, Gst.TagMergeMode.REPLACE);
- this.taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_TITLE, clipFile.get_uri());
- element.merge_tags(this.taglist, Gst.TagMergeMode.REPLACE);
- this.taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_DATE_TIME, gstreamerDateTime);
- element.merge_tags(this.taglist, Gst.TagMergeMode.REPLACE);
+ if (factory.has_interface("GstTagSetter")) {
+ let taglist = Gst.TagList.new_empty();
+ taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_APPLICATION_NAME, _("Sound
Recorder"));
+ element.merge_tags(taglist, Gst.TagMergeMode.REPLACE);
+ taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_TITLE, clipFile.get_uri());
+ element.merge_tags(taglist, Gst.TagMergeMode.REPLACE);
+ taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_DATE_TIME, gstreamerDateTime);
+ element.merge_tags(taglist, Gst.TagMergeMode.REPLACE);
}
}
});
@@ -162,9 +160,6 @@ var Recorder = GObject.registerClass({
errorDialogState = ErrState.ON;
this.onEndOfStream();
}
-
- GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGINT,
Application.application.onWindowDestroy);
- GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGTERM,
Application.application.onWindowDestroy);
}
_updateTime() {
@@ -227,6 +222,7 @@ var Recorder = GObject.registerClass({
GLib.source_remove(this.timeout);
this.timeout = null;
}
+ this.pipleline = null;
return clipFile;
}
diff --git a/src/recording.js b/src/recording.js
index 8608e74..6f4f425 100644
--- a/src/recording.js
+++ b/src/recording.js
@@ -20,11 +20,12 @@
const Gtk = imports.gi.Gtk;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
+
const GObject = imports.gi.GObject;
const Gst = imports.gi.Gst;
const GstPbutils = imports.gi.GstPbutils;
-const Player = imports.player.Player;
+
const utils = imports.utils;
const WaveForm = imports.waveform.WaveForm;
@@ -65,87 +66,67 @@ var Recording = GObject.registerClass({},
}
this.fileName = returnedName;
- let discoverer = new GstPbutils.Discoverer();
- discoverer.start();
- discoverer.discover_uri_async(this.uri);
- discoverer.connect('discovered', (_discoverer, info, error) => {
- let result = info.get_result();
- log(result);
- this._onDiscovererFinished(result, info, error);
- });
- }
-
- _onDiscovererFinished(res, info, err) {
-
- if (res == GstPbutils.DiscovererResult.OK) {
-
- this.tagInfo = info.get_tags();
+ let _discoverer = GstPbutils.Discoverer.new(10 * Gst.SECOND);
+ let info = _discoverer.discover_uri(this.uri);
- let dateTimeTag = this.tagInfo.get_date_time('datetime')[1];
- let durationInfo = info.get_duration();
- this.duration = durationInfo;
-
- /* this.file.dateCreated will usually be null since time::created it doesn't usually exist.
- Therefore, we prefer to set it with tags */
- if (dateTimeTag != null) {
- this.dateCreated = dateTimeTag.to_g_date_time();;
- }
- /* FIX ME
- this._getCapsForList(info);
- */
- } else {
- // don't index files we can't play
-
- log("File cannot be played");
- }
+ this.duration = info.get_duration();
}
+
}
);
var RecordingRow = GObject.registerClass({
- Template: 'resource:///org/gnome/SoundRecorder/recording_row.ui',
- InternalChildren: [
- 'clip_label',
- 'created_label',
- 'time_label',
- 'play_button',
- 'pause_button',
- 'overlay',
- 'buttons_stack'
- ],
- Signals: {
- }
+ Template: 'resource:///org/gnome/SoundRecorder/recording_row.ui',
+ InternalChildren: [
+ 'clip_label',
+ 'created_label',
+ 'time_label',
+ 'play_button',
+ 'duration_label',
+ 'stop_button',
+ 'overlay',
+ 'buttons_stack'
+ ],
+ Signals: {
+ 'play': {
+ flags: GObject.SignalFlags.RUN_FIRST,
+ param_types: [GObject.Object]
+ },
+ 'stop': {
+ flags: GObject.SignalFlags.RUN_FIRST
+ }
+ }
},
class RecordingRow extends Gtk.ListBoxRow {
_init(recording) {
super._init();
- this._player = new Player();
this.recording = recording;
this._clip_label.set_text(recording.fileName);
this._created_label.set_text(utils.getDisplayTime(recording.dateCreated));
this._overlay.add_overlay(recording.wave);
- this._player.setUri(recording.uri);
-
this._play_button.connect('clicked', () => {
- this._player.startPlaying();
- this._buttons_stack.set_visible_child_name("pause");
+ this.emit("play", recording);
+ this._buttons_stack.set_visible_child_name("stop");
});
- this._pause_button.connect('clicked', () => {
- this._player.pausePlaying();
+ this._stop_button.connect('clicked', () => {
+ this.emit("stop");
this._buttons_stack.set_visible_child_name("play");
});
+ this._duration_label.set_text(utils.getDisplayDuration(recording.duration))
+ /*
this._player.connect("timer-updated", (obj, seconds)=> {
this._time_label.set_text(utils.getDisplayDuration(seconds));
})
+ */
this.show_all();
}
@@ -171,10 +152,7 @@ var NewRecording = GObject.registerClass({
_init() {
super._init();
-
-
- this._state = 0;
-
+ this._wave = null;
this.show_all();
}
@@ -183,13 +161,13 @@ var NewRecording = GObject.registerClass({
}
setWave(wave) {
+ this._wave = wave;
this._overlay.add_overlay(wave);
}
reset() {
- this._overlay.remove(this._overlay.get_children()[0])
this.updateRecordTime(0);
-
+ this._wave.clearDrawing();
}
diff --git a/src/utils.js b/src/utils.js
index e052954..02ddbd4 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -23,6 +23,7 @@
const Gdk = imports.gi.Gdk;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
+const Gst = imports.gi.Gst;
const Gettext = imports.gettext;
@@ -71,7 +72,8 @@ var getDisplayTime = function (mtime) {
}
-var getDisplayDuration = function (seconds) {
+var getDisplayDuration = function (nanoseconds) {
+ let seconds = nanoseconds/Gst.SECOND;
let hoursStr = String(parseInt((seconds / 3600) % 60)).padStart(2, '0')
let minutesStr = String(parseInt((seconds / 60) % 60)).padStart(2, '0')
let secondsStr = String(parseInt(seconds % 60)).padStart(2, '0')
diff --git a/src/waveform.js b/src/waveform.js
index 7ab1351..44fd8e6 100644
--- a/src/waveform.js
+++ b/src/waveform.js
@@ -35,7 +35,7 @@ const C_ = imports.gettext.pgettext;
const MainWindow = imports.mainWindow;
const Application = imports.application;
-const INTERVAL = 100000000;
+const SAMPLE_DURATION = Gst.SECOND / 100;
const peaks = [];
const pauseVal = 10;
const waveSamples = 40;
@@ -46,18 +46,15 @@ const WaveType = {
};
var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
- _init(file) {
+ _init(recording) {
super._init();
let placeHolder = -100;
for (let i = 0; i < 40; i++)
peaks.push(placeHolder);
- if (file) {
+ if (recording) {
this.waveType = WaveType.PLAY;
- this.file = file;
- this.duration = this.file.duration;
-
- this._uri = this.file.uri;
- log(this.duration );
+ this.duration = recording.duration;
+ this._uri = recording.uri;
} else {
this.waveType = WaveType.RECORD;
}
@@ -70,7 +67,7 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
this.set_property("hexpand", true);
- this.connect("draw", (drawing, cr) => this.fillSurface(drawing, cr));
+ this.connect("draw", (drawing, cr) => this.fillSurface(cr));
if (this.waveType == WaveType.PLAY) {
this._launchPipeline();
@@ -89,12 +86,11 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
let bus = this.pipeline.get_bus();
bus.add_signal_watch();
- GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGINT,
Application.application.onWindowDestroy);
- GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGTERM,
Application.application.onWindowDestroy);
+ this.nSamples = Math.ceil(this.duration / SAMPLE_DURATION);
- this.nSamples = Math.ceil(this.duration / INTERVAL);
bus.connect("message", (bus, message) => {
+
if (message != null) {
this._messageCb(message);
}
@@ -102,20 +98,11 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
}
_messageCb(message) {
- let msg = message.type;
- switch(msg) {
- case Gst.MessageType.ELEMENT:
- let s = message.get_structure();
-
- if (s) {
-
- if (s.has_name("level")) {
- let peaknumber = 0;
- let st = s.get_value("timestamp");
- let dur = s.get_value("duration");
- let runTime = s.get_value("running-time");
- let peakVal = s.get_value("peak");
-
+ switch(message.type) {
+ case Gst.MessageType.ELEMENT:
+ let messageStructure = message.get_structure();
+ if (messageStructure && messageStructure.has_name("level")) {
+ let peakVal = messageStructure.get_value("peak");
if (peakVal) {
let val = peakVal.get_nth(0);
@@ -126,19 +113,13 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
peaks.push(value);
}
}
- }
-
- if (peaks.length == this.playTime) {
- this.pipeline.set_state(Gst.State.PAUSED);
- }
-
- if (peaks.length == pauseVal) {
- this.pipeline.set_state(Gst.State.PAUSED);
- }
+ if (peaks.length == this.playTime || peaks.length == pauseVal) {
+ this.pipeline.set_state(Gst.State.PAUSED);
+ }
break;
- case Gst.MessageType.EOS:
- this.stopGeneration();
+ case Gst.MessageType.EOS:
+ this.stopGeneration();
break;
}
}
@@ -152,7 +133,7 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
}
- fillSurface(drawing, cr) {
+ fillSurface(cr) {
let start = 0;
if (this.waveType == WaveType.PLAY) {
@@ -175,6 +156,7 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
let width = this.get_allocated_width();
let waveheight = this.get_allocated_height();
let length = this.nSamples;
+ log(`Samples are good : ${length}`)
let pixelsPerSample = width/waveSamples;
let gradient = new Cairo.LinearGradient(0, 0, width , waveheight);
if (this.waveType == WaveType.PLAY) {
@@ -188,9 +170,8 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
cr.setLineWidth(1);
cr.setSourceRGBA(0.0, 185, 161, 255);
}
-
- for(i = start; i <= end; i++) {
-
+ log(`Start ${start} end ${end}`)
+ for(i=0; i < peaks.length; i++) {
// Keep moving until we get to a non-null array member
if (peaks[i] < 0) {
cr.moveTo((xAxis * pixelsPerSample), (waveheight - (peaks[i] * waveheight)))
@@ -198,11 +179,7 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
// Start drawing when we reach the first non-null array member
if (peaks[i] != null && peaks[i] >= 0) {
- let idx = i - 1;
- if (start >= 40 && xAxis == 0) {
- cr.moveTo((xAxis * pixelsPerSample), waveheight);
- }
cr.lineTo((xAxis * pixelsPerSample), (waveheight - (peaks[i] * waveheight)));
}
@@ -218,10 +195,11 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
}
_drawEvent(playTime, recPeaks) {
+ log(`play time ${playTime}, recPeaks ${recPeaks}`)
let lastTime;
-
if (this.waveType == WaveType.PLAY) {
lastTime = this.playTime;
+ log(playTime)
this.playTime = playTime;
if (peaks.length < this.playTime) {
@@ -246,6 +224,10 @@ var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
return true;
}
+ clearDrawing() {
+
+ }
+
endDrawing() {
if (this.pipeline)
this.stopGeneration();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]