PageRenderTime 27ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/media/core/server-impl/src/main/java/org/mobicents/media/server/impl/dsp/Processor.java

http://mobicents.googlecode.com/
Java | 486 lines | 283 code | 64 blank | 139 comment | 67 complexity | 26973ff580833cbd2f0221e327a67ec8 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright XXXX, Red Hat Middleware LLC, and individual contributors as indicated
  4. * by the @authors tag. All rights reserved.
  5. * See the copyright.txt in the distribution for a full listing
  6. * of individual contributors.
  7. * This copyrighted material is made available to anyone wishing to use,
  8. * modify, copy, or redistribute it subject to the terms and conditions
  9. * of the GNU General Public License, v. 2.0.
  10. * This program is distributed in the hope that it will be useful, but WITHOUT A
  11. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  12. * PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. * You should have received a copy of the GNU General Public License,
  14. * v. 2.0 along with this distribution; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  16. * MA 02110-1301, USA.
  17. */
  18. package org.mobicents.media.server.impl.dsp;
  19. import java.io.IOException;
  20. import java.util.ArrayList;
  21. import java.util.Collection;
  22. import org.mobicents.media.Buffer;
  23. import org.mobicents.media.Format;
  24. import org.mobicents.media.MediaSink;
  25. import org.mobicents.media.MediaSource;
  26. import org.mobicents.media.server.impl.AbstractSink;
  27. import org.mobicents.media.server.impl.AbstractSource;
  28. import org.mobicents.media.server.impl.BaseComponent;
  29. import org.mobicents.media.server.spi.dsp.Codec;
  30. import org.mobicents.media.server.spi.dsp.SignalingProcessor;
  31. /**
  32. * Implements DSP features.
  33. *
  34. * Processor has input and output and is used to perform required
  35. * transcoding if needed for packets followed from source to consumer.
  36. * Processor is transparent for packets with format acceptable by consumer
  37. * by default.
  38. *
  39. * @author Oleg Kulikov
  40. */
  41. public class Processor extends BaseComponent implements SignalingProcessor {
  42. private Input input;
  43. private Output output;
  44. private transient ArrayList<Codec> codecs = new ArrayList();
  45. private Codec codec;
  46. private Buffer buff;
  47. private long timestamp;
  48. public Processor(String name) {
  49. super(name);
  50. input = new Input(name);
  51. output = new Output(name);
  52. }
  53. protected void add(Codec codec) {
  54. codecs.add(codec);
  55. }
  56. public Codec getActiveCodec() {
  57. return codec;
  58. }
  59. /**
  60. * Gets the input for original media
  61. *
  62. * @return media handler for input media.
  63. */
  64. public MediaSink getInput() {
  65. return input;
  66. }
  67. /**
  68. * Gets the output stream with transcoded media.
  69. *
  70. * @return media stream.
  71. */
  72. public MediaSource getOutput() {
  73. return output;
  74. }
  75. public void connect(MediaSource source) {
  76. input.connect(source);
  77. }
  78. public void disconnect(MediaSource source) {
  79. input.disconnect(source);
  80. }
  81. public void connect(MediaSink sink) {
  82. output.connect(sink);
  83. }
  84. public void disconnect(MediaSink sink) {
  85. output.disconnect(sink);
  86. }
  87. /**
  88. * (Non Java-doc).
  89. *
  90. * @see org.mobicents.media.Component#start()
  91. */
  92. public void start() {
  93. //start input and output channel
  94. if (!input.isStarted()) {
  95. input.start();
  96. }
  97. }
  98. /**
  99. * (Non Java-doc).
  100. *
  101. * @see org.mobicents.media.Component#stop()
  102. */
  103. public void stop() {
  104. if (input.isStarted()) {
  105. input.stop();
  106. }
  107. }
  108. private boolean contains(Format[] list, int count, Format item) {
  109. for (int i = 0; i < count; i++) {
  110. if (list[i].matches(item)) {
  111. return true;
  112. }
  113. }
  114. return false;
  115. }
  116. /**
  117. * Implements input of the processor.
  118. */
  119. private class Input extends AbstractSink {
  120. private volatile boolean started = false;
  121. public Input(String name) {
  122. super(name + ".input");
  123. }
  124. @Override
  125. public Format selectPreffered(Collection<Format> set) {
  126. if (set == null) {
  127. codec = null;
  128. return null;
  129. }
  130. //input and output should be connected to termine preffred format
  131. if (!output.isConnected()) {
  132. return null;
  133. }
  134. Format outFormat = output.getFormat();
  135. //the next case when output is connected but format is not selected yet
  136. //in this case format will be choosen later
  137. if (outFormat == null) {
  138. return null;
  139. }
  140. //possible that output format is presented in suggesed set
  141. for (Format f : set) {
  142. if (f.matches(outFormat)) {
  143. return f;
  144. }
  145. }
  146. //transcoding required. we need select codec.
  147. codec = null;
  148. for (Codec c : codecs) {
  149. if (c.getSupportedOutputFormat().matches(outFormat)) {
  150. for (Format f: set) {
  151. if (c.getSupportedInputFormat().matches(f)) {
  152. codec = c;
  153. return f;
  154. }
  155. }
  156. }
  157. }
  158. return null;
  159. }
  160. @Override
  161. public boolean isStarted() {
  162. return this.started;
  163. }
  164. @Override
  165. public void start() {
  166. this.started = true;
  167. if (!output.isStarted()) {
  168. output.start();
  169. }
  170. if (otherParty != null && !otherParty.isStarted()) {
  171. otherParty.start();
  172. }
  173. }
  174. @Override
  175. public void stop() {
  176. this.started = false;
  177. if (output.isStarted()) {
  178. output.stop();
  179. }
  180. if (otherParty != null && otherParty.isStarted()) {
  181. otherParty.stop();
  182. }
  183. }
  184. /**
  185. * (Non Java-doc.)
  186. *
  187. * @see org.mobicents.media.server.impl.AbstractSink#onMediaTransfer(org.mobicents.media.Buffer)
  188. */
  189. public void onMediaTransfer(Buffer buffer) throws IOException {
  190. timestamp = buffer.getTimeStamp();
  191. output.transmit(buffer);
  192. }
  193. /**
  194. * Gets list of formats supported by connected other party
  195. *
  196. * @return the array of format objects.
  197. */
  198. protected Format[] getOtherPartyFormats() {
  199. return otherParty != null ? otherParty.getFormats() : new Format[0];
  200. }
  201. /**
  202. * (Non Java-doc.)
  203. *
  204. * @see org.mobicents.media.MediaSink#getFormats()
  205. */
  206. public Format[] getFormats() {
  207. //if output is not connected then format can be ANY
  208. if (!output.isConnected()) {
  209. return new Format[]{Format.ANY};
  210. }
  211. //Formats supported by component connected on output
  212. //if preffered format is already know we are using it
  213. Format[] formats = output.getFormat() != null ?
  214. new Format[]{output.getFormat()} :
  215. output.getOtherPartyFormats();
  216. //Case #1. The component connected on output supports format ANY.
  217. //In this case the input of this processor also should return ANY also.
  218. if (formats.length == 1 && formats[0] == Format.ANY) {
  219. return new Format[]{Format.ANY};
  220. }
  221. //Case #2. The componentconnected to output supports set of concrete formats.
  222. //In this case the input is same set of formats plus possible transcodings.
  223. Format[] extended = new Format[20];
  224. int count = 0;
  225. for (Format f : formats) {
  226. //copy original format first
  227. extended[count++] = f;
  228. //search transcodings
  229. for (Codec codec : codecs) {
  230. //add formats which are results of transcoding if such formats
  231. //are not in the list yet
  232. if (codec.getSupportedOutputFormat().matches(f) &&
  233. !contains(extended, count, codec.getSupportedInputFormat())) {
  234. extended[count++] = codec.getSupportedInputFormat();
  235. }
  236. }
  237. }
  238. //resize array
  239. Format[] res = new Format[count];
  240. System.arraycopy(extended, 0, res, 0, count);
  241. return res;
  242. }
  243. @Override
  244. public String toString() {
  245. return "Processor.Input[" + getName() + "]";
  246. }
  247. public long getTimestamp() {
  248. return timestamp;
  249. }
  250. }
  251. /**
  252. * Implements output of the processor.
  253. */
  254. private class Output extends AbstractSource {
  255. private volatile boolean started = false;
  256. /**
  257. * Creates new instance of processor's output.
  258. *
  259. * @param name - the name of the processor;
  260. */
  261. public Output(String name) {
  262. super(name + ".output");
  263. }
  264. /**
  265. * Gets list of formats supported by connected other party
  266. *
  267. * @return the array of format objects.
  268. */
  269. protected Format[] getOtherPartyFormats() {
  270. return otherParty != null ? otherParty.getFormats() : new Format[0];
  271. }
  272. @Override
  273. public boolean isStarted() {
  274. return this.started;
  275. }
  276. @Override
  277. public void start() {
  278. this.started = true;
  279. if (!input.isStarted()) {
  280. input.start();
  281. }
  282. if (otherParty != null && !otherParty.isStarted()) {
  283. otherParty.start();
  284. }
  285. }
  286. @Override
  287. public void stop() {
  288. this.started = false;
  289. if (input.isStarted()) {
  290. input.stop();
  291. }
  292. if (otherParty != null && otherParty.isStarted()) {
  293. otherParty.stop();
  294. }
  295. }
  296. /**
  297. * Asks the sink connected to this channel to determine preffred format
  298. *
  299. * @param set the set of format to choose preffred from
  300. * @return the selected preffred format
  301. */
  302. public Format getOtherPartyPreffered(Collection<Format> set) {
  303. return ((AbstractSink)otherParty).getPreffered(set);
  304. }
  305. @Override
  306. public void setPreffered(Format fmt) {
  307. super.setPreffered(fmt);
  308. //if input is connected we have to update its soource
  309. if (!input.isConnected()) {
  310. return;
  311. }
  312. //if selected format matches to one input format we have to chose it as preffred
  313. Format[] supported = input.getOtherPartyFormats();
  314. for (Format f : supported) {
  315. if (f.matches(fmt)) {
  316. input.assignPreffered(fmt);
  317. return;
  318. }
  319. }
  320. //at this point we have to select codec
  321. for (Codec c: codecs) {
  322. if (c.getSupportedOutputFormat().matches(fmt)) {
  323. for (Format f : supported) {
  324. if (f.matches(c.getSupportedInputFormat())) {
  325. System.out.println("Assigned codec=" + codec);
  326. codec = c;
  327. input.assignPreffered(f);
  328. return;
  329. }
  330. }
  331. }
  332. }
  333. codec = null;
  334. }
  335. /**
  336. * (Non Java-doc.)
  337. *
  338. * @see org.mobicents.media.MediaSource#getFormats()
  339. */
  340. public Format[] getFormats() {
  341. //if input is not connected then format can be ANY
  342. if (!input.isConnected()) {
  343. return new Format[]{Format.ANY};
  344. }
  345. //Formats supported by component connected on input
  346. //if preffered format is already know we are using it
  347. Format[] formats = input.getFormat() != null ?
  348. new Format[]{input.getFormat()} :
  349. input.getOtherPartyFormats();
  350. //Case #1. The component connected on input supports format ANY.
  351. //In this case the output of this processor also should return ANY also.
  352. if (formats.length == 1 && formats[0] == Format.ANY) {
  353. return new Format[]{Format.ANY};
  354. }
  355. //Case #2. The componentconnected to input supports set of concrete formats.
  356. //In this case the output is same set of formats plus possible transcodings.
  357. Format[] extended = new Format[20];
  358. int count = 0;
  359. for (Format f : formats) {
  360. //copy original format first
  361. extended[count++] = f;
  362. //search transcodings
  363. for (Codec codec : codecs) {
  364. //add formats which are results of transcoding if such formats
  365. //are not in the list yet
  366. if (codec.getSupportedInputFormat().matches(f) &&
  367. !contains(extended, count, codec.getSupportedOutputFormat())) {
  368. extended[count++] = codec.getSupportedOutputFormat();
  369. }
  370. }
  371. }
  372. //resize array
  373. Format[] res = new Format[count];
  374. System.arraycopy(extended, 0, res, 0, count);
  375. return res;
  376. }
  377. /**
  378. * Transmits buffer to the output handler.
  379. *
  380. * @param buffer the buffer to transmit
  381. */
  382. protected void transmit(Buffer buffer) {
  383. if (!started) {
  384. buffer.dispose();
  385. return;
  386. }
  387. //Here we work in ReceiveStream.run method, which runs in local ReceiveStreamTimer
  388. // Discard packet silently if output handler is not assigned yet
  389. if (otherParty == null) {
  390. buffer.dispose();
  391. return;
  392. }
  393. if (codec != null) {
  394. codec.process(buffer);
  395. }
  396. // Codec can delay media transition if it has not enouph media
  397. // to perform its job.
  398. // It means that Processor should check FLAGS after codec's
  399. // work and discard packet if required
  400. if (buffer.getFlags() == Buffer.FLAG_DISCARD) {
  401. buffer.dispose();
  402. return;
  403. }
  404. //may be a situation when original format can not be trancoded to
  405. //one of the required output. In this case codec map will have no
  406. //entry for this format. also codec may has no entry in case of when
  407. //transcoding is not required. to differentiate these two cases check
  408. //if this format is acceptable by the consumer.
  409. //deliver packet to the consumer
  410. buff = buffer;
  411. perform();
  412. }
  413. @Override
  414. public void evolve(Buffer buffer, long timestamp) {
  415. buffer.copy(buff);
  416. }
  417. @Override
  418. public String toString() {
  419. return "Processor.Output[" + getName() + "]";
  420. }
  421. }
  422. }