⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcmediaservice.java

📁 jtapi for telephone
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package net.sourceforge.gjtapi.media;

/*
	Copyright (c) 2002 8x8 Inc. (www.8x8.com) 

	All rights reserved. 

	Permission is hereby granted, free of charge, to any person obtaining a 
	copy of this software and associated documentation files (the 
	"Software"), to deal in the Software without restriction, including 
	without limitation the rights to use, copy, modify, merge, publish, 
	distribute, and/or sell copies of the Software, and to permit persons 
	to whom the Software is furnished to do so, provided that the above 
	copyright notice(s) and this permission notice appear in all copies of 
	the Software and that both the above copyright notice(s) and this 
	permission notice appear in supporting documentation. 

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 
	OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
	HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 
	INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 
	FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 
	NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
	WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 

	Except as contained in this notice, the name of a copyright holder 
	shall not be used in advertising or otherwise to promote the sale, use 
	or other dealings in this Software without prior written authorization 
	of the copyright holder.
*/
import javax.telephony.InvalidStateException;
import javax.telephony.ResourceUnavailableException;
import javax.telephony.Terminal;
import javax.telephony.media.*;
import javax.telephony.media.events.MediaTermConnStateEv;

import net.sourceforge.gjtapi.*;
import net.sourceforge.gjtapi.events.FreeCallEvent;
import java.util.*;
/**
 * This is a MediaService that wraps a 1.2-style MediaTerminalConnection's access to raw media services.
 * Most of these methods are not implemented, since we are really only interested in using this
 * Listener management and binding to resources.
 * <P>Wrapping a MediaTerminalConnection's access to a media terminal in a MediaService allows us to
 * register this MediaService with the MediaMgr as assigned to the terminal.  Then events back from
 * the RawProvider can be properly delegated off and handled.
 * <P>This is also responsible for tracking play and record threads as well as the media bind and
 * release and the thread that manages this.  Basically we delay "free" requests for X seconds such
 * we can catch a subsequent allocate and only release if the resource is not re-allocated in the
 * timeout period.
 * <P>Play and Record thread lazily created and triggered through a "notify()" semaphore signal.
 *
 * <P>The only methods that are implemented are:
 * <UL>
 * <li>send(MediaTermConnDtmfEv) called by TCListener to handle DTMF events
 * <li>getListeners()
 * </UL>
 * Creation date: (2000-05-09 15:53:37)
 * @author: Richard Deadman
 */
class TCMediaService implements MediaServiceHolder {

	/**
	 * This is an abstract private Runnable block used as a common parent for Play and Record threads.
	 * @author Richard Deadman
	 **/
	abstract class BaseMediaThread extends Thread {
		private GenericProvider prov;
		protected FreeMediaTerminalConnection tc;
		protected boolean runFlag = true;
		protected boolean playFlag = false;

		BaseMediaThread(GenericProvider gp, FreeMediaTerminalConnection termConn) {
			prov = gp;
			tc = termConn;
			this.setDaemon(true);
		}
	}

	/**
	 * This is a private Runnable block for running Play requests asynchronously
	 * @author Richard Deadman
	 **/
	private class PlayThread extends BaseMediaThread {
		private String[] streams = new String[1];
		
		PlayThread(GenericProvider gp, FreeMediaTerminalConnection termConn) {
			super(gp, termConn);
		}

		void playStream(String streamId) {
			streams[0] = streamId;
				// notify the running thread
			synchronized(playerThread) {
				playFlag = true;
				playerThread.notify();
			}
		}

		public void run() {
			while (runFlag) {
				synchronized(playerThread) {
					if (!playFlag) {
						try {
								// sleep until signalled
							playerThread.wait();
						} catch (InterruptedException ie) {
							runFlag = false;
							playerThread = null;
						}
					}
					playFlag = false;	
				}
				if (runFlag) {	// not interruped
					try {
						prov.getRaw().play(tc.getTerminal().getName(), streams, 0, null, null);
					} catch (MediaResourceException mre) {
						// should we throw an event
					}

					// notify that play has stopped
					playingStopped();
				}
			}
		}
	}

	/**
	 * This is a private Runnable block for running Record requests asynchronously
	 * @author Richard Deadman
	 **/
	private class RecordThread extends BaseMediaThread {
		private String recordId;
			
		RecordThread(GenericProvider gp, FreeMediaTerminalConnection termConn) {
			super(gp, termConn);
		}

		void recordStream(String streamId) {
			recordId = streamId;
				// notify the running thread
			synchronized(recorderThread) {
				playFlag = true;
				recorderThread.notify();
			}
		}

		public void run() {
			while (runFlag) {
				// sleep until signalled
				synchronized(recorderThread) {
					if (!playFlag) {
						try {
							recorderThread.wait();
						} catch (InterruptedException ie) {
							runFlag = false;
							recorderThread = null;
						}
					}
					playFlag = false;	
				}
				if (runFlag) {	// not interruped
					try {
						prov.getRaw().record(tc.getTerminal().getName(), recordId, null, null);
					} catch (MediaResourceException mre) {
						// should we throw an event
					}

					// notify that recording has stopped
					recordingStopped();
				}
			}
		}
	}

	/**
	 * This is a private Runnable block for running release requests asynchronously
	 * @author Richard Deadman
	 **/
	private class Reaper implements Runnable {
		int milliDelay;
		
		Reaper(int wait) {
			milliDelay = wait;
		}
		
		public void run() {
			// wait before releasing
			try {
				Thread.sleep(milliDelay);
			} catch (InterruptedException ie) {
				// well let's just continue then
			}

			reallyRelease();
		}
	}

