Add Audio Playback Capability
* Add envoy.client.data.audio package * Move AudioRecorder to the audio package * Add AudioPlayer class * Add AudioControl class that acts as a small media player * Display the audio control in message controls that contain voice messages
This commit is contained in:
64
src/main/java/envoy/client/data/audio/AudioPlayer.java
Normal file
64
src/main/java/envoy/client/data/audio/AudioPlayer.java
Normal file
@ -0,0 +1,64 @@
|
||||
package envoy.client.data.audio;
|
||||
|
||||
import javax.sound.sampled.*;
|
||||
|
||||
import envoy.exception.EnvoyException;
|
||||
|
||||
/**
|
||||
* Plays back audio from a byte array.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>AudioPlayer.java</strong><br>
|
||||
* Created: <strong>05.07.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public final class AudioPlayer {
|
||||
|
||||
private final AudioFormat format;
|
||||
private final DataLine.Info info;
|
||||
|
||||
private Clip clip;
|
||||
|
||||
/**
|
||||
* Initializes the player with the default audio format.
|
||||
*
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public AudioPlayer() { this(AudioRecorder.DEFAULT_AUDIO_FORMAT); }
|
||||
|
||||
/**
|
||||
* Initializes the player with a given audio format.
|
||||
*
|
||||
* @param format the audio format to use
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public AudioPlayer(AudioFormat format) {
|
||||
this.format = format;
|
||||
info = new DataLine.Info(Clip.class, format);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if audio play back is supported
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public boolean isSupported() { return AudioSystem.isLineSupported(info); }
|
||||
|
||||
/**
|
||||
* Plays back an audio clip.
|
||||
*
|
||||
* @param data the data of the clip
|
||||
* @throws EnvoyException if the play back failed
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public void play(byte[] data) throws EnvoyException {
|
||||
try {
|
||||
clip = (Clip) AudioSystem.getLine(info);
|
||||
clip.open(format, data, 0, data.length);
|
||||
clip.start();
|
||||
} catch (LineUnavailableException e) {
|
||||
throw new EnvoyException("Cannot play back audio", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package envoy.client.data;
|
||||
package envoy.client.data.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -20,21 +20,49 @@ import envoy.exception.EnvoyException;
|
||||
*/
|
||||
public final class AudioRecorder {
|
||||
|
||||
private final AudioFormat format;
|
||||
/**
|
||||
* The default audio format used for recording and play back.
|
||||
*
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public static final AudioFormat DEFAULT_AUDIO_FORMAT = new AudioFormat(16000, 16, 1, true, false);
|
||||
|
||||
private final AudioFormat format;
|
||||
private final DataLine.Info info;
|
||||
|
||||
private DataLine.Info info;
|
||||
private TargetDataLine line;
|
||||
private Path tempFile;
|
||||
|
||||
public AudioRecorder() { this(new AudioFormat(16000, 16, 1, true, false)); }
|
||||
/**
|
||||
* Initializes the recorder with the default audio format.
|
||||
*
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public AudioRecorder() { this(DEFAULT_AUDIO_FORMAT); }
|
||||
|
||||
/**
|
||||
* Initializes the recorder with a given audio format.
|
||||
*
|
||||
* @param format the audio format to use
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public AudioRecorder(AudioFormat format) {
|
||||
this.format = format;
|
||||
info = new DataLine.Info(TargetDataLine.class, format);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if audio recording is supported
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public boolean isSupported() { return AudioSystem.isLineSupported(info); }
|
||||
|
||||
/**
|
||||
* Starts the audio recording.
|
||||
*
|
||||
* @throws EnvoyException if starting the recording failed
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public void start() throws EnvoyException {
|
||||
try {
|
||||
|
||||
@ -54,6 +82,13 @@ public final class AudioRecorder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the recording.
|
||||
*
|
||||
* @return the finished recording
|
||||
* @throws EnvoyException if finishing the recording failed
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public byte[] finish() throws EnvoyException {
|
||||
try {
|
||||
line.stop();
|
11
src/main/java/envoy/client/data/audio/package-info.java
Normal file
11
src/main/java/envoy/client/data/audio/package-info.java
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Contains classes related to recording and playing back audio clips.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>package-info.java</strong><br>
|
||||
* Created: <strong>05.07.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
package envoy.client.data.audio;
|
40
src/main/java/envoy/client/ui/AudioControl.java
Normal file
40
src/main/java/envoy/client/ui/AudioControl.java
Normal file
@ -0,0 +1,40 @@
|
||||
package envoy.client.ui;
|
||||
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
||||
import envoy.client.data.audio.AudioPlayer;
|
||||
import envoy.exception.EnvoyException;
|
||||
|
||||
/**
|
||||
* Enables the play back of audio clips through a button.
|
||||
* <p>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>AudioControl.java</strong><br>
|
||||
* Created: <strong>05.07.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public final class AudioControl extends HBox {
|
||||
|
||||
private AudioPlayer player = new AudioPlayer();
|
||||
|
||||
/**
|
||||
* Initializes the audio control.
|
||||
*
|
||||
* @param audioData the audio data to play.
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public AudioControl(byte[] audioData) {
|
||||
var button = new Button("Play");
|
||||
button.setOnAction(e -> {
|
||||
try {
|
||||
player.play(audioData);
|
||||
} catch (EnvoyException ex) {
|
||||
|
||||
}
|
||||
});
|
||||
getChildren().add(button);
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
import envoy.client.data.*;
|
||||
import envoy.client.data.audio.AudioRecorder;
|
||||
import envoy.client.event.MessageCreationEvent;
|
||||
import envoy.client.net.Client;
|
||||
import envoy.client.net.WriteProxy;
|
||||
|
@ -9,7 +9,9 @@ import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import envoy.client.ui.AudioControl;
|
||||
import envoy.client.ui.IconUtil;
|
||||
import envoy.data.Attachment.AttachmentType;
|
||||
import envoy.data.Message;
|
||||
import envoy.data.Message.MessageStatus;
|
||||
import envoy.data.User;
|
||||
@ -38,6 +40,11 @@ public class MessageControl extends VBox {
|
||||
public MessageControl(Message message) {
|
||||
// Creating the underlying VBox, the dateLabel and the textLabel
|
||||
super(new Label(dateFormat.format(message.getCreationDate())));
|
||||
|
||||
// Voice attachment
|
||||
if (message.hasAttachment() && message.getAttachment().getType() == AttachmentType.VOICE)
|
||||
getChildren().add(new AudioControl(message.getAttachment().getData()));
|
||||
|
||||
final var textLabel = new Label(message.getText());
|
||||
textLabel.setWrapText(true);
|
||||
getChildren().add(textLabel);
|
||||
|
Reference in New Issue
Block a user