Add javax.microedition.media.* and dependencies from phoneme_feature.

This commit is contained in:
Yuan Xulei 2014-10-25 18:32:51 +08:00
Родитель ab5b708833
Коммит 4c1ef19c3f
59 изменённых файлов: 13434 добавлений и 57 удалений

Просмотреть файл

@ -1,6 +1,6 @@
SRCS=$(shell find ./cldc1.1.1 -name *.java) $(shell find ./vm -name *.java) $(shell find ./midp -name *.java)
CUSTOM_SRCS=$(shell find ./custom -name *.java)
JPP_DEFS=-DENABLE_JSR_205 -DENABLE_CHAMELEON -DENABLE_SSL -DENABLE_PUBLICKEYSTORE -DENABLE_JSR_211 -DENABLE_MULTIPLE_ISOLATES
JPP_DEFS=-DENABLE_JSR_205 -DENABLE_CHAMELEON -DENABLE_SSL -DENABLE_PUBLICKEYSTORE -DENABLE_JSR_211 -DENABLE_MULTIPLE_ISOLATES -DRECORD
JPP_SRCS=$(shell find . -name *.jpp)
JPP_DESTS=$(JPP_SRCS:.jpp=.java)
EXTRA=$(shell find . -name *.png) $(shell find . -name *.bin) $(shell find . -name *.xml)

Просмотреть файл

@ -0,0 +1,35 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.j2me.app;
import com.sun.midp.main.MIDletSuiteUtils;
public class AppIsolate {
/**
* get Isolate ID
*/
public static int getIsolateId() {
return MIDletSuiteUtils.getIsolateId();
}
}

Просмотреть файл

@ -0,0 +1,43 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.j2me.app;
/**
* Abstraction for application model
*/
public class AppModel{
/** Guard from 'new' operator */
private AppModel() {
}
public final static int MIDLET = 0;
public final static int XLET = 1;
public final static int UNKNOWN_MODEL = 2;
public static int getAppModel() {
return MIDLET;
}
}

Просмотреть файл

@ -0,0 +1,44 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.j2me.security;
/**
* Connector access permissions.
*/
public class ConnectorPermission extends Permission {
static public ConnectorPermission HTTP = new ConnectorPermission(
"javax.microedition.io.Connector.http", null);
static public ConnectorPermission HTTPS = new ConnectorPermission(
"javax.microedition.io.Connector.https", null);
static public ConnectorPermission TCP = new ConnectorPermission(
"javax.microedition.io.Connector.socket", null);
public ConnectorPermission(String name, String resource) {
super(name, resource);
}
}

Просмотреть файл

@ -0,0 +1,43 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.j2me.security;
/**
* FileConnection access permissions.
*/
public class FileConnectionPermission extends Permission {
static public FileConnectionPermission READ =
new FileConnectionPermission(
"javax.microedition.io.Connector.file.read", null);
static public FileConnectionPermission WRITE =
new FileConnectionPermission(
"javax.microedition.io.Connector.file.write", null);
public FileConnectionPermission(String name, String resource) {
super(name, resource);
}
}

Просмотреть файл

@ -0,0 +1,42 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.j2me.security;
/**
* Multimedia access permissions.
*/
public class MMAPIPermission extends Permission {
static public MMAPIPermission SNAPSHOT = new MMAPIPermission(
"javax.microedition.media.control.VideoControl.getSnapshot", null);
static public MMAPIPermission RECORDING = new MMAPIPermission(
"javax.microedition.media.control.RecordControl", null);
public MMAPIPermission(String name, String resource) {
super(name, resource);
}
}

Просмотреть файл