		// define state media event
	class StateEv extends BaseMediaEv implements MediaTermConnStateEv {
		StateEv(FreeMediaTerminalConnection tc) {
			super(tc);
		}

		  /**
		   * Returns the current state of playing/recording on the TerminalConnection
		   * in the form of a bit mask.
		   * <p>
		   * @return The current playing/recording state.
		   */
	 	public int getMediaState() {
		 	return ((FreeMediaTerminalConnection)getTerminalConnection()).getMediaState();
	 	}
		 	
		public int getID() {
			return javax.telephony.media.events.MediaTermConnStateEv.ID;
		}
	}
	private final static int PLAY_REC = MediaTerminalConnection.PLAYING | MediaTerminalConnection.RECORDING;
	private final static int DTMF_DET = 0x04;
	public final static int ALLOCATED = 0;
	public final static int REAPING = 1;
	public final static int FREE = 2;
	private MediaMgr mgr = null;
	private GenericProvider prov = null;
	private FreeMediaTerminalConnection termConn = null;
	private Vector listeners = new Vector(1);	// a single listener, set in the constructor
	private PlayThread playerThread = null;
	private RecordThread recorderThread = null;
	private Thread garbageCollector = null;
	private int mediaState = MediaTerminalConnection.NOACTIVITY;
	private int allocateState = FREE;
	private int freeDelay = 2000;	// default is 2 seconds
/**
 * Create an instance of the MediaService for a 1.2 type of MediaTerminal.
 * Creation date: (2000-05-09 15:59:38)
 * @author: Richard Deadman
 * @param tc The terminalConnection the service is connected to.
 */
TCMediaService(FreeMediaTerminalConnection tc) {
	this(tc, -1);	// use default time
}
/**
 * Create an instance of the MediaService for a 1.2 type of MediaTerminal.
 * This hasn't been allocated yet.
 * Creation date: (2000-05-09 15:59:38)
 * @author: Richard Deadman
 * @param tc The terminalConnection the service is connected to.
 * @param deallocateDelay The time to delay a "free" request for, in milliseconds.
 */
TCMediaService(FreeMediaTerminalConnection tc, int deallocateDelay) {
	super();

	GenericProvider gp;
	this.setProv(gp = (GenericProvider)tc.getTerminal().getProvider());
	this.setMgr(gp.getMediaMgr());
	this.setTermConn(tc);
	this.listeners.add(new TCListener(this));	// the only addition ever
	if (deallocateDelay >= 0)
		this.setFreeDelay(deallocateDelay);

	// tell the media manager to bind us to the terminal as the event listener
	String termName = this.getTerminalName();
	this.getMgr().bind(termName, this);
}
/**
 * Add this state flag from the MediaState holder.
 * Creation date: (2000-05-15 13:09:53)
 * @author: Richard Deadman
 * @param newState The new state to add to the media statge holder.
 */
private void addMediaState(int newState) {
	if ((this.getPrivateMediaState() & newState) == 0) {
		this.mediaState |= newState;

		// do we need to notify any call listeners
		if ((newState & PLAY_REC) != 0) {
			((FreeCall)this.getTermConn().getConnection().getCall()).sendToObservers(new StateEv(this.getTermConn()));
		}
	}
}
/**
 * Make sure we are allocated.
 * Creation date: (2000-05-12 10:42:20)
 * @author: Richard Deadman
 */
private void allocate() {
	if (this.getAllocateState() != TCMediaService.ALLOCATED) {
		this.allocate(null, false);
	}
}
/**
 * Ask the system to allocate the required resources
 * Creation date: (2000-05-12 10:42:20)
 * @author: Richard Deadman
 * @param dict The resource parameters to pass down
 * @param force Force the allocation even if the RawProvider doesn't require null dictionary allocations.  This is useful to reset a resources dictionary to null.
 */
private void allocate(java.util.Dictionary dict, boolean force) {
		// ask raw provider to allocate new resources, if necessary
	GenericProvider prov = this.getProv();
	if (prov.getRawCapabilities().allocateMedia || dict != null || force) {
		prov.getRaw().allocateMedia(this.getTerminalName(), TelephonyProvider.MEDIA_RES_ALL, dict);
	}

	this.setAllocateState(TCMediaService.ALLOCATED);
}
/**
 * Forward a String of digits off to a DTMF signal generator.
 * @param digits The DTMF digits to play on the TerminalConnection
 * @exception InvalidStateException If the TerminalConnection is not ACTIVE
 * @exception ResourceUnavailableException If the raw provider threw an exception.
 */
public void generateDtmf(String digits) throws ResourceUnavailableException {
	// ensure we've allocated
	this.allocate();
	
	Terminal term = this.getTerminal();
	try {
		this.getProv().getRaw().sendSignals(this.getTerminalName(), SymbolConvertor.convert(digits), null, null);
	} catch (MediaResourceException mre) {
		throw new ResourceUnavailableException(ResourceUnavailableException.UNKNOWN);
	}
}
/**
 * Access the allocation state I'm in.  Allocated if an active media service, Reaping if in the process
 * of unbinding, and Free once unbound.
 * Creation date: (2000-05-11 15:06:28)
 * @author: Richard Deadman
 * @return ALLOCATED, REAPING or FREE
 */
private int getAllocateState() {
	return allocateState;
}
/**
 * Get the reaping delay.
 * Creation date: (2000-05-11 15:27:02)
 * @author: Richard Deadman

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -