Interface Media
- All Known Subinterfaces:
AsyncMedia
- All Known Implementing Classes:
AbstractMedia
Media control interface allows for media playback, recording. To get an instance of this interface (implemented by the native port) see the MediaManager class.
The sample code below demonstrates simple video playback.
final Form hi = new Form("MediaPlayer", new BorderLayout());
hi.setToolbar(new Toolbar());
Style s = UIManager.getInstance().getComponentStyle("Title");
FontImage icon = FontImage.createMaterial(FontImage.MATERIAL_VIDEO_LIBRARY, s);
hi.getToolbar().addCommandToRightBar(new Command("", icon) {
@Override
public void actionPerformed(ActionEvent evt) {
Display.getInstance().openGallery((e) -> {
if(e != null && e.getSource() != null) {
String file = (String)e.getSource();
try {
Media video = MediaManager.createMedia(file, true);
hi.removeAll();
hi.add(BorderLayout.CENTER, new MediaPlayer(video));
hi.revalidate();
} catch(IOException err) {
Log.e(err);
}
}
}, Display.GALLERY_VIDEO);
}
});
hi.show();
The code below demonstrates capturing audio using the Capture API and playing back audio files using the Media API:
Form hi = new Form("Capture", BoxLayout.y());
hi.setToolbar(new Toolbar());
Style s = UIManager.getInstance().getComponentStyle("Title");
FontImage icon = FontImage.createMaterial(FontImage.MATERIAL_MIC, s);
FileSystemStorage fs = FileSystemStorage.getInstance();
String recordingsDir = fs.getAppHomePath() + "recordings/";
fs.mkdir(recordingsDir);
try {
for(String file : fs.listFiles(recordingsDir)) {
MultiButton mb = new MultiButton(file.substring(file.lastIndexOf("/") + 1));
mb.addActionListener((e) -> {
try {
Media m = MediaManager.createMedia(recordingsDir + file, false);
m.play();
} catch(IOException err) {
Log.e(err);
}
});
hi.add(mb);
}
hi.getToolbar().addCommandToRightBar("", icon, (ev) -> {
try {
String file = Capture.captureAudio();
if(file != null) {
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MMM-dd-kk-mm");
String fileName =sd.format(new Date());
String filePath = recordingsDir + fileName;
Util.copy(fs.openInputStream(file), fs.openOutputStream(filePath));
MultiButton mb = new MultiButton(fileName);
mb.addActionListener((e) -> {
try {
Media m = MediaManager.createMedia(filePath, false);
m.play();
} catch(IOException err) {
Log.e(err);
}
});
hi.add(mb);
hi.revalidate();
}
} catch(IOException err) {
Log.e(err);
}
});
} catch(IOException err) {
Log.e(err);
}
hi.show();
The code below demonstrates capturing audio and playing back audio using the Media, MediaManager and MediaRecorderBuilder APIs, as alternative and more customizable approach than using the Capture API:
private static final EasyThread countTime = EasyThread.start("countTime");
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("Recording audio", BoxLayout.y());
hi.add(new SpanLabel("Example of recording and playback audio using the Media, MediaManager and MediaRecorderBuilder APIs"));
hi.add(recordAudio((String filePath) -> {
ToastBar.showInfoMessage("Do something with the recorded audio file: " + filePath);
}));
hi.show();
}
public static Component recordAudio(OnComplete callback) {
try {
// mime types supported by Android: audio/amr, audio/aac, audio/mp4
// mime types supported by iOS: audio/mp4, audio/aac, audio/m4a
// mime type supported by Simulator: audio/wav
// more info: https://www.iana.org/assignments/media-types/media-types.xhtml
List availableMimetypes = Arrays.asList(MediaManager.getAvailableRecordingMimeTypes());
String mimetype;
if (availableMimetypes.contains("audio/aac")) {
// Android and iOS
mimetype = "audio/aac";
} else if (availableMimetypes.contains("audio/wav")) {
// Simulator
mimetype = "audio/wav";
} else {
// others
mimetype = availableMimetypes.get(0);
}
String fileName = "audioExample." + mimetype.substring(mimetype.indexOf("/") + 1);
String output = FileSystemStorage.getInstance().getAppHomePath() + "/" + fileName;
// https://tritondigitalcommunity.force.com/s/article/Choosing-Audio-Bitrate-Settings
MediaRecorderBuilder options = new MediaRecorderBuilder()
.mimeType(mimetype)
.path(output)
.bitRate(64000)
.samplingRate(44100);
Media[] microphone = {MediaManager.createMediaRecorder(options)};
Media[] speaker = {null};
Container recordingUI = new Container(BoxLayout.y());
Label time = new Label("0:00");
Button recordBtn = new Button("", FontImage.MATERIAL_FIBER_MANUAL_RECORD, "Button");
Button playBtn = new Button("", FontImage.MATERIAL_PLAY_ARROW, "Button");
Button stopBtn = new Button("", FontImage.MATERIAL_STOP, "Button");
Button sendBtn = new Button("Send");
sendBtn.setEnabled(false);
Container buttons = GridLayout.encloseIn(3, recordBtn, stopBtn, sendBtn);
recordingUI.addAll(FlowLayout.encloseCenter(time), FlowLayout.encloseCenter(buttons));
recordBtn.addActionListener(l -> {
try {
// every time we have to create a new instance of Media to make it working correctly (as reported in the Javadoc)
microphone[0] = MediaManager.createMediaRecorder(options);
if (speaker[0] != null && speaker[0].isPlaying()) {
return; // do nothing if the audio is currently recorded or played
}
recordBtn.setEnabled(false);
sendBtn.setEnabled(true);
Log.p("Audio recording started", Log.DEBUG);
if (buttons.contains(playBtn)) {
buttons.replace(playBtn, stopBtn, CommonTransitions.createEmpty());
buttons.revalidateWithAnimationSafety();
}
if (speaker[0] != null) {
speaker[0].pause();
}
microphone[0].play();
startWatch(time);
} catch (IOException ex) {
Log.p("ERROR recording audio", Log.ERROR);
Log.e(ex);
}
});
stopBtn.addActionListener(l -> {
if (!microphone[0].isPlaying() && (speaker[0] == null || !speaker[0].isPlaying())) {
return; // do nothing if the audio is NOT currently recorded or played
}
recordBtn.setEnabled(true);
sendBtn.setEnabled(true);
Log.p("Audio recording stopped");
if (microphone[0].isPlaying()) {
microphone[0].pause();
} else if (speaker[0] != null) {
speaker[0].pause();
} else {
return;
}
stopWatch(time);
if (buttons.contains(stopBtn)) {
buttons.replace(stopBtn, playBtn, CommonTransitions.createEmpty());
buttons.revalidateWithAnimationSafety();
}
if (FileSystemStorage.getInstance().exists(output)) {
Log.p("Audio saved to: " + output);
} else {
ToastBar.showErrorMessage("Error recording audio", 5000);
Log.p("ERROR SAVING AUDIO");
}
});
playBtn.addActionListener(l -> {
// every time we have to create a new instance of Media to make it working correctly (as reported in the Javadoc)
if (microphone[0].isPlaying() || (speaker[0] != null && speaker[0].isPlaying())) {
return; // do nothing if the audio is currently recorded or played
}
recordBtn.setEnabled(false);
sendBtn.setEnabled(true);
if (buttons.contains(playBtn)) {
buttons.replace(playBtn, stopBtn, CommonTransitions.createEmpty());
buttons.revalidateWithAnimationSafety();
}
if (FileSystemStorage.getInstance().exists(output)) {
try {
speaker[0] = MediaManager.createMedia(output, false, () -> {
// callback on completation
recordBtn.setEnabled(true);
if (speaker[0].isPlaying()) {
speaker[0].pause();
}
stopWatch(time);
if (buttons.contains(stopBtn)) {
buttons.replace(stopBtn, playBtn, CommonTransitions.createEmpty());
buttons.revalidateWithAnimationSafety();
}
});
speaker[0].play();
startWatch(time);
} catch (IOException ex) {
Log.p("ERROR playing audio", Log.ERROR);
Log.e(ex);
}
}
});
sendBtn.addActionListener(l -> {
if (microphone[0].isPlaying()) {
microphone[0].pause();
}
if (speaker[0] != null && speaker[0].isPlaying()) {
speaker[0].pause();
}
if (buttons.contains(stopBtn)) {
buttons.replace(stopBtn, playBtn, CommonTransitions.createEmpty());
buttons.revalidateWithAnimationSafety();
}
stopWatch(time);
recordBtn.setEnabled(true);
callback.completed(output);
});
return FlowLayout.encloseCenter(recordingUI);
} catch (IOException ex) {
Log.p("ERROR recording audio", Log.ERROR);
Log.e(ex);
return new Label("Error recording audio");
}
}
private static void startWatch(Label label) {
label.putClientProperty("stopTime", Boolean.FALSE);
countTime.run(() -> {
long startTime = System.currentTimeMillis();
while (label.getClientProperty("stopTime") == Boolean.FALSE) {
// the sleep is every 200ms instead of 1000ms to make the app more reactive when stop is tapped
Util.sleep(200);
int seconds = (int) ((System.currentTimeMillis() - startTime) / 1000);
String min = (seconds / 60) + "";
String sec = (seconds % 60) + "";
if (sec.length() == 1) {
sec = "0" + sec;
}
String newTime = min + ":" + sec;
if (!label.getText().equals(newTime)) {
CN.callSerially(() -> {
label.setText(newTime);
if (label.getParent() != null) {
label.getParent().revalidateWithAnimationSafety();
}
});
}
}
});
}
private static void stopWatch(Label label) {
label.putClientProperty("stopTime", Boolean.TRUE);
}
See also
- MediaManager
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringWrite only variable that can be used with setVariable to pass the album cover Image to the native layer so the currently playing media title will be displayed in the lock screen where applicablestatic final StringWrite only variable that can be used with setVariable to pass the artist name to the native layer so the currently playing media title will be displayed in the lock screen where applicablestatic final StringWrite only variable that can be used with setVariable to pass the duration for the media as a Long object to the native layer so the currently playing media title will be displayed in the lock screen where applicablestatic final StringWrite only variable that can be used with setVariable to pass the position in the media (Long object) to the native layer so the currently playing media title will be displayed in the lock screen where applicablestatic final StringRead only variable that can be used with getVariable to query whether the native layer supports displaying the currently playing media information in the lock screen.static final StringWrite only variable that can be used with setVariable to pass a title for the native layer so the currently playing media title will be displayed in the lock screen where applicablestatic final StringWrite-only variable that can be used with getVariable() to set whether this video should include embedded native controls. -
Method Summary
Modifier and TypeMethodDescriptionvoidcleanup()Stops the audio playback and cleans up the resources related to it immediately.intReturns the length in milliseconds of the audio file or -1 if not knownintgetTime()Returns the time in milliseconds in the audio file or -1 if not knowngetVariable(String key) Allows querying platform specific information from the media objectGets the VideoComponent of this Video.intReturns the media playback volume in percentagebooleanThis method returns true if this video is in full screen mode.booleanReturns true if this Video Media is in Native player mode.booleanReturns true if the media is currently playing or recordingbooleanisVideo()This method returns true if this is a Video Mediavoidpause()Pauses (actually stops) the playback or the recording of the media filevoidplay()Starts playing or recording the media filevoidprepare()Optional call that allows the caller to prepare the upcoming media player.voidsetFullScreen(boolean fullScreen) Sets the Media to be displayed full screen, make sure the getVideoComponent() is called on the Video Component is added to the current FormvoidsetNativePlayerMode(boolean nativePlayer) By calling this the Media (if it's a Video) will be played full screen on the native Player of the device.voidsetTime(int time) Sets the position in the audio file or doesn't effect if not supportedvoidsetVariable(String key, Object value) Allows for platform specific enhancements for media playbackvoidsetVolume(int vol) Sets the media playback volume in percentage
-
Field Details
-
VARIABLE_BACKGROUND_TITLE
Write only variable that can be used with setVariable to pass a title for the native layer so the currently playing media title will be displayed in the lock screen where applicable- See Also:
-
VARIABLE_BACKGROUND_ARTIST
Write only variable that can be used with setVariable to pass the artist name to the native layer so the currently playing media title will be displayed in the lock screen where applicable- See Also:
-
VARIABLE_BACKGROUND_DURATION
Write only variable that can be used with setVariable to pass the duration for the media as a Long object to the native layer so the currently playing media title will be displayed in the lock screen where applicable- See Also:
-
VARIABLE_BACKGROUND_ALBUM_COVER
Write only variable that can be used with setVariable to pass the album cover Image to the native layer so the currently playing media title will be displayed in the lock screen where applicable- See Also:
-
VARIABLE_BACKGROUND_POSITION
Write only variable that can be used with setVariable to pass the position in the media (Long object) to the native layer so the currently playing media title will be displayed in the lock screen where applicable- See Also:
-
VARIABLE_BACKGROUND_SUPPORTED
Read only variable that can be used with getVariable to query whether the native layer supports displaying the currently playing media information in the lock screen. This will return null or Boolean.TRUE.- See Also:
-
VARIABLE_NATIVE_CONTRLOLS_EMBEDDED
Write-only variable that can be used with getVariable() to set whether this video should include embedded native controls.- See Also:
-
-
Method Details
-
play
void play()Starts playing or recording the media file -
pause
void pause()Pauses (actually stops) the playback or the recording of the media file -
prepare
void prepare()Optional call that allows the caller to prepare the upcoming media player. This is useful when streaming multiple streams one after another.
Note: On some platforms (iOS), the poster frame and native embedded controls will not appear for the video until you call this method, otherwise.
-
cleanup
void cleanup()Stops the audio playback and cleans up the resources related to it immediately. -
getTime
int getTime()Returns the time in milliseconds in the audio file or -1 if not known
Returns
time in milliseconds
-
setTime
void setTime(int time) Sets the position in the audio file or doesn't effect if not supported
Parameters
time: in milliseconds
-
getDuration
int getDuration()Returns the length in milliseconds of the audio file or -1 if not known
Returns
time in milliseconds
-
getVolume
int getVolume()Returns the media playback volume in percentage
Returns
the volume percentage
-
setVolume
void setVolume(int vol) Sets the media playback volume in percentage
Parameters
vol: the volume for media playback
-
isPlaying
boolean isPlaying()Returns true if the media is currently playing or recording
Returns
true if playing
-
getVideoComponent
Component getVideoComponent()Gets the VideoComponent of this Video.
Returns
- Returns:
- a Component of the video to be placed on a Form or null if this Media is not a Video
-
isVideo
boolean isVideo()This method returns true if this is a Video Media
Returns
true if video
-
isFullScreen
boolean isFullScreen()This method returns true if this video is in full screen mode.
Returns
true if full screen
-
setFullScreen
void setFullScreen(boolean fullScreen) Sets the Media to be displayed full screen, make sure the getVideoComponent() is called on the Video Component is added to the current Form
Parameters
fullScreen
-
isNativePlayerMode
boolean isNativePlayerMode()Returns true if this Video Media is in Native player mode. Some platforms such as BlackBerry is able to play video only on the native player on those platforms isNativePlayerMode() will always return true If Media supports native playing by calling to play() the video will start playing in the native player in full screen.
Returns
true if the player is in native mode
-
setNativePlayerMode
void setNativePlayerMode(boolean nativePlayer) By calling this the Media (if it's a Video) will be played full screen on the native Player of the device. Native playing assumes getVideoComponent() hasn't been called on this Media unexpected behaviour may occur if getVideoComponent() has been called and the Component is placed on a Form. Some platforms such as BlackBerry is able to play video only on the native player on those platforms isNativePlayerMode() will always return true -
setVariable
-
getVariable
-