@ -0,0 +1,42 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
/**
* Description of the Class - empty class in CLDC
*
*/
public class AudioTunnel {
private static AudioTunnel tunnel = null;
private AudioTunnel() {};
static synchronized AudioTunnel getInstance() {
if (tunnel == null) {
tunnel = new AudioTunnel();
}
return tunnel;
};
void start() {};
void stop() {};
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,338 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import java.util.Hashtable;
import javax.microedition.media.Control;
/**
* The configuration module for MMAPI.
*
*/
public abstract class Configuration {
/**
* Tone sequence mime type.
*/
public final static String MIME_AUDIO_TONE = "audio/x-tone-seq";
/**
* MIME_AUDI_AMR NB mime type.
*/
public final static String MIME_AUDIO_WAV = "audio/x-wav";
public final static String MIME_AUDIO_WAV_2 = "audio/wav";
/**
* MIME_AUDI_AMR mime type
*/
public final static String MIME_AUDIO_AMR = "audio/amr";
/**
* MIME_AUDI_AMR WB mime type.
*/
public final static String MIME_AUDIO_AMR_WB = "audio/amr-wb";
/**
* MIME_AUDIO_MIDI mime type.
*/
public final static String MIME_AUDIO_MIDI = "audio/midi";
public final static String MIME_AUDIO_MIDI_2 = "audio/mid";
/**
* SP-MIME_AUDIO_MIDI mime type.
*/
public static final String MIME_AUDIO_SP_MIDI = "audio/sp-midi";
/**
* MIME_AUDIO_MP3 mime type
*/
public final static String MIME_AUDIO_MP3 = "audio/mpeg";
public final static String MIME_AUDIO_MP3_2 = "audio/mp3";
/**
* MP4 audio type
*/
public final static String MIME_AUDIO_MP4 = "audio/mp4";
public final static String MIME_AUDIO_MP4_2 = "audio/mp4a-latm";
/**
* MIME_AUDIO_AAC audio type
*/
public final static String MIME_AUDIO_AAC = "audio/aac";
/**
* MIME_AUDIO_QCELP audio type
*/
public final static String MIME_AUDIO_QCELP = "audio/qcelp";
public final static String MIME_AUDIO_QCELP_2 = "audio/vnd.qcelp";
/**
* GIF mime type.
*/
public final static String MIME_IMAGE_GIF = "image/gif";
/**
* PNG mime type.
*/
public final static String MIME_IMAGE_PNG = "image/png";
/**
* JPEG mime type.
*/
public final static String MIME_IMAGE_JPEG = "image/jpeg";
/**
* Raw image mime type.
*/
public final static String MIME_IMAGE_RAW = "image/raw";
/**
* 3GPP video mime type
*/
public final static String MIME_VIDEO_3GPP = "video/3gpp";
public final static String MIME_VIDEO_3GPP_2 = "video/3gpp2";
/**
* MPEG video mime type
*/
public final static String MIME_VIDEO_MPEG = "video/mpeg";
/**
* MPEG4 video mime type
*/
public final static String MIME_VIDEO_MPEG4 = "video/mp4";
/**
* WMV video mime type
*/
public final static String MIME_VIDEO_WMV = "video/x-ms-wmv";
/**
* AVI video mime type
*/
public final static String MIME_VIDEO_AVI = "video/avi";
public final static String TONE_DEVICE_LOCATOR = javax.microedition.media.Manager.TONE_DEVICE_LOCATOR; //"device://tone";
public final static String MIDI_DEVICE_LOCATOR = javax.microedition.media.Manager.MIDI_DEVICE_LOCATOR; //"device://midi";
public final static String CAPTURE_LOCATOR = "capture://";
public final static String RADIO_CAPTURE_LOCATOR = "capture://radio";
public final static String AUDIO_CAPTURE_LOCATOR = "capture://audio";
public final static String VIDEO_CAPTURE_LOCATOR = "capture://video";
/**
* A hash table of the protocol handlers.
*/
protected Hashtable protocolHandlers;
/**
* A table of mime types.
*/
protected Hashtable mimeTypes;
/**
* A table of media formats supported by Jave.
*/
protected Hashtable mFormats;
/**
* The current configuration object.
*/
private static Configuration config;
/**
* True if players loop in native code,
* otherwise false
*/
protected static boolean nativeLooping = false;
protected Hashtable properties;
/**
* defines whether to process jsr234-specific operations or not
* (jsr135 only).
*/
protected boolean needAMMS;
/**
*Constructor for the Configuration object
*/
public Configuration() {
protocolHandlers = new Hashtable();
mimeTypes = new Hashtable();
mFormats = new Hashtable();
properties = new Hashtable();
try {
String value = System.getProperty("microedition.amms.version");
needAMMS = (value != null);
} catch (Exception e) {
needAMMS = false;
}
}
/**
* Gets supported content types for given protocol
*
* @param protocol protocol
* @return array of supported content types
*/
public abstract String[] getSupportedContentTypes(String protocol);
/**
* Gets supported protocols for given content type
*
* @param ctype content type
* @return array of supported protocols
*/
public abstract String[] getSupportedProtocols(String ctype);
public abstract String getProperty(String key);
public abstract void setProperty(String key, String value);
/**
* Gets Accessor to platform specific Image classes
* To be defined in derived classes.
*
* @return instance of ImageAccess class
*/
public abstract ImageAccess getImageAccessor();
/**
* Gets the video renderer.
*
* @return The video renderer
*/
public abstract VideoRenderer getVideoRenderer(BasicPlayer player);
/**
* Gets the tonePlayer attribute of the Configuration object
*
* @return The tonePlayer value
*/
public abstract TonePlayer getTonePlayer();
/**
* Convert from the name of a file to its corresponding mediaFormat
* format based on the extension for Java Players.
*
* @param name file's pathname
* @return media Format for this name or null, if couldn't be determined
*/
public String ext2Format(String name) {
int idx = name.lastIndexOf('.');
String ext;
if (idx != -1) {
ext = name.substring(idx + 1).toLowerCase();
} else {
ext = name.toLowerCase();
}
return (String) mFormats.get(ext);
}
/**
* Convert from the content type to its corresponding mediaFormat
* format based on the MIME types for Java Players.
*
* @param type MIME type
* @return media Format for this name or null, if couldn't be determined
*/
public String mime2Format(String type) {
String ext = null;
for (java.util.Enumeration e = mimeTypes.keys(); e.hasMoreElements();) {
String k = (String)e.nextElement();
if (mimeTypes.get(k).equals(type)) {
ext = k;
break;
}
}
if (ext != null) {
return (String)mFormats.get(ext);
}
return null;
}
/**
* Gets the handler attribute of the Configuration object
*
* @param type The content type
* @return The handler value
*/
public String getProtocolHandler(String type) {
return (String) protocolHandlers.get(type);
}
/**
* Gets the configuration attribute of the Configuration class
*
* @return The configuration value
*/
public static Configuration getConfiguration() {
if (config != null) return config;
String className = System.getProperty("mmapi-configuration");
if (className != null) {
try {
// ... try and instantiate the configuration class ...
Class handlerClass = Class.forName(className);
config = (Configuration) handlerClass.newInstance();
} catch (Exception e) {
// do nothing
}
} else {
config = new DefaultConfiguration();
}
return config;
}
/**
* Sets the configuration attribute of the Configuration class
*
* @param cnf The new configuration value
*/
/*
public static void setConfiguration(Configuration cnf) {
config = cnf;
}
*/
/**
* Description of the Method
*
* @return Description of the Return Value
*/
public static boolean nativeLoopMode() {
return nativeLooping;
}
public boolean isRadioSupported()
{
return false;
}
}

Просмотреть файл

@ -0,0 +1,386 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.Manager;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
import java.util.Vector;
/**
* The default configuration module for an MMAPI.
* implementation supporting the http, https and
* device protocols as well as the following
* content types:
*
* Tones,
* Tone Sequences,
* AMR Narrowband
* AMR Wideband.
* GIF.
*
* Please note:
*
* Tone Sequences are supported over http and https in tone sequence
* file format (.jts).
*
* Both single tones and tone sequence are also supported
* over the device protocol.
*
*/
public class DefaultConfiguration extends Configuration {
/**
* Handle for the Image Access Environment...
*/
private static ImageAccess imageAccessor;
private final static String[] JAVA_PROTOCOLS = new String[] {
// #ifdef USE_FILE_CONNECTION [
"file",
// #endif ]
// #ifdef USE_RTSP [
"rtsp",
// #endif ]
"http",
"https"
};
private static boolean isJavaProtocol(String protocol) {
for (int i = 0; i < JAVA_PROTOCOLS.length; i++) {
if (protocol.toUpperCase().equals(JAVA_PROTOCOLS[i].toUpperCase())) {
return true;
}
}
return false;
}
private final static String[] JAVA_CONTENT_TYPES = new String[] {
MIME_IMAGE_GIF
};
private static boolean isJavaContent(String mime) {
for (int i = 0; i < JAVA_CONTENT_TYPES.length; i++) {
if (mime.toUpperCase().equals(JAVA_CONTENT_TYPES[i].toUpperCase())) {
return true;
}
}
return false;
}
private final static String[] RTP_PROTOCOLS = new String[] { "rtp", "rtsp" };
private static boolean isRtpProtocol(String protocol) {
for (int i = 0; i < RTP_PROTOCOLS.length; i++) {
if (protocol.toUpperCase().equals(RTP_PROTOCOLS[i].toUpperCase())) {
return true;
}
}
return false;
}
private final static String[] RTP_CONTENT_TYPES = new String[] {
"audio/DVI4", "audio/G722", "audio/G723", "audio/G726-16",
"audio/G726-24", "audio/G726-32", "audio/G726-40", "audio/G728",
"audio/G729", "audio/G729D", "audio/G729E", "audio/GSM",
"audio/GSM-EFR", "audio/L8", "audio/L16", "audio/LPC",
"audio/MPA", "audio/PCMA", "audio/PCMU", "audio/QCELP",
"audio/RED", "audio/VDVI", "video/BT656", "video/CelB",
"video/JPEG", "video/H261", "video/H263", "video/H263-1998",
"video/H263-2000", "video/MPV", "video/MP2T", "video/MP1S",
"video/MP2P", "video/BMPEG", "video/nv"
};
private static boolean isRtpContent(String mime) {
String uMime = mime.toUpperCase();
for (int i = 0; i < RTP_CONTENT_TYPES.length; i++) {
String uRtpType = RTP_CONTENT_TYPES[i].toUpperCase();
if (uMime.equals(uRtpType) || uMime.startsWith(uRtpType+";")) {
return true;
}
}
return false;
}
/**
* Allows RTP-specific content types to by tranferred only via RTP/RTSP,
* while all other content types only via protocols other than RTP/RTSP
*/
private static boolean allowed(String ctype, String protocol) {
return isRtpContent(ctype) == isRtpProtocol(protocol);
}
/**
* Constructor for the DefaultConfiguration object
*/
public DefaultConfiguration() {
super();
// Protocol handlers.
protocolHandlers.put("http", "com.sun.mmedia.protocol.CommonDS");
protocolHandlers.put("https", "com.sun.mmedia.protocol.CommonDS");
// #ifdef USE_FILE_CONNECTION [
protocolHandlers.put("file", "com.sun.mmedia.protocol.CommonDS");
// #endif
// #ifdef USE_RTSP [
protocolHandlers.put("rtsp", "com.sun.mmedia.rtsp.RtspDS");
// protocolHandlers.put( "rtp", "com.sun.mmedia.protocol.CommonDS" );
// #else ] [
protocolHandlers.put("rtsp", "com.sun.mmedia.protocol.CommonDS");
protocolHandlers.put("rtp", "com.sun.mmedia.protocol.CommonDS");
// #endif ]
protocolHandlers.put("device", "com.sun.mmedia.protocol.CommonDS");
protocolHandlers.put("capture", "com.sun.mmedia.protocol.CommonDS");
// Mime types
mFormats.put("gif", "GIF");
// Mime types
mimeTypes.put("jts", MIME_AUDIO_TONE);
mimeTypes.put("mid", MIME_AUDIO_MIDI);
mimeTypes.put("midi", MIME_AUDIO_MIDI);
mimeTypes.put("rmi", MIME_AUDIO_MIDI);
mimeTypes.put("kar", MIME_AUDIO_MIDI);
mimeTypes.put("wav", MIME_AUDIO_WAV);
mimeTypes.put("mp3", MIME_AUDIO_MP3);
mimeTypes.put("m4a", MIME_AUDIO_MP4);
mimeTypes.put("qcp", MIME_AUDIO_QCELP);
mimeTypes.put("aac", MIME_AUDIO_AAC);
mimeTypes.put("amr", MIME_AUDIO_AMR);
mimeTypes.put("awb", MIME_AUDIO_AMR_WB);
mimeTypes.put("3gp", MIME_VIDEO_3GPP);
mimeTypes.put("mpg", MIME_VIDEO_MPEG);
mimeTypes.put("mp4", MIME_VIDEO_MPEG4);
mimeTypes.put("wmv", MIME_VIDEO_WMV);
mimeTypes.put("avi", MIME_VIDEO_AVI);
mimeTypes.put("gif", MIME_IMAGE_GIF);
// for converting
mimeTypes.put("audio/tone", MIME_AUDIO_TONE);
imageAccessor = new MIDPImageAccessor();
}
protected native int nListContentTypesOpen(String protocol);
protected native String nListContentTypesNext(int hdlr);
protected native void nListContentTypesClose(int hdlr);
protected native int nListProtocolsOpen(String mime);
protected native String nListProtocolsNext(int hdlr);
protected native void nListProtocolsClose(int hdlr);
/**
* Gets the supportedContentTypes attribute of the DefaultConfiguration object
*
* @param protocol Description of the Parameter
* @return The supportedContentTypes value
*/
public String[] getSupportedContentTypes(String protocol) {
Vector ctypes = new Vector();
if (null == protocol || isJavaProtocol(protocol)) {
// add content types supported by Java
for (int c = 0; c < JAVA_CONTENT_TYPES.length; c++) {
if (null == protocol || allowed(JAVA_CONTENT_TYPES[c],protocol)) {
ctypes.addElement(JAVA_CONTENT_TYPES[c]);
}
}
}
if (null == protocol) {
// add content types supported by javacall
int hList = nListContentTypesOpen(null);
if (hList != 0) {
String ctype;
while (null != (ctype = nListContentTypesNext(hList))) {
addIfNotExists(ctypes, ctype);
}
nListContentTypesClose(hList);
}
} else {
// add content types directly supported by javacall for this protocol
int hList = nListContentTypesOpen(protocol);
if (hList != 0) {
String ctype;
while ((ctype = nListContentTypesNext(hList)) != null) {
addIfNotExists(ctypes, ctype);
}
nListContentTypesClose(hList);
}
if (isJavaProtocol(protocol)) {
// add content types supported by javacall via memory streaming.
hList = nListContentTypesOpen("memory");
if (hList != 0) {
String ctype;
while ((ctype = nListContentTypesNext(hList)) != null) {
if (allowed(ctype,protocol)) {
addIfNotExists(ctypes, ctype);
}
}
nListContentTypesClose(hList);
}
}
}
String ret[] = new String[ctypes.size()];
ctypes.copyInto(ret);
return ret;
}
/**
* Gets the supportedProtocols attribute of the DefaultConfiguration object
*
* @param ctype Description of the Parameter
* @return The supportedProtocols value
*/
public String[] getSupportedProtocols(String ctype) {
Vector protocols = new Vector();
if (null == ctype || isJavaContent(ctype)) {
// add protocols supported by java
for (int p = 0; p < JAVA_PROTOCOLS.length; p++) {
if (null == ctype || allowed(ctype, JAVA_PROTOCOLS[p])) {
protocols.addElement(JAVA_PROTOCOLS[p]);
}
}
}
// add protocols supported by javacall
int hList = nListProtocolsOpen(ctype);
if (0 != hList) {
String protocol;
while (null != (protocol = nListProtocolsNext(hList))) {
if ("memory".equals(protocol)) {
// if javacall supports this ctype via memory streaming,
// add all protocols supported by java
for (int p = 0; p < JAVA_PROTOCOLS.length; p++) {
if (null==ctype || allowed(ctype, JAVA_PROTOCOLS[p])) {
addIfNotExists(protocols, JAVA_PROTOCOLS[p]);
}
}
} else {
addIfNotExists(protocols, protocol);
}
}
nListProtocolsClose(hList);
}
String[] ret = new String[protocols.size()];
protocols.copyInto(ret);
return ret;
}
public boolean isRadioSupported()
{
return nIsRadioSupported();
}
private native boolean nIsRadioSupported();
/**
* Hepler function adds string s to vector v if it's not already there
*/
private static void addIfNotExists(Vector v, String s) {
if (-1 == v.indexOf( s )) {
v.addElement(s);
}
}
/**
* Get content type helper function
*/
public static String getContentType(String locator) {
if (locator != null) {
if (locator.equals(Manager.TONE_DEVICE_LOCATOR)) {
return DefaultConfiguration.MIME_AUDIO_TONE;
} else if (locator.equals(Manager.MIDI_DEVICE_LOCATOR)) {
return DefaultConfiguration.MIME_AUDIO_MIDI;
} else if (locator.equals(Configuration.AUDIO_CAPTURE_LOCATOR)) {
return DefaultConfiguration.MIME_AUDIO_WAV;
} else if (locator.equals(Configuration.VIDEO_CAPTURE_LOCATOR)) {
return DefaultConfiguration.MIME_IMAGE_PNG;
}
}
return "";
}
public ImageAccess getImageAccessor() {
return imageAccessor;
}
/**
* Gets the video renderer.
*
* @return The video renderer
*/
public VideoRenderer getVideoRenderer(BasicPlayer player) {
// workaround for demo only
return ModelVideoRenderer.getVideoRenderer(player);
//return new MIDPVideoRenderer(player);
}
/**
* Gets the tonePlayer attribute of the DefaultConfiguration object
*
* @return The tonePlayer value
*/
public TonePlayer getTonePlayer() {
return new NativeTonePlayer();
}
//public MIDIRenderer getMIDIRenderer()
//{
// return null;
//}
public String getProperty(String key) {
String value = (String) properties.get(key);
return value;
}
public void setProperty(String key, String value) {
properties.put(key, value);
}
private Object createInstanceOf(String propertyName) {
try {
String propertyValue = getProperty(propertyName);
Class propertyClass = Class.forName(propertyValue);
Object propertyInstance = propertyClass.newInstance();
return propertyInstance;
} catch (Exception e) {
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,116 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.Control;
public class DirectCamera extends DirectPlayer
{
private Control _cameraControl;
private Control _exposureControl;
private Control _flashControl;
private Control _focusControl;
private Control _snapshotControl;
private Control _zoomControl;
private Control _imgFmtControl;
protected static final String JSR234_CAMERA_PACKAGE_NAME =
"javax.microedition.amms.control.camera.";
/**
* It does not need data source
*/
public DirectCamera() {
}
protected Control doGetControl(String type) {
Control c = super.doGetControl(type);
if (c == null) {
if (type.startsWith(JSR234_CAMERA_PACKAGE_NAME)) {
String camType = type.substring(
JSR234_CAMERA_PACKAGE_NAME.length() );
if( camType.equals( "CameraControl" ) )
{
if( null == _cameraControl )
{
_cameraControl =
Jsr234Proxy.getInstance().getCameraControl( this );
}
return _cameraControl;
} else if( camType.equals( "ExposureControl" ) )
{
if( null == _exposureControl )
{
_exposureControl =
Jsr234Proxy.getInstance().getExposureControl( this );
}
return _exposureControl;
} else if ( camType.equals( "FlashControl" ) )
{
if( null == _flashControl )
{
_flashControl =
Jsr234Proxy.getInstance().getFlashControl( this );
}
return _flashControl;
} else if( camType.equals( "FocusControl" ) )
{
if( null == _focusControl )
{
_focusControl =
Jsr234Proxy.getInstance().getFocusControl( this );
}
return _focusControl;
} else if( camType.equals( "SnapshotControl" ) )
{
if( null == _snapshotControl )
{
_snapshotControl =
Jsr234Proxy.getInstance().getSnapshotControl( this );
}
return _snapshotControl;
} else if( camType.equals( "ZoomControl" ) )
{
if( null == _zoomControl )
{
_zoomControl =
Jsr234Proxy.getInstance().getZoomControl( this );
}
return _zoomControl;
}
} else if (type.equals(
"javax.microedition.amms.control.ImageFormatControl" )) {
if( null == _imgFmtControl )
{
_imgFmtControl =
Jsr234Proxy.getInstance().getImageFormatControl( this );
}
return _imgFmtControl;
}
}
return c;
}
}

Просмотреть файл

@ -0,0 +1,32 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
public interface DirectControls {
void playerStarted();
void playerStopped();
void playerClosed();
}

Просмотреть файл

@ -0,0 +1,463 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
/**
* Implement all of MIDI related controls like :
* MIDIControl, RateControl, PitchControl, TempoControl
*/
class DirectMIDIControl implements DirectControls {
// MIDIControl
private native void nSetChannelVolume(int handle, int channel, int volume);
private native int nGetChannelVolume(int handle, int channel);
private native void nSetProgram(int handle, int channel, int bank, int program);
private native void nShortMidiEvent(int handle, int type, int data1, int data2);
private native int nLongMidiEvent(int handle, byte[] data, int offset, int length);
// RateControl
private native int nGetMaxRate(int handle);
private native int nGetMinRate(int handle);
private native int nSetRate(int handle, int rate);
private native int nGetRate(int handle);
// PitchControl
private native int nGetMaxPitch(int handle);
private native int nGetMinPitch(int handle);
private native int nSetPitch(int handle, int pitch);
private native int nGetPitch(int handle);
// TempoControl
private native int nGetTempo(int handle);
private native int nSetTempo(int handle, int tempo);
// Bank Query
private native boolean nIsBankQuerySupported(int handle);
private native int nGetBankList(int handle, boolean custom, int[] list);
private native int nGetKeyName(int handle, int bank, int prog, int key, byte[] keyname);
private native int nGetProgramName(int handle, int bank, int prog, byte[] progname);
private native int nGetProgramList(int handle, int bank, int[] proglist);
private native int nGetProgram(int handle, int channel, int[] program);
DirectMIDIControl(DirectPlayer p) {
_player = p;
}
// Private //////////////////////////////////////////////////////////
private void checkState() {
if (_player.state < Player.PREFETCHED) {
throw new IllegalStateException("Not prefetched");
}
}
private void checkChannel(int channel) {
if (channel < 0 || channel > 15) {
throw new IllegalArgumentException("Channel is out of range");
}
}
private void checkVolume(int volume) {
if (volume < 0 || volume > 127) {
throw new IllegalArgumentException("Volume is out of range");
}
}
private void checkType(int type) {
if (type < 0x80 || type > 0xFF || type == 0xF0 || type == 0xF7) {
throw new IllegalArgumentException("Type is out of range");
}
}
private void checkData(int data) {
if (data < 0 || data > 127) {
throw new IllegalArgumentException("Data is out of range");
}
}
private void checkLongMidiEvent(byte[] data, int offset, int length) {
if (data == null) {
throw new IllegalArgumentException("Data is null for long MIDI event ");
} else if ((offset >= data.length) || (offset < 0)) {
if (data.length != 0) {
throw new IllegalArgumentException("Invalid offset for long MIDI event");
}
} else if ((length > data.length) || (length < 0)) {
throw new IllegalArgumentException("Length is out of range for long MIDI event");
}
}
private void checkProgram(int program) {
if (program < 0 || program > 127) {
throw new IllegalArgumentException("Program is out of range");
}
}
private void checkBank(int bank) {
if (bank < 0 || bank > 16383) {
throw new IllegalArgumentException("Bank is out of range");
}
}
// DirectControls ////////////////////////////////////////////////////
public synchronized void playerStarted() {
if (_cachedRate != -1) {
// NOTE - MMAPI SPEC is not clear about this
// set cached rate at enter playing state
nSetRate(_player.hNative, _cachedRate);
_cachedRate = -1;
}
}
public synchronized void playerStopped() {
}
public synchronized void playerClosed() {
_player = null;
}
// MIDIControl ///////////////////////////////////////////////////////
private MIDIControlImpl midiCtl = null;
public synchronized MIDIControl getMIDIControl() {
if (null == midiCtl) {
midiCtl = new MIDIControlImpl();
}
return midiCtl;
}
class MIDIControlImpl implements MIDIControl {
public synchronized boolean isBankQuerySupported() {
return nIsBankQuerySupported(_player.hNative);
}
public synchronized int[] getProgram(int channel) throws MediaException {
checkState();
checkChannel(channel);
int[] p = new int[2];
int len = nGetProgram(_player.hNative, channel, p);
if(len < 0) throw new MediaException("GetProgram failure");
return p;
}
public synchronized int[] getBankList(boolean custom) throws MediaException {
checkState();
int[] bl1 = new int[20];
int len = nGetBankList(_player.hNative, custom, bl1);
if(len < 0) throw new MediaException("BankList failure");
int[] bl2 = new int[len];
for(int i=0; i<len; i++)
bl2[i] = bl1[i];
return bl2;
}
public synchronized String getKeyName(int bank, int prog, int key) throws MediaException {
checkState();
checkBank(bank);
checkProgram(prog);
if((key < 0) || (key > 127))
throw new IllegalArgumentException("key out of range");
byte[] str = new byte[64];
int len = nGetKeyName(_player.hNative, bank, prog, key, str);
if(len < 0) throw new MediaException("KeyName failure");
return new String(str, 0, len);
}
public synchronized String getProgramName(int bank, int prog) throws MediaException {
checkState();
checkBank(bank);
checkProgram(prog);
byte[] str = new byte[64];
int len = nGetProgramName(_player.hNative, bank, prog, str);
if(len < 0) throw new MediaException("ProgramName failure");
return new String(str, 0, len);
}
public synchronized int[] getProgramList(int bank) throws MediaException {
checkState();
checkBank(bank);
int[] pl1 = new int[200];
int len = nGetProgramList(_player.hNative, bank, pl1);
if(len < 0) throw new MediaException("ProgramList failure");
int[] pl2 = new int[len];
for(int i=0; i<len; i++)
pl2[i] = pl1[i];
return pl2;
}
public synchronized void setChannelVolume(int channel, int volume) {
checkState();
checkChannel(channel);
checkVolume(volume);
if (_player != null && _player.hNative != 0) {
nSetChannelVolume(_player.hNative, channel, volume);
}
}
public synchronized int getChannelVolume(int channel) {
checkState();
checkChannel(channel);
if (_player != null && _player.hNative != 0) {
return nGetChannelVolume(_player.hNative, channel);
} else {
return -1;
}
}
public synchronized void setProgram(int channel, int bank, int program) {
checkState();
checkChannel(channel);
if(bank != -1) checkBank(bank);
checkProgram(program);
if (_player != null && _player.hNative != 0) {
nSetProgram(_player.hNative, channel, bank, program);
}
}
public synchronized void shortMidiEvent(int type, int data1, int data2) {
checkState();
checkType(type);
checkData(data1);
checkData(data2);
if (_player != null && _player.hNative != 0) {
nShortMidiEvent(_player.hNative, type, data1, data2);
}
}
public synchronized int longMidiEvent(byte[] data, int offset, int length) {
checkState();
checkLongMidiEvent(data, offset, length);
if (_player != null && _player.hNative != 0) {
return nLongMidiEvent(_player.hNative, data, offset, length);
} else {
return -1;
}
}
}
// RateControl ///////////////////////////////////////////////////////
private RateControlImpl rateCtl = null;
public synchronized RateControl getRateControl() {
if (null == rateCtl) {
rateCtl = new RateControlImpl();
}
return rateCtl;
}
class RateControlImpl implements RateControl {
//
// SPEC:
// If the Player is already started, setRate will immediately take effect.
// Q - How about the other case?
//
public synchronized int setRate(int millirate) {
if (_player == null)
return 0;
int max = getMaxRate();
int min = getMinRate();
if (millirate > max) {
millirate = max;
} else if (millirate < min) {
millirate = min;
}
recalculateStopTime();
if (_player.state >= Player.STARTED) {
_cachedRate = -1;
return nSetRate(_player.hNative, millirate);
} else {
_cachedRate = millirate;
return millirate;
}
}
public synchronized int getRate() {
if (_player != null && _player.hNative != 0) {
return _cachedRate == -1 ? nGetRate(_player.hNative) : _cachedRate;
} else {
return 0;
}
}
public synchronized int getMaxRate() {
if (_player != null && _player.hNative != 0) {
return nGetMaxRate(_player.hNative);
} else {
return 0;
}
}
public synchronized int getMinRate() {
if (_player != null && _player.hNative != 0) {
return nGetMinRate(_player.hNative);
} else {
return 0;
}
}
}
// PitchControl //////////////////////////////////////////////////////
private PitchControlImpl pitchCtl = null;
public synchronized PitchControl getPitchControl() {
if (null == pitchCtl) {
pitchCtl = new PitchControlImpl();
}
return pitchCtl;
}
class PitchControlImpl implements PitchControl {
public synchronized int setPitch(int millisemitones) {
int max = getMaxPitch();
int min = getMinPitch();
if (millisemitones > max) {
millisemitones = max;
} else if (millisemitones < min) {
millisemitones = min;
}
if (_player != null && _player.hNative != 0) {
return nSetPitch(_player.hNative, millisemitones);
} else {
return 0;
}
}
public synchronized int getPitch() {
if (_player != null && _player.hNative != 0) {
return nGetPitch(_player.hNative);
} else {
return 0;
}
}
public synchronized int getMaxPitch() {
if (_player != null && _player.hNative != 0) {
return nGetMaxPitch(_player.hNative);
} else {
return 0;
}
}
public synchronized int getMinPitch() {
if (_player != null && _player.hNative != 0) {
return nGetMinPitch(_player.hNative);
} else {
return 0;
}
}
}
// TempoControl //////////////////////////////////////////////////////
private TempoControlImpl tempoCtl = null;
public synchronized TempoControl getTempoControl() {
if (null == tempoCtl) {
tempoCtl = new TempoControlImpl();
}
return tempoCtl;
}
class TempoControlImpl extends RateControlImpl implements TempoControl {
public synchronized int setTempo(int millitempo) {
if (millitempo < 0) {
millitempo = 0;
}
recalculateStopTime();
if (_player != null && _player.hNative != 0) {
return nSetTempo(_player.hNative, millitempo);
} else {
return 0;
}
}
public synchronized int getTempo() {
if (_player != null && _player.hNative != 0) {
return nGetTempo(_player.hNative);
} else {
return 0;
}
}
}
//////////////////////////////////////////////////////////////////////
private void recalculateStopTime() {
if (_player != null) {
long stopTime = _player.getStopTime();
if (stopTime != StopTimeControl.RESET) {
_player.setStopTime(StopTimeControl.RESET);
_player.setStopTime(stopTime);
}
}
}
//////////////////////////////////////////////////////////////////////
private DirectPlayer _player;
private int _cachedRate = -1;
}

Просмотреть файл

@ -0,0 +1,105 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.control.MetaDataControl;
import java.util.Vector;
public class DirectMetaData implements MetaDataControl {
private int hNative;
private Object keysLock = new Object();
private String [] keys;
private native int nGetKeyCount(int hNative);
private native String nGetKey(int hNative, int index);
private native String nGetKeyValue(int hNative, String key);
private void updateKeys() {
Vector vKeys = new Vector( 5 );
int nKeys = ( hNative != 0 ) ? nGetKeyCount( hNative ) : 0;
boolean author_key_found = false;
boolean title_key_found = false;
for( int i = 0; i < nKeys; i++ ) {
String key = nGetKey( hNative, i );
vKeys.addElement( key );
if( AUTHOR_KEY.equals( key ) ) author_key_found = true;
if( TITLE_KEY.equals( key ) ) title_key_found = true;
}
if( !author_key_found ) vKeys.addElement( AUTHOR_KEY );
if( !title_key_found ) vKeys.addElement( TITLE_KEY );
nKeys = vKeys.size();
synchronized( keysLock ) {
if( keys == null || nKeys != keys.length ) {
keys = new String[ nKeys ];
}
for( int i = 0; i < nKeys; i++ ) {
keys[ i ] = (String)( vKeys.elementAt( i ) );
}
}
}
DirectMetaData(int hNative) {
this.hNative = hNative;
}
void playerClosed() {
hNative = 0;
keys = null;
}
public String[] getKeys() {
updateKeys();
return keys;
}
public String getKeyValue(String key) {
if (key == null) {
throw new IllegalArgumentException("Key is null");
}
updateKeys();
synchronized( keysLock ) {
for( int i = 0; i < keys.length; i++ ) {
if( key.equals( keys[ i ] ) ) {
String s = nGetKeyValue( hNative, key );
if( null == s ) {
if( AUTHOR_KEY.equals( key ) || TITLE_KEY.equals( key ) ) {
s = "Unknown";
}
}
return s;
}
}
}
throw new IllegalArgumentException("Key is invalid");
}
}

Просмотреть файл

@ -0,0 +1,986 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
/*
* - Conditional Compile Flags -
*
* ENABLE_MULTIPLE_ISOLATES : MVM mode ?
* RECORD : Support Recording ?
*/
package com.sun.mmedia;
import java.io.IOException;
import java.util.*;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
import com.sun.mmedia.DefaultConfiguration;
import com.sun.mmedia.DirectVolume;
import com.sun.mmedia.DirectMetaData;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.MediaException;
import javax.microedition.media.Control;
import com.sun.mmedia.Configuration;
import com.sun.mmedia.protocol.BasicDS;
import javax.microedition.media.control.StopTimeControl;
// #ifdef RECORD [
import com.sun.mmedia.DirectRecord;
// #endif ]
/**
* Media direct player base class
* This class depends on native library to handle media data
*/
public class DirectPlayer extends BasicPlayer implements VideoSource
// #ifdef ENABLE_MULTIPLE_ISOLATES [
, MediaEventConsumer
// #endif ]
{
// Temp buffer shared by all of Player from the same isolate
private static byte[] buffer;
// Package variables
DirectVolume dVolumeControl;
DirectMetaData dMetaDataControl;
private long remained; // remained content length
private Timer stopTimer; // To support StopTimeControl
private static final long STOP_TIME_ADVANCE = 100; // ms
// #ifdef RECORD [
private DirectRecord recordControl = null;
// #endif ]
private DirectMIDIControl midiControl;
private Control tunerControl;
private Control rdsControl;
// #ifdef ENABLE_MULTIPLE_ISOLATES [
// Tunnel between media and MIDP
private static MediaTunnel mediaTunnel;
private int mvmOption = -1;
// #endif ]
private boolean isStreaming = false;
private boolean isFirstStart = true;
protected boolean wholeDataDownloaded = false;
// this field will be checked in the native finalizer
private boolean hasTakenRadioAccess = false;
private DirectVideo videoControl = null;
private Object snapshotLock = new Object();
// Native functions /////////////////////////////////////////////////
// Terminate native library
protected native int nTerm(int handle);
// Get Content Type
protected native String nGetContentType(int handle);
// Access to Radio Tuner for a Java Player is exclusive.
// Acquire it or return false if it is not available
private native boolean nAcquireRadioAccess();
// Device is available?
protected native boolean nAcquireDevice(int handle);
// Relase device reference
protected native void nReleaseDevice(int handle);
// Access to Radio Tuner for a Java Player is exclusive. Release it
private native void nReleaseRadioAccess();
// Clear buffered data
protected native boolean nFlushBuffer(int handle);
// Start playing
protected native boolean nStart(int handle);
// Stop playing
protected native boolean nStop(int handle);
// Get current media time as ms
protected native int nGetMediaTime(int handle);
// Set media time as ms
protected native int nSetMediaTime(int handle, long ms);
// Get total duration of media data
protected native int nGetDuration(int handle);
// Pause
protected native boolean nPause(int handle);
// Resume
protected native boolean nResume(int handle);
// Need buffering from Java side?
protected native boolean nIsNeedBuffering(int handle);
// Switch to foreground
private native boolean nSwitchToForeground(int hNative, int options);
// Switch to background
private native boolean nSwitchToBackground(int hNative, int options);
// #ifdef ENABLE_CDC [
protected native void finalize();
// #else ][
private native void finalize();
// #endif ]
// Ask for PcmAudio support
private native boolean nPcmAudioPlayback(int hNative);
// Start Prefetch of Native Player
protected native boolean nPrefetch(int hNative);
// Is Control supported by native or not
protected static native boolean nIsFramePositioningControlSupported(int hNative);
protected static native boolean nIsMetaDataControlSupported(int hNative);
protected static native boolean nIsMIDIControlSupported(int hNative);
protected static native boolean nIsPitchControlSupported(int hNative);
protected static native boolean nIsRateControlSupported(int hNative);
protected static native boolean nIsRecordControlSupported(int hNative);
protected static native boolean nIsStopTimeControlSupported(int hNative);
protected static native boolean nIsTempoControlSupported(int hNative);
protected static native boolean nIsVideoControlSupported(int hNative);
protected static native boolean nIsToneControlSupported(int hNative);
protected static native boolean nIsVolumeControlSupported(int hNative);
// -----------------------------
// Video related native methods
// -----------------------------
// Get video width
protected native int nGetWidth(int handle);
// Get video height
protected native int nGetHeight(int handle);
// Set display location of video
protected native boolean nSetLocation(int handle, int x, int y, int w, int h);
// Get snapshot
protected native void nStartSnapshot( int handle, String imageType );
protected native byte[] nGetSnapshotData( int handle );
// Set fullscreen
protected native boolean nSetFullScreenMode(int handle, boolean fullscreen);
// Set visible
protected native boolean nSetVisible(int handle, boolean visible);
// Turn on or off color key
private native boolean nSetColorKey(int handle, boolean on, int colorKey);
// Member functions /////////////////////////////////////////////////
/**
* Constructor
*/
public DirectPlayer()
{
super();
// #ifdef ENABLE_MULTIPLE_ISOLATES [
// Get media tunnerl singleton instance
mediaTunnel = MediaTunnel.getInstance();
// #endif ]
}
public int getNativeHandle()
{
return hNative;
}
/**
* StopTimeControl implementation of DirectPlayer
*
* @param time the time in microseconds at which the <code>Player</code>
* should stop.
*/
protected void doSetStopTime(long time) {
if (time == StopTimeControl.RESET && stopTimer != null) {
stopTimer.cancel();
stopTimer = null;
} else if (time != StopTimeControl.RESET && state == STARTED) {
long currentTime = doGetMediaTime();
if (time >= currentTime) {
scheduleStopTimer(time);
}
}
}
private boolean scheduleStopTimer(long time) {
long tempo = 100000, rate = 100000;
boolean isRateControlSupported = false;
boolean isTempoControlSupported = false;
boolean stopped = false;
long duration = doGetDuration();
long currentTime = doGetMediaTime();
if (currentTime == TIME_UNKNOWN) {
return false;
}
if (hNative != 0) {
isRateControlSupported = nIsRateControlSupported(hNative);
isTempoControlSupported = nIsTempoControlSupported(hNative);
}
if (midiControl == null &&
(isRateControlSupported || isTempoControlSupported)) {
midiControl = new DirectMIDIControl(this);
}
if (midiControl != null) {
if (isRateControlSupported) {
rate = midiControl.getRateControl().getRate();
}
if (isTempoControlSupported) {
tempo = midiControl.getTempoControl().getTempo();
}
}
if (stopTimer != null) {
stopTimer.cancel();
stopTimer = null;
}
long scheduleTime = (time - currentTime - STOP_TIME_ADVANCE) / 1000 * 100000 * 100000 / (rate * tempo);
if (scheduleTime <= 0) {
synchronized (this) {
try {
doPreStop();
doStop();
} catch (MediaException e) {
Logging.report(Logging.ERROR, LogChannels.LC_MMAPI,
"Exception during stop by stop timer");
}
}
satev();
stopped = true;
} else {
stopTimer = new Timer();
stopTimer.schedule(new StopTimeController(), scheduleTime);
}
return stopped;
}
/**
* Read header information from media data and determine media Format
*
* @exception MediaException Description of the Exception
*/
protected void doRealize() throws MediaException {
// #ifdef ENABLE_MULTIPLE_ISOLATES [
// Add to media tunnel as event consumer
// and, let native layer knows about their situation
synchronized(mediaTunnel) {
if (mvmOption == -1) {
mvmOption = mediaTunnel.isBackPlayable() ? mediaTunnel.PLAYABLE_FROM_BACKGROUND : 0;
}
if (true == mediaTunnel.registerMediaEventConsumer(this)) {
nSwitchToForeground(hNative, mvmOption);
} else {
nSwitchToBackground(hNative, mvmOption);
}
}
// #endif ]
// Is straming source?
isStreaming = isStreamingSource();
if( isVideoPlayer() )
{
videoControl = new DirectVideo( this, nGetWidth( hNative ),
nGetHeight( hNative ) );
}
}
private boolean isRadioPlayer()
{
return ( null != source.getLocator() &&
source.getLocator().startsWith(
DefaultConfiguration.RADIO_CAPTURE_LOCATOR ) );
}
private void prefetchData() throws MediaException
{
/* prefetch native player */
if (!nPrefetch(hNative)) {
throw new MediaException("Can not prefetch");
}
if (!handledByDevice) {
/* predownload media data to fill native buffers */
if (mediaDownload != null) {
try {
mediaDownload.fgDownload();
} catch (IOException ex) {
throw new MediaException("Can not start media download thread : " + ex);
}
}
}
}
private void acquireDevice() throws MediaException
{
if( isRadioPlayer() )
{
if( !nAcquireRadioAccess() )
{
throw new MediaException( "Radio Tuner is already used " +
"by a Java Player" );
}
hasTakenRadioAccess = true;
}
if(!nAcquireDevice(hNative)) {
releaseRadioAccess();
throw new MediaException("Can not acquire device");
}
}
/**
* 1. Get all data from stream and buffering it to native library
*
* @exception MediaException Description of the Exception
*/
protected void doPrefetch() throws MediaException {
prefetchData();
acquireDevice();
if (nPcmAudioPlayback(hNative)) {
AudioTunnel.getInstance().start();
}
}
/**
* Overrides from BasicPlayer
*/
// #ifdef RECORD [
protected void doReceiveRSL()
{
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"[direct] received RSL");
}
if (recordControl != null) {
recordControl.recordSizeLimitReached();
}
}
// #endif ]
protected void doPostStart() {
if (dVolumeControl != null) {
dVolumeControl.setToThisPlayerLevel(); /* set to this player's volume level */
dVolumeControl.setToPlayerMute(); /* set to this player's mute state */
}
if (stopTime != StopTimeControl.RESET) {
if (scheduleStopTimer(stopTime)) { // Media stop-time has already passed
return;
}
}
// #ifdef RECORD [
if (recordControl != null) {
recordControl.playerStarted();
}
// #endif ]
if (midiControl != null) {
midiControl.playerStarted();
}
if (mediaDownload != null) {
try {
mediaDownload.bgDownload();
} catch(Exception ex) {
try {
stop();
} catch(MediaException mEx) {
}
}
}
}
/**
* Override method in BasicPlayer to do the actual starting of the
* <code>Player</code>
*
* @return <code>true</code> if player start was successful,
* <code>false</code> otherwise.
*/
protected boolean doStart() {
boolean ret = false;
if( null != videoControl )
{
videoControl.start();
}
if (isFirstStart || (0 == getMediaTime())) {
ret = nStart(hNative);
isFirstStart = false;
} else {
ret = nResume(hNative);
}
return ret;
}
protected void continueDownload() {
/* predownload media data to fill native buffers */
if (mediaDownload != null) {
mediaDownload.continueDownload();
}
}
/**
* Override method in BasicPlayer to get the media time
* of the <code>Player</code>
*
* @return The <code>Player</code>'s current media time.
*/
protected long doGetMediaTime() {
int ret = nGetMediaTime(hNative);
if (ret != Player.TIME_UNKNOWN) {
return (ret * 1000);
}
return ret;
}
/**
* Overrides from BasicPlayer (pre works for stop)
*/
protected void doPreStop() {
if (stopTimer != null) {
stopTimer.cancel();
stopTimer = null;
}
// #ifdef RECORD [
if (recordControl != null) {
recordControl.playerStopped();
}
// #endif ]
if (midiControl != null) {
midiControl.playerStopped();
}
}
/**
* Subclasses need to implement this to realize
* the <code>Player</code>.
*
* @exception MediaException Description of the Exception
*/
protected void doStop() throws MediaException {
if ( null != videoControl )
{
videoControl.stop();
}
if (false == nPause(hNative)) {
throw new MediaException("Player cannot be stopped");
}
}
private void releaseRadioAccess()
{
if( isRadioPlayer() )
{
nReleaseRadioAccess();
hasTakenRadioAccess = false;
}
}
/**
* Override method in BasicPlayer to deallocate
* the <code>Player</code>.
*/
protected void doDeallocate() {
// release device
if (nPcmAudioPlayback(hNative)) {
AudioTunnel.getInstance().stop();
}
releaseRadioAccess();
if (mediaDownload != null) {
mediaDownload.deallocate();
}
nReleaseDevice(hNative);
isFirstStart = true;
}
/**
* Override method in BasicPlayer to close
* the <code>Player</code>.
*/
protected void doClose() {
if( null != videoControl )
{
videoControl.close();
videoControl = null;
}
// #ifdef ENABLE_MULTIPLE_ISOLATES [
// Unregister from media tunnel
mediaTunnel.unregisterMediaEventConsumer(this);
// #endif ]
// #ifdef RECORD [
if (recordControl != null) {
recordControl.playerClosed();
recordControl = null;
}
// #endif ]
if (midiControl != null) {
midiControl.playerClosed();
midiControl = null;
}
if (dMetaDataControl != null) {
dMetaDataControl.playerClosed();
dMetaDataControl = null;
}
if (dVolumeControl != null) {
dVolumeControl.playerClosed();
dVolumeControl = null;
}
if (hNative != 0) {
if ( true == nIsNeedBuffering(hNative) ) {
nFlushBuffer(hNative);
}
nTerm(hNative);
hNative = 0;
}
}
/**
* Override method in BasicPlayer to set the media time
* of the <code>Player</code>.
*
* @param now The new media time in microseconds.
* @return The actual media time set in microseconds.
* @exception MediaException Thrown if the media time cannot be set.
*/
protected long doSetMediaTime(long now) throws MediaException {
if (now <= 0) now = 0;
long dur = doGetDuration();
if (TIME_UNKNOWN != dur && now > dur) now = dur;
int ret = nSetMediaTime(hNative, now/1000);
if (ret == -1) {
throw new MediaException("media time cannot be set");
}
return (ret * 1000);
}
/**
* Override method in BasicPlayer to get the duration
* of the <code>Player</code>.
*
* @return the duration in microseconds or <code>TIME_UNKNOWN</code>
*/
protected long doGetDuration() {
if (isCapturePlayer()) {
return Player.TIME_UNKNOWN;
} else if (isDevicePlayer() && !hasToneSequenceSet) {
return 0;
} else {
int ret = nGetDuration(hNative);
if (ret != Player.TIME_UNKNOWN) {
return (ret * 1000);
}
return ret;
}
}
/**
* The worker method to actually obtain the control.
*
* @param type the class name of the <code>Control</code>.
* @return <code>Control</code> for the class or interface
* name.
*/
protected Control doGetControl(String type) {
String prefix = "javax.microedition.media.control.";
String shortType = type;
if (type.startsWith(prefix)) {
shortType = type.substring(prefix.length());
}
if (shortType.equals(fpcName)) {
// if (nIsFramePositioningControlSupported(hNative)) {
// }
} else if (shortType.equals(mdcName)) {
if (nIsMetaDataControlSupported(hNative)) {
if (dMetaDataControl == null)
dMetaDataControl = new DirectMetaData(hNative);
return dMetaDataControl;
}
} else if (shortType.equals(micName)) {
if (nIsMIDIControlSupported(hNative)) {
if (midiControl == null)
midiControl = new DirectMIDIControl(this);
return midiControl.getMIDIControl();
}
} else if (shortType.equals(picName)) {
if (nIsPitchControlSupported(hNative)) {
if (midiControl == null)
midiControl = new DirectMIDIControl(this);
return midiControl.getPitchControl();
}
} else if (shortType.equals(racName)) {
if (nIsRateControlSupported(hNative)) {
if (midiControl == null)
midiControl = new DirectMIDIControl(this);
return midiControl.getRateControl();
}
} else if (shortType.equals(recName)) {
if (nIsRecordControlSupported(hNative)) {
if (recordControl == null) {
recordControl = new DirectRecord(this);
}
return recordControl;
}
} else if (shortType.equals(stcName)) {
if (!isCapturePlayer()) {
return this;
}
// if (nIsStopTimeControlSupported(hNative)) {
// }
} else if (shortType.equals(tecName)) {
if (nIsTempoControlSupported(hNative)) {
if (midiControl == null)
midiControl = new DirectMIDIControl(this);
return midiControl.getTempoControl();
}
} else if (shortType.equals(vicName)) {
// if (nIsVideoControlSupported(hNative)) {
// }
} else if (shortType.equals(tocName)) {
// if (nIsToneControlSupported(hNative)) {
// }
} else if (shortType.equals(vocName)) {
if (nIsVolumeControlSupported(hNative)) {
if (dVolumeControl == null) {
dVolumeControl = new DirectVolume(this, hNative);
}
return dVolumeControl;
}
}
if ( null != videoControl ) {
if (shortType.equals(vicName)) { // VideoControl
return videoControl;
} else if (shortType.equals(guiName)) { // GUIControl
return videoControl;
}
}
if ( isRadioPlayer() )
{
if( type.equals(
"javax.microedition.amms.control.tuner.RDSControl" ) )
{
if( null == rdsControl )
{
rdsControl =
Jsr234Proxy.getInstance().getRDSControl( this );
}
return rdsControl;
} else if (type.equals(
"javax.microedition.amms.control.tuner.TunerControl" )) {
if (null == tunerControl) {
tunerControl =
Jsr234Proxy.getInstance().getTunerControl( this );
}
return tunerControl;
}
}
return null;
}
/**
* Is streaming source?
*/
private boolean isStreamingSource() {
String theProtocol = null;
if (source != null) {
String locStr = source.getLocator();
if (locStr != null) {
locStr = locStr.toLowerCase();
int idx = locStr.indexOf(':');
if (idx != -1) {
theProtocol = locStr.substring(0, idx);
}
}
}
if (theProtocol != null && theProtocol.equals("rtsp")) {
return true;
}
return false;
}
/**
* Make additional processing of the first block (header)
*
* @param Source buffer
* @param Length of the source buffer
*/
private void processHeader(byte[] buffer, int length) {
if (source != null) {
// Additional check to differentiate sp-midi and midi
String mimeType = getContentType();
BasicDS ds = (BasicDS)source;
if ((ds != null) && mimeType.equals(Configuration.MIME_AUDIO_MIDI)) {
final int MAX_SP_MIDI_SEARCH = 512;
int maxSearch = length - 5;
if (maxSearch > MAX_SP_MIDI_SEARCH)
maxSearch = MAX_SP_MIDI_SEARCH;
for (int i = 0; i < maxSearch; i++)
if ((buffer[i] == (byte)0xF0) &&
(buffer[i + 2] == (byte)0x7F) &&
(buffer[i + 4] == (byte)0x0B) &&
(buffer[i + 5] == (byte)0x01)) {
ds.setContentType(Configuration.MIME_AUDIO_SP_MIDI);
return;
}
}
}
}
public String getContentType()
{
String ctype = super.getContentType();
if( null == ctype ) {
ctype = nGetContentType(hNative);
if( null != ctype ) {
int s_pos = ctype.indexOf(' ');
if (-1 != s_pos) {
ctype = ctype.substring(0, s_pos);
}
}
if (ctype == null && source != null) {
ctype = DefaultConfiguration.getContentType(source.getLocator());
}
}
return ctype;
}
private boolean isVideoPlayer()
{
return nIsVideoControlSupported(hNative);
}
public void setSnapshotQuality( int quality )
{
}
/**
* Check for the multimedia snapshot permission.
*
* @exception SecurityException if the permission is not
* allowed by this token
*/
public void checkSnapshotPermission() {
try {
PermissionAccessor.checkPermissions( getLocator(), PermissionAccessor.PERMISSION_SNAPSHOT );
} catch( InterruptedException e ) {
throw new SecurityException( "Interrupted while trying to ask the user permission" );
}
}
// -------------------------------------------------
// The interface VideoSource method implementations
// -------------------------------------------------
// Set display location of video
public boolean setVideoLocation(int x, int y, int w, int h)
{
return nSetLocation( hNative, x, y, w, h );
}
private boolean isWaitingForSnapshot;
// Get snapshot
public synchronized byte[] getVideoSnapshot(String imageType) throws MediaException
{
byte [] ret = null;
checkSnapshotPermission();
try {
synchronized ( snapshotLock )
{
nStartSnapshot( hNative, imageType );
isWaitingForSnapshot = true;
snapshotLock.wait( 10000 );
if( isWaitingForSnapshot )
{
isWaitingForSnapshot = false;
throw new MediaException(
"Timed out while making a Camera Snapshot" );
}
ret = nGetSnapshotData( hNative );
}
}
catch ( InterruptedException ie )
{
throw new MediaException(
"Camera Snapshot was interrupted by user: " + ie.toString() );
}
return ret;
}
void notifySnapshotFinished()
{
synchronized( snapshotLock )
{
if( isWaitingForSnapshot )
{
snapshotLock.notify();
isWaitingForSnapshot = false;
}
}
}
// Set fullscreen
public boolean setVideoFullScreen( boolean fullscreen)
{
return nSetFullScreenMode( hNative, fullscreen );
}
// Set visible
public boolean setVideoVisible( boolean visible)
{
return nSetVisible( hNative, visible );
}
private boolean colorKeyOn = false;
// Turn on or off color key
public boolean setColorKey(boolean on, int colorKey)
{
if (colorKeyOn != on) {
colorKeyOn = on;
return nSetColorKey( hNative, on, colorKey );
}
return true;
}
// Notifies that the Display Size was changed
public void notifyDisplaySizeChange()
{
sendEvent(PlayerListener.SIZE_CHANGED, videoControl);
}
/**
* Inner class that support StopTimeControl
*/
class StopTimeController extends TimerTask {
public void run() {
synchronized(DirectPlayer.this) {
/*
try {
doSetMediaTime(stopTime); // IMPL NOTE - Force set to stop time
} catch(MediaException e) {
Logging.report(Logging.ERROR, LogChannels.LC_MMAPI,
"Exception during set time by stop timer");
}
*/
/* IMPL_NOTE: Timer used to execute this code uses system time,
which is not exactly in sync with media time, both
may change in relatively large increments. That's
why we must wait here for media time to actually pass
stop-time point.
*/
long mt = doGetMediaTime();
long dur = doGetDuration();
while ((mt != -1) &&
(mt < stopTime) && (dur <= 0 || mt < dur)) {
try {
java.lang.Thread.sleep( 10 );
} catch( InterruptedException e ) {
// just skip it
}
mt = doGetMediaTime();
}
try {
doPreStop();
doStop();
} catch (MediaException e) {
Logging.report(Logging.ERROR, LogChannels.LC_MMAPI,
"Exception during stop by stop timer");
}
}
satev();
}
}
// #ifdef ENABLE_MULTIPLE_ISOLATES [
// MVM Resource Handling Porting Layer
////////////////////////////////////////////////////////////////////
/**
* Called by event delivery when MIDlet controller (in AMS Isolate)
* notifies MIDlet and its display that there is a change in its foreground status
*/
public void handleMediaForegroundNotify() {
if (mvmOption == -1)
mvmOption = mediaTunnel.isBackPlayable() ? mediaTunnel.PLAYABLE_FROM_BACKGROUND : 0;
if (hNative != 0)
nSwitchToForeground(hNative, mvmOption);
}
/**
* Called by event delivery when MIDlet controller (in AMS Isolate)
* notifies MIDlet and its display that there is a change in its foreground status
*/
public void handleMediaBackgroundNotify() {
if (mvmOption == -1)
mvmOption = mediaTunnel.isBackPlayable() ? mediaTunnel.PLAYABLE_FROM_BACKGROUND : 0;
if (hNative != 0)
nSwitchToBackground(hNative, mvmOption);
}
// #endif ]
}

Просмотреть файл

@ -0,0 +1,563 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import java.io.*;
import javax.microedition.media.*;
import javax.microedition.media.MediaException.*;
import javax.microedition.media.control.*;
import javax.microedition.io.*;
// #ifdef USE_FILE_CONNECTION [
import javax.microedition.io.file.*;
// #endif ]
import com.sun.mmedia.*;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
/**
* RecordControl implementor
* It uses native API layer to support recording
*/
public final class DirectRecord implements RecordControl, DirectControls {
// KNI native functions
private native int nSetLocator(int handle, String locator);
private native int nStart(int handle);
private native int nStop(int handle);
private native int nPause(int handle);
private native int nCommit(int handle);
private native int nReset(int handle);
private native int nClose(int handle);
private native int nSetSizeLimit(int handle, int size);
private native int nGetRecordedSize(int handle);
private native int nGetRecordedData(int handle, int offset, int size, byte[] buffer);
private native String nGetRecordedType(int handle);
// #ifdef ENABLE_CDC [
protected native void finalize();
// #else ][
private native void finalize();
// #endif ]
public DirectRecord(DirectPlayer player) {
this.player = player;
}
/**
* Set record stream
*/
public synchronized void setRecordStream(OutputStream stream) {
if (recordRequested)
throw new IllegalStateException("startRecord has been called and commit has not been called");
if (locator != null)
throw new IllegalStateException("setRecordLocation has been called and commit has not been called");
if (stream == null)
throw new IllegalArgumentException("null stream specified");
// Check for the record permissions.
checkPermission();
recordingByNative = false;
this.locator = null;
this.stream = stream;
extStream = true;
}
/**
* Set record location
*/
public synchronized void setRecordLocation(String locator) throws IOException, MediaException {
if (player == null)
return;
if (recordRequested)
throw new IllegalStateException("startRecord has been called and commit has not been called");
if (stream != null)
throw new IllegalStateException("setRecordStream has been called and commit has not been called");
if (locator == null)
throw new IllegalArgumentException("null locator specified");
// Check about the string. Is this URL format?
int colonIndex = locator.indexOf(":");
if (colonIndex < 0) {
throw new MediaException("Invalid locator " + locator);
}
// Check for record permissions
checkPermission();
// Query if native function can handle this locator
int ret = nSetLocator(player.hNative, locator);
if (-1 == ret) {
throw new MediaException("setRecordLocation: invalid locator " + locator);
} else if (0 == ret) {
// #ifdef USE_FILE_CONNECTION [
if (!(locator.startsWith("file:") || locator.startsWith("http:") || locator.startsWith("https:"))) {
throw new MediaException("Unsupported protocol");
}
// #else ][
if (!(locator.startsWith("http:") || locator.startsWith("https:"))) {
throw new MediaException("Unsupported protocol");
}
// #endif
if (locator.startsWith("http:")) {
try {
httpCon = (HttpConnection)Connector.open(locator);
} catch (IllegalArgumentException e) {
throw new MediaException(e.getMessage());
} catch (ConnectionNotFoundException e) {
throw new IOException(e.getMessage());
}
httpCon.setRequestMethod(HttpConnection.POST);
httpCon.setRequestProperty("Content-Type", "audio/wav");
stream = httpCon.openOutputStream();
extStream = false;
} else if (locator.startsWith("https:")) {
try {
httpsCon = (HttpsConnection)Connector.open(locator);
} catch (IllegalArgumentException e) {
throw new MediaException(e.getMessage());
} catch (ConnectionNotFoundException e) {
throw new IOException(e.getMessage());
}
httpsCon.setRequestMethod(HttpConnection.POST);
httpsCon.setRequestProperty("Content-Type", "audio/wav");
stream = httpsCon.openOutputStream();
extStream = false;
}
// #ifdef USE_FILE_CONNECTION [
if (locator.startsWith("file:")) {
String fileName = locator.substring(colonIndex + 1);
if (fileName.length() <= 0) // Note: length can never be less than zero
throw new MediaException("setRecordLocation: invalid locator " + locator);
try {
fileCon = (FileConnection) Connector.open(locator, Connector.READ_WRITE);
} catch (IllegalArgumentException e) {
throw new MediaException(e.getMessage());
} catch (ConnectionNotFoundException e) {
throw new IOException(e.getMessage());
}
if (fileCon.exists()) {
// Truncate the file if it exists
fileCon.truncate(0);
} else {
fileCon.create();
}
// Output stream is now file by using FC
stream = fileCon.openOutputStream();
extStream = false;
}
// #endif ]
recordingByNative = false;
} else {
stream = null;
recordingByNative = true;
}
this.locator = locator;
}
/**
* Start recording
*/
public synchronized void startRecord() throws IllegalStateException {
if ((locator == null) && (stream == null)) {
throw new
IllegalStateException("Should call setRecordLocation or setRecordStream before calling startRecord");
}
if (recordRequested == true || player == null) {
return;
}
recordRequested = true;
if (player.getState() == Player.STARTED) {
if (1 == nStart(player.hNative)) {
recording = true;
player.sendEvent(PlayerListener.RECORD_STARTED, new Long(player.getMediaTime()));
} else {
player.sendEvent(PlayerListener.RECORD_ERROR, new String("Can't start recording"));
}
} else {
suspended = true;
}
}
/**
* Stop or pause recording
*/
private synchronized void stopRecord(boolean pause) {
if (player == null)
return;
if (recordRequested == true) {
recordRequested = false;
if (recording == true) {
if (suspended == false) {
if (pause)
nPause(player.hNative);
else
nStop(player.hNative);
}
player.sendEvent(PlayerListener.RECORD_STOPPED, new Long(player.getMediaTime()));
recording = false;
hasDataToCommit = true;
}
}
}
/**
* Stop recording
*/
public void stopRecord() {
// pause
stopRecord(true);
}
/**
* Commit the current recording
*/
public synchronized void commit() throws IOException {
if (stream == null && locator == null) {
return;
}
if (player == null || 0 == player.hNative) {
return;
}
// stop
stopRecord(false);
if( hasDataToCommit )
{
if (1 != nCommit(player.hNative)) {
cleanUp();
throw new IOException("I/O error occurs during commit");
}
// Get recorded data
if (stream != null) {
int offset = 0;
int getSize = 1024 * 50; // 50 Kbytes
if (httpCon != null || httpsCon != null) {
getSize = 100; // 100 bytes
}
dataBuffer = new byte[getSize];
int size = nGetRecordedSize(player.hNative);
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"Recorded data size is " + size);
}
while (size >= getSize) {
if (1 != nGetRecordedData(player.hNative, offset, getSize, dataBuffer)) {
cleanUp();
throw new IOException("I/O error occurs during commit");
}
size -= getSize;
offset += getSize;
// Write to stream
stream.write(dataBuffer);
stream.flush();
}
if (size > 0) {
dataBuffer = new byte[size];
if (1 != nGetRecordedData(player.hNative, offset, size, dataBuffer)) {
cleanUp();
throw new IOException("I/O error occurs during commit");
}
stream.write(dataBuffer);
stream.flush();
}
} else if (locator != null && recordingByNative == false) {
// Need revisit
}
}
// Release native resources
nClose(player.hNative);
if (locator != null) {
if (httpCon != null) {
int rescode = httpCon.getResponseCode();
if (rescode != HttpConnection.HTTP_OK) {
cleanUp();
throw new IOException("HTTP response code: " + rescode);
}
} else if (httpsCon != null) {
int rescode = httpsCon.getResponseCode();
if (rescode != HttpConnection.HTTP_OK) {
cleanUp();
throw new IOException("HTTP response code: " + rescode);
}
}
}
cleanUp();
// We're done.
dataBuffer = null;
locator = null;
recordingByNative = false;
hasDataToCommit = false;
}
/**
* Reset the current recording
*/
public synchronized void reset() throws IOException {
if (player == null)
return;
if (recordRequested == true) {
stopRecord(false);
if (1 != nReset(player.hNative)) {
cleanUp();
throw new IOException("The current recording cannot be erased");
}
} else {
stopRecord(false);
}
hasDataToCommit = false;
}
/**
* Set record size limit
*/
public synchronized int setRecordSizeLimit(int size) throws MediaException {
if (player == null)
return 0;
if (size <= 0)
throw new IllegalArgumentException("Given size is invalid");
if (Integer.MAX_VALUE == size) {
nSetSizeLimit(player.hNative, -1);
} else {
size = nSetSizeLimit(player.hNative, size);
if (size == 0) {
throw new MediaException("Setting the record size limit is not supported");
}
}
// If the requested size is less than the already recorded size, commit
if (recording == true) {
int recordedSize = nGetRecordedSize(player.hNative);
if (recordedSize > size) {
try {
commit();
} catch(IOException e) {
// Nothing to do
}
}
}
return size;
}
/**
* Get content type
*/
public String getContentType() {
return nGetRecordedType(player.hNative);
}
///////////////////////////////////////////////////////////////
public synchronized void recordSizeLimitReached()
{
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"[direct] received RSL");
}
try
{
commit();
}
catch( java.io.IOException e )
{
}
}
// Is recording suspended by player?
private boolean suspended = false;
/**
* Start recording (from Player object)
*/
public synchronized void playerStarted() {
// Automatically resume recording from Player
if (suspended) {
if (1 == nStart(player.hNative)) {
recording = true;
player.sendEvent(PlayerListener.RECORD_STARTED, new Long(player.getMediaTime()));
} else {
player.sendEvent(PlayerListener.RECORD_ERROR, new String("Can't start recording"));
}
suspended = false;
return;
}
if (recordRequested && !recording) {
if (1 == nStart(player.hNative)) {
recording = true;
player.sendEvent(PlayerListener.RECORD_STARTED, new Long(player.getMediaTime()));
} else {
player.sendEvent(PlayerListener.RECORD_ERROR, new String("Can't start recording"));
}
}
}
/**
* Suspend recording (from Player object)
*/
public synchronized void playerStopped() {
if (recording) {
stopRecord();
suspended = true;
}
}
/**
* Player closed. reset recording.
*/
public synchronized void playerClosed() {
try {
reset();
nClose(player.hNative);
} catch(IOException e) {
// Nothing to do
}
player = null;
cleanUp();
}
/**
* Clean up connection resources if any
*/
private void cleanUp() {
try {
if (stream != null && !extStream) {
stream.close();
}
} catch(Exception e) {
}
try {
if (httpCon != null) {
httpCon.close();
}
} catch(Exception e) {
}
try {
if (httpsCon != null) {
httpsCon.close();
}
} catch(Exception e) {
}
// #ifdef USE_FILE_CONNECTION [
try {
if (fileCon != null) {
fileCon.close();
}
} catch(Exception e) {
}
// #endif ]
stream = null;
httpCon = null;
httpsCon = null;
// #ifdef USE_FILE_CONNECTION [
fileCon = null;
// #endif ]
}
/**
* Check for the multimedia record permission.
*
* @exception SecurityException if the permission is not
* allowed by this token
*/
private void checkPermission() {
try {
PermissionAccessor.checkPermissions(player.getLocator(), PermissionAccessor.PERMISSION_RECORDING);
} catch (InterruptedException e) {
throw new SecurityException("Interrupted while trying to ask the user permission");
}
}
///////////////////////////////////////////////////////////////
/* The string in URL format specifying where the recorded media will be saved */
private String locator; // null;
/* Set the output stream where the data will be recorded. */
private OutputStream stream; // null
private DirectPlayer player; // null;
/* specifies whether recording is requested via <code>startRecord</code> */
private boolean recordRequested; // false;
/* This is set to true when recording starts (RECORD_STARTED event
* is posted). Is set to false when recording stops (RECORD_STOPPED event
* is posted).
*/
private boolean recording; // false;
/* This recording handled by native API layer? */
private boolean recordingByNative; // false
/* Recording data buffer */
private byte[] dataBuffer;
/* External Output Stream flag */
private boolean extStream = false;
private boolean hasDataToCommit=false;
// #ifdef USE_FILE_CONNECTION [
private FileConnection fileCon;
// #endif ]
private HttpConnection httpCon;
private HttpsConnection httpsCon;
}

