зеркало из https://github.com/mozilla/pluotsorbet.git
Add javax.microedition.media.* and dependencies from phoneme_feature.
This commit is contained in:
Родитель
ab5b708833
Коммит
4c1ef19c3f
|
@ -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 <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> <CODE>Player</CODE>
|
||||
* 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 <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>
|
||||
* try{
|
||||
* <br> Player
|
||||
* p = Manager.createPlayer(Manager.MIDI_DEVICE_LOCATOR);
|
||||
* <br> MIDIControl
|
||||
* synth = (MIDIControl)p.getControls("javax.microedition.media.control.MIDIControl");
|
||||
* <br> } catch (MediaException e) {
|
||||
* <br> }
|
||||
* </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 "Panic": immediately turn off all
|
||||
* sounds and notes. It can be implemented using the following code fragment:<br>
|
||||
* <code>
|
||||
* int CONTROL_ALL_SOUND_OFF = 0x78;<br>
|
||||
* for (int channel = 0; channel < 16; channel++) {<br>
|
||||
* shortMidiEvent(CONTROL_CHANGE | channel, CONTROL_ALL_SOUND_OFF, 0);<br>
|
||||
* }<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>
|
||||
* shortMidiEvent(CONTROL_CHANGE | channel, CONTROL_BANK_CHANGE_MSB, bank >> 7);<br>
|
||||
* shortMidiEvent(CONTROL_CHANGE | channel, CONTROL_BANK_CHANGE_LSB, bank & 0x7F);<br>
|
||||
* 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>
|
||||
* shortMidiEvent(PROGRAM_CHANGE | channel, program, 0);
|
||||
* </code><p>
|
||||
*
|
||||
* In both examples, the following constants are used:<p>
|
||||
* <code>
|
||||
* int PROGRAM_CHANGE = 0xC0;<br>
|
||||
* int CONTROL_BANK_CHANGE_MSB = 0x00;<br>
|
||||
* 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>
|
||||
* shortMidiEvent(CONTROL_CHANGE | channel, CONTROL_MAIN_VOLUME, 0);
|
||||
* </code><p>
|
||||
* where this constant is used:<p>
|
||||
* <code> 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> 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> < 0x80 are
|
||||
* not valid MIDI events (-> 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 "milli-
|
||||
* semitones" 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 "milli-
|
||||
* semitones", 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 "milli-semitones".
|
||||
* @return The actual pitch raise set in "milli-semitones".
|
||||
* @see #getPitch
|
||||
*/
|
||||
int setPitch(int millisemitones);
|
||||
|
||||
/**
|
||||
* Gets the current playback pitch raise.
|
||||
*
|
||||
* @return the current playback pitch raise in "milli-semitones".
|
||||
* @see #setPitch
|
||||
*/
|
||||
int getPitch();
|
||||
|
||||
/**
|
||||
* Gets the maximum playback pitch raise supported by the <code>Player</code>.
|
||||
*
|
||||
* @return the maximum pitch raise in "milli-semitones".
|
||||
*/
|
||||
int getMaxPitch();
|
||||
|
||||
/**
|
||||
* Gets the minimum playback pitch raise supported by the <code>Player</code>.
|
||||
*
|
||||
* @return the minimum pitch raise in "milli-semitones".
|
||||
*/
|
||||
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> <i>media time</i> and its
|
||||
* <code>TimeBase</code>. Rates are specified in "milli-
|
||||
* percentage".<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 "milli-percentage" value.
|
||||
* @return The actual rate set in "milli-percentage".
|
||||
* @see #getRate
|
||||
*/
|
||||
int setRate(int millirate);
|
||||
|
||||
/**
|
||||
* Gets the current playback rate.
|
||||
*
|
||||
* @return the current playback rate in "milli-percentage".
|
||||
* @see #setRate
|
||||
*/
|
||||
int getRate();
|
||||
|
||||
/**
|
||||
* Gets the maximum playback rate supported by the <code>Player</code>.
|
||||
*
|
||||
* @return the maximum rate in "milli-percentage".
|
||||
*/
|
||||
int getMaxRate();
|
||||
|
||||
/**
|
||||
* Gets the minimum playback rate supported by the <code>Player</code>.
|
||||
*
|
||||
* @return the minimum rate in "milli-percentage".
|
||||
*/
|
||||
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
|
||||
* "milli-beat" 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 "milli-percent", 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>
|
||||
* 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 > 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();
|
||||
}
|
Загрузка…
Ссылка в новой задаче