bug#210212 (initial commit)
diff --git a/plugins/org.eclipse.actf.ai.audio.description/.classpath b/plugins/org.eclipse.actf.ai.audio.description/.classpath
new file mode 100644
index 0000000..751c8f2
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.actf.ai.audio.description/.project b/plugins/org.eclipse.actf.ai.audio.description/.project
new file mode 100644
index 0000000..f0c20b7
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.actf.ai.audio.description</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.actf.ai.audio.description/META-INF/MANIFEST.MF b/plugins/org.eclipse.actf.ai.audio.description/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..e62719a
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Eclipse ACTF Audio Description Plug-in (Incubation)
+Bundle-SymbolicName: org.eclipse.actf.ai.audio.description;singleton:=true
+Bundle-Version: 0.0.1
+Bundle-Activator: org.eclipse.actf.ai.audio.description.DescriptionPlugin
+Bundle-Vendor: Eclipse.org
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.actf.ai.fennec,
+ org.eclipse.actf.common,
+ org.eclipse.actf.ai.navigator,
+ org.eclipse.actf.ai.voice,
+ org.eclipse.actf.ai.xmlstore
+Eclipse-LazyStart: true
+Export-Package: org.eclipse.actf.ai.audio.description,
+ org.eclipse.actf.ai.audio.description.impl,
+ org.eclipse.actf.ai.audio.description.util,
+ org.eclipse.actf.ai.audio.description.views
diff --git a/plugins/org.eclipse.actf.ai.audio.description/about.html b/plugins/org.eclipse.actf.ai.audio.description/about.html
new file mode 100644
index 0000000..481dbcf
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/about.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2006</p>
+<h3>License</h3>
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content").
+Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor’s license
+that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/plugins/org.eclipse.actf.ai.audio.description/build.properties b/plugins/org.eclipse.actf.ai.audio.description/build.properties
new file mode 100644
index 0000000..86eff37
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/build.properties
@@ -0,0 +1,21 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties,\
+ plugin_ja.properties,\
+ icons/,\
+ about.html,\
+ src/messages.properties,\
+ src/messages_ja.properties
diff --git a/plugins/org.eclipse.actf.ai.audio.description/icons/micx16.gif b/plugins/org.eclipse.actf.ai.audio.description/icons/micx16.gif
new file mode 100644
index 0000000..f60045c
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/icons/micx16.gif
Binary files differ
diff --git a/plugins/org.eclipse.actf.ai.audio.description/icons/micx48.gif b/plugins/org.eclipse.actf.ai.audio.description/icons/micx48.gif
new file mode 100644
index 0000000..3b79303
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/icons/micx48.gif
Binary files differ
diff --git a/plugins/org.eclipse.actf.ai.audio.description/plugin.properties b/plugins/org.eclipse.actf.ai.audio.description/plugin.properties
new file mode 100644
index 0000000..35d412b
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/plugin.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+AudioDescription.preference.name=Audio Description
+AudioDescription.view.name=Audio Description
diff --git a/plugins/org.eclipse.actf.ai.audio.description/plugin.xml b/plugins/org.eclipse.actf.ai.audio.description/plugin.xml
new file mode 100644
index 0000000..9b67bb3
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/plugin.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension
+ point="org.eclipse.actf.ai.navigator.MediaControl">
+ <controller class="org.eclipse.actf.ai.audio.description.impl.MediaControlImpl"/>
+ </extension>
+ <extension
+ point="org.eclipse.ui.views">
+ <view
+ class="org.eclipse.actf.ai.audio.description.views.DescriptionView"
+ icon="icons/micx16.gif"
+ id="org.eclipse.actf.ai.audio.description.views.DescriptionView"
+ name="%AudioDescription.view.name"/>
+ </extension>
+ <extension
+ point="org.eclipse.ui.perspectiveExtensions">
+ <perspectiveExtension targetID="org.eclipse.actf.examples.aibrowser.DefaultPerspective">
+ <view
+ closeable="false"
+ id="org.eclipse.actf.ai.audio.description.views.DescriptionView"
+ moveable="true"
+ ratio="0.7"
+ relationship="bottom"
+ relative="org.eclipse.actf.ai.navigator.views.NavigatorTreeView"
+ showTitle="true"
+ standalone="false"
+ visible="true"/>
+ </perspectiveExtension>
+ </extension>
+ <!--extension
+ point="org.eclipse.ui.actionSets">
+ <actionSet
+ id="org.eclipse.actf.ai.audio.description.actionSet1"
+ label="org.eclipse.actf.ai.audio.description.actionSet1"
+ visible="true">
+ <action
+ class="org.eclipse.actf.ai.audio.description.actions.AudioDescriptionActionDelegate"
+ id="org.eclipse.actf.ai.audio.description.AudioDescription"
+ label="&Audio Description"
+ menubarPath="org.eclipse.actf.examples.aibrowser.FileMenu/filegroup"
+ state="false"
+ style="toggle"
+ tooltip="Toggle audio description mode"/>
+ </actionSet>
+ </extension-->
+ <extension
+ point="org.eclipse.ui.preferencePages">
+ <page
+ class="org.eclipse.actf.ai.audio.description.preferences.ADPreferencePage"
+ id="org.eclipse.actf.ai.audio.description.preferences.ADPreferencePage"
+ name="%AudioDescription.preference.name"/>
+ </extension>
+ <extension
+ point="org.eclipse.core.runtime.preferences">
+ <initializer class="org.eclipse.actf.ai.audio.description.preferences.ADPreferenceInitializer"/>
+ </extension>
+
+</plugin>
diff --git a/plugins/org.eclipse.actf.ai.audio.description/plugin_ja.properties b/plugins/org.eclipse.actf.ai.audio.description/plugin_ja.properties
new file mode 100644
index 0000000..db0b66b
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/plugin_ja.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+AudioDescription.preference.name=\u97f3\u58f0\u89e3\u8aac
+AudioDescription.view.name=\u97f3\u58f0\u89e3\u8aac
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/messages.properties b/plugins/org.eclipse.actf.ai.audio.description/src/messages.properties
new file mode 100644
index 0000000..86b5145
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/messages.properties
@@ -0,0 +1,21 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+AudioDescription.view.time=Time
+AudioDescription.view.desc=Description
+AudioDescription.view.enable=Enable
+AudioDescription.view.notEnable=Not Enable
+
+AudioDescription.preference.title=Audio Description Preference
+AudioDescription.voice.engine=TTS engine
+Metadata.available=Audio Description is Available
+
+AudioDescription.on=Audio Description is on
+AudioDescription.off=Audio Description is off
\ No newline at end of file
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/messages_ja.properties b/plugins/org.eclipse.actf.ai.audio.description/src/messages_ja.properties
new file mode 100644
index 0000000..c0b1c63
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/messages_ja.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+AudioDescription.view.time=\u6642\u9593
+AudioDescription.view.desc=\u8aac\u660e
+AudioDescription.view.enable=\u89e3\u8aac\u30aa\u30f3
+AudioDescription.view.notEnable=\u89e3\u8aac\u30aa\u30d5
+
+AudioDescription.preference.title=\u97f3\u58f0\u8a2d\u5b9a
+AudioDescription.voice.engine=TTS\u30a8\u30f3\u30b8\u30f3
+
+Metadata.available=\u97f3\u58f0\u89e3\u8aac\u5229\u7528\u53ef\u80fd
+
+AudioDescription.on=\u97f3\u58f0\u89e3\u8aac\u30aa\u30f3
+AudioDescription.off=\u97f3\u58f0\u89e3\u8aac\u30aa\u30d5
\ No newline at end of file
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/DescriptionPlugin.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/DescriptionPlugin.java
new file mode 100644
index 0000000..317860e
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/DescriptionPlugin.java
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.actf.ai.audio.description;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+
+import org.eclipse.actf.ai.audio.description.impl.MetadataManager;
+import org.eclipse.actf.ai.audio.description.impl.MetadataProviderImpl;
+import org.eclipse.actf.ai.audio.description.views.DescriptionView;
+import org.eclipse.actf.ai.navigator.IMediaControl;
+import org.eclipse.actf.ai.tts.ITTSEngine;
+import org.eclipse.actf.ai.voice.internal.AbstractPreferenceUIPlugin;
+import org.eclipse.actf.ai.voice.internal.TTSRegistry;
+import org.eclipse.actf.ai.xmlstore.IXMLInfo;
+import org.eclipse.actf.ai.xmlstore.IXMLSelector;
+import org.eclipse.actf.ai.xmlstore.IXMLStore;
+import org.eclipse.actf.ai.xmlstore.IXMLStoreService;
+import org.eclipse.actf.ai.xmlstore.XMLStorePlugin;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.osgi.framework.BundleContext;
+
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class DescriptionPlugin extends AbstractPreferenceUIPlugin implements IPropertyChangeListener {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.actf.ai.audio.description";
+
+ public static final String PREF_ENGINE = "AudioDescriptionTTSEngine";
+
+ // The shared instance
+ private static DescriptionPlugin plugin;
+
+ private boolean enable = false;
+
+ private MetadataManager activeManager;
+
+ ITTSEngine engine;
+
+ /**
+ * The constructor
+ */
+ public DescriptionPlugin() {
+ plugin = this;
+ }
+
+ public IMetadataProvider getMetadata(String url) {
+ IXMLStoreService service = XMLStorePlugin.getDefault().getXMLStoreService();
+ IXMLStore store = service.getRootStore();
+ IXMLSelector selector1 = service.getSelectorWithDocElem("puits", "urn:puits");
+ IXMLSelector selector2 = service.getSelectorWithIRI(url);
+ store = store.specify(selector1);
+ store = store.specify(selector2);
+
+ ArrayList<IXMLInfo> list = new ArrayList<IXMLInfo>();
+ for(Iterator<IXMLInfo> i = store.getInfoIterator(); i.hasNext();){
+ list.add(i.next());
+ }
+ if(list.size() == 0)
+ return null;
+ MetadataProviderImpl provider = new MetadataProviderImpl(list);
+ if (provider != null){
+ provider.reload();
+ provider.setLocale(Locale.getDefault());
+ provider.getAlternatives();
+ }
+ return provider;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ initialize();
+ }
+
+ private void initialize() {
+ engine = newTTSEngine();
+ DescriptionPlugin.getDefault().addPropertyChangeListener(this);
+ }
+
+ private ITTSEngine newTTSEngine() {
+ ITTSEngine engine;
+ String e = DescriptionPlugin.getDefault().getPreferenceStore().getString(DescriptionPlugin.PREF_ENGINE);
+
+ // TODO
+ if (e.equals("org.eclipse.actf.ai.screenreader.jaws"))
+ return null;
+ engine = TTSRegistry.createTTSEngine(e);
+ if(engine != null)
+ engine.setSpeed(50);
+ return engine;
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ if (DescriptionPlugin.PREF_ENGINE.equals(event.getProperty())) {
+ if (null != engine) {
+ engine.stop();
+ engine.dispose();
+ engine = newTTSEngine();
+ }
+ }
+ }
+
+ public ITTSEngine getTTSEngine() {
+ return engine;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DescriptionPlugin getDefault() {
+ return plugin;
+ }
+
+ DescriptionView view;
+
+ public void setDescriptionView(DescriptionView view) {
+ this.view = view;
+ }
+
+ public DescriptionView getDescriptionView() {
+ return view;
+ }
+
+ public int setEnable(boolean flag) {
+ if(!isAvailable()){
+ enable = false;
+ return IMediaControl.STATUS_NOT_AVAILABLE;
+ }
+
+ enable = flag;
+ getDescriptionView().setEnable(enable);
+ if (enable) {
+ return IMediaControl.STATUS_ON;
+ } else {
+ return IMediaControl.STATUS_OFF;
+ }
+ }
+
+ public boolean isAvailable() {
+ if (activeManager == null)
+ return false;
+ return activeManager.hasMetadata();
+ }
+
+ public boolean canSpeak() {
+ return engine != null;
+ }
+
+ public void speak(String str) {
+ if(engine != null)
+ engine.speak(str, ITTSEngine.TTSFLAG_FLUSH, -1);
+ }
+
+ public int toggleEnable() {
+ return setEnable(!getEnable());
+ }
+
+ public boolean getEnable() {
+ return enable;
+ }
+
+ public void setActiveMetadata(MetadataManager manager) {
+ this.activeManager = manager;
+ }
+
+ public static String getString(String key) {
+ return Platform.getResourceString(getDefault().getBundle(), key);
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/IMetadata.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/IMetadata.java
new file mode 100644
index 0000000..73b69c7
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/IMetadata.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description;
+
+
+
+
+public interface IMetadata {
+ int IMPORTANCE_LOW = 0;
+ int IMPORTANCE_MIDDLE = 1;
+ int IMPORTANCE_HIGH = 2;
+
+ int MASK_NONE = 0;
+ int MASK_PAUSE_BEFORE = 1;
+ int MASK_SPEAK = 2;
+ int MASK_PAUSE_AFTER = 4;
+
+ public String getDescription();
+ public int getStartTime();
+ public int getDuration();
+ public String getLang();
+ public int getType();
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/IMetadataProvider.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/IMetadataProvider.java
new file mode 100644
index 0000000..2ec27de
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/IMetadataProvider.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.actf.ai.audio.description;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+public interface IMetadataProvider {
+ public int getSize();
+
+ public IMetadata getItem(int index);
+
+ public ArrayList<IMetadata> getAllItems();
+
+ public int getIndex(int position);
+
+ public void setLocale(Locale locale);
+
+ public int getAlternatives();
+
+ public void setAlternative(int index);
+
+ public void reload();
+
+ public boolean hasMetadata();
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/Messages.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/Messages.java
new file mode 100644
index 0000000..4da2611
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/Messages.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Takashi ITOH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+
+
+public class Messages {
+ private static final String BUNDLE_NAME = "messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ // TODO Auto-generated method stub
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MediaControlImpl.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MediaControlImpl.java
new file mode 100644
index 0000000..49be20b
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MediaControlImpl.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description.impl;
+
+import java.util.HashMap;
+
+import org.eclipse.actf.ai.audio.description.DescriptionPlugin;
+import org.eclipse.actf.ai.audio.description.IMetadataProvider;
+import org.eclipse.actf.ai.audio.description.Messages;
+import org.eclipse.actf.ai.navigator.IMediaControl;
+
+
+
+
+public class MediaControlImpl implements IMediaControl {
+
+ private HashMap<IHandle, MetadataManager> map = new HashMap<IHandle, MetadataManager>();
+ //private List<MetadataManager> managers = new Vector<MetadataManager>();
+
+ MetadataManager manager;
+ MetadataManager oldManager;
+
+ IHandle old = null;
+
+ IHandle handle;
+
+ public void dispose(IHandle handle) {
+ }
+
+ public void start(IHandle handle) {
+ //if (handle.getSoundControl() == null || handle.getVideoControl() == null)
+ //return;
+ initialize(handle);
+ }
+
+ private void initialize(IHandle handle) {
+ this.handle = handle;
+ MetadataManager temp = map.get(handle);
+
+ if(temp == null){
+ String url = handle.getWebBrowser().getURL();
+ IMetadataProvider provider = DescriptionPlugin.getDefault().getMetadata(url);
+ temp = new MetadataManager(handle, provider);
+
+ if(handle.getVideoControl() != null)
+ handle.getVideoControl().addEventListener(new MediaSyncEventListener(handle, temp));
+ //System.out.println(temp);
+ //map.put(handle, temp);
+ }
+ if(manager != null){
+ manager.stop();
+ }
+ manager = temp;
+ manager.start();
+ DescriptionPlugin.getDefault().setActiveMetadata(manager);
+
+ if(manager.hasMetadata()){
+ if(oldManager != null){
+ System.out.println(oldManager.getMetadataProvider());
+ System.out.println(manager.getMetadataProvider());
+ }
+ if(oldManager == null || oldManager.getMetadataProvider() != manager.getMetadataProvider()){
+ if(handle.getVoice() != null){
+ //speakInfo(false);
+ }
+ oldManager = manager;
+ }
+ }else{
+ //handle.getVoice().speak(Messages.getString("Metadata.notAvailable"), false);
+ }
+ }
+
+ public void speakInfo(boolean flush) {
+ DescriptionPlugin plugin = DescriptionPlugin.getDefault();
+ if (!plugin.isAvailable())
+ return;
+ if (handle.getVoice() == null)
+ return;
+
+ if (plugin.getEnable()) {
+ handle.getVoice().speak(Messages.getString("AudioDescription.on"), flush);
+ } else {
+ handle.getVoice().speak(Messages.getString("AudioDescription.off"), flush);
+ }
+ }
+
+ public int toggleEnable() {
+ DescriptionPlugin plugin = DescriptionPlugin.getDefault();
+ return plugin.toggleEnable();
+ }
+
+ public boolean isAvailable(){
+ DescriptionPlugin plugin = DescriptionPlugin.getDefault();
+ return plugin.isAvailable();
+ }
+
+ public boolean toggleViewShowing() {
+ DescriptionPlugin plugin = DescriptionPlugin.getDefault();
+ return plugin.getDescriptionView().toggleViewShowing();
+ }
+
+ public boolean isEnabled() {
+ DescriptionPlugin plugin = DescriptionPlugin.getDefault();
+ return plugin.getEnable();
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MediaSyncEventListener.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MediaSyncEventListener.java
new file mode 100644
index 0000000..6b50620
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MediaSyncEventListener.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description.impl;
+
+import org.eclipse.actf.ai.fennec.treemanager.IMediaSyncEventListener;
+import org.eclipse.actf.ai.navigator.IMediaControl.IHandle;
+
+
+
+
+public class MediaSyncEventListener implements IMediaSyncEventListener {
+
+ private static final double EVENT_INTERVAL = 0.1; // 100ms
+
+ private IHandle handle;
+ private MetadataManager manager;
+
+ public MediaSyncEventListener(IHandle handle, MetadataManager manager) {
+ this.handle = handle;
+ this.manager = manager;
+ }
+
+ public void run(){
+ if(handle.getVideoControl() != null){
+ double time = handle.getVideoControl().getCurrentPosition();
+ manager.process(time);
+ }
+ }
+
+ public double getInterval() {
+ return EVENT_INTERVAL;
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataContentProvider.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataContentProvider.java
new file mode 100644
index 0000000..d7574c1
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataContentProvider.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description.impl;
+
+import org.eclipse.actf.ai.audio.description.IMetadata;
+import org.eclipse.actf.ai.audio.description.IMetadataProvider;
+import org.eclipse.actf.ai.audio.description.util.TimeFormatUtil;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.graphics.Image;
+
+
+
+
+public class MetadataContentProvider extends LabelProvider implements IStructuredContentProvider, ITableLabelProvider{
+
+ @Override
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public Object[] getElements(Object inputElement) {
+ if(inputElement instanceof IMetadataProvider){
+ IMetadataProvider provider = (IMetadataProvider)inputElement;
+
+ String[][] ret = new String[provider.getSize()][2];
+ for(int i=0; i<ret.length; i++){
+ IMetadata metadata = provider.getItem(i);
+ ret[i][0] = ""+TimeFormatUtil.getTimeString(metadata.getStartTime()/100.0);
+ ret[i][1] = ""+metadata.getDescription();
+ }
+ return ret;
+ }
+ return null;
+ }
+
+ public Image getColumnImage(Object element, int columnIndex) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getColumnText(Object element, int columnIndex) {
+ if(element instanceof String[]){
+ return ((String[])element)[columnIndex];
+ }
+ return "";
+ }
+
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataImpl.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataImpl.java
new file mode 100644
index 0000000..abf203e
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataImpl.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.actf.ai.audio.description.impl;
+
+import java.util.Locale;
+
+import org.eclipse.actf.ai.audio.description.IMetadata;
+
+
+public class MetadataImpl implements IMetadata {
+ private double scale = 1;
+
+ private String sTime;
+
+ private int type = MASK_SPEAK;
+
+ private int start;
+
+ private int originalTime;
+
+ private int duration;
+
+ private String description;
+
+ private int importance;
+
+ private String lang;
+
+ public MetadataImpl(String start, String duration, String desc, String lang, String importance) {
+ setStart(start);
+ setDuration(duration);
+ setLang(lang);
+ setDescription(desc);
+ setImportance(importance);
+
+ }
+
+ private void setStart(String start) {
+ this.start = string2time(start);
+ setStringTime();
+ }
+
+ private void setDuration(String duration) {
+ this.duration = string2time(duration);
+ }
+
+ private void setLang(String lang) {
+ this.lang = (new Locale(lang)).getLanguage();
+ }
+
+ private void setDescription(String desc) {
+ this.description = desc;
+ }
+
+ private void setImportance(String importance) {
+ importance = importance.toLowerCase();
+ if (importance.equals("low")) {
+ this.importance = IMPORTANCE_LOW;
+ } else if (importance.equals("middle")) {
+ this.importance = IMPORTANCE_MIDDLE;
+ } else if (importance.equals("high")) {
+ this.importance = IMPORTANCE_HIGH;
+ }
+ }
+
+ private int string2time(String str) {
+ int time = 0;
+ try {
+ String[] part = str.split(":");
+ int[] r = new int[] { 1, 1000, 60000, 3600000 };
+
+ time = 0;
+ for (int i = part.length - 1, j = 0; i >= 0; i--, j++) {
+ int temp = Integer.parseInt(part[i]);
+ time += temp * r[j];
+ }
+ time /= 10;
+ } catch (Exception e) {
+ e.printStackTrace();
+ time = 0;
+ }
+ return time;
+ }
+
+ private void setStringTime() {
+ int temp = getStartTime();
+ int mm = 0;
+ int s = 0;
+ int m = 0;
+ int h = 0;
+ mm = temp % 100;
+ temp -= mm;
+ temp /= 100;
+ s = temp % 60;
+ temp -= s;
+ temp /= 60;
+ m = temp % 60;
+ temp -= m;
+ temp /= 60;
+ h = temp;
+
+ StringBuffer sb = new StringBuffer();
+ if (h != 0) {
+ sb.append(h + "h");
+ }
+ sb.append((m < 10 ? "0" : "") + m + "m");
+ sb.append((s < 10 ? "0" : "") + s + "s");
+ sb.append((mm < 10 ? "0" : "") + mm);
+
+ sTime = sb.toString();
+ }
+
+ public void setScale(double scale) {
+ this.scale = scale;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public int getStartTime() {
+ int temp = start;
+ if (temp < 0) {
+ temp = 0;
+ }
+ return (int) (temp * scale);
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return start + " (" + duration+") "+description + ", " + importance;
+ }
+
+ public String getStringTime() {
+ return sTime;
+ }
+
+ public void refresh() {
+ start = originalTime;
+ setStringTime();
+ }
+
+ public int getDuration() {
+ return duration;
+ }
+
+ public String getLang() {
+ return lang;
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataManager.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataManager.java
new file mode 100644
index 0000000..af6d17c
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataManager.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description.impl;
+
+
+import org.eclipse.actf.ai.audio.description.DescriptionPlugin;
+import org.eclipse.actf.ai.audio.description.IMetadata;
+import org.eclipse.actf.ai.audio.description.IMetadataProvider;
+import org.eclipse.actf.ai.fennec.treemanager.ISoundControl;
+import org.eclipse.actf.ai.fennec.treemanager.IVideoControl;
+import org.eclipse.actf.ai.navigator.IMediaControl.IHandle;
+
+
+
+
+public class MetadataManager{
+
+ private IMetadataProvider metadataProvider;
+
+ private int index;
+
+ private int oldIndex;
+
+ private int forceFlag = IMetadata.MASK_NONE;
+
+ private IHandle handle;
+
+ private IVideoControl video;
+
+ @SuppressWarnings("unused")
+ private ISoundControl sound;
+
+ private boolean stopFlag = false;
+
+ public void setForceFlag(int flag) {
+ forceFlag = flag;
+ }
+
+ public MetadataManager(IHandle handle, IMetadataProvider metadataProvider) {
+ this.handle = handle;
+ this.video = handle.getVideoControl();
+ this.sound = handle.getSoundControl();
+
+ this.metadataProvider = metadataProvider;
+ index = oldIndex = -1;
+ }
+
+ private boolean pauseBeforeFlag = false;
+
+ private boolean speakFlag = false;
+
+ private boolean pauseAfterFlag = false;
+
+ public void process(double time) {
+ if(stopFlag)
+ return;
+
+ DescriptionPlugin.getDefault().getDescriptionView().setTime(time);
+
+ if (metadataProvider == null)
+ return;
+ index = metadataProvider.getIndex((int) (time * 100));
+ // System.out.println(time+", "+metadataProvider.getItem(index).getTime());
+
+ if (oldIndex != index && oldIndex < index) {
+ int type = metadataProvider.getItem(index).getType();
+
+ pauseBeforeFlag = isIt(type | forceFlag, IMetadata.MASK_PAUSE_BEFORE);
+ speakFlag = isIt(type | forceFlag, IMetadata.MASK_SPEAK);
+ pauseAfterFlag = isIt(type | forceFlag, IMetadata.MASK_PAUSE_AFTER);
+ }
+
+ if (pauseBeforeFlag) {
+ pauseBeforeFlag = false;
+ processPause();
+ }
+ if (speakFlag) {
+ speakFlag = false;
+ processSpeak();
+ }
+ if (pauseAfterFlag) {
+ pauseAfterFlag = false;
+ processPlay();
+ }
+
+ oldIndex = index;
+ }
+
+ private boolean isIt(int type, int pause) {
+ return (type & pause) == pause;
+ }
+
+ private void processPause() {
+ if (DescriptionPlugin.getDefault().getEnable())
+ video.pauseMedia();
+ }
+
+ private void processPlay() {
+ if (DescriptionPlugin.getDefault().getEnable())
+ video.playMedia();
+ }
+
+ private void processSpeak() {
+ if (DescriptionPlugin.getDefault().getEnable()) {
+
+ /*
+ int[] volumes = null;
+ volumes = sound.getVolumes();
+ int[] volumes2 = new int[volumes.length];
+ for(int i=0; i<volumes2.length; i++)
+ volumes2[i] = 200;
+ sound.setVolumes(volumes2);
+ */
+
+ String desc = metadataProvider.getItem(index).getDescription();
+ say(desc);
+ }
+ }
+
+ public void say(String str) {
+ //System.out.println(str);
+ DescriptionPlugin plugin = DescriptionPlugin.getDefault();
+
+ if (plugin.canSpeak()) {
+ plugin.speak(str);
+ } else {
+ handle.getVoice().speak(str, true);
+ }
+ }
+
+ public void stop() {
+ stopFlag = true;
+ }
+
+ public void start(){
+ stopFlag = false;
+ DescriptionPlugin.getDefault().getDescriptionView().setInput(metadataProvider);
+ }
+
+ public boolean hasMetadata(){
+ if (metadataProvider == null)
+ return false;
+ return metadataProvider.hasMetadata();
+ }
+
+ public Object getMetadataProvider() {
+ return metadataProvider;
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataProviderImpl.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataProviderImpl.java
new file mode 100644
index 0000000..a05afff
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/impl/MetadataProviderImpl.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.actf.ai.audio.description.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.Stack;
+
+import org.eclipse.actf.ai.audio.description.IMetadata;
+import org.eclipse.actf.ai.audio.description.IMetadataProvider;
+import org.eclipse.actf.ai.xmlstore.IXMLInfo;
+import org.eclipse.actf.ai.xmlstore.XMLStoreException;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+public class MetadataProviderImpl implements IMetadataProvider {
+
+ private static class Key {
+ public String id;
+
+ public String lang;
+
+ public Key(String id, String lang) {
+ this.id = id;
+ if (lang == null || lang.length() == 0) {
+ this.lang = "";
+ } else {
+ this.lang = (new Locale(lang)).getLanguage();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return toString().equals(o.toString());
+ }
+
+ @Override
+ public String toString(){
+ return id+lang;
+ }
+ }
+
+ private HashMap<Key, ArrayList<IMetadata>> metadataList = new HashMap<Key, ArrayList<IMetadata>>();
+
+ private ArrayList<IMetadata> metadata;
+
+ private ArrayList<IXMLInfo> entries;
+
+ private Locale locale = null;
+
+ public MetadataProviderImpl(ArrayList<IXMLInfo> entries) {
+ this.entries = entries;
+ }
+
+ public void reload() {
+ metadataList.clear();
+ readFile();
+ }
+
+ private Stack<String> langStack = new Stack<String>();
+
+ private class BaseHandler extends DefaultHandler {
+ private BaseHandler back;
+
+ private IXMLInfo entry;
+
+ public BaseHandler(BaseHandler back, IXMLInfo entry) {
+ this.back = back;
+ this.entry = entry;
+ }
+
+ public BaseHandler(BaseHandler back) {
+ this.back = back;
+ this.entry = back.getEntry();
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ if (attributes.getValue("xml:lang") != null) {
+ langStack.push(attributes.getValue("xml:lang"));
+ } else {
+ langStack.push(langStack.peek() + "");
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ langStack.pop();
+ getEntry().setContentHandler(back);
+ }
+
+ public IXMLInfo getEntry() {
+ return entry;
+ }
+ }
+
+ private class AllHandler extends BaseHandler {
+ private boolean altFlag;
+
+ public AllHandler(IXMLInfo entry) {
+ super(null, entry);
+ langStack.clear();
+ langStack.push("");
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ super.startElement(uri, localName, qName, attributes);
+
+ if (altFlag) {
+ if ("item".equals(localName)) {
+ String importance = attributes.getValue("importance");
+ if (importance == null || importance.length() == 0) {
+ importance = "middle";
+ }
+ getEntry().setContentHandler(new ItemHandler(this, importance));
+ }
+ } else {
+ if ("alternative".equals(localName)) {
+ String type = attributes.getValue("type");
+ if (type != null && type.equals("audio-description")) {
+ altFlag = true;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ // super.endElement(uri, localName, qName);
+ }
+ }
+
+ private class ItemHandler extends BaseHandler {
+ private boolean descFlag = false;
+
+ private boolean startFlag = false;
+
+ private boolean durationFlag = false;
+
+ private StringBuffer buf = new StringBuffer();
+
+ private String start;
+
+ private String duration;
+
+ private ArrayList<String> desc = new ArrayList<String>();
+
+ private ArrayList<String> lang = new ArrayList<String>();
+
+ private String importance;
+
+ public ItemHandler(BaseHandler back, String importance) {
+ super(back);
+ this.importance = importance;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ super.startElement(uri, localName, qName, attributes);
+
+ if ("start".equals(localName)) {
+ if (attributes.getValue("type").equals("relTime")) {
+ startFlag = true;
+ }
+ } else if ("duration".equals(localName)) {
+ durationFlag = true;
+ } else if ("description".equals(localName)) {
+ descFlag = true;
+ }
+
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ if (startFlag) {
+ buf.append(ch, start, length);
+ } else if (durationFlag) {
+ buf.append(ch, start, length);
+ } else if (descFlag) {
+ buf.append(ch, start, length);
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if ("start".equals(localName)) {
+ startFlag = false;
+ start = buf.toString();
+ buf.delete(0, buf.length());
+ } else if ("duration".equals(localName)) {
+ durationFlag = false;
+ duration = buf.toString();
+ buf.delete(0, buf.length());
+ } else if ("description".equals(localName)) {
+ descFlag = false;
+ desc.add(buf.toString());
+ lang.add(langStack.peek());
+ buf.delete(0, buf.length());
+ } else if ("item".equals(localName)) {
+
+ for (int i = 0; i < desc.size(); i++) {
+ MetadataImpl mi = new MetadataImpl(start, duration, desc.get(i), lang.get(i), importance);
+ //System.out.println(start + ", " + duration + ", " + desc.get(i) + ", " + lang.get(i));
+
+ Key key = new Key(getEntry().getDocumentation(), lang.get(i));
+
+ ArrayList<IMetadata> list = metadataList.get(key);
+
+ if (list == null) {
+ list = new ArrayList<IMetadata>();
+ metadataList.put(key, list);
+ }
+ list.add(mi);
+ }
+ super.endElement(uri, localName, qName);
+ }
+ }
+ }
+
+ private void readFile() {
+ for (int i = 0; i < entries.size(); i++) {
+ IXMLInfo entry = entries.get(i);
+
+ AllHandler ah = new AllHandler(entry);
+ entry.setContentHandler(ah);
+ try {
+ entry.startSAX();
+ } catch (XMLStoreException e) {
+ e.printStackTrace();
+ } catch (SAXException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+ ArrayList<ArrayList<IMetadata>> alternatives;
+
+ public int getAlternatives() {
+ Set<Key> keys = metadataList.keySet();
+ alternatives = new ArrayList<ArrayList<IMetadata>>();
+ for (Iterator<Key> i = keys.iterator(); i.hasNext();) {
+ Key key = i.next();
+ if (key.lang.equals(locale.getLanguage())) {
+ alternatives.add(metadataList.get(key));
+ }
+ }
+ if (alternatives.size() > 0)
+ setMetadata(alternatives.get(0));
+ return alternatives.size();
+ }
+
+ public void setAlternative(int index) {
+ metadata = alternatives.get(index);
+ }
+
+ public void setMetadata(ArrayList<IMetadata> metadata) {
+ this.metadata = metadata;
+ }
+
+ public IMetadata getItem(int index) {
+ if (0 <= index && index < metadata.size())
+ return metadata.get(index);
+ return null;
+ }
+
+ public ArrayList<IMetadata> getAllItems() {
+ return metadata;
+ }
+
+ public int getIndex(int position) {
+ if (metadata == null)
+ return 0;
+
+ int ret = 0;
+ for (int i = 0; i < metadata.size(); i++) {
+ if (metadata.get(i).getStartTime() >= position) {
+ ret = i - 1;
+ return ret;
+ }
+ }
+ return metadata.size() - 1;
+ }
+
+ public int getSize() {
+ if (metadata == null)
+ return 0;
+ return metadata.size();
+ }
+
+ public boolean hasMetadata() {
+ return metadata.size() > 0;
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/preferences/ADPreferenceInitializer.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/preferences/ADPreferenceInitializer.java
new file mode 100644
index 0000000..6ce4251
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/preferences/ADPreferenceInitializer.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.actf.ai.audio.description.preferences;
+
+import org.eclipse.actf.ai.audio.description.DescriptionPlugin;
+import org.eclipse.actf.ai.voice.internal.TTSRegistry;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+
+public class ADPreferenceInitializer extends AbstractPreferenceInitializer {
+
+ @Override
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = DescriptionPlugin.getDefault().getPreferenceStore();
+ store.setDefault(DescriptionPlugin.PREF_ENGINE, TTSRegistry.getDefaultEngine());
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/preferences/ADPreferencePage.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/preferences/ADPreferencePage.java
new file mode 100644
index 0000000..6bca77d
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/preferences/ADPreferencePage.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description.preferences;
+
+import org.eclipse.actf.ai.audio.description.DescriptionPlugin;
+import org.eclipse.actf.ai.audio.description.Messages;
+import org.eclipse.actf.ai.voice.internal.TTSRegistry;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.RadioGroupFieldEditor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+
+
+
+public class ADPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage{
+
+ public ADPreferencePage() {
+ super(GRID);
+ setPreferenceStore(DescriptionPlugin.getDefault().getPreferenceStore());
+ setDescription(Messages.getString("AudioDescription.preference.title")); //$NON-NLS-1$
+ }
+
+ @Override
+ public void createFieldEditors() {
+ RadioGroupFieldEditor rgfe;
+ String[][] labelAndIds = TTSRegistry.getLabelAndIds();
+ addField(rgfe = new RadioGroupFieldEditor(DescriptionPlugin.PREF_ENGINE,
+ Messages.getString("AudioDescription.voice.engine"), 1, labelAndIds, //$NON-NLS-1$
+ getFieldEditorParent()));
+ Composite c = rgfe.getRadioBoxControl(getFieldEditorParent());
+ for(int i=0; i<labelAndIds.length; i++){
+ if(labelAndIds[i][1].length() == 0){
+ c.getChildren()[i].setEnabled(false);
+ }
+ }
+ }
+
+ public void init(IWorkbench workbench) {
+
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/util/TimeFormatUtil.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/util/TimeFormatUtil.java
new file mode 100644
index 0000000..4749921
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/util/TimeFormatUtil.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description.util;
+
+
+public class TimeFormatUtil {
+
+ public static String getTimeString(double time){
+ int mi, se, ms;
+ int intTime = (int)(time*100);
+
+ ms = intTime%100;
+ intTime /= 100;
+ se = intTime%60;
+ intTime /= 60;
+ mi = intTime;
+
+ return (mi<10?"0":"")+mi+":"+(se<10?"0":"")+se+"."+(ms<10?"0":"")+ms;
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/views/DescriptionView.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/views/DescriptionView.java
new file mode 100644
index 0000000..136cbf8
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/views/DescriptionView.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description.views;
+
+import org.eclipse.actf.ai.audio.description.DescriptionPlugin;
+import org.eclipse.actf.ai.audio.description.Messages;
+import org.eclipse.actf.ai.audio.description.impl.MetadataContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+
+
+
+public class DescriptionView extends ViewPart {
+ public static final String ID = "org.eclipse.actf.ai.audio.description.views.DescriptionView";
+
+ private VideoStatusViewer status;
+
+ private TableViewer tableViewer;
+
+ @Override
+ public void createPartControl(Composite parent) {
+ initView(parent);
+ DescriptionPlugin.getDefault().setDescriptionView(this);
+ }
+
+ private void initView(Composite parent) {
+ GridLayout gLayout = new GridLayout(1, true);
+ gLayout.marginWidth = 0;
+ gLayout.marginHeight = 0;
+ parent.setLayout(gLayout);
+
+ status = new VideoStatusViewer(parent);
+
+ tableViewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+ MetadataContentProvider provider = new MetadataContentProvider();
+ tableViewer.setContentProvider(provider);
+ tableViewer.setLabelProvider(provider);
+
+ Table table = tableViewer.getTable();
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+ TableColumn tableColumnProperty = new TableColumn(table, SWT.LEFT);
+ tableColumnProperty.setText(Messages.getString("AudioDescription.view.time"));
+ tableColumnProperty.setWidth(70);
+ TableColumn tableColumnValue = new TableColumn(table, SWT.LEFT);
+ tableColumnValue.setText(Messages.getString("AudioDescription.view.desc"));
+ tableColumnValue.setWidth(130);
+
+ GridData data = new GridData(GridData.FILL_BOTH);
+ table.setLayoutData(data);
+ }
+
+ @Override
+ public void setFocus() {
+
+ }
+
+ public void setTime(double time) {
+ status.setTime(time);
+ }
+ public void setInput(Object input){
+ if(tableViewer.getTable().isDisposed())
+ return;
+ tableViewer.setInput(input);
+ }
+ public void setIndex(int index){
+ if(tableViewer.getTable().isDisposed())
+ return;
+ tableViewer.getTable().select(index);
+ }
+
+ public void setEnable(boolean b) {
+ status.setEnable(b);
+ }
+
+ public boolean toggleViewShowing() {
+ IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ IViewPart part = page.findView(ID);
+
+ if (part != null) {
+ page.hideView(part);
+ return false;
+ } else {
+ try {
+ page.showView(ID);
+ return true;
+ } catch (PartInitException e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/views/VideoStatusViewer.java b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/views/VideoStatusViewer.java
new file mode 100644
index 0000000..fa0328a
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.description/src/org/eclipse/actf/ai/audio/description/views/VideoStatusViewer.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.description.views;
+
+import org.eclipse.actf.ai.audio.description.DescriptionPlugin;
+import org.eclipse.actf.ai.audio.description.Messages;
+import org.eclipse.actf.ai.audio.description.util.TimeFormatUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+
+
+
+public class VideoStatusViewer {
+
+ private Composite parent;
+ private Label status;
+ private boolean enable = false;
+ private String timeText;
+
+
+ public VideoStatusViewer(Composite parent){
+ this.parent = parent;
+ initialize();
+ }
+
+ public void initialize(){
+ status = new Label(parent, SWT.NONE);
+ GridData data = new GridData(GridData.FILL_HORIZONTAL);
+ status.setLayoutData(data);
+ status.setAlignment(SWT.RIGHT);
+ setTime(0);
+ enable = DescriptionPlugin.getDefault().getEnable();
+ }
+
+ public void setTime(double time){
+ timeText = TimeFormatUtil.getTimeString(time);
+ refreshText();
+ }
+
+ private void refreshText(){
+ if(status.isDisposed())
+ return;
+ if(enable){
+ status.setText(Messages.getString("AudioDescription.view.enable")+" "+timeText);
+ }else{
+ status.setText(Messages.getString("AudioDescription.view.notEnable")+" "+timeText);
+ }
+ }
+
+ public void setEnable(boolean b) {
+ enable = b;
+ refreshText();
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/.classpath b/plugins/org.eclipse.actf.ai.audio.io/.classpath
new file mode 100644
index 0000000..751c8f2
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.actf.ai.audio.io/.project b/plugins/org.eclipse.actf.ai.audio.io/.project
new file mode 100644
index 0000000..cc0b860
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.actf.ai.audio.io</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.actf.ai.audio.io/META-INF/MANIFEST.MF b/plugins/org.eclipse.actf.ai.audio.io/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..89dee95
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Eclipse ACTF Audio IO Plug-in (Incubation)
+Bundle-SymbolicName: org.eclipse.actf.ai.audio.io
+Bundle-Version: 0.0.1
+Bundle-Activator: org.eclipse.actf.ai.audio.io.Activator
+Bundle-Vendor: Eclipse.org
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime
+Eclipse-LazyStart: true
+Export-Package: org.eclipse.actf.ai.audio.io
diff --git a/plugins/org.eclipse.actf.ai.audio.io/about.html b/plugins/org.eclipse.actf.ai.audio.io/about.html
new file mode 100644
index 0000000..481dbcf
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/about.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2006</p>
+<h3>License</h3>
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content").
+Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor’s license
+that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/plugins/org.eclipse.actf.ai.audio.io/build.properties b/plugins/org.eclipse.actf.ai.audio.io/build.properties
new file mode 100644
index 0000000..e1942be
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/build.properties
@@ -0,0 +1,15 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ about.html,\
+ .
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/Activator.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/Activator.java
new file mode 100644
index 0000000..f948ffd
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/Activator.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.actf.ai.audio.io;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.actf.ai.audio.io";
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioFactory.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioFactory.java
new file mode 100644
index 0000000..ea98776
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioFactory.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io;
+
+import java.net.URL;
+
+import javax.sound.sampled.Mixer;
+
+import org.eclipse.actf.ai.audio.io.impl.AudioFileReader;
+import org.eclipse.actf.ai.audio.io.impl.AudioPipe;
+import org.eclipse.actf.ai.audio.io.impl.LoopedAudioPipe;
+import org.eclipse.actf.ai.audio.io.impl.PlaybackDevice;
+import org.eclipse.actf.ai.audio.io.impl.RecordDevice;
+
+
+
+
+public class AudioFactory {
+ public static IAudioReader createAudioReader(String file) {
+ return new AudioFileReader(file);
+ }
+
+ public static IAudioReader createAudioReader(URL url) {
+ return new AudioFileReader(url);
+ }
+
+ public static IAudioWriter createDefaultWriter() {
+ return new PlaybackDevice();
+ }
+
+ public static IAudioPipe createAudioPipe(IAudioReader reader, IAudioWriter writer) {
+ return new AudioPipe(reader, writer);
+ }
+
+ public static IAudioPipe createLoopedAudioPipe(IAudioReader reader, IAudioWriter writer) {
+ return new LoopedAudioPipe(reader, writer);
+ }
+
+ public static IAudioWriter createAudioWriter(Mixer mixer) {
+ return new PlaybackDevice(mixer);
+ }
+
+ public static IAudioReader createAudioReader(Mixer mixer, int recordingSmapleRate, int recordingChannels) {
+ return new RecordDevice(mixer, recordingSmapleRate, recordingChannels);
+ }
+
+ public static void main(String[] args) {
+ IAudioReader reader = AudioFactory.createAudioReader("16-16-short-pcm-lpf.wav");
+ IAudioWriter writer = AudioFactory.createDefaultWriter();
+ IAudioPipe pipe = AudioFactory.createLoopedAudioPipe(reader, writer);
+
+ // buffer size for reading (in milli seconds)
+ pipe.setBufferSize(100);
+
+ // interval time to try writing (in milli seconds)
+ pipe.setInterval(1);
+
+ // Create new thread and start playing.
+ // The pipe automatically opens reader and writer.
+ pipe.prepare();
+
+ pipe.start();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ pipe.stop();
+
+ pipe.start();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ pipe.stop();
+ }
+
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioIOException.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioIOException.java
new file mode 100644
index 0000000..8fea0c6
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioIOException.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io;
+
+
+public class AudioIOException extends Exception{
+
+ public AudioIOException(String string) {
+ super(string);
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioPipeListener.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioPipeListener.java
new file mode 100644
index 0000000..1395187
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioPipeListener.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io;
+
+
+public interface AudioPipeListener {
+ void finished(IAudioPipe pipe);
+ void stopped(IAudioPipe pipe);
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioUtil.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioUtil.java
new file mode 100644
index 0000000..f61869b
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/AudioUtil.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io;
+
+import java.nio.ByteOrder;
+
+import javax.sound.sampled.AudioFormat;
+
+
+
+public class AudioUtil {
+
+ public static int getBytesPerSecondLR(AudioFormat format) {
+ return (int) getBytesPerSecond(format) * format.getChannels();
+ }
+
+ public static int getBytesPerSecond(AudioFormat format) {
+ return (int) getBitsPerSecond(format) / 8;
+ }
+
+ public static int getBitsPerSecond(AudioFormat format){
+ return (int) format.getSampleRate() * format.getSampleSizeInBits();
+ }
+
+ public static int getSamplesPerSecond(AudioFormat format) {
+ return (int) format.getSampleRate();
+ }
+
+ public static int getSamplesPerSecondLR(AudioFormat format) {
+ return (int) getSamplesPerSecond(format) * format.getChannels();
+ }
+
+ public static int getBytesPerSample(AudioFormat format){
+ return format.getSampleSizeInBits() / 8;
+ }
+
+ public static int getBytesPerSampleLR(AudioFormat format) {
+ return getBytesPerSample(format) * format.getChannels();
+ }
+
+ public static ByteOrder getEndian(AudioFormat format) {
+ if(format.isBigEndian())
+ return ByteOrder.BIG_ENDIAN;
+ else
+ return ByteOrder.LITTLE_ENDIAN;
+ }
+
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioPipe.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioPipe.java
new file mode 100644
index 0000000..11899e2
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioPipe.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io;
+
+
+public interface IAudioPipe {
+ void addAudioPipeListener(AudioPipeListener listener);
+
+ void setInterval(int interval);
+ void setPriority(int priority);
+ void setBufferSize(int miliSeconds);
+ boolean isActive();
+
+ void prepare();
+ void start(int delay);
+ void start();
+ void stop();
+ void join();
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioReader.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioReader.java
new file mode 100644
index 0000000..c1d4a9b
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioReader.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.eclipse.actf.ai.audio.io.AudioIOException;
+
+
+
+
+
+public interface IAudioReader {
+
+ String getName();
+
+ AudioFormat getAudioFormat();
+
+ boolean canRead();
+
+ void open() throws AudioIOException;
+
+ void close();
+
+ int read(byte[] data, int offset, int length) throws AudioIOException;
+
+ boolean isClosed();
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioWriter.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioWriter.java
new file mode 100644
index 0000000..381299c
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/IAudioWriter.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.eclipse.actf.ai.audio.io.AudioIOException;
+
+
+
+
+
+public interface IAudioWriter {
+
+ String getName();
+
+ int write(byte[] data, int offset, int length) throws AudioIOException;
+
+ boolean canWrite();
+
+ void open(AudioFormat format) throws AudioIOException;
+
+ void close();
+
+ boolean isClosed();
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/AudioFileReader.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/AudioFileReader.java
new file mode 100644
index 0000000..2db216b
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/AudioFileReader.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import org.eclipse.actf.ai.audio.io.AudioIOException;
+import org.eclipse.actf.ai.audio.io.IAudioReader;
+
+
+
+
+public class AudioFileReader implements IAudioReader {
+
+ private File file;
+
+ private URL url;
+
+ private AudioFormat format;
+
+ private AudioInputStream stream;
+
+ private boolean opened = false;
+
+ private boolean closed = false;
+
+ public AudioFileReader(String fileName) {
+ setFile(fileName);
+ }
+
+ public AudioFileReader(URL url) {
+ setURL(url);
+ }
+
+ public String getName() {
+ if (file != null)
+ return "File \"" + file.getName() + "\"";
+ if (url != null)
+ return "URL \"" + url.getPath() + "\"";
+ return "";
+ }
+
+ private void setFile(String fileName) {
+ this.file = new File(fileName);
+ }
+
+ private void setURL(URL url) {
+ this.url = url;
+ }
+
+ public boolean canRead() {
+ try {
+ if (file != null)
+ AudioSystem.getAudioInputStream(file);
+ if (url != null)
+ AudioSystem.getAudioFileFormat(url);
+ return true;
+ } catch (UnsupportedAudioFileException e) {
+ } catch (IOException e) {
+ }
+ return false;
+ }
+
+ synchronized public void open() throws AudioIOException {
+ try {
+ if (file != null)
+ stream = AudioSystem.getAudioInputStream(file);
+ if (url != null)
+ stream = AudioSystem.getAudioInputStream(url);
+ AudioFormat baseFormat = stream.getFormat();
+
+ AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(),
+ 16, baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);
+
+ stream = AudioSystem.getAudioInputStream(decodedFormat, stream);
+
+ format = stream.getFormat();
+ opened = true;
+ closed = false;
+ } catch (UnsupportedAudioFileException e) {
+ throw new AudioIOException("Unsupported audio file type");
+ } catch (IOException e) {
+ throw new AudioIOException(e.toString());
+ }
+ }
+
+ public AudioFormat getAudioFormat() {
+ return format;
+ }
+
+ synchronized public int read(byte[] data, int offset, int length) throws AudioIOException {
+ if (!opened) {
+ throw new AudioIOException("not opened");
+ }
+ try {
+ int nBytesRead = stream.read(data, offset, length);
+ if (nBytesRead == -1) {
+ stream.close();
+ opened = false;
+ closed = true;
+ nBytesRead = 0;
+ }
+ return nBytesRead;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return 0;
+ }
+
+ synchronized public void close() {
+ try {
+ if (stream != null)
+ stream.close();
+ } catch (IOException e) {
+ }
+ opened = false;
+ closed = true;
+ }
+
+ public boolean isClosed() {
+ return closed;
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/AudioPipe.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/AudioPipe.java
new file mode 100644
index 0000000..7059bab
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/AudioPipe.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io.impl;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.Date;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.eclipse.actf.ai.audio.io.AudioIOException;
+import org.eclipse.actf.ai.audio.io.AudioPipeListener;
+import org.eclipse.actf.ai.audio.io.AudioUtil;
+import org.eclipse.actf.ai.audio.io.IAudioPipe;
+import org.eclipse.actf.ai.audio.io.IAudioReader;
+import org.eclipse.actf.ai.audio.io.IAudioWriter;
+
+
+
+
+public class AudioPipe implements IAudioPipe{
+
+ private IAudioReader reader;
+
+ private IAudioWriter writer;
+
+ private AudioFormat format;
+
+ private Thread thread;
+
+ private Runnable runner;
+
+ private byte[] buffer;
+
+ private int bufferSize;
+
+ private int interval = 100;
+
+ private int priority = Thread.NORM_PRIORITY;
+
+ private int bufferSizeInMs = 1000;
+
+ private boolean active;
+
+ private boolean waiting;
+
+ private boolean stopFlag = false;
+
+ private boolean stopFlag2 = false;
+
+ private ArrayList<AudioPipeListener> listeners = new ArrayList<AudioPipeListener>();
+
+ public AudioPipe(IAudioReader reader, IAudioWriter writer) {
+ this.reader = reader;
+ this.writer = writer;
+ runner = new ReaderWriterRunner();
+ }
+
+ public void addAudioPipeListener(AudioPipeListener listener) {
+ listeners.add(listener);
+ }
+
+ class ReaderWriterRunner implements Runnable {
+ private void fadeout(byte[] buffer, int nBytesRead) {
+ int bps = AudioUtil.getBytesPerSample(format);
+
+ ByteBuffer bb = ByteBuffer.wrap(buffer);
+ ShortBuffer sb = null;
+ if (format.isBigEndian())
+ bb.order(ByteOrder.BIG_ENDIAN);
+ else
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ if (bps == 2)
+ sb = bb.asShortBuffer();
+
+ int len = nBytesRead / bps;
+
+ for (int i = 0; i < len; i++) {
+ double k = (double) (len - i) / (double) len;
+ if (bps == 1)
+ bb.put(i, (byte) (bb.get(i) * k));
+ else
+ sb.put(i, (short) (sb.get(i) * k));
+ }
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ if (reader.isClosed())
+ break;
+
+ int nBytesRead = reader.read(buffer, 0, buffer.length);
+
+ int nBytesWritten = 0;
+ do {
+ if (writer.isClosed()){
+ active = false;
+ fireStopped();
+ return;
+ }
+ if (stopFlag) {
+ fadeout(buffer, nBytesRead);
+ stopFlag = false;
+ stopFlag2 = true;
+ }
+ int temp = writer.write(buffer, nBytesWritten, nBytesRead);
+ nBytesWritten += temp;
+ nBytesRead -= temp;
+ sleep();
+ } while (nBytesRead > 0);
+
+ if (stopFlag2) {
+ stopFlag2 = false;
+ writer.close();
+ }
+ }
+ writer.close();
+ } catch (AudioIOException e) {
+ writer.close();
+ } catch (Exception e){
+ e.printStackTrace();
+ writer.close();
+ }
+ active = false;
+ fireFinished();
+ }
+ }
+
+ private void fireFinished() {
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).finished(this);
+ }
+ }
+
+ private void fireStopped() {
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).stopped(this);
+ }
+ }
+
+ synchronized public void setInterval(int interval) {
+ this.interval = interval;
+ }
+
+ synchronized public void setPriority(int priority){
+ this.priority = priority;
+ if(thread != null)
+ thread.setPriority(priority);
+ }
+
+ public void prepare() {
+ try {
+ reader.open();
+ format = reader.getAudioFormat();
+ writer.open(format);
+ } catch (AudioIOException e) {
+ e.printStackTrace();
+ return;
+ }
+ }
+
+ public void start() {
+ start(0);
+ }
+
+ public void start(final int delay) {
+ if (active || waiting)
+ return;
+ waiting = true;
+ thread = new Thread(new Runnable() {
+ public void run(){
+ long s = (new Date()).getTime();
+
+ while (true) {
+ long n = (new Date()).getTime();
+ if (stopFlag) {
+ waiting = false;
+ stopFlag = false;
+ active = false;
+ fireStopped();
+ return;
+ }
+ if (s + delay <= n) {
+ break;
+ }
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e){
+ }
+ }
+
+ while (active) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e){
+ }
+ }
+
+ prepare();
+
+ int Bps = AudioUtil.getBytesPerSampleLR(format);
+ bufferSize = AudioUtil.getBytesPerSecondLR(format) * bufferSizeInMs / 1000 / Bps * Bps;
+ buffer = new byte[bufferSize];
+ active = true;
+ waiting = false;
+ runner.run();
+ }
+ });
+ thread.setPriority(priority);
+ thread.setName(reader.getName()+"<->"+writer.getName());
+ thread.start();
+ }
+
+ synchronized private void sleep() {
+ try {
+ Thread.sleep(interval);
+ Thread.yield();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public boolean isActive(){
+ return active;
+ }
+
+ public void stop() {
+ if (active || waiting)
+ stopFlag = true;
+ }
+
+ public void join() {
+ if(thread == null)
+ return;
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setBufferSize(int miliSeconds){
+ bufferSizeInMs = miliSeconds;
+ }
+
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/LoopedAudioPipe.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/LoopedAudioPipe.java
new file mode 100644
index 0000000..ff3c059
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/LoopedAudioPipe.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io.impl;
+
+import java.util.ArrayList;
+
+import org.eclipse.actf.ai.audio.io.AudioPipeListener;
+import org.eclipse.actf.ai.audio.io.IAudioPipe;
+import org.eclipse.actf.ai.audio.io.IAudioReader;
+import org.eclipse.actf.ai.audio.io.IAudioWriter;
+
+
+
+
+public class LoopedAudioPipe implements IAudioPipe, AudioPipeListener {
+
+ IAudioPipe target;
+
+ boolean isActive;
+
+ boolean joining = false;
+
+ private ArrayList<AudioPipeListener> listeners = new ArrayList<AudioPipeListener>();
+
+ public LoopedAudioPipe(IAudioReader reader, IAudioWriter writer) {
+ target = new AudioPipe(reader, writer);
+ target.addAudioPipeListener(this);
+ }
+
+ public void addAudioPipeListener(AudioPipeListener listener) {
+ listeners.add(listener);
+ }
+
+ public boolean isActive() {
+ return isActive;
+ }
+
+ public void join() {
+ joining = true;
+ target.join();
+ fireFinished();
+ }
+
+ public void setBufferSize(int miliSeconds) {
+ target.setBufferSize(miliSeconds);
+ }
+
+ public void setInterval(int interval) {
+ target.setInterval(interval);
+ }
+
+ public void setPriority(int priority) {
+ target.setPriority(priority);
+ }
+
+ public void prepare() {
+ target.prepare();
+ }
+
+ public void start() {
+ start(0);
+ }
+
+ public void start(int delay) {
+ target.start(delay);
+ isActive = true;
+ joining = false;
+ }
+
+ public void stop() {
+ target.stop();
+ isActive = false;
+ fireStopped();
+ }
+
+ private void fireFinished() {
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).finished(this);
+ }
+ }
+
+ private void fireStopped() {
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).stopped(this);
+ }
+ }
+
+ public void finished(IAudioPipe pipe) {
+ if (!joining)
+ pipe.start();
+ }
+
+ public void stopped(IAudioPipe pipe) {
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/PlaybackDevice.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/PlaybackDevice.java
new file mode 100644
index 0000000..71c15f1
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/PlaybackDevice.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io.impl;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Mixer;
+import javax.sound.sampled.SourceDataLine;
+
+import org.eclipse.actf.ai.audio.io.AudioIOException;
+import org.eclipse.actf.ai.audio.io.IAudioWriter;
+
+
+
+
+public class PlaybackDevice implements IAudioWriter {
+
+ private Mixer playbackMixer;
+
+ private SourceDataLine playbackLine;
+
+ private int limit;
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof PlaybackDevice) {
+ return playbackMixer.equals(((PlaybackDevice) o).playbackMixer);
+ }
+ return false;
+ }
+
+ public PlaybackDevice(Mixer mixer) {
+ this.playbackMixer = mixer;
+ }
+
+ public PlaybackDevice() {
+ this.playbackMixer = null;
+ }
+
+ public String getName() {
+ if (playbackMixer != null)
+ return "Device \"" + playbackMixer.getMixerInfo().getName() + "\"";
+ else
+ return "Device \"default\"";
+ }
+
+ synchronized public void close() {
+ if (playbackLine != null) {
+ playbackLine.drain();
+ playbackLine.close();
+ }
+ }
+
+ public boolean isClosed() {
+ if (playbackLine == null)
+ return true;
+ return !playbackLine.isOpen();
+ }
+
+ public boolean canWrite() {
+ return true;
+ }
+
+ synchronized public void open(AudioFormat format) throws AudioIOException {
+
+ DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
+
+ try {
+ if (playbackMixer != null)
+ playbackLine = (SourceDataLine) playbackMixer.getLine(info);
+ else
+ playbackLine = (SourceDataLine) AudioSystem.getLine(info);
+
+ playbackLine.open();
+
+ limit = playbackLine.available() / 10 * 5;
+
+ playbackLine.start();
+ } catch (LineUnavailableException e1) {
+ e1.printStackTrace();
+ }
+ }
+
+ synchronized public int write(byte[] data, int offset, int length) throws AudioIOException {
+ if (playbackLine.available() > limit) {
+ return playbackLine.write(data, offset, length);
+ }
+ return 0;
+ }
+}
diff --git a/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/RecordDevice.java b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/RecordDevice.java
new file mode 100644
index 0000000..8a8cbae
--- /dev/null
+++ b/plugins/org.eclipse.actf.ai.audio.io/src/org/eclipse/actf/ai/audio/io/impl/RecordDevice.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and Others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daisuke SATO - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.actf.ai.audio.io.impl;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Mixer;
+import javax.sound.sampled.TargetDataLine;
+
+import org.eclipse.actf.ai.audio.io.AudioIOException;
+import org.eclipse.actf.ai.audio.io.IAudioReader;
+
+
+
+
+public class RecordDevice implements IAudioReader {
+
+ private Mixer recordMixer;
+
+ private AudioFormat format;
+
+ private TargetDataLine recordLine;
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof RecordDevice) {
+ RecordDevice rd = (RecordDevice) o;
+ if (recordMixer.equals(rd.recordMixer)) {
+ return format.getChannels() == rd.format.getChannels()
+ && format.getFrameRate() == rd.format.getFrameRate()
+ && format.getSampleSizeInBits() == rd.format.getSampleSizeInBits();
+ }
+ }
+ return false;
+ }
+
+ public RecordDevice(Mixer mixer, int sampleRate, int channels) {
+ this.recordMixer = mixer;
+ format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sampleRate, 16, channels, 2 * channels, sampleRate,
+ false);
+ if (!recordMixer.isLineSupported(new DataLine.Info(TargetDataLine.class, format))) {
+ check(sampleRate, channels);
+ }
+ }
+
+ private void check(int sampleRate, int channels) {
+ AudioFormat temp;
+ int[] samples = new int[] { 48000, 44100, 22050, 16000, 8000 };
+
+ outer: for (int i = 0; i < samples.length; i++) {
+ if (samples[i] < sampleRate) {
+ temp = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, samples[i], 16, channels, 2 * channels,
+ samples[i], false);
+ if (recordMixer.isLineSupported(new DataLine.Info(TargetDataLine.class, temp))) {
+ format = temp;
+ break outer;
+ }
+ }
+ }
+ }
+
+ public String getName() {
+ return "Device \"" + recordMixer.getMixerInfo().getName() + //
+ " (" + (format.getFrameRate() / 1000) + " kHz, " + format.getChannels() + "ch)" + "\"";
+ }
+
+ public AudioFormat getAudioFormat() {
+ return format;
+ }
+
+ synchronized public void close() {
+ if (recordLine != null)
+ recordLine.close();
+ }
+
+ public boolean isClosed() {
+ return !recordLine.isOpen();
+ }
+
+ public boolean canRead(){
+ DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
+ return recordMixer.isLineSupported(info);
+ }
+
+ synchronized public void open() throws AudioIOException {
+ DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
+
+ try {
+ recordLine = (TargetDataLine) recordMixer.getLine(info);
+ recordLine.open(format);
+ recordLine.start();
+ } catch (LineUnavailableException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+
+ synchronized public int read(byte[] data, int offset, int length) throws AudioIOException {
+ return recordLine.read(data, offset, length);
+ }
+
+}