Просмотреть файл

@ -0,0 +1,775 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
// #ifdef ENABLE_CDC [
import com.sun.j2me.proxy.lcdui.*;
import com.sun.j2me.proxy.mmedia.*;
// #else ][
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.CustomItem;
import javax.microedition.lcdui.Display;
// #endif ]
import javax.microedition.media.MediaException;
import javax.microedition.media.control.VideoControl;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
/**
* Common MIDP/LCDUI-based Video Control
* it implements VideoControl for DirectPlayer.
*/
class DirectVideo implements VideoControl, MIDPVideoPainter {
private VideoSource source;
private final int DEFAULT_WIDTH = 80;
private final int DEFAULT_HEIGHT = 80;
private final int COLOR_KEY = 0x010101;
// NOTE: You have to calibrate this value carefully
// If you increase this value, fake preview quality goes down but, system overhead decrease
// If you decrease this value, fake preview quality goes up but, system overhead increase
// If you set this value 0 or negative value, fake preview support still image only
private final static int FAKE_PREVIEW_INTERVAL = 250;
// Canvas and item reference
private Canvas canvas;
private DVItem item;
// original video size
private int sw;
private int sh;
// Display position and size + temporary values for fullscreen mode
private int dx, tmp_dx;
private int dy, tmp_dy;
private int dw, tmp_dw;
private int dh, tmp_dh;
// visible?
private boolean visible = false;
private boolean hidden = false;
private boolean started = false;
private boolean locationInited = false; // Is location initialized?
// current display mode
private int displayMode = -1;
// MMHelper to communicate with Canvas
private MMHelper mmh = null;
// Lock
private Object boundLock = new Object();
/**
* Refers to current display mode: normal or full screen, provides location
* services such as size and position settings. Separates different mode
* implementations in a clean way, based on the State Pattern.
*/
private VideoLocationControl locationControl;
// member functions /////////////////////////////////////////////
// this is to suppress the default package-private empty constructor
private DirectVideo() {}
// the only possible way to instantiate this class
DirectVideo( VideoSource src, int width, int height )
{
source = src;
sw = width;
sh = height;
locationControl = normalScreenLocationControl;
// initialize default rendering width and height
if (sw <= 0) dw = DEFAULT_WIDTH;
else dw = sw;
if (sh <= 0) dh = DEFAULT_HEIGHT;
else dh = sh;
}
/**
* Is in clipping area?
*/
private boolean isInClippingArea(Graphics g, int x, int y, int w, int h) {
int diffx = g.getTranslateX();
int diffy = g.getTranslateY();
int clipx = g.getClipX();
int clipy = g.getClipY();
int clipw = g.getClipWidth();
int cliph = g.getClipHeight();
x += diffx;
y += diffy;
clipx += diffx;
clipy += diffy;
if (x < clipx) return false;
if (y < clipy) return false;
if (x + w > clipx + clipw) return false;
if (y + h > clipy + cliph) return false;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"isInClippingArea return true - No graphic outside of clipping area");
}
return true;
}
/**
* Prepare direct video rendering surface
*/
private void prepareVideoSurface(Graphics g, int x, int y, int w, int h) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"prepareVideoSurface " + x + "," + y + "," + w + "," + h);
}
// Turn off color key
source.setColorKey( false, COLOR_KEY);
locationControl.setTranslatedVideoLocation(g, x, y, w, h);
source.setVideoVisible( !hidden);
}
/**
* Prepare clipped preview region by using color key masking
*/
private void prepareClippedPreview(Graphics g, int x, int y, int w, int h) {
if (source.setColorKey( true, COLOR_KEY)) {
g.setColor(COLOR_KEY); // IMPL NOTE - Consider RGB565 conversion
g.fillRect(x, y, w, h);
locationControl.setTranslatedVideoLocation(g, x, y, w, h);
source.setVideoVisible( !hidden);
} else {
source.setVideoVisible( false);
}
}
/**
* request to repaint
*/
private void repaint() {
if (canvas != null) {
canvas.repaint();
} else if (item != null) {
item.forcePaint();
}
}
/**
* Check mode value
*/
protected void checkState() {
if (displayMode == -1) {
throw new IllegalStateException("initDisplayMode not called yet");
}
}
void start() {
started = true;
repaint();
}
void stop() {
started = false;
}
/**
* Init display mode
*/
public Object initDisplayMode(int mode, Object container) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"initDisplayMode mode=" + mode + ", container=" + container);
}
Object ret = null;
if (displayMode != -1) {
throw new IllegalStateException("mode already set");
}
if (mode != USE_DIRECT_VIDEO && mode != USE_GUI_PRIMITIVE) {
throw new IllegalArgumentException("unsupported mode");
}
// #ifdef ENABLE_CDC [
boolean containerIsCanvas = Canvas.__getMyClass().isInstance(container);
// #else ][
boolean containerIsCanvas = Canvas.class.isInstance(container);
// #endif ]
if (mode == USE_DIRECT_VIDEO && !containerIsCanvas) {
throw new IllegalArgumentException("container needs to be a Canvas");
}
if (mode == USE_GUI_PRIMITIVE && container != null) {
if (!(container instanceof String)) {
throw new IllegalArgumentException("container not valid");
}
if (!(container.equals("javax.microedition.lcdui.Item"))) {
throw new IllegalArgumentException("container not valid");
}
}
if (mmh == null) {
mmh = MMHelper.getMMHelper();
if (mmh == null) {
throw new RuntimeException("initDisplayMode: unable to set the display mode");
}
}
if (mode == USE_DIRECT_VIDEO) {
// #ifdef ENABLE_CDC [
canvas = (Canvas)Canvas.__getInstance(container);
// #else ][
canvas = (Canvas)container;
// #endif ]
if (!canvas.isShown()) {
hidden = true;
}
displayMode = mode;
// register this direct video handler to MMH
// MMH used to communicate with Canvas
mmh.registerPlayer(canvas, this);
setDisplayLocation(dx, dy);
} else {
displayMode = mode;
item = new DVItem(null);
// #ifdef ENABLE_CDC [
ret = (Object)item.__getInternal();
// #else ][
ret = (Object)item;
// #endif ]
visible = true;
}
return ret;
}
/**
* Override method in BasicPlayer to close
* the <code>Player</code>.
*/
void close() {
if (mmh != null && canvas != null) {
// unregister this direct video handler with MMH
mmh.unregisterPlayer(canvas, this);
}
}
/**
* Set display location
*/
public void setDisplayLocation(int x, int y) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"setDisplayLocation x=" + x + ",y=" + y);
}
checkState();
if (displayMode == USE_DIRECT_VIDEO) {
locationControl.setDisplayLocation(x, y);
}
}
/**
* Set display size
*/
public void setDisplaySize(int width, int height) throws MediaException {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"setDisplaySize w=" + width + ",h=" + height);
}
checkState();
if (width < 1 || height < 1) {
throw new IllegalArgumentException("invalid size ("+width+","+height+")");
}
locationControl.setDisplaySize(width, height);
if (item != null) {
// this will raise sizeChanged event
// and sizeChanged shall raise paint event also
item.setPreferredSize( width, height );
} else {
repaint();
}
}
public int getDisplayX() {
return dx;
}
public int getDisplayY() {
return dy;
}
/**
* Get actual width of rendering
*/
public int getDisplayWidth() {
checkState();
return dw;
}
/**
* Get actual height of rendering
*/
public int getDisplayHeight() {
checkState();
return dh;
}
/**
* return source video width
*/
public int getSourceWidth() {
return sw;
}
/**
* return source video height
*/
public int getSourceHeight() {
return sh;
}
/**
* set visible or unvisible
*/
public void setVisible(boolean visible) {
boolean old = this.visible;
checkState();
this.visible = visible;
if (old != visible) {
repaint();
}
if (visible == false) {
source.setVideoVisible( false);
}
}
/**
* Sets video display mode to full screen or normal.
* Note: the video container doesn't need to be notified since video source
* supports full screen directly.
*
* @param fullScreenMode true for full screen, false for normal display mode
*/
public void setDisplayFullScreen(boolean fullScreenMode) throws MediaException {
checkState();
synchronized( boundLock ) {
if( locationControl.isFullScreen() != fullScreenMode ) {
if( !source.setVideoFullScreen(fullScreenMode) )
{
throw new MediaException(
"Unable to set full-screen mode" );
}
if( fullScreenMode ) {
locationControl = fullScreenLocationControl;
} else {
locationControl = normalScreenLocationControl;
}
locationControl.activate();
}
}
}
public byte[] getSnapshot( String imageType ) throws MediaException
{
checkState();
if (null == imageType)
{
imageType = System.getProperty("video.snapshot.encodings");
if (null == imageType)
{
throw new MediaException( "No supported snapshot formats found" );
}
int spacePos = imageType.indexOf(' ');
if (spacePos > 0)
{
imageType = imageType.substring(0, spacePos);
}
}
else
{
String supported = System.getProperty( "video.snapshot.encodings" );
if (null == supported)
{
throw new MediaException( "No supported snapshot formats found" );
}
int idx = supported.indexOf( imageType );
if( -1 == idx )
{
throw new MediaException( "Snapshot format ('" +
imageType +
"')is not supported" );
}
}
byte[] data = null;
data = source.getVideoSnapshot(imageType.toLowerCase());
if (null == data)
{
throw new MediaException( "Snapshot in '" + imageType + "' format failed." );
}
return data;
}
/**
* called from Canvas.paint routine
* We have to paint direct video region on Canvas
* Notice: This have to be done before device painting action
*/
public void paintVideo(Graphics g) {
int x, y, w, h;
synchronized(boundLock) {
x = dx;
y = dy;
w = dw;
h = dh;
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"paintVideo x=" + x + ",y=" + y + ",w=" + w + ",h=" + h);
}
if (canvas != null && !canvas.isShown()) {
hidden = true;
}
if (!hidden) {
boolean isOverlapped = false;
if (mmh != null) {
isOverlapped = mmh.isDisplayOverlapped(g);
}
if (isOverlapped) {
prepareClippedPreview(g, x, y, w, h);
} else if (visible && started) {
prepareVideoSurface(g, x, y, w, h);
}
}
}
/**
* Hide video preview (called from CanvasLFImpl)
*/
public void hideVideo() {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"hideVideoPreview");
}
source.setVideoVisible( false);
hidden = true;
repaint();
}
/**
* Show video preview (called from CanvasLFImpl)
*/
public void showVideo() {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"showVideoPreview");
}
hidden = false;
repaint();
// IMPL NOTE - we shouldn't show video immediately: it will appear after drawVideo()
}
// Inner class ///////////////////////////////////////////////////////////
/**
* Support USE_GUI_PRIMITIVE mode
*/
class DVItem extends CustomItem {
private MMHelper mmh = null;
DVItem(String label) {
super(label);
mmh = MMHelper.getMMHelper();
}
void forcePaint() {
repaint();
}
public void paint(Graphics g, int w, int h) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"DVItem.paint visible=" + visible);
}
if (!hidden) {
boolean isOverlapped = false;
if (mmh != null) {
isOverlapped = mmh.isDisplayOverlapped(g);
}
if (isOverlapped) {
prepareClippedPreview(g, 0, 0, w, h);
} else if (visible) {
prepareVideoSurface(g, 0, 0, w, h);
}
}
}
public int getMinContentWidth() {
return 1;
}
public int getMinContentHeight() {
return 1;
}
public int getPrefContentWidth(int height) {
return dw;
}
public int getPrefContentHeight(int width) {
return dh;
}
public void sizeChanged(int w, int h) {
synchronized(boundLock) {
dw = w;
dh = h;
}
repaint();
}
// Now this function used to control visible state of direct video preview
// Called from MIDPWindow class
public void showNotify() {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI, "showNotify");
}
hidden = false;
repaint();
}
// Now this function used to control visible state of direct video preview
// Called from MIDPWindow class
public void hideNotify() {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI, "hideNotify");
}
source.setVideoVisible( false);
hidden = true;
repaint();
}
};
/**
* Provides display location services for video
*/
private interface VideoLocationControl {
public void setDisplayLocation(int x, int y);
public void setDisplaySize(int width, int height);
public void setTranslatedVideoLocation(Graphics g, int x, int y, int w, int h);
public boolean isFullScreen();
/**
* Service routine for switching between full screen and normal modes
*/
public void activate();
};
/**
* Provides full screen location services for video.
* All location change requests are saved to temporary variables and
* take effect only after switching the full screen mode off.
*/
private final VideoLocationControl fullScreenLocationControl = new VideoLocationControl() {
public void setDisplayLocation(int x, int y) {
tmp_dx = x;
tmp_dy = y;
}
public void setDisplaySize(int width, int height) {
tmp_dw = width;
tmp_dh = height;
}
public void setTranslatedVideoLocation(Graphics g, int x, int y, int w, int h) {
// No translation in full screen mode, position and dimensions ignored
source.setVideoLocation(dx, dy, dw, dh);
}
public boolean isFullScreen() {
return true;
}
public void activate() {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI, "fullScreenLocationControl.activate");
}
// Save normal mode settings
tmp_dx = dx;
tmp_dy = dy;
tmp_dw = dw;
tmp_dh = dh;
// Apply full screen dimensions and position settings
dx = 0;
dy = 0;
/*
* Revisit: these can swap when device screen orientation changes or
* UI object got moved to another Display.
*/
Display myDisplay;
switch (displayMode) {
case USE_DIRECT_VIDEO:
myDisplay = mmh.getDisplayFor(canvas);
break;
case USE_GUI_PRIMITIVE:
myDisplay = mmh.getDisplayFor(item);
break;
default:
myDisplay = null;
}
dw = mmh.getDisplayWidth(myDisplay);
dh = mmh.getDisplayHeight(myDisplay);
}
};
/**
* Provides normal (not full screen) location services for video.
* Changing size or location take place immediately.
*/
private final VideoLocationControl normalScreenLocationControl = new VideoLocationControl() {
public void setDisplayLocation(int x, int y) {
synchronized(boundLock) {
dx = x;
dy = y;
boolean needRepaint = ( dw != 0 && dh != 0 );
if( needRepaint ) {
repaint();
}
}
}
public void setDisplaySize(int width, int height) {
synchronized(boundLock) {
boolean sizeChanged = ( dw != width || dh != height );
if (sizeChanged) {
dw = width;
dh = height;
source.notifyDisplaySizeChange();
}
}
}
public void setTranslatedVideoLocation(Graphics g, int x, int y, int w, int h) {
int diffx = g.getTranslateX();
int diffy = g.getTranslateY();
int px, py, pw, ph;
// Calculate positions
// And, do a physical clipping
px = x + diffx;
py = y + diffy;
pw = dw;
ph = dh;
if (px + pw <= 0) {
return;
}
if (py + ph <= 0) {
return;
}
/*
* Revisit: these can swap when device screen orientation changes or
* UI object got moved to another Display.
*/
Display myDisplay;
switch (displayMode) {
case USE_DIRECT_VIDEO:
myDisplay = mmh.getDisplayFor(canvas);
break;
case USE_GUI_PRIMITIVE:
myDisplay = mmh.getDisplayFor(item);
break;
default:
myDisplay = null;
}
int displayWidth = mmh.getDisplayWidth(myDisplay);
int displayHeight = mmh.getDisplayHeight(myDisplay);
if (px >= displayWidth) {
return;
}
if (py >= displayHeight) {
return;
}
source.setVideoLocation(px, py, pw, ph);
}
public boolean isFullScreen() {
return false;
}
public void activate() {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI, "normalScreenLocationControl.activate");
}
// Apply previously saved normal mode position and dimensions
if( tmp_dx != dx || tmp_dy != dy ) {
setDisplayLocation( tmp_dx, tmp_dy );
}
if( tmp_dw != dw || tmp_dh != dh ) {
setDisplaySize( tmp_dw, tmp_dh );
}
}
};
}

Просмотреть файл

@ -0,0 +1,131 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
/**
* Native volume control implementation
*/
public class DirectVolume implements VolumeControl {
// VolumeControl functions
protected native int nGetVolume(int hNative);
protected native int nSetVolume(int hNative, int level);
protected native boolean nIsMuted(int hNative);
protected native boolean nSetMute(int hNative, boolean mute);
private int _level = -1;
private int _mute = -1;
private int _hNative;
private BasicPlayer _player;
DirectVolume(BasicPlayer player, int hNative) {
_player = player;
_hNative = hNative;
}
void setToThisPlayerLevel() {
if (_level == -1)
return;
if (_hNative != 0)
nSetVolume(_hNative, _level);
}
void setToPlayerMute() {
if (_mute == -1)
return;
if (_hNative != 0)
nSetMute(_hNative, _mute == 1);
}
void playerClosed() {
_hNative = 0;
}
public int getLevel() {
if (_hNative != 0 && _level == -1) {
_level = nGetVolume(_hNative);
}
return _level;
}
public int setLevel(int level) {
if (level < 0) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_MMAPI,
"volume level " + level + " is negative, change to 0");
}
level = 0;
} else if (level > 100) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_MMAPI,
"volume level " + level + " is too big, change to 100");
}
level = 100;
}
// Volume value is the same or player is closed. Just return.
if (_level == level || _hNative == 0) {
return _level;
}
// Try to set the native player volume
if (-1 == nSetVolume(_hNative, level)) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_MMAPI,
"set volume failed volume=" + _level);
}
}
_level = level;
_player.sendEvent(PlayerListener.VOLUME_CHANGED, this);
return _level;
}
public boolean isMuted() {
if (_hNative == 0 || _mute != -1)
return (_mute == 1);
if (nIsMuted(_hNative)) {
_mute = 1;
return true;
} else {
_mute = 0;
return false;
}
}
public void setMute(boolean mute) {
if (_hNative != 0) {
nSetMute(_hNative, mute);
}
_mute = mute ? 1 : 0;
}
}

Просмотреть файл

@ -0,0 +1,103 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
/**
* Utility class that provides various array conversion
*
*/
public final class FormatConversionUtils {
/**
* Private constructor to prevent instantiation
*/
private FormatConversionUtils(){}
/**
* Converts image int[] array (32-bit per pixel)
* to byte[] xRGB array (4 bytes per pixel)
* int<->byte[4] conversion is platform specific !
*
* @param ints integer array to convert
* @return same array but converted to byte[] (in big-endian format)
*/
public static byte[] intArrayToByteArray(int[] ints) {
if (ints == null) return null;
byte[] bytes = new byte[ints.length * 4];
int intcount, bytecount;
for (intcount = 0, bytecount = 0; intcount < ints.length; ) {
bytes[bytecount++] = (byte)((ints[intcount] & 0xFF000000) >> 24);
bytes[bytecount++] = (byte)((ints[intcount] & 0x00FF0000) >> 16);
bytes[bytecount++] = (byte)((ints[intcount] & 0x0000FF00) >> 8);
bytes[bytecount++] = (byte)((ints[intcount] & 0x000000FF) );
intcount++;
}
return bytes;
}
/**
* Converts image byte[] xRGB array (4 bytes per pixel)
* to int[] array (32-bit per pixel),
* int<->byte[4] conversion is platform specific !
*
* @param bytes byte array to convert
* @return same array but converted to int[] (in big-endian format)
*/
public static int[] byteArrayToIntArray(byte[] bytes) {
if (bytes == null) return null;
int[] ints = new int[bytes.length / 4];
int intcount, bytecount;
for (intcount = 0, bytecount = 0; bytecount < bytes.length; ) {
ints[intcount] =
(( ((int)(bytes[bytecount + 0])) << 24) & 0xFF000000) | //A
(( ((int)(bytes[bytecount + 1])) << 16) & 0x00FF0000) | //R
(( ((int)(bytes[bytecount + 2])) << 8) & 0x0000FF00) | //G
(( ((int)(bytes[bytecount + 3])) ) & 0x000000FF); //B
intcount++;
bytecount+=4;
}
return ints;
}
/**
* Creates a copy of a string array.
* Primary usage of this method is to create copies of
* preset, parameter, metadata and other arrays, returned to user.
*
* @param array String array to copy
* @return copy of array
*/
public static String[] stringArrayCopy(String[] array) {
if (array == null) return null;
String[] copy = new String[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
}

Просмотреть файл

@ -0,0 +1,92 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
/**
* Provides methods to set parameters of platform specific images.
* Since Image class is defined differently on different platforms
* (midp, j2se, etc), core components can refer to images only as instances
* of class Object.
* This interface can help in checking if a given Object is an image and to
* retrieve image parameters.
*
* @created November 8, 2005
*/
public interface ImageAccess {
/*
* returns how many alpha levels supported by the system.
* Min value is 2: totally opaque & totally transparent.
*/
int alphaLevelsNumber();
/*
* Checks if the object is Image or not.
*/
boolean isImage(Object image);
/*
* Checks if the object is mutable or immutable Image.
* Shall be called only after isImage() check passed.
*/
boolean isMutableImage(Object image);
/*
* Returns Image width, or -1 if Object is not Image.
*/
int getImageWidth(Object image);
/*
* Returns Image height, or -1 if Object is not Image.
*/
int getImageHeight(Object image);
/*
* Returns RGB image data (4 bytes in ARGB format per pixel)
or null if Object is not Image.
*/
byte[] getRGBByteImageData(Object image);
/*
* Returns RGB image data (32-bit int per pixel)
or null if Object is not Image.
*/
int[] getRGBIntImageData(Object image);
/*
* Returns an immutable copy of a given Image or null if Object is not Image.
*/
Object imageCreateFromImage(Object image);
/*
* Returns an image created from the stream or null in case of failure.
*/
Object imageCreateFromStream(java.io.InputStream stream);
/*
* Returns an image created from the byte array or null in case of filure.
*/
Object imageCreateFromByteArray(byte[] data, int offset, int length);
}

Просмотреть файл

@ -0,0 +1,98 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.Control;
public class Jsr234Proxy {
private static Jsr234Proxy _instance;
private static String[] _emptyNamesList = { };
protected Jsr234Proxy() {}
public static Jsr234Proxy getInstance() {
if( null == _instance )
{
try {
_instance = ( Jsr234Proxy )Class.forName( "com.sun.amms." +
"SupplementsToMMAPI" ).newInstance();
} catch ( Throwable t )
{
_instance = new Jsr234Proxy();
}
}
return _instance;
}
public String [] getJsr234PlayerControlNames() {
return _emptyNamesList;
}
public Control getRDSControl( DirectPlayer p )
{
return null;
}
public Control getTunerControl( DirectPlayer p )
{
return null;
}
public Control getCameraControl( DirectCamera cam )
{
return null;
}
public Control getExposureControl( DirectPlayer p )
{
return null;
}
public Control getFlashControl( DirectPlayer p )
{
return null;
}
public Control getFocusControl( DirectCamera cam )
{
return null;
}
public Control getSnapshotControl( DirectCamera cam )
{
return null;
}
public Control getZoomControl( DirectPlayer p )
{
return null;
}
public Control getImageFormatControl( DirectCamera cam )
{
return null;
}
}

Просмотреть файл

@ -0,0 +1,143 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.lcdui.Image;
/**
* The image access class for MIDP.
*
* @created December 16, 2005
*/
class MIDPImageAccessor implements ImageAccess {
/*
* ImageAccess I/F method
*/
public int alphaLevelsNumber() {
/**
* TBD: get display for current MIDlet
* javax.microedition.lcdui.Display d = ...;
* return d.numAlphaLevels();
*/
return 2;
}
/*
* ImageAccess I/F method
*/
public boolean isImage(Object image) {
return ((null != image) && (image instanceof Image));
}
/*
* ImageAccess I/F method
*/
public boolean isMutableImage(Object image){
if (!isImage(image)) return false;
Image img = (Image)image;
return img.isMutable();
}
/*
* ImageAccess I/F method
*/
public int getImageWidth(Object image) {
if (!isImage(image)) return -1;
Image img = (Image)image;
return img.getWidth();
}
/*
* ImageAccess I/F method
*/
public int getImageHeight(Object image) {
if (!isImage(image)) return -1;
Image img = (Image)image;
return img.getHeight();
}
/*
* ImageAccess I/F method
*/
public byte[] getRGBByteImageData(Object image) {
if (!isImage(image)) return null;
return FormatConversionUtils.
intArrayToByteArray(getRGBIntImageData(image));
}
/*
* ImageAccess I/F method
*/
public int[] getRGBIntImageData(Object image) {
if (!isImage(image)) return null;
Image img = (Image)image;
int w = img.getWidth();
int h = img.getHeight();
int[] data = new int[w * h];
img.getRGB(data, 0, w, 0, 0, w, h);
return data;
}
/*
* ImageAccess I/F method
*/
public Object imageCreateFromImage(Object image) {
if (!isImage(image)) return null;
Image img = (Image)image;
return Image.createImage(img);
}
/*
* ImageAccess I/F method
*/
public Object imageCreateFromStream(java.io.InputStream stream) {
if (stream == null)
return null;
Image image = null;
try {
image = Image.createImage(stream);
} catch (java.io.IOException ioe) {
return null;
}
return image;
}
/*
* ImageAccess I/F method
*/
public Object imageCreateFromByteArray(byte[] data, int offset, int length) {
return Image.createImage(data, offset, length);
}
}

Просмотреть файл

@ -0,0 +1,662 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.media.Control;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.MediaException;
import javax.microedition.media.control.VideoControl;
/**
* VideoControl implementation for MIDP
*/
public final class MIDPVideoRenderer extends VideoRenderer
implements VideoControl, MIDPVideoPainter {
/** If the application requests an Item */
private MMItem mmItem;
/** LCDUI notifications registration */
private MMHelper mmHelper = null;
/** If the application requests to draw in a Canvas */
private Canvas canvas;
/** Full screen mode flag */
private boolean fsmode;
/** Is the player closed */
private boolean closed;
/** The display mode */
private int mode = -1;
/** Container visible flag. True if the Canvas is visible */
private boolean cvis;
/** Application specified visibility flag. True if setVisible(true) */
private boolean pvis;
/** Player which is being controlled */
private BasicPlayer player;
/** Display X */
private int dx, tmpdx;
/** Display Y */
private int dy, tmpdy;
/** Display Width */
private int dw, tmpdw;
/** Display Height */
private int dh, tmpdh;
/** Source width */
private int videoWidth;
/** Source height */
private int videoHeight;
/** To check the frame rate */
private static final boolean TRACE_FRAMERATE = false;
/** To check the frame rate */
private int frameCount;
/** To check the frame rate */
private long frameStartTime = 0;
public static final String SNAPSHOT_RGB888 = "rgb888";
public static final String SNAPSHOT_BGR888 = "bgr888";
public static final String SNAPSHOT_RGB565 = "rgb565";
public static final String SNAPSHOT_RGB555 = "rgb555";
public static final String SNAPSHOT_ENCODINGS = SNAPSHOT_RGB888 + " "
+ SNAPSHOT_BGR888 + " " + SNAPSHOT_RGB565 + " " + SNAPSHOT_RGB555;
/** used to protect dx, dy, dw, dh set & read */
private Object dispBoundsLock = new Object();
/*
* Locator string used to open the Player instance which this VideoControl is assoicated with.
*/
private String locatorString;
/****************************************************************
* VideoControl implementation
****************************************************************/
MIDPVideoRenderer(Player p) {
if (p instanceof BasicPlayer) {
this.player = (BasicPlayer)p;
locatorString = player.getLocator();
} else {
System.err.println("video renderer can't work with Players of this class: " + p.toString());
}
}
private void checkState() {
if (mode == -1)
throw new IllegalStateException("initDisplayMode not called yet");
}
public Object initDisplayMode(int mode, Object container) {
if (this.mode != -1)
throw new IllegalStateException("mode is already set");
if (mode == USE_DIRECT_VIDEO) {
if (!(container instanceof Canvas))
throw new IllegalArgumentException(
"container needs to be a Canvas for USE_DIRECT_VIDEO mode");
if (mmHelper == null) {
mmHelper = MMHelper.getMMHelper();
if (mmHelper == null)
throw new IllegalArgumentException(
"unable to set USE_DIRECT_VIDEO mode");
}
this.mode = mode;
fsmode = false;
cvis = true;
canvas = (Canvas) container;
mmHelper.registerPlayer(canvas, this);
setVisible(false); // By default video is not shown in USE_DIRECT_VIDEO mode
return null;
} else if (mode == USE_GUI_PRIMITIVE) {
if (container != null &&
(!(container instanceof String) ||
!(container.equals("javax.microedition.lcdui.Item"))))
throw new IllegalArgumentException("container needs to be a javax.microedition.lcdui.Item for USE_GUI_PRIMITIVE mode");
this.mode = mode;
fsmode = false;
cvis = true;
mmItem = new MMItem();
setVisible(true);
return mmItem;
} else {
throw new IllegalArgumentException("unsupported mode");
}
}
public void setDisplayLocation(int x, int y) {
checkState();
// Applicable only in USE_DIRECT_VIDEO mode
if (mode == USE_DIRECT_VIDEO) {
if (fsmode) { // Just store location in fullscreen mode
synchronized (dispBoundsLock) {
tmpdx = x;
tmpdy = y;
}
} else {
synchronized (dispBoundsLock) {
dx = x;
dy = y;
}
if (pvis && cvis)
canvas.repaint();
}
}
}
public int getDisplayX() {
return dx;
}
public int getDisplayY() {
return dy;
}
/**
* Check for the image snapshot permission.
*
* @exception SecurityException if the permission is not
* allowed by this token
*/
private void checkPermission() throws SecurityException {
try {
PermissionAccessor.checkPermissions(locatorString, PermissionAccessor.PERMISSION_SNAPSHOT);
} catch (InterruptedException e) {
throw new SecurityException("Interrupted while trying to ask the user permission");
}
}
public void setVisible(boolean visible) {
checkState();
pvis = visible;
if (canvas != null) // USE_DIRECT_VIDEO
canvas.repaint();
else if (mmItem != null) // USE_GUI_PRIMITIVE
mmItem.refresh(false);
}
public void setDisplaySize(int width, int height)
throws javax.microedition.media.MediaException {
checkState();
if (width < 1 || height < 1)
throw new IllegalArgumentException("Invalid size");
boolean sizeChanged = (dw != width || dh != height);
if (fsmode) { // Just store sizes in fullscreen mode
synchronized (dispBoundsLock) {
tmpdw = width;
tmpdh = height;
}
} else {
synchronized (dispBoundsLock) {
dw = width;
dh = height;
}
scaleToDest();
if (pvis)
if (mmItem != null)
mmItem.refresh(true);
else if (cvis)
canvas.repaint();
}
// Makes sense only if NOT in Full Screen mode
if (sizeChanged && !fsmode)
player.sendEvent(PlayerListener.SIZE_CHANGED, this);
}
public void setDisplayFullScreen(boolean fullScreenMode)
throws javax.microedition.media.MediaException {
checkState();
if (fsmode != fullScreenMode) {
fsmode = fullScreenMode;
if (fsmode) { //switching from Normal to Full Screen
synchronized (dispBoundsLock) {
tmpdx = dx;
tmpdy = dy;
tmpdw = dw;
tmpdh = dh;
}
if (mode == USE_DIRECT_VIDEO) {
canvas.setFullScreenMode(true);
} else {
canvas = mmItem.toFullScreen(this, this);
if (canvas == null) {
// No owner or no display - thus invisible
// Do nothing, but simulate fullscreen (lock sizes - for compliance)
return;
}
}
synchronized (dispBoundsLock) {
dx = 0;
dy = 0;
// Keep aspect ratio
int scrw = canvas.getWidth();
int scrh = canvas.getHeight();
dw = scrh * videoWidth / videoHeight;
if (dw > scrw) {
dw = scrw;
dh = scrw * videoHeight / videoWidth;
dy = (scrh - dh) / 2;
} else {
dh = scrh;
dx = (scrw - dw) / 2;
}
}
scaleToDest();
if (cvis)
canvas.repaint();
} else { //switching from Full to Normal Screen
synchronized (dispBoundsLock) {
dx = tmpdx;
dy = tmpdy;
dw = tmpdw;
dh = tmpdh;
}
scaleToDest();
if (mode == USE_DIRECT_VIDEO) {
canvas.setFullScreenMode(false);
if (pvis && cvis)
canvas.repaint();
} else {
mmItem.toNormal();
canvas = null;
if (pvis)
mmItem.refresh(false);
}
}
player.sendEvent(PlayerListener.SIZE_CHANGED, this);
}
}
public int getDisplayWidth() {
checkState();
return dw;
}
public int getDisplayHeight() {
checkState();
return dh;
}
public int getSourceWidth() {
return videoWidth;
}
public int getSourceHeight() {
return videoHeight;
}
public byte[] getSnapshot(String imageType)
throws MediaException, SecurityException {
checkState();
checkPermission();
/* REVISIT: Not currently supported.
* Need to update video.snapshot.encodings property accordingly
*
int format = 0, pixelsize = 0;
if (imageType == null || imageType.equalsIgnoreCase(SNAPSHOT_RGB888)) {
format = 1;
pixelsize = 3;
} else if (imageType.equalsIgnoreCase(SNAPSHOT_BGR888)) {
format = 2;
pixelsize = 3;
} else if (imageType.equalsIgnoreCase(SNAPSHOT_RGB565)) {
format = 3;
pixelsize = 2;
} else if (imageType.equalsIgnoreCase(SNAPSHOT_RGB555)) {
format = 4;
pixelsize = 2;
} else */
throw new MediaException("Image format " + imageType + " not supported");
/*
if (rgbData == null)
throw new IllegalStateException("No image available");
byte [] arr = new byte[pixelsize * rgbData.length];
int idx = 0;
switch (format) {
case 1: // RGB888
for (int i = 0; i < rgbData.length; i++) {
arr[idx++] = (byte)((rgbData[i] >> 16) & 0xFF);
arr[idx++] = (byte)((rgbData[i] >> 8) & 0xFF);
arr[idx++] = (byte)(rgbData[i] & 0xFF);
}
break;
case 2: // BGR888
for (int i = 0; i < rgbData.length; i++) {
arr[idx++] = (byte)((rgbData[i] >> 16) & 0xFF);
arr[idx++] = (byte)((rgbData[i] >> 8) & 0xFF);
arr[idx++] = (byte)(rgbData[i] & 0xFF);
}
break;
case 3: // RGB565
for (int i = 0; i < rgbData.length; i++) {
int r = (rgbData[i] >> 19) & 0x1F;
int g = (rgbData[i] >> 10) & 0x3F;
int b = (rgbData[i] >> 3) & 0x1F;
arr[idx++] = (byte)((r << 3) | (g >> 3));
arr[idx++] = (byte)((g << 5) | b);
}
break;
case 4: // RGB555
for (int i = 0; i < rgbData.length; i++) {
int r = (rgbData[i] >> 19) & 0x1F;
int g = (rgbData[i] >> 11) & 0x1F;
int b = (rgbData[i] >> 3) & 0x1F;
arr[idx++] = (byte)((r << 2) | (g >> 3));
arr[idx++] = (byte)((g << 5) | b);
}
break;
}
return arr; */
}
/*private int tryParam(String tok, String prop, int def) {
if (tok.startsWith(prop)) {
tok = tok.substring(prop.length(), tok.length());
try {
return Integer.parseInt(tok);
} catch (NumberFormatException nfe) {
}
}
return def;
}*/
/****************************************************************
* Rendering interface
****************************************************************/
//private int colorMode;
//private boolean nativeRender;
private boolean useAlpha;
private int [] rgbData;
private int [] scaledData;
private boolean scaled;
private volatile boolean painting; // to prevent deadlocks
//private Image image;
public Control getVideoControl() {
return this;
}
public void initRendering(int mode, int width, int height) {
//colorMode = mode & 0x7F; // mask out NATIVE_RENDER
//nativeRender = (mode & NATIVE_RENDER) > 0;
useAlpha = (mode & USE_ALPHA) > 0;
if (width < 1 || height < 1)
throw new IllegalArgumentException("Positive width and height expected");
if ((mode & ~(USE_ALPHA | NATIVE_RENDER)) != XRGB888)
throw new IllegalArgumentException("Only XRGBA888 mode supported");
videoWidth = width;
videoHeight = height;
// Default display width and height
synchronized (dispBoundsLock) {
dw = videoWidth;
dh = videoHeight;
}
rgbData = null;
scaledData = null;
scaled = false;
painting = false;
//image = null;
}
/**
* Public render method
*/
public void render(int[] colorData) {
rgbData = colorData;
scaleToDest();
if (!pvis)
return;
if (canvas != null) {
if (cvis) {
canvas.repaint(dx, dy, dw, dh);
}
} else if (mmItem != null) {
mmItem.refresh(false);
}
}
/**
* Public render method
*/
public void render(byte[] colorData) {
throw new IllegalStateException("Only 32 bit pixel format supported");
}
/**
* Public render method
*/
public void render(short[] colorData) {
throw new IllegalStateException("Only 32 bit pixel format supported");
}
public void close() {
if (!closed && canvas != null)
mmHelper.unregisterPlayer(canvas, this);
if (rgbData != null)
synchronized (rgbData) {
rgbData = null;
scaledData = null;
}
//image = null;
closed = true;
}
/**
* Scales an input rgb image to the destination size.
*/
private void scaleToDest() {
int ldw = 0;
int ldh = 0;
synchronized (dispBoundsLock) {
ldw = dw;
ldh = dh;
}
if (rgbData != null)
synchronized (rgbData) { // To avoid interference with close()
scaled = ldw != videoWidth || ldh != videoHeight;
if (scaled) {
if (scaledData == null || scaledData.length < ldw * ldh)
scaledData = new int[ldw * ldh];
// Scale using nearest neighbor
int dp = 0;
for (int y = 0; y < ldh; y++)
for (int x = 0; x < ldw; x++)
scaledData[dp++] = rgbData[((y * videoHeight) / ldh)
* videoWidth + ((x * videoWidth) / ldw)];
}
}
}
/**
* Scale an image to the destination size. This first gets the
* pixels from the image and then uses the other scaleToDist()
* to do the scaling.
*/
/*private void scaleToDest(Image img) {
if (rgbData == null)
rgbData = new int[videoWidth * videoHeight];
int width = img.getWidth();
int height = img.getHeight();
// REVISIT: width and height need to be stored...
img.getRGB(rgbData, 0, videoWidth, 0, 0, width, height);
scaleToDest();
}*/
/****************************************************************
* MIDPVideoPainter interface
****************************************************************/
/**
* Paint video into canvas - in USE_DIRECT_VIDEO mode
*/
public void paintVideo(Graphics g) {
// Don't paint if Canvas visible flag is false
if (!pvis || !cvis || painting)
return;
painting = true;
// Save the clip region
int cx = g.getClipX();
int cy = g.getClipY();
int cw = g.getClipWidth();
int ch = g.getClipHeight();
// Change the clip to clip the video area
g.clipRect(dx, dy, dw, dh);
// Check if its within the bounds
if (g.getClipWidth() > 0 && g.getClipHeight() > 0 && pvis) {
int w = dw, h = dh;
if (w > videoWidth)
w = videoWidth;
if (h > videoHeight)
h = videoHeight;
try {
if (rgbData != null) {
synchronized (rgbData) {
if (scaled) {
g.drawRGB(scaledData, 0, dw, dx, dy, dw, dh, useAlpha);
} else {
g.drawRGB(rgbData, 0, videoWidth, dx, dy, w, h, useAlpha);
}
}
}
} finally {
// Revert the clip region
g.setClip(cx, cy, cw, ch);
painting = false;
}
} else {
g.setClip(cx, cy, cw, ch);
painting = false;
}
if (TRACE_FRAMERATE) {
if (frameStartTime == 0) {
frameStartTime = System.currentTimeMillis();
} else {
frameCount++;
if ((frameCount % 30) == 0) {
int frameRate = (int) ( (frameCount * 1000) / (System.currentTimeMillis() - frameStartTime + 1));
System.err.println("Frame Rate = " + frameRate);
}
}
}
}
/**
* Enable/disable rendering for canvas (USE_DIRECT_VIDEO mode)
*/
public void showVideo() {
if (canvas != null && !cvis) {
cvis = true;
canvas.repaint();
}
}
public void hideVideo() {
if (canvas != null && cvis) {
cvis = false;
canvas.repaint();
}
}
/****************************************************************
* MMItem (CustomItem) - USE_GUI_PRIMITIVE mode
****************************************************************/
final class MMItem extends MMCustomItem {
public MMItem() {
super("");
}
public void refresh(boolean resize) {
if (resize) {
invalidate();
repaint();
} else
repaint(dx, dy, dw, dh);
}
protected void paint(Graphics g, int w, int h) {
// Don't paint if VideoControl visible flag is false
if (!pvis || painting)
return;
painting = true;
if (rgbData != null) {
synchronized (rgbData) {
if (scaled) {
g.drawRGB(scaledData, 0, dw, 0, 0, dw, dh, useAlpha);
} else {
g.drawRGB(rgbData, 0, videoWidth, 0, 0, videoWidth, videoHeight, useAlpha);
}
}
}
painting = false;
}
protected int getMinContentWidth() {
return 1;
}
protected int getMinContentHeight() {
return 1;
}
protected int getPrefContentWidth(int h) {
return dw;
}
protected int getPrefContentHeight(int w) {
return dh;
}
protected void hideNotify() {
super.hideNotify();
}
}
}

Просмотреть файл

@ -0,0 +1,136 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.lcdui.*;
import javax.microedition.media.MediaException;
import javax.microedition.media.control.VideoControl;
/**
* CustomItem, which supports full screen
* (as an off-screen canvas, replacing current Displayable)...
*/
public abstract class MMCustomItem extends CustomItem {
// Full screen canvas
private Canvas fullScreen = null;
// Display to set current displayable
private Display display = null;
// Saved displayable replaced by canvas in fullscreen mode
private Displayable oldDisplayable = null;
// Callback to VideoControl implementation to restore sizes of the item
// when user manually exits fullscreen mode from the canvas.
private VideoControl callerVideoControl = null;
// Canvas painter
private MIDPVideoPainter videoPainter = null;
// Constructor
protected MMCustomItem(String label) { super(label); }
// Enter fullscreen mode,
// setting VideoControl callback to restore normal mode
// when user manually exits fullscreen mode from the canvas.
public Canvas toFullScreen(VideoControl caller, MIDPVideoPainter painter) {
if (fullScreen == null) {
fullScreen = new FullScreenCanvas();
}
if (display == null) {
MMHelper mmh = MMHelper.getMMHelper();
if (mmh == null)
return null;
display = mmh.getDisplayFor(this);
if (display == null)
return null;
}
callerVideoControl = caller;
videoPainter = painter;
if (oldDisplayable == null)
oldDisplayable = display.getCurrent();
// Setting fullscreen canvas
display.setCurrent(fullScreen);
fullScreen.setFullScreenMode(true);
return fullScreen;
}
// Return to normal, non-fullscreen mode, restoring old displayable
public void toNormal() {
if (oldDisplayable != null) {
display.setCurrent(oldDisplayable);
oldDisplayable = null;
}
callerVideoControl = null;
videoPainter = null;
}
// Fullscreen canvas implementation
// Any key or pointer press returns to non-fullscreen mode.
class FullScreenCanvas extends Canvas {
FullScreenCanvas() {
}
protected void paint(Graphics g) {
g.fillRect(0, 0, getWidth(), getHeight());
videoPainter.paintVideo(g);
}
// Any key returns to normal mode
protected void keyPressed(int keyCode) {
if (callerVideoControl != null)
try {
callerVideoControl.setDisplayFullScreen(false);
} catch (MediaException me) {}
super.keyPressed(keyCode);
}
// Any click returns to normal mode
protected void pointerPressed(int x, int y) {
if (callerVideoControl != null)
try {
callerVideoControl.setDisplayFullScreen(false);
} catch (MediaException me) {}
super.pointerPressed(x, y);
}
// Leave fullscreen mode when Canvas becomes invisible
protected void hideNotify() {
if (callerVideoControl != null)
try {
callerVideoControl.setDisplayFullScreen(false);
} catch (MediaException me) {}
super.hideNotify();
}
}
}

Просмотреть файл

@ -0,0 +1,155 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.*;
import com.sun.midp.events.*;
/**
* Event listener for events delivered from native layer
*/
class MMEventListener implements EventListener {
/**
* the following constants must be consistent
* with javacall_media_notification_type enum values
* JAVACALL_EVENT_MEDIA_***, defined in javacall_multimedia.h
*/
private static final int EVENT_MEDIA_END_OF_MEDIA = 1;
private static final int EVENT_MEDIA_DURATION_UPDATED = 2;
private static final int EVENT_MEDIA_RECORD_SIZE_LIMIT = 3;
private static final int EVENT_MEDIA_RECORD_ERROR = 4;
private static final int EVENT_MEDIA_DEVICE_AVAILABLE = 5;
private static final int EVENT_MEDIA_DEVICE_UNAVAILABLE = 6;
private static final int EVENT_MEDIA_NEED_MORE_MEDIA_DATA = 7;
private static final int EVENT_MEDIA_BUFFERING_STARTED = 8;
private static final int EVENT_MEDIA_BUFFERING_STOPPED = 9;
private static final int EVENT_MEDIA_VOLUME_CHANGED = 10;
private static final int EVENT_MEDIA_SNAPSHOT_FINISHED = 11;
private static final int EVENT_MEDIA_ERROR = 12;
MMEventListener() {
MMEventHandler.setListener(this);
}
public boolean preprocess(Event event, Event waitingEvent) {
return true;
}
/**
* Process an event.
* This method will get called in the event queue processing thread.
*
* @param event event to process
*/
public void process(Event event) {
NativeEvent nevt = (NativeEvent)event;
BasicPlayer p;
if( EventTypes.MMAPI_EVENT != nevt.getType() ) return;
switch ( nevt.intParam4 ) {
case EVENT_MEDIA_END_OF_MEDIA:
p = PlayerImpl.get(nevt.intParam1);
if (p != null) {
p.sendEvent(PlayerListener.END_OF_MEDIA, new Long(nevt.intParam2 * 1000));
}
break;
case EVENT_MEDIA_DURATION_UPDATED:
p = PlayerImpl.get(nevt.intParam1);
if (p != null) {
p.sendEvent(PlayerListener.DURATION_UPDATED, new Long(nevt.intParam2 * 1000));
}
break;
/* Extern volume event handler - Send to the all players in this isolate */
case EVENT_MEDIA_VOLUME_CHANGED:
if (nevt.intParam2 < 0) {
nevt.intParam2 = 0;
}
if (nevt.intParam2 > 100) {
nevt.intParam2 = 100;
}
PlayerImpl.sendExternalVolumeChanged(PlayerListener.VOLUME_CHANGED, nevt.intParam2);
break;
case EVENT_MEDIA_RECORD_SIZE_LIMIT:
p = PlayerImpl.get(nevt.intParam1);
if(p != null) {
p.doReceiveRSL();
}
break;
case EVENT_MEDIA_RECORD_ERROR:
p = PlayerImpl.get(nevt.intParam1);
if (p != null) {
p.sendEvent(PlayerListener.RECORD_ERROR, new String("Unexpected Record Error"));
}
break;
case EVENT_MEDIA_BUFFERING_STARTED:
p = PlayerImpl.get(nevt.intParam1);
if (p != null) {
p.sendEvent(PlayerListener.BUFFERING_STARTED, new Long(nevt.intParam2 * 1000));
}
break;
case EVENT_MEDIA_BUFFERING_STOPPED:
p = PlayerImpl.get(nevt.intParam1);
if (p != null) {
p.sendEvent(PlayerListener.BUFFERING_STOPPED, new Long(nevt.intParam2 * 1000));
}
break;
case EVENT_MEDIA_ERROR:
p = PlayerImpl.get(nevt.intParam1);
if (p != null) {
p.sendEvent(PlayerListener.ERROR, new String("Unexpected Media Error"));
}
break;
case EVENT_MEDIA_NEED_MORE_MEDIA_DATA:
p = PlayerImpl.get(nevt.intParam1);
if (p != null) {
p.continueDownload();
}
break;
case EVENT_MEDIA_SNAPSHOT_FINISHED:
p = PlayerImpl.get( nevt.intParam1 );
if( null != p )
{
try{
DirectPlayer dp = ( DirectPlayer )p;
dp.notifySnapshotFinished();
}
catch( ClassCastException e ){}
}
break;
}
}
}

Просмотреть файл

@ -0,0 +1,264 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.*;
import javax.microedition.media.protocol.SourceStream;
import java.io.IOException;
/**
* The thread that's downloads media data
*
*/
class MediaDownload {
/**
* the stream instance
*/
private SourceStream stream;
private long contLength = -1;
private int packetSize = 0;
private int javaBufSize = 0;
private byte[] buffer = null;
private boolean eom = false;
private int hNative;
private boolean needMoreData = false;
private Thread downloadThread = null;
private boolean stopDownloadFlag = false;
// get java buffer size to determine media format
static native int nGetJavaBufferSize(int handle);
// get first packet size to determine media format
static native int nGetFirstPacketSize(int handle);
// buffering media data
static native int nBuffering(int handle, byte[] buffer, int offset, int size);
// ask Native Player if it needs more data immediatelly
static native boolean nNeedMoreDataImmediatelly(int hNative);
// Provide whole media content size, if known
static native void nSetWholeContentSize(int hNative, long contentSize);
/**
* The constructor
*
* @param stream the instance of stream.
*/
MediaDownload(int hNative, SourceStream stream) {
this.hNative = hNative;
this.stream = stream;
eom = false;
contLength = -1;
}
void deallocate() {
stopDownload();
eom = false;
contLength = -1;
buffer = null;
javaBufSize = 0;
packetSize = 0;
}
/**
*
*/
void fgDownload() throws IOException, MediaException {
download(false);
}
/**
*
*/
void bgDownload() {
if (!eom) {
downloadThread = new Thread() {
public void run() {
try {
download(true);
} catch (Exception e) {
}
}
};
downloadThread.start();
}
}
synchronized void continueDownload() {
needMoreData = true;
notifyAll();
}
void stopDownload() {
if (downloadThread != null && downloadThread.isAlive()) {
stopDownloadFlag = true;
try {
downloadThread.join();
} catch(InterruptedException ex) {;}
stopDownloadFlag = false;
downloadThread = null;
needMoreData = false;
}
}
private synchronized void download( boolean inBackground ) throws MediaException, IOException {
int roffset = 0;
int woffset = 0;
if (contLength == -1) {
contLength = stream.getContentLength();
if (contLength > 0) {
nSetWholeContentSize(hNative, contLength);
}
}
int newJavaBufSize = nGetJavaBufferSize(hNative);
packetSize = nGetFirstPacketSize(hNative);
if(packetSize > 0 && !eom) {
if (newJavaBufSize < packetSize) {
newJavaBufSize = packetSize;
}
if (buffer == null || newJavaBufSize > buffer.length) {
do {
try {
buffer = new byte[ newJavaBufSize ];
} catch(OutOfMemoryError er) {
if (newJavaBufSize == packetSize) {
throw new MediaException("Not enough memory");
} else {
newJavaBufSize = newJavaBufSize/2;
if (newJavaBufSize < packetSize) {
newJavaBufSize = packetSize;
}
}
};
}while (buffer == null);
javaBufSize = newJavaBufSize;
}
if (inBackground) {
woffset = bgDownloadAndWait(woffset);
}
if (!stopDownloadFlag) {
do {
int num_read = woffset - roffset;
int ret;
if (num_read > packetSize) {
num_read = packetSize;
}
if (num_read < packetSize && !eom) {
if ((roffset + packetSize) > javaBufSize) {
woffset = moveBuff(roffset, woffset);
roffset = 0;
}
do {
ret = stream.read(buffer, woffset, packetSize-num_read);
if (ret == -1) {
eom = true;
break;
}
num_read += ret;
woffset += ret;
}while(num_read<packetSize);
}
packetSize = nBuffering(hNative, buffer, roffset, num_read);
roffset += num_read;
if (packetSize == -1) {
packetSize = 0;
needMoreData = false;
throw new MediaException("Error data buffering or encoding");
} else if (packetSize > javaBufSize){
if ((woffset - roffset)==0) {
javaBufSize = packetSize;
buffer = new byte[ javaBufSize ];
} else {
javaBufSize = packetSize;
byte[] b = new byte[ javaBufSize ];
for (int i=0, j=roffset; j<woffset; i++, j++) {
b[i] = buffer[j];
}
buffer = b;
woffset -= roffset;
roffset = 0;
}
}
if (roffset == woffset) {
roffset = 0;
woffset = 0;
if (eom) {
break;
}
}
needMoreData = nNeedMoreDataImmediatelly(hNative);
if (inBackground && !needMoreData) {
woffset = moveBuff(roffset, woffset);
roffset = 0;
woffset = bgDownloadAndWait(woffset);
}
}while (needMoreData && !stopDownloadFlag);
}
if (eom) {
packetSize = nBuffering(hNative, null, 0, 0);
needMoreData = false;
}
buffer = null;
}
}
private int moveBuff(int roffset, int woffset) {
for (int i=0, j=roffset; j<woffset; i++, j++) {
buffer[i] = buffer[j];
}
return woffset-roffset;
}
private int bgDownloadAndWait(int offset) throws IOException {
while (!needMoreData && !stopDownloadFlag) {
if (offset<javaBufSize && !eom) {
int num_read = packetSize;
if (offset + num_read >javaBufSize) {
num_read = javaBufSize - offset;
}
int ret = stream.read(buffer, offset, num_read);
if (ret == -1) {
eom = true;
} else {
offset += ret;
}
} else {
try {
wait(500);
} catch (InterruptedException e) {
}
}
}
return offset;
}
}

Просмотреть файл

@ -0,0 +1,45 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
/**
* This interfcae provides a set of methods to handle
* media related events; foregournd / background switch
*/
public interface MediaEventConsumer {
/**
* Called by event delivery when MIDlet controller (in AMS Isolate)
* notifies MIDlet and its display that there is a change in its foreground status
*/
void handleMediaForegroundNotify();
/**
* Called by event delivery when MIDlet controller (in AMS Isolate)
* notifies MIDlet and its display that there is a change in its foreground status
*/
void handleMediaBackgroundNotify();
}

Просмотреть файл

@ -0,0 +1,132 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import java.util.Vector;
import com.sun.midp.midlet.*;
import com.sun.midp.main.MIDletSuiteLoader;
/**
* Tunnel between media and lcdui
* This is a singleton object per JVM
*/
public final class MediaTunnel {
/* Playable from background? */
public final static int PLAYABLE_FROM_BACKGROUND = 1;
private static MediaTunnel instance;
private Vector map;
private boolean hasForeground = true;
private MediaTunnel() {
}
/**
* Is this midlet background playable?
*/
public boolean isBackPlayable() {
return false;
}
/**
* Get media tunnel singleton object
*/
public static MediaTunnel getInstance() {
if (instance == null) {
instance = new MediaTunnel();
}
return instance;
}
/**
* Register media event consumer
*
* @retval true if the current status is in foreground
* @retval false if the current status is in background
*/
public synchronized boolean registerMediaEventConsumer(MediaEventConsumer consumer) {
if (map == null) {
map = new Vector(5);
}
if (false == map.contains(consumer)) {
map.addElement(consumer);
}
return hasForeground;
}
/**
* Register media event consumer
*
* @retval true if the current status is in foreground
* @retval false if the current status is in background
*/
public synchronized void unregisterMediaEventConsumer(MediaEventConsumer consumer) {
if (map == null) {
return;
}
if (true == map.contains(consumer)) {
map.removeElement(consumer);
}
}
/**
* Notify media event consumer about the switch to foreground
*/
public synchronized void callForegroundEventHandler() {
if (map == null) {
return;
}
int size = map.size();
hasForeground = true;
for (int i = 0; i < size; ++i) {
MediaEventConsumer c = (MediaEventConsumer)map.elementAt(i);
c.handleMediaForegroundNotify();
}
}
/**
* Notify media event consumer about the switch to background
*/
public synchronized void callBackgroundEventHandler() {
if (map == null) {
return;
}
int size = map.size();
hasForeground = false;
for (int i = 0; i < size; ++i) {
MediaEventConsumer c = (MediaEventConsumer)map.elementAt(i);
c.handleMediaBackgroundNotify();
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import com.sun.j2me.app.AppModel;
/**
* Abstraction for the video renderer for the particular application model
*/
public class ModelVideoRenderer{
/** Guard from 'new' operator */
private ModelVideoRenderer()
{
}
public static VideoRenderer getVideoRenderer(BasicPlayer player) {
return new MIDPVideoRenderer(player);
}
}

Просмотреть файл

@ -0,0 +1,79 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.MediaException;
import com.sun.mmedia.TonePlayer;
import com.sun.j2me.app.AppPackage;
/**
* Tone Player to play a single note of specified duration
* and at the specified volume.
*
* @created January 13, 2005
*/
public class NativeTonePlayer implements TonePlayer {
/**
* The native implementation method to play a tone.
*
* @param note Defines the tone of the note.
* @param dur The duration of the tone in milli-seconds.
* @param vol Audio volume range from 0 to 100.
* @return the tone player handle, or 0 if it failed to play the tone
*/
private native boolean nPlayTone(int appId, int note, int dur, int vol);
private native boolean nStopTone(int appId);
// native finalizer
// #ifdef ENABLE_CDC [
protected native void finalize();
// #else ][
private native void finalize();
// #endif ]
public void playTone(int note, int duration, int volume)
throws MediaException {
// Set audioTunnel to Driver
AudioTunnel.getInstance().start();
// Get current application ID to support MVM
int appId = AppPackage.getInstance().getId();
if (false == nPlayTone(appId, note, duration, volume)) {
throw new MediaException("can't play tone");
}
}
/**
* Stop current tone playing
*/
public void stopTone() {
// Get current application ID to support MVM
int appId = AppPackage.getInstance().getId();
nStopTone(appId);
}
}

Просмотреть файл

@ -0,0 +1,140 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
/**
* A manager class for platform/product specific permission management.
*/
public final class PermissionAccessor {
public static final int PERMISSION_SYSTEM = 0;
public static final int PERMISSION_HTTP_READ = 1;
public static final int PERMISSION_HTTP_WRITE = 2;
public static final int PERMISSION_FILE_READ = 3;
public static final int PERMISSION_FILE_WRITE = 4;
public static final int PERMISSION_SOCKET_READ = 5;
public static final int PERMISSION_SOCKET_WRITE = 6;
public static final int PERMISSION_SNAPSHOT = 7;
public static final int PERMISSION_RECORDING = 8;
public static final int PERMISSION_HTTPS_READ = 9;
public static final int PERMISSION_HTTPS_WRITE = 10;
/**
* Method indended to be called by Players & Controls to check
* if user application has enough permissions to perform
* a secured operation ...
*
*
* @param locator - Locator name.
* @param thePermission - one of PERMISSION_* constants that
* define permissions in an product-independent form.
*/
public static void checkPermissions(String locator, int thePermission) throws SecurityException, InterruptedException {
/*
* IMPL_NOTE: Choose appropriate PermissionAccessorPlatform
*/
PermissionAccessorAbstractions.checkPermissions(locator, thePermission);
}
private static final String locatorTypes[] = {
"capture://audio",
"capture://video",
"capture://radio",
"capture://",
"device://",
"file://",
"http://",
"https://",
};
// inidicates that corresponding locator type needs no special permissions.
private static final int NEED_NO_PERMISSIONS = -2;
private static final int FAILED_PERMISSIONS = -1;
private static final int mapLocatorPermissions[] = {
/* "capture://audio" */ NEED_NO_PERMISSIONS,
/* "capture://video" */ NEED_NO_PERMISSIONS,
/* "capture://radio" */ NEED_NO_PERMISSIONS,
/* "capture://" */ NEED_NO_PERMISSIONS,
/* "device://" */ NEED_NO_PERMISSIONS,
/* "file://" */ PERMISSION_FILE_READ,
/* "http://" */ PERMISSION_HTTP_READ,
/* "https://" */ PERMISSION_HTTPS_READ
};
/**
* Method indended to be called by Manager.createDataSource(locator)
* and checks if user application has enough permissions to use given type
* of locators to play media contents.
*
* @param locator - the URL to be used as media source for player
*/
public static void checkLocatorPermissions(String locator) throws SecurityException {
int permission = FAILED_PERMISSIONS;
try {
/*
* Find Locator type, and map this type to permission.
* Any incorrect locator will result in
* ArrayIndexOutOfBoundsException or NullPointerException ->
* a SecurityException will be thrown !
*/
String locStr = locator.toLowerCase();
for (int i = 0; i < locatorTypes.length; ++i) {
if (locStr.startsWith(locatorTypes[i])) {
permission = mapLocatorPermissions[i];
if (permission == NEED_NO_PERMISSIONS)
return;
break;
}
}
checkPermissions(locator, permission);
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
throw new SecurityException(
"Failed to check locator permission");
}
}
/**
* Method indended to be called by Manager.createPlayer(DataSource)
* and checks if user application has enough permissions to playback
* media of a given content-type using given type
* of locators.
*
* @param locator - the URL to be used as media source for player,
* can be null if DataSOurce has been created not from locator
* @param contentType - content-type boolean of the media
*/
public static void checkContentTypePermissions(
String locator, String contentType) throws SecurityException {
/*
* THIS IS A STUB
*/
}
}

Просмотреть файл

@ -0,0 +1,102 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import com.sun.j2me.app.AppPackage;
import com.sun.j2me.security.Permission;
import com.sun.j2me.security.MMAPIPermission;
import com.sun.j2me.security.FileConnectionPermission;
import com.sun.j2me.security.ConnectorPermission;
/**
* A Wrapper class for platform/product specific permission management.
* This file contains permission checker, which is based on abstractions.
*/
final class PermissionAccessorAbstractions {
/**
* Method indended to be called by PermissionAccessor to check
* if user application has enough permissions to perform
* a secured operation ...
*
* @param thePermission - one of PERMISSION_* constants that
* define permissions in an product-independent form.
*/
public static void checkPermissions(String locator, int thePermission) throws SecurityException, InterruptedException {
try {
Permission permission = null;
switch(thePermission) {
case PermissionAccessor.PERMISSION_SNAPSHOT:
permission = new MMAPIPermission(
MMAPIPermission.SNAPSHOT.getName(), locator);
break;
case PermissionAccessor.PERMISSION_RECORDING:
permission = new MMAPIPermission(
MMAPIPermission.RECORDING.getName(), locator);
break;
case PermissionAccessor.PERMISSION_FILE_READ:
permission = new FileConnectionPermission(
FileConnectionPermission.READ.getName(), locator);
break;
case PermissionAccessor.PERMISSION_FILE_WRITE:
permission = new FileConnectionPermission(
FileConnectionPermission.WRITE.getName(), locator);
break;
case PermissionAccessor.PERMISSION_HTTP_READ:
case PermissionAccessor.PERMISSION_HTTP_WRITE:
permission = new ConnectorPermission(
ConnectorPermission.HTTP.getName(), locator);
break;
case PermissionAccessor.PERMISSION_HTTPS_READ:
case PermissionAccessor.PERMISSION_HTTPS_WRITE:
permission = new ConnectorPermission(
ConnectorPermission.HTTPS.getName(), locator);
break;
case PermissionAccessor.PERMISSION_SOCKET_READ:
case PermissionAccessor.PERMISSION_SOCKET_WRITE:
permission = new ConnectorPermission(
ConnectorPermission.TCP.getName(), locator);
break;
default:
throw new SecurityException("Failed to check user permission");
}
AppPackage appPackage = AppPackage.getInstance();
appPackage.checkForPermission(permission);
} catch (SecurityException se) {
///*DEBUG:*/ se.printStackTrace();
throw se;
} catch (Exception e) {
///*DEBUG:*/ e.printStackTrace();
throw new SecurityException(
"Failed to check user permission");
}
}
}

Просмотреть файл

@ -0,0 +1,971 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import javax.microedition.media.protocol.SourceStream;
import javax.microedition.media.protocol.DataSource;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import com.sun.j2me.app.AppPackage;
import com.sun.j2me.app.AppIsolate;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
import com.sun.mmedia.PlayerStateSubscriber;
import java.io.IOException;
public class PlayerImpl implements Player {
public PlayerStateSubscriber state_subscriber = null;
protected BasicPlayer playerInst = null;
public BasicPlayer getPlayerInst(){ return playerInst; };
protected DataSource source;
protected SourceStream stream;
private boolean isClosed = false;
private String mediaFormat = null;
private boolean handledByDevice = false;
private boolean handledByJava = false;
private int hNative; // handle of native API library
private int loopCount = 0; /* if set in unrealized state */
private Vector listeners = new Vector(2);
/**
* hastable to map playerID to instances
*/
private static Hashtable mplayers = new Hashtable(4);
/**
* table of player states
*/
private static Hashtable pstates = new Hashtable();
/**
* table of media times
*/
private static Hashtable mtimes = new Hashtable();
/**
* VM paused?
*/
private static boolean vmPaused = false;
/**
* global player id
*/
private static int pcount = -1;
/**
* player ID of this player
*/
protected int pID = 0;
/**
* lock object
*/
private static Object idLock = new Object();
// Init native library
protected native int nInit(int appId, int pID, String URI);
// Terminate native library
protected native int nTerm(int handle);
// Get Media Format
protected native String nGetMediaFormat(int handle);
// Need media Download in Java side?
protected native boolean nIsHandledByDevice(int handle);
// Realize native player
protected native boolean nRealize(int handle, String mime);
private static String PL_ERR_SH = "Cannot create a Player: ";
/**
* Constructor
*/
private PlayerImpl() {};
public PlayerImpl(DataSource source) throws MediaException, IOException {
// Get current application ID to support MVM
int appId = AppIsolate.getIsolateId();
synchronized (idLock) {
pcount = (pcount + 1) % 32767;
pID = pcount;
}
String locator = source.getLocator();
hNative = nInit(appId, pID, locator);
if (0 == hNative) {
throw new MediaException("Unable to create native player");
} else if (-1 == hNative) {
throw new IOException("Unable to create native player");
}
mediaFormat = nGetMediaFormat(hNative);
if( mediaFormat.equals( BasicPlayer.MEDIA_FORMAT_UNSUPPORTED ) ) {
/* verify if handled by Java */
mediaFormat = Configuration.getConfiguration().ext2Format(source.getLocator());
if( mediaFormat == null || mediaFormat.equals( BasicPlayer.MEDIA_FORMAT_UNSUPPORTED ) ) {
nTerm(hNative);
throw new MediaException("Unsupported Media Format:" + mediaFormat + " for " + source.getLocator());
} else {
handledByJava = true;
}
}
if (locator != null && mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNKNOWN)) {
if (locator.equals(Manager.TONE_DEVICE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_DEVICE_TONE;
handledByDevice = true;
} else if (locator.equals(Manager.MIDI_DEVICE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_DEVICE_MIDI;
handledByDevice = true;
}
} else if (locator != null && locator.startsWith(Configuration.CAPTURE_LOCATOR)) {
if (locator.startsWith(Configuration.AUDIO_CAPTURE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_CAPTURE_AUDIO;
} else if (locator.startsWith(Configuration.VIDEO_CAPTURE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_CAPTURE_VIDEO;
} else if (locator.startsWith(Configuration.RADIO_CAPTURE_LOCATOR)) {
mediaFormat = BasicPlayer.MEDIA_FORMAT_CAPTURE_RADIO;
}
handledByDevice = true;
}
if (!handledByJava && !handledByDevice) {
handledByDevice = nIsHandledByDevice(hNative);
}
this.source = source;
if (!handledByDevice) {
source.connect();
SourceStream[] streams = source.getStreams();
if (null == streams) {
throw new MediaException("DataSource.getStreams() returned null");
} else if (0 == streams.length) {
throw new MediaException("DataSource.getStreams() returned an empty array");
} else if (null == streams[0]) {
throw new MediaException("DataSource.getStreams()[0] is null");
} else {
if (streams.length > 1 && Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"*** DataSource.getStreams() returned " + streams.length +
" streams, only first one will be used!");
}
stream = streams[0];
}
}
// Set event listener
new MMEventListener();
}
/**
* Constructs portions of the <code>Player</code> without
* acquiring the scarce and exclusive resources.
* This may include examining media data and may
* take some time to complete.
* <p>
* When <code>realize</code> completes successfully,
* the <code>Player</code> is in the
* <i>REALIZED</i> state.
* <p>
* If <code>realize</code> is called when the <code>Player</code> is in
* the <i>REALIZED</i>, <i>PREFETCHTED</i> or <i>STARTED</i> state,
* the request will be ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be realized.
* @exception SecurityException Thrown if the caller does not
* have security permission to realize the <code>Player</code>.
*
*/
public void realize() throws MediaException {
if (playerInst != null) {
if (isClosed) {
throw new IllegalStateException();
}
return;
}
String type = source.getContentType();
if (type == null && stream != null && stream.getContentDescriptor() != null) {
type = stream.getContentDescriptor().getContentType();
}
/* try to realize native player */
if (!nRealize(hNative, type)) {
throw new MediaException("Can not realize");
}
MediaDownload mediaDownload = null;
if (!handledByDevice && !handledByJava) {
mediaFormat = nGetMediaFormat(hNative);
if (mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNSUPPORTED)) {
String format;
/* verify if handled by Java */
if (type != null &&
(format = Configuration.getConfiguration().mime2Format(type)) != null &&
!format.equals(BasicPlayer.MEDIA_FORMAT_UNKNOWN) &&
!format.equals(BasicPlayer.MEDIA_FORMAT_UNSUPPORTED)) {
mediaFormat = format;
handledByJava = true;
} else {
throw new MediaException("Unsupported media format");
}
}
/* predownload media data to recognize media format and/or
specific media parameters (e.g. duration) */
if (!mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_TONE)) {
mediaDownload = new MediaDownload(hNative, stream);
try {
mediaDownload.fgDownload();
} catch(IOException ex1) {
ex1.printStackTrace();
throw new MediaException("Can not start download Thread: " + ex1);
}catch(Exception ex) {
ex.printStackTrace();
throw new MediaException( "Can not start download Thread: " + ex );
}
}
}
if (mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNKNOWN)) {
/* ask media format if unknown */
mediaFormat = nGetMediaFormat(hNative);
if (mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNKNOWN)) {
throw new MediaException("Unknown Media Format");
}
if (mediaFormat.equals(BasicPlayer.MEDIA_FORMAT_UNSUPPORTED)) {
throw new MediaException("Unsupported Media Format");
}
}
/* create Implementation Player */
playerInst = getPlayerFromType(mediaFormat);
playerInst.notificationSource = this;
playerInst.hNative = hNative;
playerInst.mediaFormat = mediaFormat;
playerInst.handledByDevice = handledByDevice;
playerInst.pID = pID;
playerInst.mediaDownload = mediaDownload;
playerInst.setSource(source);
if (loopCount != 0) {
playerInst.setLoopCount(loopCount);
}
if (listeners.size() > 0) {
for(int i=0; i<listeners.size(); i++)
playerInst.addPlayerListener((PlayerListener)listeners.elementAt(i));
listeners.removeAllElements();
}
mplayers.put(new Integer(pID), playerInst);
playerInst.realize();
if (null != state_subscriber) {
state_subscriber.PlayerRealized(this);
}
}
/**
* Gets the playerFromType attribute of the Manager class
*
* @param type Description of the Parameter
* @return The playerFromType value
* @exception IOException Description of the Exception
* @exception MediaException Description of the Exception
*/
private BasicPlayer getPlayerFromType(String type) throws MediaException {
String className = null;
if ("GIF".equals(type)) {
className = "com.sun.mmedia.GIFPlayer";
} else if (BasicPlayer.MEDIA_FORMAT_CAPTURE_VIDEO.equals(type)) {
className = "com.sun.mmedia.DirectCamera";
} else if (DirectPlayer.nIsToneControlSupported(hNative)) {
className = "com.sun.mmedia.DirectTone";
} else if (DirectPlayer.nIsMIDIControlSupported(hNative)) {
className = "com.sun.mmedia.DirectMIDI";
} else {
className = "com.sun.mmedia.DirectPlayer";
}
if ((type == null) || className == null) {
throw new MediaException(PL_ERR_SH + "MediaFormat " + type + " is not supported");
}
BasicPlayer p = null;
try {
// ... try and instantiate the handler ...
Class handlerClass = Class.forName(className);
p = (BasicPlayer) handlerClass.newInstance();
} catch (Exception e) {
throw new MediaException(PL_ERR_SH + e.getMessage());
}
return p;
}
/**
* Acquires the scarce and exclusive resources
* and processes as much data as necessary
* to reduce the start latency.
* <p>
* When <code>prefetch</code> completes successfully,
* the <code>Player</code> is in
* the <i>PREFETCHED</i> state.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> state,
* it will implicitly call <code>realize</code>.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is already in the <i>PREFETCHED</i> state, the <code>Player</code>
* may still process data necessary to reduce the start
* latency. This is to guarantee that start latency can
* be maintained at a minimum.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is in the <i>STARTED</i> state,
* the request will be ignored.
* <p>
* If the <code>Player</code> cannot obtain all
* of the resources it needs, it throws a <code>MediaException</code>.
* When that happens, the <code>Player</code> will not be able to
* start. However, <code>prefetch</code> may be called again when
* the needed resource is later released perhaps by another
* <code>Player</code> or application.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be prefetched.
* @exception SecurityException Thrown if the caller does not
* have security permission to prefetch the <code>Player</code>.
*
*/
public void prefetch() throws MediaException {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst == null) {
realize();
}
if (playerInst != null) {
playerInst.chkClosed(false);
if (vmPaused) {
return;
}
playerInst.prefetch();
if (null != state_subscriber) {
state_subscriber.PlayerPrefetched(this);
}
}
};
/**
* Starts the <code>Player</code> as soon as possible.
* If the <code>Player</code> was previously stopped
* by calling <code>stop</code> or reaching a preset
* stop time, it will resume playback
* from where it was previously stopped. If the
* <code>Player</code> has reached the end of media,
* calling <code>start</code> will automatically
* start the playback from the start of the media.
* <p>
* When <code>start</code> returns successfully,
* the <code>Player</code> must have been started and
* a <code>STARTED</code> event will
* be delivered to the registered <code>PlayerListener</code>s.
* However, the <code>Player</code> is not guaranteed to be in
* the <i>STARTED</i> state. The <code>Player</code> may have
* already stopped (in the <i>PREFETCHED</i> state) because
* the media has 0 or a very short duration.
* <p>
* If <code>start</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i> state,
* it will implicitly call <code>prefetch</code>.
* <p>
* If <code>start</code> is called when the <code>Player</code>
* is in the <i>STARTED</i> state,
* the request will be ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be started.
* @exception SecurityException Thrown if the caller does not
* have security permission to start the <code>Player</code>.
*/
public void start() throws MediaException {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst == null) {
realize();
}
if ( getState() == REALIZED )
{
prefetch();
}
if (playerInst != null) {
playerInst.chkClosed(false);
if (vmPaused) {
return;
}
playerInst.start();
}
};
/**
* Stops the <code>Player</code>. It will pause the playback at
* the current media time.
* <p>
* When <code>stop</code> returns, the <code>Player</code> is in the
* <i>PREFETCHED</i> state.
* A <code>STOPPED</code> event will be delivered to the registered
* <code>PlayerListener</code>s.
* <p>
* If <code>stop</code> is called on
* a stopped <code>Player</code>, the request is ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code>
* cannot be stopped.
*/
public void stop() throws MediaException {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
playerInst.stop();
}
}
/**
* Release the scarce or exclusive
* resources like the audio device acquired by the <code>Player</code>.
* <p>
* When <code>deallocate</code> returns, the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i> state.
* <p>
* If the <code>Player</code> is blocked at
* the <code>realize</code> call while realizing, calling
* <code>deallocate</code> unblocks the <code>realize</code> call and
* returns the <code>Player</code> to the <i>UNREALIZED</i> state.
* Otherwise, calling <code>deallocate</code> returns the
* <code>Player</code> to the <i>REALIZED</i> state.
* <p>
* If <code>deallocate</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i>
* state, the request is ignored.
* <p>
* If the <code>Player</code> is <code>STARTED</code>
* when <code>deallocate</code> is called, <code>deallocate</code>
* will implicitly call <code>stop</code> on the <code>Player</code>.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
*/
public void deallocate() {
if (playerInst != null) {
playerInst.deallocate();
if( null != state_subscriber &&
( getState() == PREFETCHED || getState() == STARTED ) ) {
state_subscriber.PlayerDeallocated(this);
}
} else {
// Player in the UNREALIZED or CLOSED state
if (isClosed) {
throw new IllegalStateException();
}
}
};
/**
* Close the <code>Player</code> and release its resources.
* <p>
* When the method returns, the <code>Player</code> is in the
* <i>CLOSED</i> state and can no longer be used.
* A <code>CLOSED</code> event will be delivered to the registered
* <code>PlayerListener</code>s.
* <p>
* If <code>close</code> is called on a closed <code>Player</code>
* the request is ignored.
*/
public void close() {
if (playerInst != null) {
playerInst.close();
mplayers.remove(new Integer(pID));
} else {
if (!isClosed) {
/* close source of unrealized player */
if (source != null) {
source.disconnect();
source = null;
}
/* close native part of unrealized player */
if(hNative != 0) {
nTerm(hNative);
}
}
}
isClosed = true;
}
/**
* Sets the <code>TimeBase</code> for this <code>Player</code>.
* <p>
* A <code>Player</code> has a default <code>TimeBase</code> that
* is determined by the implementation.
* To reset a <code>Player</code> to its default
* <code>TimeBase</code>, call <code>setTimeBase(null)</code>.
*
* @param master The new <CODE>TimeBase</CODE> or
* <CODE>null</CODE> to reset the <code>Player</code>
* to its default <code>TimeBase</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i>, <i>STARTED</i> or <i>CLOSED</i> state.
* @exception MediaException Thrown if
* the specified <code>TimeBase</code> cannot be set on the
* <code>Player</code>.
* @see #getTimeBase
*/
public void setTimeBase(TimeBase master) throws MediaException {
if (playerInst != null) {
playerInst.setTimeBase(master);
} else {
// Player in the UNREALIZED or CLOSED state
throw new IllegalStateException();
}
};
/**
* Gets the <code>TimeBase</code> that this <code>Player</code> is using.
* @return The <code>TimeBase</code> that this <code>Player</code> is using.
* @see #setTimeBase
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
*/
public TimeBase getTimeBase() {
if (playerInst != null) {
return playerInst.getTimeBase();
}
// Player in the UNREALIZED or CLOSED state
throw new IllegalStateException();
};
/**
* Sets the <code>Player</code>'s&nbsp;<i>media time</i>.
* <p>
* For some media types, setting the media time may not be very
* accurate. The returned value will indicate the
* actual media time set.
* <p>
* Setting the media time to negative values will effectively
* set the media time to zero. Setting the media time to
* beyond the duration of the media will set the time to
* the end of media.
* <p>
* There are some media types that cannot support the setting
* of media time. Calling <code>setMediaTime</code> will throw
* a <code>MediaException</code> in those cases.
*
* @param now The new media time in microseconds.
* @return The actual media time set in microseconds.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
* @exception MediaException Thrown if the media time
* cannot be set.
* @see #getMediaTime
*/
public long setMediaTime(long now) throws MediaException {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
return playerInst.setMediaTime(now);
}
throw new IllegalStateException();
};
/**
* Gets this <code>Player</code>'s current <i>media time</i>.
* <p>
* <code>getMediaTime</code> may return <code>TIME_UNKNOWN</code> to
* indicate that the media time cannot be determined.
* However, once <code>getMediaTime</code> returns a known time
* (time not equals to <code>TIME_UNKNOWN</code>), subsequent calls
* to <code>getMediaTime</code> must not return
* <code>TIME_UNKNOWN</code>.
*
* @return The current <i>media time</i> in microseconds or
* <code>TIME_UNKNOWN</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #setMediaTime
*/
public long getMediaTime() {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
return playerInst.getMediaTime();
} else {
return Player.TIME_UNKNOWN;
}
};
/**
* Gets the current state of this <code>Player</code>.
* The possible states are: <i>UNREALIZED</i>,
* <i>REALIZED</i>, <i>PREFETCHED</i>, <i>STARTED</i>, <i>CLOSED</i>.
*
* @return The <code>Player</code>'s current state.
*/
public int getState() {
if (playerInst != null) {
return playerInst.getState();
}
return isClosed ? Player.CLOSED : Player.UNREALIZED;
};
/**
* Get the duration of the media.
* The value returned is the media's duration
* when played at the default rate.
* <br>
* If the duration cannot be determined (for example, the
* <code>Player</code> is presenting live
* media) <CODE>getDuration</CODE> returns <CODE>TIME_UNKNOWN</CODE>.
*
* @return The duration in microseconds or <code>TIME_UNKNOWN</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
*/
public long getDuration() {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
return playerInst.getDuration();
} else {
return Player.TIME_UNKNOWN;
}
};
/**
* Get the content type of the media that's
* being played back by this <code>Player</code>.
* <p>
* See <a href="Manager.html#content-type">content type</a>
* for the syntax of the content type returned.
*
* @return The content type being played back by this
* <code>Player</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
*/
public String getContentType() {
if (playerInst != null) {
return playerInst.getContentType();
}
throw new IllegalStateException();
};
/**
* Set the number of times the <code>Player</code> will loop
* and play the content.
* <p>
* By default, the loop count is one. That is, once started,
* the <code>Player</code> will start playing from the current
* media time to the end of media once.
* <p>
* If the loop count is set to N where N is bigger than one,
* starting the <code>Player</code> will start playing the
* content from the current media time to the end of media.
* It will then loop back to the beginning of the content
* (media time zero) and play till the end of the media.
* The number of times it will loop to the beginning and
* play to the end of media will be N-1.
* <p>
* Setting the loop count to 0 is invalid. An
* <code>IllegalArgumentException</code> will be thrown.
* <p>
* Setting the loop count to -1 will loop and play the content
* indefinitely.
* <p>
* If the <code>Player</code> is stopped before the preset loop
* count is reached either because <code>stop</code> is called or
* a preset stop time (set with the <code>StopTimeControl</code>)
* is reached, calling <code>start</code> again will
* resume the looping playback from where it was stopped until it
* fully reaches the preset loop count.
* <p>
* An <i>END_OF_MEDIA</i> event will be posted
* every time the <code>Player</code> reaches the end of media.
* If the <code>Player</code> loops back to the beginning and
* starts playing again because it has not completed the loop
* count, a <i>STARTED</i> event will be posted.
*
* @param count indicates the number of times the content will be
* played. 1 is the default. 0 is invalid. -1 indicates looping
* indefintely.
* @exception IllegalArgumentException Thrown if the given
* count is invalid.
* @exception IllegalStateException Thrown if the
* <code>Player</code> is in the <i>STARTED</i>
* or <i>CLOSED</i> state.
*/
public void setLoopCount(int count) {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
playerInst.setLoopCount(count);
} else {
if (count != 0) {
loopCount = count;
} else {
throw new IllegalArgumentException();
}
}
};
/**
* Add a player listener for this player.
*
* @param playerListener the listener to add.
* If <code>null</code> is used, the request will be ignored.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #removePlayerListener
*/
public void addPlayerListener(PlayerListener playerListener) {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
playerInst.addPlayerListener(playerListener);
} else {
if (playerListener != null) {
listeners.addElement(playerListener);
}
}
};
/**
* Remove a player listener for this player.
*
* @param playerListener the listener to remove.
* If <code>null</code> is used or the given
* <code>playerListener</code> is not a listener for this
* <code>Player</code>, the request will be ignored.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #addPlayerListener
*/
public void removePlayerListener(PlayerListener playerListener) {
if (isClosed) {
throw new IllegalStateException();
}
if (playerInst != null) {
playerInst.removePlayerListener(playerListener);
} else {
listeners.removeElement(playerListener);
}
};
/**
* Gets the controls attribute of the BasicPlayer object
*
* @return The controls value
*/
public final Control[] getControls() {
if (playerInst != null) {
return playerInst.getControls();
}
throw new IllegalStateException();
}
/**
* Gets the <code>Control</code> that supports the specified
* class or interface. The full class
* or interface name should be specified.
* <code>Null</code> is returned if the <code>Control</code>
* is not supported.
*
* @param type Description of the Parameter
* @return <code>Control</code> for the class or interface
* name.
*/
public Control getControl(String type) {
if (playerInst != null) {
return playerInst.getControl(type);
}
throw new IllegalStateException();
}
/**
* For global PlayerID management
*
* @param pid Description of the Parameter
* @return Description of the Return Value
*/
public static BasicPlayer get(int pid) {
return (BasicPlayer) (mplayers.get(new Integer(pid)));
}
/**
* Send external volume changed event to all of the player from this VM
*/
public static void sendExternalVolumeChanged(String evt, int volume) {
if (mplayers == null) {
return;
}
/* Send event to player if this player is in realized state (or above) */
for (Enumeration e = mplayers.elements(); e.hasMoreElements();) {
BasicPlayer p = (BasicPlayer) e.nextElement();
int state = p.getState();
if (state >= Player.REALIZED) {
VolumeControl vc = (VolumeControl)p.getControl("VolumeControl");
if (vc != null) {
vc.setLevel(volume);
}
}
}
}
/**
* Pauses and deallocates all media players.
*
* After this call all players are either in realized
* or unrealized state.
*
* Resources are being released during deallocation.
*/
public static void pauseAll() {
vmPaused = true;
if (mplayers == null) {
return;
}
for (Enumeration e = mplayers.elements(); e.hasMoreElements();) {
BasicPlayer p = (BasicPlayer) e.nextElement();
int state = p.getState();
long time = p.getMediaTime();
// save the player's state
pstates.put(p, new Integer(state));
// save the player's media time
mtimes.put(p, new Long(time));
try {
// Stop the player
if (state == Player.STARTED) {
p.stop();
}
} catch(MediaException ex) {
}
}
}
/**
* Resumes all media players' activities.
*
* Players that were in STARTED state when pause
* was called will resume playing at the media time
* they were stopped and deallocated.
*/
public static void resumeAll() {
vmPaused = false;
if (mplayers == null || pstates.size() == 0) {
return;
}
for (Enumeration e = mplayers.elements(); e.hasMoreElements();) {
BasicPlayer p = (BasicPlayer) e.nextElement();
int state = ((Integer) pstates.get(p)).intValue();
long time = ((Long) mtimes.get(p)).longValue();
switch (state) {
/*
case Player.PREFETCHED:
try {
p.prefetch();
p.setMediaTime(time);
} catch (MediaException ex) {
}
break;
*/
case Player.STARTED:
try {
//p.realize();
//p.prefetch();
if (p.getState() != Player.STARTED) {
p.setMediaTime(time);
p.start();
}
} catch (MediaException ex) {
}
break;
}
}
// clear player states and media times
pstates.clear();
mtimes.clear();
}
}

Просмотреть файл

@ -0,0 +1,36 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.Player;
import javax.microedition.media.MediaException;
public interface PlayerStateSubscriber
{
void PlayerRealized(Player player) throws MediaException;
void PlayerPrefetched(Player player) throws MediaException;
void PlayerDeallocated( Player player );
}

Просмотреть файл

@ -0,0 +1,49 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.MediaException;
/**
* The Tone Player Interface
*
* @created January 31, 2005
*/
public interface TonePlayer {
/**
* Plays a note of specified duration and volume
*
* @param note Defines the tone of the note.
* @param duration The duration of the tone in milli-seconds.
* @param volume Audio volume range from 0 to 100.
*/
void playTone(int note, int duration, int volume)
throws MediaException;
/**
* Stop current tone playing
*/
void stopTone();
}

Просмотреть файл

@ -0,0 +1,89 @@
/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.Control;
/**
* Description of the Class
*/
public abstract class VideoRenderer {
/**
* Description of the Field
*/
public final static int RGB565 = 1; // short []
/**
* Description of the Field
*/
public final static int RGB888 = 2; // byte []
/**
* Description of the Field
*/
public final static int XRGB888 = 3; // int []
/**
* Description of the Field
*/
public final static int XBGR888 = 4; // int []
/**
* Description of the Field
*/
public final static int RGBX888 = 5; // int []
/**
* Description of the Field
*/
public final static int YUV420_PLANAR = 6; // byte []
/**
* Description of the Field
*/
public final static int YUV422_PLANAR = 7; // byte []
/**
* Description of the Field
*/
public final static int YUYV = 8; // byte []
/**
* Description of the Field
*/
public final static int UYVY = 9; // byte []
/**
* Description of the Field
*/
public final static int YVYU = 10; // byte []
/**
* Description of the Field
*/
public final static int NATIVE_RENDER = 128; // to be ORed with above
/**
* Description of the Field
*/
public final static int USE_ALPHA = 256;
public abstract void initRendering(int colorMode, int width, int height);
public abstract void render(byte[] colorData);
public abstract void render(short[] colorData);
public abstract void render(int[] colorData);
public abstract void close();
public abstract Control getVideoControl();
}

Просмотреть файл

@ -0,0 +1,50 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.MediaException;
interface VideoSource
{
// Set display location of video
boolean setVideoLocation(int x, int y, int w, int h);
// Get snapshot
byte[] getVideoSnapshot(String imageType) throws MediaException;
// Set fullscreen
boolean setVideoFullScreen( boolean fullscreen);
// Set visible
boolean setVideoVisible( boolean visible);
// Turn on or off color key
boolean setColorKey(boolean on, int colorKey);
// Notifies that the Display Size was changed
void notifyDisplaySizeChange();
}

Просмотреть файл

@ -0,0 +1,117 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia.control;
/**
* <code>DualToneControl</code> is the interface to enable playback of a
* user-defined monotonic tone sequence with dual tone capabilities.
* <p>
* A tone sequence is specified as a list of tone-duration pairs and
* user-defined sequence blocks. The list is packaged as an
* array of bytes. The <code>setSequence</code> method is used to
* input the sequence to the <code>ToneControl</code>. In addition,
* the tone sequence format specified below can also be used as a
* file format to define tone sequences. A file containing a
* tone sequence as specified must use ".jts" as the file extension.
* <code>"audio/x-tone-seq"</code> designates the MIME type for this
* format.
* <p>
* <a name="tone_sequence_format"></a>
* The syntax of a tone sequence is described in
* <a href="http://www.ietf.org/rfc/rfc2234">Augmented BNF</a> notations:
* <blockquote>
* <pre>
* sequence = version *1tempo_definition *1resolution_definition
* *block_definition 1*sequence_event *dualtone_definition
*
* version = VERSION version_number
* VERSION = byte-value
* version_number = 1 ; version # 1
*
* tempo_definition = TEMPO tempo_modifier
* TEMPO = byte-value
* tempo_modifier = byte-value
* ; multiply by 4 to get the tempo (in bpm) used
* ; in the sequence.
*
* resolution_definition = RESOLUTION resolution_unit
* RESOLUTION = byte-value
* resolution_unit = byte-value
*
* block_definition = BLOCK_START block_number
* 1*sequence_event
* BLOCK_END block_number
* BLOCK_START = byte-value
* BLOCK_END = byte-value
* block_number = byte-value
* ; block_number specified in BLOCK_END has to be the
* ; same as the one in BLOCK_START
*
* sequence_event = tone_event / block_event /
* volume_event / repeat_event
*
* tone_event = note duration
* note = byte-value ; note to be played
* duration = byte-value ; duration of the note
*
* block_event = PLAY_BLOCK block_number
* PLAY_BLOCK = byte-value
* block_number = byte-value
* ; block_number must be previously defined
* ; by a full block_definition
*
* volume_event = SET_VOLUME volume
* SET_VOLUME = byte-value
* volume = byte-value ; new volume
*
* repeat_event = REPEAT multiplier tone_event
* REPEAT = byte-value
* multiplier = byte-value
* ; number of times to repeat a tone
*
* dualtone_definition = DUALTONE duration note note
* DUALTONE = byte-value
*
* byte-value = -128 - 127
* ; the value of each constant and additional
* ; constraints on each parameter are specified below.
* </pre>
* </blockquote>
*
* <A HREF="#DUALTONE"><code>DUALTONE</code></A>
* is pre-defined constant.
* <p>
*
*/
public interface DualToneControl extends javax.microedition.media.control.ToneControl {
/**
* The DUALTONE attribute tag.
* <p>
* Value -50 is assigned to <code>DUALTONE</code>.
*/
byte DUALTONE = -50;
}

Просмотреть файл

@ -0,0 +1,83 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia.protocol;
import java.io.*;
import javax.microedition.media.*;
import javax.microedition.media.protocol.*;
import java.util.Hashtable;
/**
* A DataSource base class
*/
public abstract class BasicDS extends DataSource {
protected String locator = null;
protected String contentType = null;
public BasicDS() {
super(null);
}
public void setLocator(String ml) throws MediaException {
locator = ml;
}
public String getLocator() {
return locator;
}
public String getContentType() {
return contentType;
}
public void setContentType(String type) {
contentType = type;
}
public Control[] getControls() {
return new Control[0];
}
public Control getControl(String controlType) {
return null;
}
/**
* Parse the protocol part of the locator string.
*/
static public String getProtocol(String loc) {
String proto = "";
int idx = loc.indexOf(':');
if( idx != -1) {
proto = loc.substring(0,idx);
}
return proto;
}
}

Просмотреть файл

@ -0,0 +1,459 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia.protocol;
import com.sun.mmedia.Configuration;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.media.*;
import javax.microedition.media.protocol.*;
// #ifdef USE_FILE_CONNECTION
import javax.microedition.io.file.*;
// #endif
import java.util.Hashtable;
/**
* A DataSource wrapper for InputStreams.
*/
public class CommonDS extends BasicDS implements SourceStream {
//native private static int nFileExists(String filename);
private long contentLength = -1;
private InputStream inputStream;
private ContentDescriptor contentDescriptor = null;
private boolean connected = false;
public void setLocator(String ml) throws MediaException {
super.setLocator(urlCvrt(ml));
}
/**
* Sets the inputStream attribute of the CommonDS object
*
* @param is The new inputStream value
*/
public void setInputStream(InputStream is) {
connected = true;
try {
super.setLocator(null);
} catch (MediaException e) { }
inputStream = is;
try {
//enable to call to is.reset()
is.mark(is.available());
} catch (IOException ioe) {
//ignore
}
/*
try {
contentLength = is.available();
} catch(IOException e) {
contentLength = -1;
}
*/
}
public void connect() throws IOException {
if (connected) {
return;
}
getConnection();
connected = true;
}
/**
* Gets the connection attribute of the CommonDS object
*
* @exception IOException Description of the Exception
*/
void getConnection() throws IOException {
boolean goodurl = false;
if (locator == null) {
throw (new IOException(this + ": connect() failed"));
}
String fileName = getRemainder(locator);
if (fileName == null) {
throw new IOException("bad url: " + locator);
}
try {
String locStr = locator.toLowerCase();
if (locStr.startsWith("http:") || locStr.startsWith("https:")) {
HttpConnection httpCon =
(HttpConnection)Connector.open(locator);
int rescode = httpCon.getResponseCode();
// If the response code of HttpConnection is in the range of
// 4XX and 5XX, that means the connection failed.
if (rescode >= 400) {
httpCon.close();
goodurl = false;
} else {
String ct = httpCon.getType();
if (ct != null) {
int idx;
if ((idx = ct.indexOf(',')) > 0) {
ct = ct.substring(0,idx);
} else if ((idx = ct.indexOf(';')) > 0) {
ct = ct.substring(0,idx);
} else if ((idx = ct.indexOf(' ')) > 0) {
ct = ct.substring(0,idx);
}
contentDescriptor = new ContentDescriptor(ct);
}
inputStream = httpCon.openInputStream();
contentLength = httpCon.getLength();
httpCon.close();
goodurl = true;
}
} else if (locator.startsWith("file:")) {
// #ifdef USE_FILE_CONNECTION [
FileConnection fileCon =
(FileConnection)Connector.open(locator);
if (fileCon.exists() && !fileCon.isDirectory() &&
fileCon.canRead()) {
inputStream = fileCon.openInputStream();
contentLength = fileCon.fileSize();
fileCon.close();
goodurl = true;
} else {
fileCon.close();
goodurl = false;
}
// #else ] [
throw new IOException("file protocol isn't supported");
// #endif ]
} else if (locator.startsWith("rtp:")) {
if( "unknown".equals( contentType ) ) {
contentType = "content.rtp";
}
inputStream = null;
contentLength = -1;
goodurl = true;
} else if (locator.startsWith("rtsp:")) {
System.out.println( "*** CommonDS::getConnection() -- RTSP!!!" );
//if( "unknown".equals( contentType ) ) {
contentType = "application/sdp";
//}
inputStream = null;
contentLength = -1;
goodurl = true;
} else if (locator.equals(Manager.TONE_DEVICE_LOCATOR)
|| locator.equals(Manager.MIDI_DEVICE_LOCATOR)) {
inputStream = null;
contentLength = -1;
goodurl = true;
}
} catch (RuntimeException re) {
throw re;
} catch (Exception ex) {
throw new IOException("failed to connect to " +
locator + " : " + ex.getMessage());
}
if ( !goodurl)
throw new IOException("bad url");
}
public synchronized void disconnect() {
if (!connected) {
return;
}
close();
connected = false;
}
public void start() throws IOException {
}
public void stop() {
}
/**
* Gets the streams attribute of the CommonDS object
*
* @return The streams value
*/
public SourceStream[] getStreams() {
if (inputStream == null) {
return new SourceStream [] { null };
}
return new SourceStream [] { this };
}
public long getDuration() {
return Player.TIME_UNKNOWN;
}
/**
* Methods for SourceStream.
*/
private long location;
/**
* Gets the contentDescriptor attribute of the CommonDS object
*
* @return The contentDescriptor value
*/
public ContentDescriptor getContentDescriptor() {
return contentDescriptor;
}
/**
* Gets the transferSize attribute of the CommonDS object
*
* @return The transferSize value
*/
public int getTransferSize() {
return -1;
}
/**
* read will perform a blocking read from stream. If
* buffer is null up to length bytes are read and discarded.
*
* @param buffer buffer to read into
* @param offset offset in the buffer to put data
* @param length bytes to read
* @returns bytes read or -1 for end of media
* @exception IOException
*/
public int read(byte buffer[], int offset, int length) throws IOException {
int bytesRead;
int len = length;
int off = offset;
do {
bytesRead = inputStream.read(buffer, off, len);
if (bytesRead == -1) {
int totalBytesRead = length - len;
return (totalBytesRead > 0) ? totalBytesRead : -1;
} else {
location += bytesRead;
len -= bytesRead;
off += bytesRead;
}
if ( len != 0)
Thread.yield();
} while (len != 0);
return length;
}
/**
* Seek to the specified point in the stream.
*
* @param where the position to seek to
* @returns the new stream position
*/
public long seek(long where) throws IOException {
int seekable = this.getSeekType();
if (seekable == NOT_SEEKABLE) {
throw new IOException("can't seek");
}
if (where < 0) {
where = 0;
}
if (seekable == SEEKABLE_TO_START && where != 0) {
throw new IOException("can't seek");
}
if ((contentLength > 0) && (where > contentLength)) {
where = contentLength;
}
long oldLocation = location;
long skipped = 0;
if (where < oldLocation) { // seek backward
reopenStream();
location = skip(inputStream, where);
} else {
skipped = skip(inputStream, (where - oldLocation));
location = oldLocation + skipped;
}
return (location);
}
/**
* Description of the Method
*
* @exception IOException Description of the Exception
*/
public void reopenStream() throws IOException {
if (inputStream == null) {
return;
}
// reopen the stream and go to the beginning of the stream
try {
inputStream.reset();
return;
} catch (IOException ex) {
if (getLocator() == null) {
throw ex;
}
}
if (inputStream != null) {
inputStream.close();
inputStream = null;
}
getConnection();
}
/**
* Obtain the current point in the stream.
*
* @returns the current point in the stream
*/
public long tell() {
return location;
}
/**
* close the stream which PullSourceStream handles
*
* @exception if an I/O error occurs
*/
public synchronized void close() {
if (inputStream == null) {
return;
}
try {
inputStream.close();
inputStream = null;
} catch (Exception e) {
}
}
public long getContentLength() {
return contentLength;
}
static final private int BUFLEN = 512;
static private byte[] buf = null;
/**
* @return number of bytes actually skipped
*/
private long skip(InputStream istream, long amount) throws IOException {
long remaining = amount;
int actual;
if (buf == null)
buf = new byte[BUFLEN];
while (remaining > 0) {
// istream.skip() does not work in particular impl cldc
actual = (int)(remaining > BUFLEN ? BUFLEN : remaining);
actual = istream.read(buf, 0, actual);
if (actual == 0) {
// in the of case that amount > the rest available length of
// inputstream, end the while loop,otherwise will loop forever
// inputstream.available always return 0, can not be used here.
break;
}
remaining -= actual;
}
return (amount - remaining);
}
public int getSeekType() {
if (inputStream == null) {
return NOT_SEEKABLE;
}
return RANDOM_ACCESSIBLE;
}
static private String getRemainder(String loc) {
String proto = "";
int idx = loc.indexOf(':');
if( idx != -1) {
proto = loc.substring(idx+1);
}
return proto;
}
public static String urlCvrt(String theml) {
String proto = getProtocol(theml);
String ret = theml;
// If it's file protocol, we'll try to strip out special characters
// in the URL syntax:
// %xx = the ASCII represented by the hexadecimal number "xx".
if (proto != null && proto.equals("file")) {
int idx;
String file = getRemainder(theml);
boolean changed = false;
if (file == null) {
return (theml);
}
try {
idx = 0;
while ((idx = file.indexOf("%", idx)) >= 0) {
if (file.length() > idx + 2) {
byte [] bytes = new byte[1];
try {
bytes[0] = (byte)Integer.valueOf(
file.substring(idx + 1, idx + 3), 16).intValue();
file = file.substring(0, idx) + new String(bytes) +
file.substring(idx + 3);
changed = true;
} catch (NumberFormatException ne) {
}
}
idx++;
}
if (changed)
ret = proto + ":" + file;
} catch (Exception e) {
ret = theml;
}
}
return ret;
}
}

Просмотреть файл

@ -1,5 +1,4 @@
/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER

Просмотреть файл

@ -1,5 +1,4 @@
/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER

Просмотреть файл

@ -1,5 +1,4 @@
/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
@ -25,11 +24,24 @@
*/
package javax.microedition.media;
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import java.util.Enumeration;
import java.util.Hashtable;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
import com.sun.mmedia.BasicPlayer;
import com.sun.mmedia.PlayerImpl;
import com.sun.mmedia.TonePlayer;
import com.sun.mmedia.Configuration;
import com.sun.mmedia.protocol.*;
import com.sun.mmedia.DefaultConfiguration;
import com.sun.mmedia.DirectPlayer;
import javax.microedition.media.protocol.*;
/**
* <code>Manager</code> is the access point for obtaining
@ -417,6 +429,9 @@ import java.io.IOException;
*/
public final class Manager {
private static Configuration config = Configuration.getConfiguration();
private static TonePlayer tonePlayer;
/**
* The locator to create a tone <code>Player</code>
@ -448,14 +463,36 @@ public final class Manager {
*/
public final static String TONE_DEVICE_LOCATOR = "device://tone";
// private final static String RADIO_CAPTURE_LOCATOR = "capture://radio";
private final static String DS_ERR = "Cannot create a DataSource for: ";
private final static String PL_ERR = "Cannot create a Player for: ";
/**
* The locator to create a MIDI <code>Player</code>
* which gives access to the MIDI device by making
* {@link javax.microedition.media.control.MIDIControl MIDIControl}
* available. For example,
* <pre>
* try {
* Player p = Manager.createPlayer(Manager.MIDI_DEVICE_LOCATOR);
* p.prefetch(); // opens the MIDI device
* MIDIControl m = (MIDIControl)p.getControl("MIDIControl");
* } catch (IOException ioe) {
* } catch (MediaException me) {}
* </pre>
*
* The MIDI <code>Player</code> returned does not carry any
* media data. <code>getDuration</code> returns 0 for this
* <code>Player</code>.
* <p>
* The content type of the <code>Player</code> created from this
* locator is <code>audio/midi</code>.
* <p>
* A <code>Player</code> for this locator may not be supported
* for all implementations.
* <p>
* Value "device://midi" is assigned to <code>MIDI_DEVICE_LOCATOR</code>.
*/
public final static String MIDI_DEVICE_LOCATOR = "device://midi";
private final static String REDIRECTED_MSG = " with exception message: ";
private static String DS_ERR = "Cannot create a DataSource for: ";
private static String PL_ERR = "Cannot create a Player for: ";
/**
* This private constructor keeps anyone from actually
@ -488,7 +525,7 @@ public final class Manager {
* @return The list of supported content types for the given protocol.
*/
public static String[] getSupportedContentTypes(String protocol) {
return new String[0];
return config.getSupportedContentTypes(protocol);
}
@ -520,9 +557,10 @@ public final class Manager {
* @return The list of supported protocols for the given content type.
*/
public static String[] getSupportedProtocols(String content_type) {
return new String[0];
return config.getSupportedProtocols(content_type);
}
/**
* Create a <code>Player</code> from an input locator.
*
@ -536,14 +574,289 @@ public final class Manager {
*/
public static Player createPlayer(String locator)
throws IOException, MediaException {
if (locator == null) {
throw new IllegalArgumentException();
}
throw new MediaException("Cannot create Player");
String locStr = locator.toLowerCase();
// System.out.println("[mmapi] createPlayer with " + locator);
/* Verify if Protocol is supported */
String theProtocol = null;
boolean found = false;
int idx = locStr.indexOf(':');
if (idx != -1) {
theProtocol = locStr.substring(0, idx);
} else {
throw new MediaException("Malformed locator");
}
if (locStr.startsWith(DefaultConfiguration.RADIO_CAPTURE_LOCATOR))
{
if (!config.isRadioSupported())
{
throw new MediaException( "Radio Capture is not supported" );
}
parseRadioLocatorStr(locator);
}
else if (locStr.startsWith(DefaultConfiguration.AUDIO_CAPTURE_LOCATOR) ||
locStr.startsWith(DefaultConfiguration.VIDEO_CAPTURE_LOCATOR))
{
// separate device & encodings
int encInd = locator.indexOf('?');
String encStr = null;
if (encInd > 0) {
locStr = locStr.substring(0, encInd);
idx = locator.indexOf("encoding=");
if (idx != -1) {
encStr = locator.substring(idx+9);
if (encStr != null) {
idx = encStr.indexOf('&');
if (idx > 0) {
encStr = encStr.substring(0, idx);
}
encStr = encStr.toLowerCase();
}
}
}
found = true;
String encodings = null;
if (locStr.equals(DefaultConfiguration.AUDIO_CAPTURE_LOCATOR)) {
String supported = System.getProperty("supports.audio.capture");
encodings = System.getProperty("audio.encodings");
if (supported == null || supported.equals("false") || encodings == null) {
found = false;
}
} else if (locStr.equals(DefaultConfiguration.VIDEO_CAPTURE_LOCATOR)) {
String supported = System.getProperty("supports.video.capture");
encodings = System.getProperty("video.encodings");
if (supported == null || supported.equals("false") || encodings == null) {
found = false;
}
}
if (encStr != null && encodings != null && encodings.indexOf(encStr) == -1) {
found = false;
}
if (!found) {
throw new MediaException("Player cannot be created for " + locator);
}
} else {
String supportedProtocols[] = getSupportedProtocols(null);
for (int i = 0; i < supportedProtocols.length && !found; i++) {
if (theProtocol.equals(supportedProtocols[i])) {
found = true;
}
}
if (!found) {
throw new MediaException("Player cannot be created for " + locator +
" Unsupported protocol " + theProtocol);
}
}
DataSource ds = createDataSource(locator);
Player pp = null;
try {
pp = createPlayer(ds);
} catch (MediaException ex) {
ds.disconnect();
throw ex;
} catch (IOException ex) {
ds.disconnect();
throw ex;
}
return pp;
}
private static void parseRadioLocatorStr( String locator ) throws MediaException
{
final int prefixLen =
DefaultConfiguration.RADIO_CAPTURE_LOCATOR.length();
if( null == locator )
{
throw new MediaException( "radio locator is null" );
}
if( !locator.startsWith( DefaultConfiguration.RADIO_CAPTURE_LOCATOR ) )
{
throw new MediaException( "bad radio locator" );
}
if ( locator.length() == prefixLen )
{
return;
}
if( locator.charAt( prefixLen ) != '?' )
{
throw new MediaException( "bad radio locator" );
}
String params = locator.substring( prefixLen + 1 );
parseRadioParamsString( params );
}
private static void parseRadioParamsString( String params ) throws MediaException
{
boolean foundFreq = false;
boolean foundMod = false;
boolean foundStereoMode = false;
boolean foundId = false;
boolean foundPreset = false;
int i = 0, j = -1;
do {
j = params.indexOf( '&', i );
String param = j < 0 ? params.substring( i ) : params.substring( i,
j );
if( param.startsWith( "f=" ) )
{
if( foundFreq )
{
throw new MediaException( "frequency is set more than" +
" once in the radio locator string" );
}
parseRadioFreqParam( param );
foundFreq = true;
}
else if ( param.startsWith( "mod=" ) )
{
if( foundMod )
{
throw new MediaException( "modulation is set more than" +
" once in the radio locator string" );
}
parseRadioModParam( param );
foundMod = true;
}
else if ( param.startsWith( "st=" ) )
{
if( foundStereoMode )
{
throw new MediaException( "stereo mode is set more than" +
" once in the radio locator string" );
}
parseRadioStereoParam( param );
foundStereoMode = true;
}
else if ( param.startsWith( "id=" ) )
{
if( foundId )
{
throw new MediaException( "Program ID is set more than" +
" once in the radio locator string" );
}
parseRadioIdParam( param );
foundId = true;
}
else if ( param.startsWith( "preset=" ) )
{
if( foundPreset )
{
throw new MediaException( "Preset is set more than" +
" once in the radio locator string" );
}
parseRadioPresetParam( param );
foundPreset = true;
}
else
{
throw new MediaException( "Unknown parameter in the" +
" radio locator string" );
}
i = j + 1;
} while( j >= 0 );
}
private static void parseRadioFreqParam( String s )
throws MediaException
{
String param = s;
if( 'M' == param.charAt( param.length() - 1 ) ||
'k' == param.charAt( param.length() - 1 ) )
{
param = param.substring( 0, param.length() - 1 );
}
try {
if( 0 >= Float.parseFloat( param.substring( 2 ) ) )
{
throw new MediaException( "Frequency is not positive" +
" in the radio locator string" );
}
} catch (NumberFormatException e)
{
throw new MediaException( "Frequency is not numeric or too big" +
" in the radio locator string" );
}
}
private static void parseRadioModParam( String param )
throws MediaException
{
String mod = param.substring( "mod=".length() );
if( !mod.equals( "am" ) && !mod.equals( "fm" ) )
{
throw new MediaException( "Unknown modulation in the" +
" radio locator string parameters" );
}
}
private static void parseRadioStereoParam( String param )
throws MediaException
{
String mode = param.substring( "st=".length() );
if( !mode.equals( "mono" ) &&
!mode.equals( "stereo" ) &&
!mode.equals( "auto" ))
{
throw new MediaException( "Unknown stereo mode in the" +
" radio locator string parameters" );
}
}
private static void parseRadioIdParam( String param )
throws MediaException
{
String id = param.toLowerCase().substring( "id=".length() );
if( 0 == id.length() )
{
throw new MediaException( "Empty Program ID name in" +
" the radio locator string parameters" );
}
for( int i = 0; i < id.length(); i++ )
{
char ch = id.charAt( i );
if( !Character.isLowerCase( ch ) &&
!Character.isDigit( ch ) )
{
throw new MediaException( "Not an alphanumeric Program" +
" ID in the radio locator string parameters" );
}
}
}
private static void parseRadioPresetParam( String param )
throws MediaException
{
String preset = param.substring( "preset=".length() );
try {
if( 0 >= Byte.parseByte( preset ) )
{
throw new MediaException( "Preset number is not positive" +
" in the radio locator string" );
}
} catch (NumberFormatException e)
{
throw new MediaException( "Preset number is not numeric" +
" or too big in the radio locator string" );
}
}
/**
* Create a <code>Player</code> to play back media from an
@ -569,16 +882,29 @@ public final class Manager {
*/
public static Player createPlayer(InputStream stream, String type)
throws IOException, MediaException {
if (stream == null) {
throw new IllegalArgumentException();
}
if (type == null) {
throw new MediaException(PL_ERR + "NULL content-type");
throw new MediaException(PL_ERR + "cannot determine the media type");
}
throw new MediaException("Cannot create Player");
type = type.toLowerCase();
// Wrap the input stream with a CommonDS where the input
// can be handled in a generic way.
CommonDS ds = new CommonDS();
ds.setInputStream(stream);
ds.setContentType(type);
try {
return createPlayer(ds);
} catch (IOException ex) {
throw new MediaException(PL_ERR + ex.getMessage());
}
}
@ -610,9 +936,182 @@ public final class Manager {
*/
public static void playTone(int note, int duration, int volume)
throws MediaException {
if (note < 0 || note > 127 || duration <= 0) {
throw new IllegalArgumentException("bad param");
throw new IllegalArgumentException( "Invalid note(" + note +
") or duration (" + duration + ")" );
}
if (volume < 0) {
volume = 0;
} else if (volume > 100) {
volume = 100;
}
if (duration == 0 || volume == 0) {
return;
}
if (tonePlayer == null) {
tonePlayer = config.getTonePlayer();
}
if (tonePlayer != null) {
tonePlayer.playTone(note, duration, volume);
} else {
throw new MediaException("no tone player");
}
}
/**
* MMAPI full specific methods.
*
* @param source Description of the Parameter
* @return Description of the Return Value
* @exception IOException Description of the Exception
* @exception MediaException Description of the Exception
*/
/**
* Create a <code>Player</code> for a <code>DataSource</code>.
*
* @param source The <CODE>DataSource</CODE> that provides
* the media content.
* @return A new <code>Player</code>.
* @exception MediaException Thrown if a <code>Player</code> cannot
* be created for the given <code>DataSource</code>.
* @exception IOException Thrown if there was a problem connecting
* with the source.
*/
public static Player createPlayer(DataSource source)
throws IOException, MediaException
{
if (source == null) {
throw new IllegalArgumentException();
}
String type;
try {
type = source.getContentType();
} catch( IllegalStateException e ) {
type = null;
}
if (type != null) {
String theProtocol = null;
String locator = source.getLocator();
if (locator != null) {
int idx = locator.indexOf(':');
if (idx != -1) {
theProtocol = locator.substring(0, idx);
}
}
String supportedContentTypes[] = getSupportedContentTypes(theProtocol);
boolean found = false;
for(int i=0; i<supportedContentTypes.length && !found; i++) {
if (type.equals(supportedContentTypes[i])) {
found = true;
}
}
if (!found) {
throw new MediaException("Player cannot be created for " + type);
}
}
PlayerImpl p = new PlayerImpl(source);
return p;
}
/**
* Create a <code>DataSource</code> for the specified media
* identified by a locator. The <code>DataSource</code>
* returned can be used to read the media data from the input
* source.
* <p>
* The returned data source is <i>connected</i>;
* <code>DataSource.connect</code> has been invoked.
* <p>
* If no suitable <code>DataSource</code> can be found to
* handle the input, a <CODE>MediaException</CODE>
* is thrown.
*
* @param locator The source protocol for the media data.
* @return A connected <CODE>DataSource</CODE>.
* @exception MediaException Thrown if no <CODE>DataSource</CODE>
* can be found that supports the given protocol as specified by
* the locator.
* @exception IOException Thrown if there was a problem connecting
* with the source (e.g. the source media does not exist).
*/
private static DataSource createDataSource(String locator)
throws IOException, MediaException {
String className = config.getProtocolHandler(BasicDS.getProtocol(locator));
if (className == null) {
throw new MediaException(DS_ERR + locator);
}
try {
// ... Try to create a DataSource instance ...
Class protoClass = Class.forName(className);
DataSource source = (DataSource) protoClass.newInstance();
// ... and get it connected ...
((BasicDS) source).setLocator(locator);
if (locator.equals(TONE_DEVICE_LOCATOR)) {
((BasicDS) source).setContentType("audio/x-tone-seq");
} else if (locator.equals(MIDI_DEVICE_LOCATOR)) {
((BasicDS) source).setContentType("audio/midi");
}
return source;
} catch (MediaException e) {
throw e;
} catch (Exception e) {
throw new MediaException(DS_ERR + e.getMessage());
}
}
private static TimeBase sysTimeBase = null;
/**
* Get the time-base object for the system.
*
* @return The system time base.
*/
public static TimeBase getSystemTimeBase() {
if (sysTimeBase == null) {
sysTimeBase = new SystemTimeBase();
}
return sysTimeBase;
}
}
/**
* SystemTimeBase is the implementation of the default <CODE>TimeBase</CODE>
* based on the system clock.
*
* @see TimeBase
*/
class SystemTimeBase implements TimeBase {
/*
* Pick some offset (start-up time) so the system time won't be
* so huge. The huge numbers overflow floating point operations
* in some cases.
*/
private static long offset = System.currentTimeMillis() * 1000L;
/**
* This is a straight-forward implementation of a
* system time base using the system clock.
*
* @return The time value
*/
public long getTime() {
return (System.currentTimeMillis() * 1000L) - offset;
}
}

Просмотреть файл

@ -1,5 +1,4 @@
/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER

Просмотреть файл

@ -1,5 +1,4 @@
/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
@ -26,81 +25,734 @@
package javax.microedition.media;
import javax.microedition.media.protocol.DataSource;
import java.io.IOException;
/**
* This class is defined by the JSR-118 specification
* <em>MIDP 2,
* Version 2.0.</em>
* <code>Player</code> controls the rendering of time based media data.
* It provides the methods to manage the <code>Player</code>'s life
* cycle, controls the playback progress, obtains the presentation
* components, controls and provides the means to synchronize
* with other <code>Players</code>.
*
* <h2>Simple Playback</h2>
*
* <blockquote>
* A <code>Player</code> can be created from one of the
* <code>Manager</code>'s <code>createPlayer</code> methods.
* After the <code>Player</code> is created,
* calling <code>start</code> will start the playback as soon as possible.
* The method will return when the
* playback is started. The playback will continue in the background
* and will stop automatically when the end of media is reached.
* <p>
* <a href="#example">Simple playback example</a> illustrates this.
* </blockquote>
*
* <h2>Player Life Cycle</h2>
*
* <blockquote>
* A <code>Player</code> has five states:
* <a href="#unrealizedState"><i>UNREALIZED</i></a>,
* <a href="#realizedState"><i>REALIZED</i></a>,
* <a href="#prefetchedState"><i>PREFETCHED</i></a>,
* <a href="#startedState"><i>STARTED</i></a>,
* <a href="#closedState"><i>CLOSED</i></a>.
* <p>
*
* The purpose of these life-cycle states is to provide
* programmatic control over potentially time-consuming operations.
* For example, when a <code>Player</code> is first constructed, it's in
* the <i>UNREALIZED</i> state.
* Transitioned from <I>UNREALIZED</I> to <I>REALIZED</I>, the
* <code>Player</code>
* performs the communication necessary to locate all of the resources
* it needs to function (such as communicating with a server
* or a file system).
* The <code>realize</code> method allows an application to initiate this
* potentially time-consuming process at an
* appropriate time.
* <p>
*
* Typically, a <code>Player</code> moves from the <i>UNREALIZED</i> state
* to the <i>REALIZED</i> state, then to the <i>PREFETCHED</i> state,
* and finally on to the <i>STARTED</i> state.
* <p>
*
* A <code>Player</code> stops when it reaches the
* end of media; when
* its stop time is reached;
* or when the <code>stop</code> method is invoked.
* When that happens, the <code>Player</code> moves from the
* <i>STARTED</i> state
* back to the <i>PREFETCHED</i> state.
* It is then ready to repeat the cycle.
* <p>
*
* To use a <code>Player</code>, you must set up parameters to
* manage its movement through these life-cycle states and then
* move it through the states using the <code>Player</code>'s
* state transition methods.
*
* </blockquote>
* <p>
*
* <h2>Player States</h2>
*
* <blockquote>
* This section describes the semantics of each of the <code>Player</code>
* states.
*
* <a name="unrealizedState"></a>
* <h3>UNREALIZED State</h3>
* <blockquote>
* A <code>Player</code> starts in
* the <i>UNREALIZED</i> state.
* An unrealized <code>Player</code>
* does not have enough information to acquire all the resources it needs
* to function.
* <p>
* The following methods must not be used
* when the <code>Player</code> is in
* the <i>UNREALIZED</i> state.
* <ul>
* <li> <CODE>getContentType</CODE>
* <li> <CODE>setTimeBase</CODE>
* <li> <CODE>getTimeBase</CODE>
* <li> <CODE>setMediaTime</CODE>
* <li> <CODE>getControls</CODE>
* <li> <CODE>getControl</CODE>
* </ul>
*
* An <code>IllegalStateException</code> will be thrown.
* <p>
* The <a href="#realize()"><code>realize</code></a> method transitions
* the <code>Player</code> from the <i>UNREALIZED</i> state to the
* <i>REALIZED</i> state.
* </blockquote>
*
* <a name="realizedState"></a>
* <h3>REALIZED State</h3>
*
* <blockquote>
* A <code>Player</code> is in the <i>REALIZED</i> state when it
* has obtained
* the information required to acquire the media resources.
* Realizing a <code>Player</code> can be a resource and
* time consuming process.
* The <code>Player</code> may have to communicate with
* a server, read a file, or interact with a set of objects.
* <p>
*
* Although a realized <code>Player</code> does not have
* to acquire any resources, it
* is likely to have acquired all of the resources it needs except
* those that imply exclusive use of a
* scarce system resource, such as an audio device.
* <p>
*
* Normally, a <code>Player</code> moves from the <i>UNREALIZED</i> state
* to the <i>REALIZED</i> state.
* After <a href="#realize()"><code>realize</code></a> has been
* invoked on a <code>Player</code>,
* the only way it can return
* to the <i>UNREALIZED</i> state is if
* <a href="#deallocate()"><code>deallocate</code></a> is
* invoked before <code>realize</code> is completed.
* Once a <code>Player</code> reaches the <i>REALIZED</i> state, it
* never returns to the <i>UNREALIZED</i> state. It remains in one of four
* states: <i>REALIZED</i>, <i>PREFETCHED</i>, <i>STARTED</i> or
* <i>CLOSED</i>.
* </blockquote>
*
* <a name="prefetchedState"></a>
* <h3>PREFETCHED State</h3>
*
* <blockquote>
* Once realized, a <code>Player</code> may still need to
* perform a number of time-consuming tasks before it is ready to be started.
* For example, it may need to acquire scarce or exclusive resources,
* fill buffers with media data, or perform other start-up processing.
* Calling
* <a href="#prefetch()"><code>prefetch</code></a>
* on the <code>Player</code> carries
* out these tasks.
* <p>
*
* Once a <code>Player</code> is in the <i>PREFETCHED</i> state, it may
* be started.
* Prefetching reduces the startup latency of a <code>Player</code>
* to the minimum possible value.
* <p>
*
* When a started <code>Player</code> stops,
* it returns
* to the <i>PREFETCHED</i> state.
* </blockquote>
* <p>
*
* <a name="startedState"></a>
* <h3>STARTED State</h3>
*
* <blockquote>
* Once prefetched, a <code>Player</code> can enter the
* <i>STARTED</i> state by calling the
* <a href="#start()"><code>start</code></a> method.
* A <I>STARTED</I>&nbsp;<CODE>Player</CODE>&nbsp;
* means the <code>Player</code> is running and processing data.
* A <code>Player</code> returns to the <i>PREFETCHED</i>
* state when it stops, because the
* <a href="#stop()"><code>stop</code></a> method was invoked,
* it has reached the end of the media, or its stop time.
* <p>
*
* When the <code>Player</code> moves from the <i>PREFETCHED</i>
* to the <i>STARTED</i> state, it posts a <code>STARTED</code> event.
* When it moves from the <i>STARTED</i> state to the
* <i>PREFETCHED</i> state,
* it posts a <code>STOPPED</code>, <code>END_OF_MEDIA</code> or
* <code>STOPPED_AT_TIME</code> event depending on the reason it
* stopped.
* <p>
*
* The following methods must not be used
* when the <code>Player</code> is in the <i>STARTED</i> state:
* <ul>
* <li> <CODE>setTimeBase</CODE>
* <li> <CODE>setLoopCount</CODE>
* </ul>
*
* An <code>IllegalStateException</code> will be thrown.
*
* </blockquote>
*
* <a name="closedState"></a>
* <h3>CLOSED state</h3>
*
* <blockquote>
* Calling <code>close</code> on the <code>Player</code>
* puts it in the <i>CLOSED</i> state. In the <i>CLOSED</i>
* state, the <code>Player</code> has
* released most of its resources and must not
* be used again.
* </blockquote>
*
* The <code>Player</code>'s five states and the state transition
* methods are summarized in the following diagram:
* <p>
* <blockquote>
* <img src="states.gif" width="492" height="183">
* </blockquote>
*
* </blockquote>
* <p>
*
* <a name="CE">
* <h2>Player Events</h2></a>
*
* <blockquote>
* <code>Player</code> events asynchronously deliver
* information about the <code>Player</code>'s state changes
* and other relevant information from the <code>Player</code>'s
* <code>Control</code>s.
* <p>
*
* To receive events, an object must implement the
* <code>PlayerListener</code> interface and use the
* <code>addPlayerListener</code> method to register its
* interest in a <code>Player</code>'s events.
* All <code>Player</code> events are posted to each
* registered listener.
* <p>
*
* The events are guaranteed to be delivered in the order
* that the actions representing the events occur.
* For example, if a <code>Player</code>
* stops shortly after it starts because it is playing back
* a very short media file, the <code>STARTED</code> event
* must always
* preceed the <code>END_OF_MEDIA</code> event.
* <p>
*
* An <code>ERROR</code> event may be sent any time
* an irrecoverable error has occured. When that happens, the
* <code>Player</code> is in the <i>CLOSED</i> state.
* <p>
*
* The <code>Player</code> event mechanism is extensible and
* some <code>Players</code> define events other than
* the ones described here. For a list of pre-defined player
* events, check the <code>PlayerListener</code> interface.
* </blockquote>
*
* <h3>Managing the Resources Used by a Player</h3>
*
* <blockquote>
* The <a href="#prefetch()"><code>prefetch</code></a>
* method is used to acquire scarce or exclusive resources
* such as the audio device.
* Conversely, the <a href="#deallocate()"><code>deallocate</code></a>
* method is used to release the scarce or exclusive
* resources. By using these two methods, an application can
* programmatically manage the <code>Player</code>'s resources.
* <p>
* For example, in an implementation with an exclusive audio device, to
* alternate the audio playback of multiple <code>Player</code>s,
* an application can selectively deallocate and prefetch individual
* <code>Player</code>s.
*
* </blockquote>
* <p>
*
* <h2>Player's TimeBase</h2>
*
* <blockquote>
* The <code>TimeBase</code> of a <code>Player</code> provides the
* basic measure of time for the <code>Player</code> to synchronize
* its media playback. Each <code>Player</code> must provide one
* default <code>TimeBase</code>. The <code>getTimeBase</code>
* method can be used to retrieve that.
* <p>
*
* Setting a different <code>TimeBase</code> on a
* <code>Player</code> instructs the <code>Player</code> to synchronize
* its playback rate according to the given <code>TimeBase</code>.
* <p>
*
* Two <code>Player</code>s can be synchronized by getting the
* <code>TimeBase</code> from one <code>Player</code> and setting
* that on the second <code>Player</code>.
* <p>
*
* However, not all <code>Player</code>s support using a different
* <code>TimeBase</code> other than its own. In such cases,
* a <code>MediaException</code> will be thrown when
* <code>setTimeBase</code> is called.
* </blockquote>
* <p>
*
* <a name="controls"></a>
* <h2>Player's Controls</h2>
* <blockquote>
* <code>Player</code> implements <code>Controllable</code> which
* provides extra controls via some type-specific <code>Control</code>
* interfaces. <code>getControl</code> and <code>getControls</code>
* cannot be called when the <code>Player</code> is in the
* <i>UNREALIZED</i> or <i>CLOSED</i> state.
* An <code>IllegalStateException</code> will be thrown.
* </blockquote>
* <p>
*
* <a name="example"></a>
* <h2>Simple Playback Example</h2>
*
* <blockquote>
* <pre>
* try {
* Player p = Manager.createPlayer("http://abc.mpg");
* p.realize();
* VideoControl vc;
* if ((vc = (VideoControl)p.getControl("VideoControl")) != null)
* add((Component)vc.initDisplayMode(vc.USE_GUI_PRIMITIVE, null));
* p.start();
* } catch (MediaException pe) {
* } catch (IOException ioe) {
* }
* </pre>
* </blockquote>
*
*/
// JAVADOC COMMENT ELIDED
public interface Player extends Controllable {
// JAVADOC COMMENT ELIDED
static final int UNREALIZED = 100;
/**
* The state of the <code>Player</code> indicating that it has
* not acquired the required information and resources to function.
* <p>
* Value 100 is assigned to <code>UNREALIZED</code>.
*/
int UNREALIZED = 100;
// JAVADOC COMMENT ELIDED
static final int REALIZED = 200;
/**
* The state of the <code>Player</code> indicating that it has
* acquired the required information but not the resources to function.
* <p>
* Value 200 is assigned to <code>REALIZED</code>.
*/
int REALIZED = 200;
// JAVADOC COMMENT ELIDED
static final int PREFETCHED = 300;
/**
* The state of the <code>Player</code> indicating that it has
* acquired all the resources to begin playing.
* <p>
* Value 300 is assigned to <code>PREFETCHED</code>.
*/
int PREFETCHED = 300;
// JAVADOC COMMENT ELIDED
static final int STARTED = 400;
/**
* The state of the <code>Player</code> indicating that the
* <code>Player</code> has already started.
* <p>
* Value 400 is assigned to <code>STARTED</code>.
*/
int STARTED = 400;
// JAVADOC COMMENT ELIDED
static final int CLOSED = 0;
/**
* The state of the <code>Player</code> indicating that the
* <code>Player</code> is closed.
* <p>
* Value 0 is assigned to <code>CLOSED</code>.
*/
int CLOSED = 0;
// JAVADOC COMMENT ELIDED
static final long TIME_UNKNOWN = -1;
/**
* The returned value indicating that the requested time is unknown.
* <p>
* Value -1 is assigned to <code>TIME_UNKNOWN</code>.
*/
long TIME_UNKNOWN = -1;
// JAVADOC COMMENT ELIDED
/**
* Constructs portions of the <code>Player</code> without
* acquiring the scarce and exclusive resources.
* This may include examining media data and may
* take some time to complete.
* <p>
* When <code>realize</code> completes successfully,
* the <code>Player</code> is in the
* <i>REALIZED</i> state.
* <p>
* If <code>realize</code> is called when the <code>Player</code> is in
* the <i>REALIZED</i>, <i>PREFETCHTED</i> or <i>STARTED</i> state,
* the request will be ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be realized.
* @exception SecurityException Thrown if the caller does not
* have security permission to realize the <code>Player</code>.
*
*/
void realize() throws MediaException;
// JAVADOC COMMENT ELIDED
/**
* Acquires the scarce and exclusive resources
* and processes as much data as necessary
* to reduce the start latency.
* <p>
* When <code>prefetch</code> completes successfully,
* the <code>Player</code> is in
* the <i>PREFETCHED</i> state.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> state,
* it will implicitly call <code>realize</code>.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is already in the <i>PREFETCHED</i> state, the <code>Player</code>
* may still process data necessary to reduce the start
* latency. This is to guarantee that start latency can
* be maintained at a minimum.
* <p>
* If <code>prefetch</code> is called when the <code>Player</code>
* is in the <i>STARTED</i> state,
* the request will be ignored.
* <p>
* If the <code>Player</code> cannot obtain all
* of the resources it needs, it throws a <code>MediaException</code>.
* When that happens, the <code>Player</code> will not be able to
* start. However, <code>prefetch</code> may be called again when
* the needed resource is later released perhaps by another
* <code>Player</code> or application.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be prefetched.
* @exception SecurityException Thrown if the caller does not
* have security permission to prefetch the <code>Player</code>.
*
*/
void prefetch() throws MediaException;
// JAVADOC COMMENT ELIDED
/**
* Starts the <code>Player</code> as soon as possible.
* If the <code>Player</code> was previously stopped
* by calling <code>stop</code> or reaching a preset
* stop time, it will resume playback
* from where it was previously stopped. If the
* <code>Player</code> has reached the end of media,
* calling <code>start</code> will automatically
* start the playback from the start of the media.
* <p>
* When <code>start</code> returns successfully,
* the <code>Player</code> must have been started and
* a <code>STARTED</code> event will
* be delivered to the registered <code>PlayerListener</code>s.
* However, the <code>Player</code> is not guaranteed to be in
* the <i>STARTED</i> state. The <code>Player</code> may have
* already stopped (in the <i>PREFETCHED</i> state) because
* the media has 0 or a very short duration.
* <p>
* If <code>start</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i> state,
* it will implicitly call <code>prefetch</code>.
* <p>
* If <code>start</code> is called when the <code>Player</code>
* is in the <i>STARTED</i> state,
* the request will be ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code> cannot
* be started.
* @exception SecurityException Thrown if the caller does not
* have security permission to start the <code>Player</code>.
*/
void start() throws MediaException;
// JAVADOC COMMENT ELIDED
/**
* Stops the <code>Player</code>. It will pause the playback at
* the current media time.
* <p>
* When <code>stop</code> returns, the <code>Player</code> is in the
* <i>PREFETCHED</i> state.
* A <code>STOPPED</code> event will be delivered to the registered
* <code>PlayerListener</code>s.
* <p>
* If <code>stop</code> is called on
* a stopped <code>Player</code>, the request is ignored.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @exception MediaException Thrown if the <code>Player</code>
* cannot be stopped.
*/
void stop() throws MediaException;
// JAVADOC COMMENT ELIDED
/**
* Release the scarce or exclusive
* resources like the audio device acquired by the <code>Player</code>.
* <p>
* When <code>deallocate</code> returns, the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i> state.
* <p>
* If the <code>Player</code> is blocked at
* the <code>realize</code> call while realizing, calling
* <code>deallocate</code> unblocks the <code>realize</code> call and
* returns the <code>Player</code> to the <i>UNREALIZED</i> state.
* Otherwise, calling <code>deallocate</code> returns the
* <code>Player</code> to the <i>REALIZED</i> state.
* <p>
* If <code>deallocate</code> is called when the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>REALIZED</i>
* state, the request is ignored.
* <p>
* If the <code>Player</code> is <code>STARTED</code>
* when <code>deallocate</code> is called, <code>deallocate</code>
* will implicitly call <code>stop</code> on the <code>Player</code>.
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
*/
void deallocate();
// JAVADOC COMMENT ELIDED
/**
* Close the <code>Player</code> and release its resources.
* <p>
* When the method returns, the <code>Player</code> is in the
* <i>CLOSED</i> state and can no longer be used.
* A <code>CLOSED</code> event will be delivered to the registered
* <code>PlayerListener</code>s.
* <p>
* If <code>close</code> is called on a closed <code>Player</code>
* the request is ignored.
*/
void close();
/**
* Sets the <code>TimeBase</code> for this <code>Player</code>.
* <p>
* A <code>Player</code> has a default <code>TimeBase</code> that
* is determined by the implementation.
* To reset a <code>Player</code> to its default
* <code>TimeBase</code>, call <code>setTimeBase(null)</code>.
*
* @param master The new <CODE>TimeBase</CODE> or
* <CODE>null</CODE> to reset the <code>Player</code>
* to its default <code>TimeBase</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i>, <i>STARTED</i> or <i>CLOSED</i> state.
* @exception MediaException Thrown if
* the specified <code>TimeBase</code> cannot be set on the
* <code>Player</code>.
* @see #getTimeBase
*/
void setTimeBase(TimeBase master) throws MediaException;
// JAVADOC COMMENT ELIDED
/**
* Gets the <code>TimeBase</code> that this <code>Player</code> is using.
* @return The <code>TimeBase</code> that this <code>Player</code> is using.
* @see #setTimeBase
*
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
*/
TimeBase getTimeBase();
/**
* Sets the <code>Player</code>'s&nbsp;<i>media time</i>.
* <p>
* For some media types, setting the media time may not be very
* accurate. The returned value will indicate the
* actual media time set.
* <p>
* Setting the media time to negative values will effectively
* set the media time to zero. Setting the media time to
* beyond the duration of the media will set the time to
* the end of media.
* <p>
* There are some media types that cannot support the setting
* of media time. Calling <code>setMediaTime</code> will throw
* a <code>MediaException</code> in those cases.
*
* @param now The new media time in microseconds.
* @return The actual media time set in microseconds.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
* @exception MediaException Thrown if the media time
* cannot be set.
* @see #getMediaTime
*/
long setMediaTime(long now) throws MediaException;
// JAVADOC COMMENT ELIDED
/**
* Gets this <code>Player</code>'s current <i>media time</i>.
* <p>
* <code>getMediaTime</code> may return <code>TIME_UNKNOWN</code> to
* indicate that the media time cannot be determined.
* However, once <code>getMediaTime</code> returns a known time
* (time not equals to <code>TIME_UNKNOWN</code>), subsequent calls
* to <code>getMediaTime</code> must not return
* <code>TIME_UNKNOWN</code>.
*
* @return The current <i>media time</i> in microseconds or
* <code>TIME_UNKNOWN</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #setMediaTime
*/
long getMediaTime();
// JAVADOC COMMENT ELIDED
/**
* Gets the current state of this <code>Player</code>.
* The possible states are: <i>UNREALIZED</i>,
* <i>REALIZED</i>, <i>PREFETCHED</i>, <i>STARTED</i>, <i>CLOSED</i>.
*
* @return The <code>Player</code>'s current state.
*/
int getState();
// JAVADOC COMMENT ELIDED
/**
* Get the duration of the media.
* The value returned is the media's duration
* when played at the default rate.
* <br>
* If the duration cannot be determined (for example, the
* <code>Player</code> is presenting live
* media) <CODE>getDuration</CODE> returns <CODE>TIME_UNKNOWN</CODE>.
*
* @return The duration in microseconds or <code>TIME_UNKNOWN</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
*/
long getDuration();
// JAVADOC COMMENT ELIDED
/**
* Get the content type of the media that's
* being played back by this <code>Player</code>.
* <p>
* See <a href="Manager.html#content-type">content type</a>
* for the syntax of the content type returned.
*
* @return The content type being played back by this
* <code>Player</code>.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>UNREALIZED</i> or <i>CLOSED</i> state.
*/
String getContentType();
// JAVADOC COMMENT ELIDED
/**
* Set the number of times the <code>Player</code> will loop
* and play the content.
* <p>
* By default, the loop count is one. That is, once started,
* the <code>Player</code> will start playing from the current
* media time to the end of media once.
* <p>
* If the loop count is set to N where N is bigger than one,
* starting the <code>Player</code> will start playing the
* content from the current media time to the end of media.
* It will then loop back to the beginning of the content
* (media time zero) and play till the end of the media.
* The number of times it will loop to the beginning and
* play to the end of media will be N-1.
* <p>
* Setting the loop count to 0 is invalid. An
* <code>IllegalArgumentException</code> will be thrown.
* <p>
* Setting the loop count to -1 will loop and play the content
* indefinitely.
* <p>
* If the <code>Player</code> is stopped before the preset loop
* count is reached either because <code>stop</code> is called or
* a preset stop time (set with the <code>StopTimeControl</code>)
* is reached, calling <code>start</code> again will
* resume the looping playback from where it was stopped until it
* fully reaches the preset loop count.
* <p>
* An <i>END_OF_MEDIA</i> event will be posted
* every time the <code>Player</code> reaches the end of media.
* If the <code>Player</code> loops back to the beginning and
* starts playing again because it has not completed the loop
* count, a <i>STARTED</i> event will be posted.
*
* @param count indicates the number of times the content will be
* played. 1 is the default. 0 is invalid. -1 indicates looping
* indefintely.
* @exception IllegalArgumentException Thrown if the given
* count is invalid.
* @exception IllegalStateException Thrown if the
* <code>Player</code> is in the <i>STARTED</i>
* or <i>CLOSED</i> state.
*/
void setLoopCount(int count);
// JAVADOC COMMENT ELIDED
/**
* Add a player listener for this player.
*
* @param playerListener the listener to add.
* If <code>null</code> is used, the request will be ignored.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #removePlayerListener
*/
void addPlayerListener(PlayerListener playerListener);
// JAVADOC COMMENT ELIDED
/**
* Remove a player listener for this player.
*
* @param playerListener the listener to remove.
* If <code>null</code> is used or the given
* <code>playerListener</code> is not a listener for this
* <code>Player</code>, the request will be ignored.
* @exception IllegalStateException Thrown if the <code>Player</code>
* is in the <i>CLOSED</i> state.
* @see #addPlayerListener
*/
void removePlayerListener(PlayerListener playerListener);
}

Просмотреть файл

@ -1,5 +1,4 @@
/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
@ -88,6 +87,19 @@ public interface PlayerListener {
*/
String STOPPED = "stopped";
/**
* Posted when a <code>Player</code> is stopped as responding to
* the <code>setStopTime</code> call using the
* <code>StopTimeControl</code>.
* When this event is received, the <code>eventData</code> parameter
* will be a <code>Long</code> object designating the media
* time when the <code>Player</code> is stopped.
* <p>
* Value <code>stoppedAtTime</code> is assigned to
* <code>STOPPED_AT_TIME</code>.
*/
String STOPPED_AT_TIME = "stoppedAtTime";
/**
* Posted when a <code>Player</code> has reached the
* end of the media.
@ -174,7 +186,21 @@ public interface PlayerListener {
*/
String VOLUME_CHANGED = "volumeChanged";
/**
* Posted when the size of the video is changed either because
* the source video size or the display size is changed.
* When this event is received, the <code>eventData</code> parameter
* will be a <a href="control/VideoControl.html">
* <code>VideoControl</code></a>
* object. The new sizes
* can be queried from the <code>VideoControl</code>.
* <p>
* Value <code>sizeChanged</code> is assigned to
* <code>SIZE_CHANGED</code>.
*/
String SIZE_CHANGED = "sizeChanged";
/**
* Posted when an error had occurred.
* When this event is received, the <code>eventData</code> parameter
@ -193,6 +219,69 @@ public interface PlayerListener {
*/
String CLOSED = "closed";
/**
* Posted when recording is started.
* <p>
* When this event is received, the <code>eventData</code> parameter
* will be a <code>Long</code> object designating the media
* time when the recording is started.
* <p>
* Value <code>recordStarted</code> is assigned to
* <code>RECORD_STARTED</code>.
*/
String RECORD_STARTED = "recordStarted";
/**
* Posted when recording is stopped.
* <p>
* When this event is received, the <code>eventData</code> parameter
* will be a <code>Long</code> object designating the media
* time when the recording stopped.
* <p>
* Value <code>recordStopped</code> is assigned to
* <code>RECORD_STOPPED</code>.
*/
String RECORD_STOPPED = "recordStopped";
/**
* Posted when an error occurs during the recording.
* The current recording will be discarded. The
* application may set a new record location or
* stream to start recording again.
* When this event is received, the <code>eventData</code> parameter
* will be a <code>String</code> object specifying the error message.
* <p>
* Value <code>recordError</code> is assigned to
* <code>RECORD_ERROR</code>.
*/
String RECORD_ERROR = "recordError";
/**
* Posted when the <code>Player</code> enters into a buffering mode.
* Applications may require this event to handle other tasks.
* <p>
* When this event is received, the <code>eventData</code> parameter
* will be a <code>Long</code> object designating the media
* time when the buffering is started.
* <p>
* Value <code>bufferingStarted</code> is assigned to
* <code>BUFFERING_STARTED</code>.
*/
String BUFFERING_STARTED = "bufferingStarted";
/**
* Posted when the <code>Player</code> leaves the buffering mode.
* Applications may require this event to handle other tasks.
* <p>
* When this event is received, the <code>eventData</code> parameter
* will be a <code>Long</code> object designating the media
* time when the buffering stopped.
* <p>
* Value <code>bufferingStopped</code> is assigned to
* <code>BUFFERING_STOPPED</code>.
*/
String BUFFERING_STOPPED = "bufferingStopped";
/**
* This method is called to deliver an event to a registered
* listener when a <code>Player</code> event is observed.

Просмотреть файл

@ -0,0 +1,57 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media;
/**
* A <code>TimeBase</code> is a constantly ticking source of time.
* It measures the progress of time and
* provides the basic means for synchronizing media playback for
* <code>Player</code>s.
* <p>
* A <code>TimeBase</code> measures time in microseconds in
* order to provide the necessary resolution for synchronization.
* It is acknowledged that some implementations may not be able to
* support time resolution in the microseconds range. For such
* implementations, the internal representation of time can be done
* within their limits.
* But the time reported via the API must be scaled to the microseconds
* range.
* <p>
* <code>Manager.getSystemTimeBase</code> provides the default
* <code>TimeBase</code> used by the system.
*
* @see Player
*/
public interface TimeBase {
/**
* Get the current time of this <code>TimeBase</code>. The values
* returned must be non-negative and non-decreasing over time.
*
* @return the current <code>TimeBase</code> time in microseconds.
*/
long getTime();
}

Просмотреть файл

@ -0,0 +1,166 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
/**
* <code>GUIControl</code> extends <code>Control</code> and is defined
* for controls that provide GUI functionalities.
* <p>
* <code>Control</code>s that support a GUI component
* should implement this interface.
*/
public interface GUIControl extends javax.microedition.media.Control {
/**
* This defines a mode on how the GUI is displayed.
* It is used in conjunction with
* <a href="#initDisplayMode(int, java.lang.Object)">
* <code>initDisplayMode</code></a>.
* <p>
* When <code>USE_GUI_PRIMITIVE</code> is specified for
* <code>initDisplayMode</code>, a GUI primitive will be
* returned. This object is where the GUI
* of this control will be displayed.
* It can be used
* in conjunction with other GUI objects, and conforms
* to the GUI behaviors as specified by
* the platform.
* <p>
* For a given platform, the object returned
* must implement or extend from the appropriate GUI primitive
* of the platform. For platforms that support only AWT such as
* some CDC implementations, the object must
* extend from <code>java.awt.Component</code>; for MIDP
* implementations with only LCDUI support, it must extend from
* <code>javax.microedition.lcdui.Item</code>.
* <p>
* In these cases, the <code>arg</code> argument must be
* <code>null</code> or a <code>String</code> that specifies
* the fully-qualified classname of the GUI primitive.
* <p>
* On some platforms that support multiple types of GUI primitives,
* the <code>arg</code> argument must be used to arbitrate among the
* options. The <code>arg</code> argument must be a
* <code>String</code> that specifies the fully-qualified
* classname of the GUI primitive to be returned by the method.
* <p>
* For example, a platform that supports both AWT and LCDUI
* must use either <code>"java.awt.Component"</code> or
* <code>"javax.microedition.lcdui.Item"</code> as the
* <code>arg</code> argument. The object returned will be
* of either type according to what's specified.
* <p>
* Here are some sample usage scenarios:
* <p>
* For CDC implementations with only AWT support:
* <pre>
* <code>
* try {
* Player p = Manager.createPlayer("http://abc.mpg");
* p.realize();
* GUIControl gc;
* if ((gc = (GUIControl)p.getControl("GUIControl")) != null)
* add((Component)gc.initDisplayMode(GUIControl.USE_GUI_PRIMITIVE, null));
* p.start();
* } catch (MediaException pe) {
* } catch (IOException ioe) {
* }
* </code>
* </pre>
* <p>
* For MIDP implementations with only LCDUI support:
* <pre>
* <code>
* try {
* Player p = Manager.createPlayer("http://abc.mpg");
* p.realize();
* GUIControl gc;
* if ((gc = (GUIControl)p.getControl("GUIControl")) != null) {
* Form form = new Form("My GUI");
* form.append((Item)gc.initDisplayMode(GUIControl.USE_GUI_PRIMITIVE, null));
* Display.getDisplay().setCurrent(form);
* }
* p.start();
* } catch (MediaException pe) {
* } catch (IOException ioe) {
* }
* </code>
* </pre>
* <p>
* For implementations with both AWT and LCDUI support:
* <pre>
* <code>
* try {
* Player p = Manager.createPlayer("http://abc.mpg");
* p.realize();
* GUIControl gc;
* if ((gc = (GUIControl)p.getControl("GUIControl")) != null)
* add((Component)gc.initDisplayMode(GUIControl.USE_GUI_PRIMITIVE,
* "java.awt.Component");
* p.start();
* } catch (MediaException pe) {
* } catch (IOException ioe) {
* }
* </code>
* </pre>
* <p>
* Value 0 is assigned to <code>USE_GUI_PRIMITIVE</code>.
*/
int USE_GUI_PRIMITIVE = 0;
/**
* Initialize the mode on how the GUI is displayed.
*
* @param mode The mode that determines how the GUI is
* displayed. <code>GUIControl</code> defines only
* one mode:
* <a href="#USE_GUI_PRIMITIVE"><code>USE_GUI_PRIMITIVE</code></a>.
* Subclasses of this may introduce more modes.
*
* @param arg The exact semantics of this argument is
* specified in the respective mode definitions.
*
* @return The exact semantics and type of the object returned
* are specified in the respective mode definitions.
*
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> is called again after it has
* previously been called successfully.
*
* @exception IllegalArgumentException Thrown if
* the <code>mode</code> or <code>arg</code>
* argument is invalid. <code>mode</code> must be
* defined by GUIControl or its subclasses; or a custom mode
* supported by this implementation.
* <code>arg</code> must conform to the
* constraints defined by the
* respective mode definitions.
* Refer to the mode definitions for the required type
* of <code>arg</code>.
*/
Object initDisplayMode(int mode, Object arg);
}

Просмотреть файл

@ -0,0 +1,452 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
import javax.microedition.media.MediaException;
/**
* <code>MIDIControl</code> provides access to MIDI rendering
* and transmitting devices.<p>
*
* Typical devices that are controlled with <code>MIDIControl</code>
* are internal synthesizers (software/hardware) or external
* hardware ports. Devices are virtual, i.e. even if there is only
* one physical synthesizer, all instances of <code>MIDIControl</code> seem
* to operate on its own synthesizer.<p>
*
* General functionality of this control is:
* <ol>
* <li>Querying current state of the device:
* <ul>
* <li>The programs that are currently assigned to each of the 16 channels</li>
* <li>Volume of each channel</li>
* </ul></li>
* <li>Querying the banks of the synthesizer:
* <ul>
* <li>Get a list of internal sound banks</li>
* <li>Get a list of custom sound banks</li>
* <li>Get the list of programs of a sound bank</li>
* <li>Get the name of a specific program</li>
* </ul></li>
* <li>Set the volume assigned to a channel</li>
* <li>Set the bank/program assigned to a channel</li>
* <li>Send short MIDI messages to the device</li>
* <li>Send long MIDI messages (system exclusive)</li>
* </ol>
*
* In Java Sound terms, <code>MIDIControl</code> combines
* methods and concepts of the interfaces Transmitter,
* Receiver, Synthesizer, MidiChannel, Soundbank, and Patch.<p>
*
* In this context, the following naming conventions are used:
* <ul>
* <li>A <i>program</i> refers to a single instrument. This is
* also known as a patch.</li>
* <li>A <i>bank</i> is short for sound bank. It contains up
* to 128 programs, numbered in the range from 0..127.</li>
* <li>An <i>internal bank</i> is provided by the software
* implementation or the hardware of the device.</li>
* <li>A <i>custom bank</i> is installed by an application,
* e.g. by loading an XMF meta file with an embedded bank.</li>
* </ul>
* <p>
* The conception of <code>MIDIControl</code> is based on scope and
* abstraction level:
* <ul>
* <li><code>MIDIControl</code> has methods that are specific
* to the device or renderer, and do not directly relate to a specific
* MIDI file or sequence to be played. However, as devices are virtual,
* MIDIControl's methods only operate on this virtual device.
* On the other hand, it is also
* possible to get an instance of <code>MIDIControl</code>
* without providing a sequence or MIDI file; this is done by
* specifying a magic Locator:<br>
* <br><code>
* &nbsp;&nbsp;try{
* <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Player
* p = Manager.createPlayer(Manager.MIDI_DEVICE_LOCATOR);
* <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MIDIControl
* synth = (MIDIControl)p.getControls("javax.microedition.media.control.MIDIControl");
* <br>&nbsp;&nbsp;} catch (MediaException e) {
* <br>&nbsp;&nbsp;}
* </code></li>
*
* <li><code>MIDIControl</code>'s methods can be considered
* advanced, low level functionality. This has 2 implications:
* <ol>
* <li><code>MIDIControl</code> is optional, i.e. no Player
* instance is required to provide an implementation of
* it</li>
* <li>Basic media or MIDI player applications will not need
* <code>MIDIControl</code>; {@link VolumeControl VolumeControl},
* {@link TempoControl TempoControl}, and {@link PitchControl PitchControl}
* are sufficient for basic needs.
* </li>
* </ol></li>
* </ul>
* <p>
* A useful function is &quot;Panic&quot;: immediately turn off all
* sounds and notes. It can be implemented using the following code fragment:<br>
* <code>
* &nbsp;&nbsp;int CONTROL_ALL_SOUND_OFF = 0x78;<br>
* &nbsp;&nbsp;for (int channel = 0; channel < 16; channel++) {<br>
* &nbsp;&nbsp;&nbsp;&nbsp;shortMidiEvent(CONTROL_CHANGE | channel, CONTROL_ALL_SOUND_OFF, 0);<br>
* &nbsp;&nbsp;}<br>
* </code>
* <p>
* The implementation need not support the various query methods.
* This is a technical limitation, as the MIDI standard does not
* provide a standardized means to query the current program or
* the installed
* soundbanks. This especially applies to external MIDI ports.
* Optional methods must not be called if {@link #isBankQuerySupported isBankQuerySupported}
* returns false.
*
* @see javax.microedition.media.Player
* @see javax.microedition.media.control.RateControl
* @see javax.microedition.media.control.TempoControl
* @see javax.microedition.media.control.PitchControl
*/
public interface MIDIControl extends javax.microedition.media.Control {
// constants for MIDI status (upper nibble of first byte)
/**
* Command value for Note On message (0x90, or 144).
* To turn a note off, send a NOTE_ON message with 0
* velocity. Alternatively, a Note Off message (0x80)
* can be sent.
*
* @see #shortMidiEvent(int, int, int)
*/
int NOTE_ON = 0x90; // 144
/**
* Command value for Control Change message (0xB0, or 176).
* @see #shortMidiEvent(int, int, int)
*/
int CONTROL_CHANGE = 0xB0; // 176
// query device state
/**
* Returns whether banks of the synthesizer can be queried.
* <p>
* If this functions returns true,
* then the following methods can be used to query banks:
* <ul>
* <li>{@link #getProgram(int) getProgram(int)}</li>
* <li>{@link #getBankList(boolean) getBankList(boolean)}</li>
* <li>{@link #getProgramList(int) getProgramList(int)}</li>
* <li>{@link #getProgramName(int, int) getProgramName(int, int)}</li>
* <li>{@link #getKeyName(int, int, int) getKeyName(int, int, int)}</li>
* </ul>
*
* @return true if this device supports querying of banks
*/
boolean isBankQuerySupported();
// send a Program Change short MIDI message, or
/**
* Returns program assigned to channel. It represents the current
* state of the channel. During playback of a MIDI file, the program
* may change due to program change events in the MIDI file.<p>
* To set a program for a channel,
* use setProgram(int, int, int).<p>
*
* The returned array is represented by an array {bank,program}.<p>
* If the device has not been initialized with a MIDI file, or the MIDI file
* does not contain a program change for this channel, an implementation
* specific default value is returned.<p>
*
* As there is no MIDI equivalent to this method, this method is
* optional, indicated by {@link #isBankQuerySupported isBankQuerySupported}.
* If it returns false, this function is not supported and throws an exception.
*
* @param channel 0-15
* @return program assigned to channel, represented by array {bank,program}.
* @exception IllegalArgumentException Thrown if <code>channel</code>
* is out of range.
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @exception MediaException Thrown if querying of banks is not supported.
* @see #isBankQuerySupported
* @see #setProgram
*/
int[] getProgram(int channel)
throws MediaException;
/**
* Get volume for the given channel. The return value is
* independent of the master volume, which is set and retrieved
* with {@link VolumeControl VolumeControl}.<p>
*
* As there is no MIDI equivalent to this method, the implementation
* may not always know the current volume for a given channel. In
* this case the return value is -1.
*
* @param channel 0-15
* @return channel volume, 0-127, or -1 if not known
* @exception IllegalArgumentException Thrown if <code>channel</code>
* is out of range.
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @see #setChannelVolume(int, int)
*/
int getChannelVolume(int channel);
// set device state
/**
* Set program of a channel. This sets the current program for the
* channel and may be overwritten during playback by events in a MIDI sequence.<p>
* It is a high level convenience function. Internally, these method calls are
* executed:<p>
* <code>
* &nbsp;&nbsp;shortMidiEvent(CONTROL_CHANGE | channel, CONTROL_BANK_CHANGE_MSB, bank >> 7);<br>
* &nbsp;&nbsp;shortMidiEvent(CONTROL_CHANGE | channel, CONTROL_BANK_CHANGE_LSB, bank & 0x7F);<br>
* &nbsp;&nbsp;shortMidiEvent(PROGRAM_CHANGE | channel, program, 0);
* </code><p>
*
* In order to use the default bank (the initial bank), set the bank parameter to -1.
* <p>
*
* In order to set a program without explicitly setting the bank,
* use the following call: <p>
* <code>
* &nbsp;&nbsp;shortMidiEvent(PROGRAM_CHANGE | channel, program, 0);
* </code><p>
*
* In both examples, the following constants are used:<p>
* <code>
* &nbsp;&nbsp;int PROGRAM_CHANGE = 0xC0;<br>
* &nbsp;&nbsp;int CONTROL_BANK_CHANGE_MSB = 0x00;<br>
* &nbsp;&nbsp;int CONTROL_BANK_CHANGE_LSB = 0x20;
* </code><p>
*
* @param channel 0-15
* @param bank 0-16383, or -1 for default bank
* @param program 0-127
* @exception IllegalArgumentException Thrown if any of the given
* parameters is out of range.
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @see #getProgram
*/
void setProgram(int channel, int bank, int program);
/**
* Set volume for the given channel. To mute, set to 0.
* This sets the current volume for the
* channel and may be overwritten during playback by events in a MIDI sequence.<p>
* It is a high level convenience function. Internally, the following command
* is executed:<p>
* <code>
* &nbsp;&nbsp;shortMidiEvent(CONTROL_CHANGE | channel, CONTROL_MAIN_VOLUME, 0);
* </code><p>
* where this constant is used:<p>
* <code>&nbsp;&nbsp;int CONTROL_MAIN_VOLUME = 0x07</code><p>
*
* The channel volume is independent of the master volume, which
* is accessed with {@link VolumeControl VolumeControl}.
* Setting the channel volume does not modify the value of the master
* volume - and vice versa: changing the value of master volume does not
* change any channel's volume value.<br>
* The synthesizer
* mixes the output of up to 16 channels, each channel with its own
* channel volume. The master volume then controls the volume of the mix.
* Consequently, the effective output volume of a channel is the product
* of master volume and channel volume. <p>
*
* Setting the channel volume does not generate a
* {@link javax.microedition.media.PlayerListener#VOLUME_CHANGED VOLUME_CHANGED event}.
*
* @param channel 0-15
* @param volume 0-127
* @exception IllegalArgumentException Thrown if
* <code>channel</code> or <code>volume</code> is out of range.
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @see #getChannelVolume
*/
void setChannelVolume(int channel, int volume);
// banks
/**
* Returns list of installed banks.
* If the <code>custom</code> parameter is true, a list of custom banks is returned.
* Otherwise, a list of all banks (custom and internal) is returned.
* <p>
* As there is no MIDI equivalent to this method, this method is
* optional, indicated by {@link #isBankQuerySupported isBankQuerySupported}.
* If it returns false, this function is not supported and throws an exception.
*
* @param custom if set to true, returns list of custom banks.
* @return an array of all installed bank numbers.
* Each bank number is in the range of 0..16383
* @exception MediaException if this device does not support retrieval of
* banks
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @see #isBankQuerySupported
*/
int[] getBankList(boolean custom)
throws MediaException;
/**
* Given bank, get list of program numbers. If and only if
* this bank is not installed, an empty array is returned.<p>
*
* As there is no MIDI equivalent to this method, this method is
* optional, indicated by {@link #isBankQuerySupported isBankQuerySupported}.
* If it returns false, this function is not supported and throws an exception.
*
* @param bank 0..16383
* @return an array of programs defined in the given bank.
* Each program number is from 0..127.
* @exception IllegalArgumentException Thrown if <code>bank</code>
* is out of range.
* @exception MediaException Thrown if the device does not support
* retrieval of programs.
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @see #setProgram
* @see #isBankQuerySupported
*/
int[] getProgramList(int bank)
throws MediaException;
/**
* Given bank and program, get name of program.
* For space-saving reasons, an implementation may return an empty string.
* <p>
* As there is no MIDI equivalent to this method, this method is
* optional, indicated by {@link #isBankQuerySupported isBankQuerySupported}.
* If it returns false, this function is not supported and throws an exception.
*
* @param bank 0-16383
* @param prog 0-127
* @exception IllegalArgumentException Thrown if <code>bank</code>
* or <code>prog</code> is out of range.
* @exception MediaException Thrown if the bank or program is
* not installed (internal or custom), or if this device does not
* support retrieval of program names
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @return name of the specified program, or empty string.
* @see #isBankQuerySupported
*/
String getProgramName(int bank, int prog)
throws MediaException;
/**
* Given bank, program and key, get name of key.
* This method applies to key-mapped banks (i.e. percussive banks
* or effect banks) only.
* A return value of <code>null</code> means that the specified key
* is not mapped to a sound. For melodic banks,
* where each key (=note) produces the same sound at different pitch, this method
* always returns <code>null</code>.
* For space-saving reasons, an implementation may return an empty string
* instead of the key name. To find out which keys in a specific program
* are mapped to a sound, iterate through all keys (0-127) and compare
* the return value of <code>getKeyName</code> to non-<code>null</code>.
* <p>
* As there is no MIDI equivalent to this method, this method is
* optional, indicated by {@link #isBankQuerySupported isBankQuerySupported}.
* If it returns false, this function is not supported and throws an exception.
*
* @param bank 0-16383
* @param prog 0-127
* @param key 0-127
* @exception IllegalArgumentException Thrown if <code>bank</code>,
* <code>prog</code> or <code>key</code> is out of range.
* @exception MediaException Thrown if the bank or program is
* not installed (internal or custom), or if this device does not
* support retrieval of key names
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @return name of the specified key, empty string, or <code>null</code> if
* the key is not mapped to a sound.
* @see #isBankQuerySupported
*/
String getKeyName(int bank, int prog, int key)
throws MediaException;
/**
* Sends a short MIDI event to the device.
* Short MIDI events consist of 1, 2, or 3 unsigned bytes.
* For non-realtime events, the first byte is split up into
* status (upper nibble, 0x80-0xF0) and channel (0x00-0x0F).
* For example, to send a <code>Note On</code> event on a given channel,
* use this line:<p>
* <code>&nbsp;&nbsp;shortMidiEvent(NOTE_ON | channel, note, velocity);</code><p>
* For events with less than 3 bytes, set the remaining data bytes to 0.<p>
*
* There is no guarantee that a specific
* implementation of a MIDI device supports all event types.
* Also, the MIDI protocol does not implement flow control and it is not
* guaranteed that an event reaches the destination.
* In both these cases, this method fails silently. <p>
*
* Static error checking is performed on the passed parameters. They have to
* specify a valid, complete MIDI event. Events with <code>type</code> &lt; 0x80 are
* not valid MIDI events (-&gt; running status). When an invalid event
* is encountered, an IllegalArgumentException is thrown.
*
* @param type 0x80..0xFF, excluding 0xF0 and 0xF7, which are reserved for system exclusive
* @param data1 for 2 and 3-byte events: first data byte, 0..127
* @param data2 for 3-byte events: second data byte, 0..127
* @exception IllegalArgumentException Thrown if one of the parameters
* is out of range.
* @exception IllegalStateException Thrown if the player has not been prefetched.
*/
void shortMidiEvent(int type, int data1, int data2);
/**
* Sends a long MIDI event to the device, typically a system exclusive message.
* This method passes the data directly to the receiving device.
* The data array's contents are not checked for validity.<p>
* It is possible to send short events, or even a series of short events
* with this method.<p>
*
* @param data array of the bytes to send
* @param offset start offset in data array
* @param length number of bytes to be sent
* @exception IllegalArgumentException Thrown if any one of the given
* parameters is not valid.
* @exception IllegalStateException Thrown if the player has not been prefetched.
* @return the number of bytes actually sent to the device or
* -1 if an error occurred
*/
int longMidiEvent(byte[] data, int offset, int length);
}

Просмотреть файл

@ -0,0 +1,102 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
/**
* <code>MetaDataControl</code> is used to retrieve metadata information
* included within the media streams. A <code>MetaDataControl</code>
* object recognizes and stores metadata and provides XML-like accessor
* methods to retrieve this information.
* <br>
* Predefined keys are provided to refer to commonly used metadata fields
* (title, copyright, data, author).
*/
public interface MetaDataControl extends javax.microedition.media.Control {
/**
* Default key for AUTHOR information.
* <p>
* Value "author" is assigned to <code>AUTHOR_KEY</code>.
*/
String AUTHOR_KEY = "author";
/**
* Default key for COPYRIGHT information.
* <p>
* Value "copyright" is assigned to <code>COPYRIGHT_KEY</code>.
*/
String COPYRIGHT_KEY = "copyright";
/**
* Default key for DATE information.
* <p>
* Value "date" is assigned to <code>DATE_KEY</code>.
*/
String DATE_KEY = "date";
/**
* Default key for TITLE information.
* <p>
* Value "title" is assigned to <code>TITLE_KEY</code>.
*/
String TITLE_KEY = "title";
/**
* Return the list of keys for the available metadata values.
* The returned array must be an array with at least one
* key.
*
* @return The list of keys for the available metadata values.
*/
String[] getKeys();
/**
* Retrieve the value found in the metadata associated with the
* given key. Only keys obtained from <code>getKeys</code>
* are valid and can be used to retrieve metadata values.
* If <code>null</code> or an invalid key is used, an
* <code>IllegalArgumentException</code> will be thrown.
* <p>
* Some keys are valid but the associated metadata may not
* be available before a certain portion of the media is
* played. For example, some streaming media types may
* contain metadata that's stored at the end of the file.
* As a result, the metadata may not be available
* until the playback reaches the end of media. When
* that happens, calling <code>getKeyValues</code> with
* those keys will return <code>null</code> before the
* data is available. However, when the playback reaches
* the end of media, all metadata values must be
* made available.
*
* @param key a key to retrieve the value.
* @return the value of the key or null if the given key is valid but
* the value is not yet available.
* @exception IllegalArgumentException Thrown if the given key is
* <code>null</code> or invalid.
*/
String getKeyValue(String key);
}

Просмотреть файл

@ -0,0 +1,112 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
/**
* PitchControl raises or lowers the playback pitch of audio without
* changing the playback speed.
* <p>
*
* PitchControl can be implemented in Players for MIDI media or
* sampled audio. It is not possible to set audible output to
* an absolute pitch value. This control raises or lowers pitch
* relative to the original.<p>
*
* The pitch change is specified in number of &quot;milli-
* semitones&quot; to raise the pitch. As an example,
* specifying a pitch of 12'000 results in playback one octave
* higher. For MIDI that means that all MIDI notes are raised
* by 12 (semitones). For sampled audio playback, it means doubling the
* frequency of perceived sounds (i.e. a 440Hz sound will become a 880Hz
* sound.).
* Negative values are used to lower the pitch.
* <p>
* All <code>Players</code> by default support 0, or no pitch change.
* A <code>Player</code> which supports only 0 pitch change
* must not implement <code>PitchControl</code>.
* <p>
*
* PitchControl does not influence playback volume in any way.
*
* @see javax.microedition.media.Player
* @see javax.microedition.media.control.RateControl
* @see javax.microedition.media.control.TempoControl
*/
public interface PitchControl extends javax.microedition.media.Control {
/**
* Sets the relative pitch raise.
*
* The pitch change is specified in &quot;milli-
* semitones&quot;, i.e. 1000 times the number of
* semitones to raise the pitch. Negative values
* lower the pitch by the number of milli-semitones.<p>
*
* The <code>setPitch()</code> method returns the actual pitch
* change set by the {@link javax.microedition.media.Player Player}.
* <code>Players</code>
* should set their pitch raise as close to the requested value
* as possible, but are not required to set it to the exact
* value of any argument other than 0. A <code>Player</code> is
* only guaranteed to set its pitch change exactly to 0.
* If the given pitch raise is less than the value returned by
* <code>getMinPitch</code>
* or greater than the value returned by <code>getMaxPitch</code>,
* it will be adjusted to the minimum or maximum
* supported pitch raise respectively.
*
* @param millisemitones The number of semi tones to raise the playback pitch.
* It is specified in &quot;milli-semitones&quot;.
* @return The actual pitch raise set in &quot;milli-semitones&quot;.
* @see #getPitch
*/
int setPitch(int millisemitones);
/**
* Gets the current playback pitch raise.
*
* @return the current playback pitch raise in &quot;milli-semitones&quot;.
* @see #setPitch
*/
int getPitch();
/**
* Gets the maximum playback pitch raise supported by the <code>Player</code>.
*
* @return the maximum pitch raise in &quot;milli-semitones&quot;.
*/
int getMaxPitch();
/**
* Gets the minimum playback pitch raise supported by the <code>Player</code>.
*
* @return the minimum pitch raise in &quot;milli-semitones&quot;.
*/
int getMinPitch();
}

Просмотреть файл

@ -0,0 +1,114 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
/**
* <code>RateControl</code> controls the playback rate of a
* <code>Player</code>.<p>
*
* The rate defines the relationship between the
* <code>Player's</code>&nbsp;<i>media time</i> and its
* <code>TimeBase</code>. Rates are specified in &quot;milli-
* percentage&quot;.<p>
*
* For example, a rate of 200'000 indicates that <i>media
* time</i> will pass twice as fast as the
* <code>TimeBase</code> time once the <code>Player</code>
* starts. Similarly, a negative rate indicates that the
* <code>Player</code> runs in the opposite direction of its
* <code>TimeBase</code>, i.e. playing in reverse.<p>
*
* All <code>Player</code> must support the default rate
* 100'000. <code>Player</code>s that support only the default
* rate must not implement this interface.
* <code>Player</code>s that support other rates besides
* 100'000, should implement this interface and specify the
* appropriate minimum and maximum playback rates.<p>
*
* For audio, specific implementations may change the playback
* pitch when changing the playback rate. This may be viewed as an
* undesirable side-effect. See <code>PitchControl</code> for
* changing pitch without changing playback rate.
*
* @see javax.microedition.media.Player
* @see javax.microedition.media.control.TempoControl
* @see javax.microedition.media.control.PitchControl
*/
public interface RateControl extends javax.microedition.media.Control {
/**
* Sets the playback rate.
*
* The specified rate is 1000 times the percentage of the
* actual rate. For example, to play back at twice the speed, specify
* a rate of 200'000.<p>
*
* The <code>setRate</code> method returns the actual rate set by the
* <code>Player</code>. <code>Player</code> should set their rate
* as close to the requested
* value as possible, but are not required to set the rate to the exact
* value of any argument other than 100'000. A <code>Player</code>
* is only guaranteed to set
* its rate exactly to 100'000.
* If the given rate is less than <code>getMinRate</code>
* or greater than <code>getMaxRate</code>,
* the rate will be adjusted to the minimum or maximum
* supported rate respectively.
* <p>
* If the <code>Player</code> is already
* started, <code>setRate</code> will immediately take effect.
*
* @param millirate The playback rate to set. The rate is given in
* a &quot;milli-percentage&quot; value.
* @return The actual rate set in &quot;milli-percentage&quot;.
* @see #getRate
*/
int setRate(int millirate);
/**
* Gets the current playback rate.
*
* @return the current playback rate in &quot;milli-percentage&quot;.
* @see #setRate
*/
int getRate();
/**
* Gets the maximum playback rate supported by the <code>Player</code>.
*
* @return the maximum rate in &quot;milli-percentage&quot;.
*/
int getMaxRate();
/**
* Gets the minimum playback rate supported by the <code>Player</code>.
*
* @return the minimum rate in &quot;milli-percentage&quot;.
*/
int getMinRate();
}

Просмотреть файл

@ -0,0 +1,270 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
import java.io.IOException;
import java.io.OutputStream;
import javax.microedition.media.MediaException;
/**
* <code>RecordControl</code> controls the recording of media
* from a <code>Player</code>. <code>RecordControl</code> records
* what's currently being played by the <code>Player</code>.
* <p>
* <h2>Example</h2>
* <blockquote>
* <pre>
* try {
* // Create a Player that captures live audio.
* Player p = Manager.createPlayer("capture://audio");
* p.realize();
* // Get the RecordControl, set the record stream,
* // start the Player and record for 5 seconds.
* RecordControl rc = (RecordControl)p.getControl("RecordControl");
* ByteArrayOutputStream output = new ByteArrayOutputStream();
* rc.setRecordStream(output);
* rc.startRecord();
* p.start();
* Thread.currentThread().sleep(5000);
* rc.commit();
* p.close();
* } catch (IOException ioe) {
* } catch (MediaException me) {
* } catch (InterruptedException ie) { }
* </pre>
* </blockquote>
*
* @see javax.microedition.media.Player
*/
public interface RecordControl extends javax.microedition.media.Control {
/**
* Set the output stream where the data will be
* recorded.
* <p>
* Whenever possible, the recording format is the same as the format
* of the input media. In some cases, the recording format may be
* different from the input format if the input format is not a
* recordable format, e.g. streaming media data. An application
* can query the recorded format by calling the
* <code>getContentType</code> method.
*
* @param stream The output stream where the data will be recorded.
* @exception IllegalStateException Thrown if one of the following
* conditions is true:
* <ul>
* <li>
* <code>startRecord</code> has been called and <code>commit</code> has
* not been called.
* <li>
* <code>setRecordLocation</code> has been called and <code>commit</code> has
* not been called.
* </ul>
*
* @exception IllegalArgumentException Thrown if
* <code>stream</code> is null.
* @exception SecurityException Thrown if the caller does not
* have security permission to set the record stream.
*/
void setRecordStream(OutputStream stream);
/**
* Set the output location where the data will be recorded.
* <p>
* Whenever possible, the recording format is the same as the format
* of the input media. In some cases, the recording format may be
* different from the input format if the input format is not a
* recordable format, e.g. streaming media data. An application
* can query the recorded format by calling the
* <code>getContentType</code> method.
*
* @param locator The locator specifying where the
* recorded media will be saved. The locator must be
* specified as a URL.
* @exception IllegalStateException Thrown if one of the following
* conditions is true:
* <ul>
* <li>
* <code>startRecord</code> has been called and <code>commit</code> has
* not been called.
* <li>
* <code>setRecordStream</code> has been called and <code>commit</code> has
* not been called.
* </ul>
* @exception IllegalArgumentException Thrown if <code>locator</code>
* is null.
* @exception IOException Thrown if protocol is valid but the
* media cannot be created at the specified location.
* @exception MediaException Thrown if the locator is not in URL syntax
* or it specifies a protocol that is not supported.
* @exception SecurityException Thrown if the caller does not
* have security permission to set the record location.
*/
void setRecordLocation(String locator)
throws IOException, MediaException;
/**
* Return the content type of the recorded media.
*
* The content type is given in the
* <a HREF="../Manager.html#content-type">content type syntax</a>.
*
* @return The content type of the media.
*/
String getContentType();
/**
* Start recording the media.
* <p>
* If the <code>Player</code> is already started, <code>startRecord</code>
* will immediately start the recording. If the <code>Player</code>
* is not already started, <code>startRecord</code> will not
* record any media. It will put the recording in a "standby" mode.
* As soon as the <code>Player</code> is started,
* the recording will start right away.
* <p>
* If <code>startRecord</code> is called when the recording has
* already started, it will be ignored.
* <p>
* When <code>startRecord</code> returns, the recording has started
* and a <i>RECORD_STARTED</i> event will be delivered through the
* <code>PlayerListener</code>.
* <p>
* If an error occurs while recording is in progress,
* <i>RECORD_ERROR</i> event will be delivered via the PlayerListener.
*
* @exception IllegalStateException Thrown if any of the following
* conditions is true:
* <ul>
* <li>
* if <code>setRecordLocation</code> or <code>setRecordStream</code> has
* not been called for the first time.
* <li>
* If <code>commit</code> has been called and
* <code>setRecordLocation</code> or <code>setRecordStream</code>
* has not been called.
* </ul>
*/
void startRecord();
/**
* Stop recording the media. <code>stopRecord</code> will not
* automatically stop the <code>Player</code>. It only stops
* the recording.
* <p>
* Stopping the <code>Player</code> does not imply
* a <code>stopRecord</code>. Rather, the recording
* will be put into a "standby" mode. Once the <code>Player</code>
* is re-started, the recording will resume automatically.
* <p>
* After <code>stopRecord</code>, <code>startRecord</code> can
* be called to resume the recording.
* <p>
* If <code>stopRecord</code> is called when the recording has
* already stopped, it will be ignored.
* <p>
* When <code>stopRecord</code> returns, the recording has stopped
* and a <i>RECORD_STOPPED</i> event will be delivered through the
* <code>PlayerListener</code>.
*/
void stopRecord();
/**
* Complete the current recording.
* <p>
* If the recording is in progress, <code>commit</code>
* will implicitly call <code>stopRecord</code>.
* <p>
* To record again after <code>commit</code> has been called,
* <code>setRecordLocation</code> or <code>setRecordStream</code>
* must be called.
*
* @exception IOException Thrown if an I/O error occurs during commit.
* The current recording is not valid. To record again,
* <code>setRecordLocation</code> or <code>setRecordStream</code>
* must be called.
*
*/
void commit() throws IOException;
/**
* Set the record size limit. This limits the size of the
* recorded media to the number of bytes specified.
* <p>
* When recording is in progress, <code>commit</code> will be
* called implicitly in the following cases:
* <ul>
* <li>
* Record size limit is reached
* <li>
* If the requested size is less than the already recorded size
* <li>
* No more space is available.
* </ul>
* <p>
* Once a record size limit has been set, it will remain so
* for future recordings until it is changed by another
* <code>setRecordSizeLimit</code> call.
* <p>
* To remove the record size limit, set it to
* <code>Integer.MAX_VALUE</code>.
* By default, the record size limit is not set.
* <p>
* Only positive values can be set. Zero or negative values
* are invalid and an <code>IllegalArgumentException</code>
* will be thrown.
*
* @param size The record size limit in number of bytes.
* @return The actual size limit set.
* @exception IllegalArgumentException Thrown if the given size
* is invalid.
* @exception MediaException Thrown if setting the record
* size limit is not supported.
*/
int setRecordSizeLimit(int size) throws MediaException;
/**
* Erase the current recording.
* <p>
* If the recording is in progress, <code>reset</code>
* will implicitly call <code>stopRecord</code>.
* <p>
* Calling <code>reset</code> after <code>commit</code>
* will have no effect on the current recording.
* <p>
* If the <code>Player</code> that is associated with this
* <code>RecordControl</code> is closed, <code>reset</code>
* will be called implicitly.
*
* @exception IOException Thrown if the current recording
* cannot be erased. The current recording is not valid.
* To record again, <code>setRecordLocation</code> or
* <code>setRecordStream</code> must be called.
*
*/
void reset() throws IOException;
}

Просмотреть файл

@ -0,0 +1,93 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
/**
* <code>StopTimeControl</code> allows one to specify a preset stop time for
* a <code>Player</code>.
* <p>
*/
public interface StopTimeControl extends javax.microedition.media.Control {
/**
* Returned by <CODE>getStopTime</CODE> if no stop-time is set.
* <p>
* Value <code>Long.MAX_VALUE</code> is assigned to <code>RESET</code>.
*/
long RESET = Long.MAX_VALUE;
/**
*
* Sets the <i>media time</i> at which you want the <code>Player</code>
* to stop.
* The <code>Player</code> will stop when its <i>media time</i>
* reaches the stop-time.
* A <code>STOPPED_AT_TIME</code> event
* will be delivered through the <code>PlayerListener</code>.
* <p>
* The <code>Player</code> is guaranteed
* to stop within one second past the preset stop-time
* (i.e. <code>stop-time <= current-media-time <= stop-time + 1 sec.</code>);
* unless the current media time is already passed the preset stop time
* when the stop time is set.
* If the current media time is already past the stop time set,
* the <code>Player</code> will stop immediately. A
* <code>STOPPED_AT_TIME</code> event will be delivered.
* After the <code>Player</code> stops due to the stop-time set,
* the previously set stop-time will be cleared automatically.
* Alternatively, the stop time can be explicitly removed by
* setting it to: <code>RESET</code>.
* <p>
*
* You can always call <code>setStopTime</code> on a stopped
* <code>Player</code>.
* To avoid a potential race condition, it is illegal to
* call <code>setStopTime</code> on a started <code>Player</code> if a
* <i>media stop-time</i> has already been set.
*
* @param stopTime The time in microseconds at which you want the
* <code>Player</code> to stop, in <i>media time</i>.
* @exception IllegalStateException Thrown if
* <code>setStopTime</code> is called on a started
* <code>Player</code> and the
* <i>media stop-time</i> has already been set.
* @see #getStopTime
*/
void setStopTime(long stopTime);
/**
* Gets the last value successfully set by <CODE>setStopTime</CODE>.
*
* Returns the constant <CODE>RESET</CODE> if no stop time is set.
* This is the default.
*
* @return The current stop time in microseconds.
* @see #setStopTime
*/
long getStopTime();
}

Просмотреть файл

@ -0,0 +1,159 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
/**
* TempoControl controls the tempo, in musical terms, of a song.
* <p>
*
* TempoControl is typically implemented in Players for MIDI
* media, i.e. playback of a Standard MIDI File (SMF).<p>
*
* TempoControl is basic functionality for a MIDI playback
* application. This is in contrast to {@link MIDIControl MIDIControl},
* which targets advanced applications. Moreover, TempoControl
* needs a sequence - e.g. a MIDI file - to operate. MIDIControl
* does not require a sequence.<p>
*
* Musical tempo is usually specified in beats per minute. To
* provide a means to access tempos with fractional beats per
* minute, the methods to set and get the tempo work on
* &quot;milli-beat&quot; per minute. A simple division by
* 1000 is sufficient to get the actual beats per minute.<p>
*
* As a MIDI file can contain any number of tempo changes
* during playback, the absolute tempo is a state of the
* sequencer. During playback of a MIDI file, setting the tempo
* in response to a user interaction will not always yield the
* desired result: the user's tempo can be overridden by the
* playing MIDI file to another tempo just moments later.<br>
* In order to overcome this problem, a relative tempo rate is
* used (in Java Sound terms: tempo factor). This rate is
* applied to all tempo settings. The tempo rate is specified
* in &quot;milli-percent&quot;, i.e. a value of 100'000 means
* playback at original tempo. The tempo rate is set with the
* <code>setRate()</code> method of the super class,
* {@link RateControl RateControl}.<p>
*
* The concept of tempo rate allows one to play back a MIDI sequence
* at a different tempo without losing the relative tempo changes
* in it.<p>
*
* The <code>setTempo()</code> and <code>getTempo()</code> methods
* do <b>not</b> affect or reflect the playback rate. This means that
* changing the
* rate will not result in a change of the value returned by
* <code>getTempo()</code>. Similarly, setting the tempo with
* <code>setTempo()</code> does not change the rate, i.e.
* the return value of <code>getRate()</code> is not changed. The
* effective playback tempo is always the product of tempo and rate:<br>
* <br>
* <code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
* effectiveBeatsPerMinute = getTempo()
* getRate() / 1000 / 100000</code>
* <p>
*
* @see javax.microedition.media.Player
* @see javax.microedition.media.control.RateControl
* @see javax.microedition.media.control.PitchControl
* @see javax.microedition.media.control.MIDIControl
*/
public interface TempoControl extends RateControl {
/**
* Sets the current playback tempo.
*
* Tempo is a volatile state of the sequencer. As MIDI sequences
* may contain META tempo events, tempo may change during
* playback of the sequence. Setting the tempo with
* <code>setTempo()</code> does not prevent the tempo from
* being changed subsequently by tempo events in the MIDI
* sequence. Example: during playback of a sequence,
* the user changes the tempo. But just moments later, the
* MIDI sequence changes the tempo to another value, so
* effectively the user interaction is ignored.
* To overcome this, and to allow consistent user interaction,
* use <code>{@link RateControl#setRate(int) setRate()}</code>
* inherited from <code>RateControl</code>.<p>
*
* The <code>setTempo()</code> method returns the actual tempo
* set by the <code>Player</code>'s implementation. It
* sets the tempo as close to the requested value as possible,
* but is not required to set it to the exact value. Specifically,
* implementations may have a lower or upper limit, which will
* be used as tempo if the requested tempo is out of limits.
* 0 or negative tempo does not exist and will always result
* in the lower tempo limit of the implementation. Implementations
* are guaranteed to support 10'000 to 300'000 milli-beats per minute.<p>
*
* Setting tempo to a stopped sequence will force the
* sequence to start with that tempo, even if the sequence has a tempo
* event at the start position. Any subsequent tempo events in
* the sequence will be considered, though. Rewinding back to
* a position with a tempo event will result in a
* tempo change caused by the tempo event, too. Example: a sequence
* with initial tempo of 120bpm has not been started yet. The
* user sets the tempo to 140bpm and starts playback. When the
* playback position is then reset to the beginning, the tempo will be
* set to 120bpm due to the tempo event at the beginning of the sequence.<p>
*
* Playback rate (see <code>{@link RateControl#setRate(int) setRate()}</code>)
* and tempo are independent factors of the effective tempo. Modifying
* tempo with <code>setTempo()</code> does not affect the playback
* rate and vice versa. The effective tempo is the product of tempo and rate.
*
* @param millitempo The tempo specified in milli-beats
* per minute (must be &gt; 0, e.g. 120'000 for 120 beats per minute)
* @return tempo that was actually set, expressed in milli-beats per minute
* @see #getTempo
*/
int setTempo(int millitempo);
/**
* Gets the current playback tempo.
* This represents the current state of the sequencer:
* <ul>
* <li>A sequencer may not be initialized before the
* <code>Player</code> is prefetched. An uninitialized
* sequencer in this case returns
* a default tempo of 120 beats per minute.</li>
* <li>After prefetching has finished, the tempo is
* set to the start tempo of the MIDI sequence (if any).</li>
* <li>During playback, the return value is the current tempo and
* varies with tempo events in the MIDI file</li>
* <li>A stopped sequence retains the last tempo it had
* before it was stopped.</li>
* <li>A call to <code>setTempo()</code> changes current tempo
* until a tempo event in the MIDI file is encountered.</li>
* </ul>
* @return current tempo, expressed in milli-beats per minute
* @see #setTempo
*/
int getTempo();
}

Просмотреть файл

@ -0,0 +1,320 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.control;
import javax.microedition.media.MediaException;
/**
* <code>VideoControl</code> controls the display of video.
* A <code>Player</code> which supports the playback of video
* must provide a <code>VideoControl</code> via its
* <code>getControl</code> and <code>getControls</code>
* method.
*
*/
public interface VideoControl extends GUIControl {
/**
* This defines a mode on how the video is displayed.
* It is used in conjunction with
* <a href="#initDisplayMode(int, java.lang.Object)">
* <code>initDisplayMode</code></a>.
* <p>
* <code>USE_DIRECT_VIDEO</code> mode can only be used
* on platforms with LCDUI support.
* <p>
* When <code>USE_DIRECT_VIDEO</code> is specified for
* <code>initDisplayMode</code>, the <code>arg</code>
* argument must not be null and must be a
* <code>javax.microedition.lcdui.Canvas</code> or a subclass of it.
* In this mode, the video is directly
* rendered onto the canvas. The region where the video
* is rendered can be set by the <code>setDisplayLocation</code>
* method. By default, the location is (0, 0).
* Drawing any graphics or rendering other video at the same
* region on the canvas may not be supported.
* <p>
* <code>initDisplayMode</code>
* returns <code>null</code> in this mode.
* <p>
* Here is one sample usage scenario:
* <pre>
* <code>
* javax.microedition.lcdui.Canvas canvas;
* // canvas must be created before being used in the following code.
*
* try {
* Player p = Manager.createPlayer("http://mymachine/abc.mpg");
* p.realize();
* VideoControl vc;
* if ((vc = (VideoControl)p.getControl("VideoControl")) != null) {
* vc.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, canvas);
* vc.setVisible(true);
* }
* p.start();
* } catch (MediaException pe) {
* } catch (IOException ioe) {
* }
* </code>
* </pre>
* <p>
* Value 1 is assigned to <code>USE_DIRECT_VIDEO</code>.
*/
int USE_DIRECT_VIDEO = 1;
/**
* Initialize the mode on how the video is displayed.
* This method must be called before video can be displayed.
* <p>
* Two modes are defined:
* <ul>
* <li> <a href="GUIControl.html#USE_GUI_PRIMITIVE"><code>USE_GUI_PRIMITIVE</code></a> (inherited from GUIControl)
* <li> <a href="#USE_DIRECT_VIDEO"><code>USE_DIRECT_VIDEO</code></a>
* </ul>
* On platforms with LCDUI support, both modes must be supported.
*
* @param mode The video mode that determines how video is
* displayed. It can be <code>USE_GUI_PRIMITIVE</code>,
* <code>USE_DIRECT_VIDEO</code> or an implementation-
* specific mode.
*
* @param arg The exact semantics of this argument is
* specified in the respective mode definitions.
*
* @return The exact semantics and type of the object returned
* are specified in the respective mode definitions.
*
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> is called again after it has
* previously been called successfully.
*
* @exception IllegalArgumentException Thrown if
* the <code>mode</code> or <code>arg</code>
* argument is invalid. <code>mode</code> must be
* <code>USE_GUI_PRIMITIVE</code>,
* <code>USE_DIRECT_VIDEO</code>, or a custom mode
* supported by this implementation.
* <code>arg</code> must conform to the
* conditions defined by the
* respective mode definitions.
* Refer to the mode definitions for the required type
* of <code>arg</code>.
*/
Object initDisplayMode(int mode, Object arg);
/**
* Set the location of the video with respect to
* the canvas where the video is displayed.
* <p>
* This method only works when the <code>USE_DIRECT_VIDEO</code>
* mode is set. In <code>USE_GUI_PRIMITIVE</code> mode,
* this call will be ignored.
* <p>
* The location is specified in pixel values relative to the
* upper left hand corner of the GUI object.
* <p>
* By default, video appears at location (0,0).
* <p>
* The location can be given in negative values or can be
* greater than the actual size of the canvas. When
* that happens, the video should be clipped to the
* boundaries of the canvas.
*
* @param x The x coordinate (in pixels) of the video location.
* @param y The y coordinate (in pixels) of the video location.
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> has not been called.
*/
void setDisplayLocation(int x, int y);
/**
* Return the X-coordinate of the video with respect
* to the GUI object where the video is displayed.
* The coordinate is specified in pixel values relative to the
* upper left hand corner of the GUI object.
* <p>
* The return value is undefined if <code>initDisplayMode</code>
* has not been called.
*
* @return the X-coordinate of the video.
*/
int getDisplayX();
/**
* Return the Y-coordinate of the video with respective
* to the GUI object where the video is displayed.
* The coordinate is specified in pixel values relative to the
* upper left hand corner of the GUI object.
* <p>
* The return value is undefined if <code>initDisplayMode</code>
* has not been called.
*
* @return the Y-coordinate of the video.
*/
int getDisplayY();
/**
* Show or hide the video.
* <p>
* If <code>USE_GUI_PRIMITIVE</code> is set, the video by
* default is shown when the GUI primitive is displayed.
* If <code>USE_DIRECT_VIDEO</code> is set, the video by
* default is not shown when the canvas is displayed
* until <code>setVisible(true)</code> is called. If
* the canvas is removed from the screen, the video
* will not be displayed.
*
* @param visible Show the video if true, hide it otherwise.
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> has not been called.
*/
void setVisible(boolean visible);
/**
* Resize the video image.
* <p>
* If the video mode is set to <code>USE_DIRECT_VIDEO</code>,
* setting the size of the video will not
* affect the size of the GUI object that the video is
* displayed.
* If the video is scaled to beyond the size of the
* GUI object, the video will be clipped.
* <p>
* If the video mode is set to <code>USE_GUI_PRIMITIVE</code>,
* Scaling the video will also scale the GUI object.
* <p>
* The actual scaling algorithm is left up
* to the underlying implementation. If
* the dimensions of the requested display size are smaller than
* the dimensions of the video clip, some implementations may
* choose to merely clip the video while other implementations
* may resize the video.
* <p>
* If the dimensions of the requested display size are bigger than
* the dimensions of the video clip, some implementations may
* resize the video while others may leave the video clip in the
* original size and just enlarge the display region. It is
* left up to the implementation
* where the video clip is placed in the display region in this
* instance (i.e., it can be in the center of the window or
* in a corner of the window).
*
* @param width Desired width (in pixels) of the display window
* @param height Desired height (in pixels) of the display window
* @exception IllegalArgumentException Thrown if the
* given <code>width</code> and <code>height</code> are
* non-positive values.
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> has not been called.
* @exception MediaException Thrown if resizing is not supported or
* the operation failed due to hardware or software limitations.
*/
void setDisplaySize(int width, int height)
throws MediaException;
/**
* Set the size of the render region for the video clip to be
* fullscreen. It is left up to the underlying implementation how
* fullscreen mode is
* implemented and what actual dimensions constitutes fullscreen.
* This is useful when the application does not know the actual
* width and height dimensions
* that are needed to make setDisplaySize(width, height) go to
* fullscreen mode.
* For example, on a device with a 400 pixel wide by 200 pixel
* high screen, a video
* clip that is 50 pixels wide by 100 pixels high in fullscreen
* mode may be
* 100 pixels wide by 200 pixels high if the underlying implementation
* wants
* to preserve the aspect ratio. In this case, an exception
* is not thrown.
* @param fullScreenMode Indicates whether or not to render
* in full screen mode
* @exception MediaException Thrown if resizing to full screen size
* is not supported.
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> has not been called.
*/
void setDisplayFullScreen(boolean fullScreenMode) throws MediaException;
/**
* Return the width of the source video. The
* width must be a positive number.
* @return the width of the source video
*/
int getSourceWidth();
/**
* Return the height of the source video. The
* height must be a positive number.
* @return the height of the source video
*/
int getSourceHeight();
/**
* Return the actual width of the current render video.
*
* @return width of the display video
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> has not been called.
*/
int getDisplayWidth();
/**
* Return the actual height of the current render video.
*
* @return height of the display video
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> has not been called.
*/
int getDisplayHeight();
/**
* Get a snapshot of the displayed content. Features and format
* of the captured image are specified by <code>imageType</code>.
* Supported formats can be queried from <code>System.getProperty</code>
* with
* <a href="../../../../overview-summary.html#video.snapshot.encodings">
* <code>video.snapshot.encodings</code></a> as the key.
* The first format in the supported list is the default capture format.
*
* @param imageType Format and resolution of the returned image.
* If <code>null</code> is given, the default capture format is used.
* @return image as a byte array in required format.
* @exception IllegalStateException Thrown if
* <code>initDisplayMode</code> has not been called.
* @exception MediaException Thrown if the requested format is
* not supported or the <code>Player</code> does not support
* snapshots.
* @exception SecurityException Thrown if the caller does
* not have the security permission to take the snapshot.
*/
byte[] getSnapshot(String imageType) throws MediaException;
}

Просмотреть файл

@ -0,0 +1,59 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.protocol;
/**
* A <CODE>ContentDescriptor</CODE> identifies media data containers.
*
* @see SourceStream
*/
public class ContentDescriptor {
private String encoding;
/**
* Obtain a string that represents the content type
* for this descriptor.
* If the content type is not known, <code>null</code> is returned.
*
* @return The content type.
*/
public String getContentType() {
return encoding;
}
/**
* Create a content descriptor with the specified content type.
*
* @param contentType The content type of this descriptor.
* If <code>contentType</code> is <code>null</code>, the type
* of the content is unknown.
*/
public ContentDescriptor(String contentType) {
encoding = contentType;
}
}

Просмотреть файл

@ -0,0 +1,195 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.protocol;
import javax.microedition.media.Controllable;
import javax.microedition.media.Control;
import java.io.IOException;
/**
* A <CODE>DataSource</CODE> is an abstraction for media protocol-handlers.
* It hides the details of how the data is read from source--whether
* the data is
* coming from a file, streaming server or proprietary delivery mechanism.
* It provides the methods for a <code>Player</code> to access
* the input data.
* <p>
* An application-defined protocol can be implemented with a custom
* <code>DataSource</code>. A <code>Player</code> can then be
* created for playing back the media from the custom
* <code>DataSource</code> using the
* <a href="../Manager.html#createPlayer(javax.microedition.media.protocol.DataSource)">
* <code>Manager.createPlayer</code></a> method.
* <p>
* There are a few reasons why one would choose to implement
* a <code>DataSource</code> as opposed to an <code>InputStream</code>
* for a custom protocol:
* <ul>
* <li>
* <code>DataSource/SourceStream</code> provides the random
* seeking API that
* is not supported by an <code>InputStream</code>. i.e., if
* the custom protocol
* requires random seeking capabilities, a custom
* <code>DataSource</code> can be used.
* <li>
* <code>DataSource/SourceStream</code> supports the concept of
* transfer size
* that is more suited for frame-delimited data, e.g. video.
* </ul>
* <p>
* A <code>DataSource</code> contains a set of <code>SourceStream</code>s.
* Each <code>SourceStream</code> represents one elementary data stream
* of the source. In the most common case, a <code>DataSource</code>
* only provides one <code>SourceStream</code>. A <code>DataSource</code>
* may provide multiple <code>SourceStream</code>s if it encapsulates
* multiple elementary data streams.
* <p>
* Each of the <code>SourceStream</code>s provides the methods to allow
* a <code>Player</code> to read data for processing.
* <p>
* <CODE>DataSource</CODE> manages the life-cycle of the media source
* by providing a simple connection protocol.
*
* <p>
* <a name="controls">
* <code>DataSource</code> implements <code>Controllable</code> which
* provides extra controls via some type-specific <code>Control</code>
* interfaces. <code>getControl</code> and <code>getControls</code>
* can only be called when the <code>DataSource</code> is connected.
* An <code>IllegalStateException</code> will be thrown otherwise.
*
* @see javax.microedition.media.Manager
* @see javax.microedition.media.protocol.SourceStream
* @see javax.microedition.media.protocol.ContentDescriptor
*/
abstract public class DataSource implements Controllable {
private String sourceLocator;
/**
* Construct a <CODE>DataSource</CODE> from a locator.
* This method should be overloaded by subclasses;
* the default implementation just keeps track of
* the locator.
*
* @param locator The locator that describes
* the <CODE>DataSource</CODE>.
*/
public DataSource(String locator) {
sourceLocator = locator;
}
/**
* Get the locator that describes this source.
* Returns <CODE>null</CODE> if the locator hasn't been set.
*
* @return The locator for this source.
*/
public String getLocator() {
return sourceLocator;
}
/**
* Get a string that describes the content-type of the media
* that the source is providing.
*
* @return The name that describes the media content.
* Returns <code>null</code> if the content is unknown.
* @exception IllegalStateException Thrown if the source is
* not connected.
*/
public abstract String getContentType();
/**
* Open a connection to the source described by
* the locator and initiate communication.
*
* @exception IOException Thrown if there are IO problems
* when <CODE>connect</CODE> is called.
* @exception SecurityException Thrown if the caller does not
* have security permission to call <code>connect</code>.
*/
public abstract void connect() throws IOException;
/**
* Close the connection to the source described by the locator
* and free resources used to maintain the connection.
* <p>
* If no resources are in use, <CODE>disconnect</CODE> is ignored.
* If <CODE>stop</CODE> hasn't already been called,
* calling <CODE>disconnect</CODE> implies a stop.
*
*/
public abstract void disconnect();
/**
* Initiate data-transfer. The <CODE>start</CODE> method must be
* called before data is available for reading.
*
* @exception IllegalStateException Thrown if the
* <code>DataSource</code> is not connected.
* @exception IOException Thrown if the <code>DataSource</code>
* cannot be started due to some IO problems.
* @exception SecurityException Thrown if the caller does not
* have security permission to call <code>start</code>.
*/
public abstract void start() throws IOException;
/**
* Stop the data-transfer.
* If the <code>DataSource</code> has not been connected and started,
* <CODE>stop</CODE> is ignored.
*
* @exception IOException Thrown if the <code>DataSource</code>
* cannot be stopped due to some IO problems.
*/
public abstract void stop() throws IOException;
/**
* Get the collection of streams that this source
* manages. The collection of streams is entirely
* content dependent. The MIME type of this
* <CODE>DataSource</CODE> provides the only indication of
* what streams may be available on this connection.
*
* @return The collection of streams for this source.
* @exception IllegalStateException Thrown if the source
* is not connected.
*/
public abstract SourceStream[] getStreams();
// These two methods are declared here (Controllable interface)
// because of a feature in KVM/VM when code is compiled with JDK 1.4
// Need to declare these abstract
public abstract Control [] getControls();
public abstract Control getControl(String controlType);
}

Просмотреть файл

@ -0,0 +1,196 @@
/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.media.protocol;
import java.io.IOException;
import javax.microedition.media.Controllable;
/**
* Abstracts a single stream of media data. It is used in
* conjunction with <code>DataSource</code> to provide the
* input interface to a <code>Player</code>
* <p>
* SourceStream may provide type-specific controls. For that
* reason, it implements the <code>Controllable</code> interface
* to provide additional controls.
*
* @see DataSource
*
*/
public interface SourceStream extends Controllable {
/**
* The value returned by <code>getSeekType</code> indicating that this
* <code>SourceStream</code> is not seekable.
* <p>
* Value 0 is assigned to <code>NOT_SEEKABLE</code>.
*/
int NOT_SEEKABLE = 0;
/**
* The value returned by <code>getSeekType</code> indicating that this
* <code>SourceStream</code> can be seeked only to the beginning
* of the media stream.
* <p>
* Value 1 is assigned to <code>SEEKABLE_TO_START</code>.
*/
int SEEKABLE_TO_START = 1;
/**
* The value returned by <code>getSeekType</code> indicating that this
* <code>SourceStream</code> can be seeked anywhere within the media.
* <p>
* Value 2 is assigned to <code>RANDOM_ACCESSIBLE</code>.
*/
int RANDOM_ACCESSIBLE = 2;
/**
* Get the content type for this stream.
*
* @return The current <CODE>ContentDescriptor</CODE> for this stream.
*/
ContentDescriptor getContentDescriptor();
/**
* Get the size in bytes of the content on this stream.
*
* @return The content length in bytes. -1 is returned if the
* length is not known.
*/
long getContentLength();
/**
* Reads up to <code>len</code> bytes of data from the input stream into
* an array of bytes. An attempt is made to read as many as
* <code>len</code> bytes, but a smaller number may be read.
* The number of bytes actually read is returned as an integer.
*
* <p> This method blocks until input data is available, end of file is
* detected, or an exception is thrown.
*
* <p> If <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
*
* <p> If <code>off</code> is negative, or <code>len</code> is negative, or
* <code>off+len</code> is greater than the length of the array
* <code>b</code>, then an <code>IndexOutOfBoundsException</code> is
* thrown.
*
* <p> If <code>len</code> is zero, then no bytes are read and
* <code>0</code> is returned; otherwise, there is an attempt to read at
* least one byte. If no byte is available because the stream is at end of
* file, the value <code>-1</code> is returned; otherwise, at least one
* byte is read and stored into <code>b</code>.
*
* <p> The first byte read is stored into element <code>b[off]</code>, the
* next one into <code>b[off+1]</code>, and so on. The number of bytes read
* is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
* bytes actually read; these bytes will be stored in elements
* <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
* leaving elements <code>b[off+</code><i>k</i><code>]</code> through
* <code>b[off+len-1]</code> unaffected.
*
* <p> If the first byte cannot be read for any reason other than end of
* file, then an <code>IOException</code> is thrown. In particular, an
* <code>IOException</code> is thrown if the input stream has been closed.
*
* @param b the buffer into which the data is read.
* @param off the start offset in array <code>b</code>
* at which the data is written.
* @param len the maximum number of bytes to read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
int read(byte[] b, int off, int len)
throws IOException;
/**
* Get the size of a "logical" chunk of media data from the source.
* This method can be used to determine the minimum size of the
* buffer to use in conjunction with the <code>read</code> method
* to read data from the source.
*
* @return The minimum size of the buffer needed to read a "logical"
* chunk of data from the source. Returns -1 if the size cannot be
* determined.
* @see #read(byte[], int, int)
*/
int getTransferSize();
/**
* Seek to the specified point in the stream. The <code>seek</code>
* method may, for a variety of reasons, fail to seek to the specified
* position. For example,
* it may be asked to seek to a position beyond the size of the stream;
* or the stream may only be seekable to the beginning
* (<code>getSeekType</code> returns <code>SEEKABLE_TO_START</code>).
* The return value indicates whether the seeking is successful.
* If it is successful, the value returned will be the same as the
* given position. Otherwise, the return value will indicate what
* the new position is.
* <p>
* If the given position is negative, seek will treat that as 0
* and attempt to seek to 0.
* <p>
* An IOException will be thrown if an I/O error occurs, e.g. when
* the stream comes from a remote connection and the connection is
* broken.
*
* @param where The position to seek to.
* @return The new stream position.
* @exception IOException Thrown if an I/O error occurs.
*/
long seek(long where) throws IOException;
/**
* Obtain the current position in the stream.
* @return The current position in the stream.
*/
long tell();
/**
* Find out if the stream is seekable.
* The return value can be one of these three:
* <code>NOT_SEEKABLE</code>, <code>SEEKABLE_TO_START</code> and
* <code>RANDOM_ACCESSIBLE</code>.
* If the return value is <code>SEEKABLE_TO_START</code>, it means
* that the stream can only be repositioned to the beginning of
* the stream. If the return value is <code>RANDOM_ACCESSIBLE</code>,
* the stream can be seeked anywhere within the stream.
*
* @return Returns an enumerated value to indicate the level of seekability.
*/
int getSeekType();
}