PageRenderTime 67ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Assignment6/myStreamPublisherClient/src/applicationCode.as

https://github.com/nepa/KMA-Lab
ActionScript | 583 lines | 213 code | 75 blank | 295 comment | 34 complexity | 9bb16fe55946dc020e7520520fe072a6 MD5 | raw file
  1. /**
  2. * /////////////////////////////////////////////////////////////////////////////////////////
  3. *
  4. * Important usage information:
  5. *
  6. * The flash user controls are a bit difficult to handle at runtime. If you hit
  7. * the play button once, playback will start after some time. Hitting the pause
  8. * or toggle pause button then, will result in slowly stopping the movie. That
  9. * means playback will continue for a couple of seconds (but pause internally).
  10. *
  11. * Pressing the resume or toggle pause button again, will then make the movie
  12. * go back a couple of frames (where you pressed pause initially) and resume
  13. * playback from there. So everything works as expected, except for the fact
  14. * that the visual playback does not stopp instantly. So there is always some
  15. * delay if you hit one of the buttons. - Keep this in mind.
  16. *
  17. * Furthermore playback speed increases after pausing, due to some buffering issues.
  18. *
  19. * /////////////////////////////////////////////////////////////////////////////////////////
  20. */
  21. package
  22. {
  23. // Imports
  24. import flash.events.MouseEvent;
  25. import flash.events.NetStatusEvent;
  26. import flash.media.Video;
  27. import flash.net.NetConnection;
  28. import flash.net.NetStream;
  29. import flash.display.*;
  30. // Own imports
  31. import flash.display.Sprite;
  32. import flash.text.TextField;
  33. // We cannot use MX extensions on Linux
  34. // import mx.controls.Alert;
  35. // import mx.core.UIComponent;
  36. // import mx.events.FlexEvent;
  37. public class applicationCode extends Sprite
  38. {
  39. /**
  40. * Communication Systems for Multimedia Applications Exercises (KMA2011)
  41. * Exercise 6
  42. * Summer Term 2011
  43. *
  44. * Bashar Altakrouri | Ambient Computing Group | Institute of Telematics | University of Luebeck | www.itm.uni-luebeck.de | altakrouri@itm.uni-luebeck.de
  45. *
  46. * OVERVIEW
  47. * The aim of this exercise is to be familiar with the basic streaming for recorded videos via flex and red5 applications.
  48. * This is a full client/server example to illustrate the follow
  49. * - Server side streaming of locally stored video files on the server.
  50. * - Client side to play streams broadcasted by the server.
  51. * - Network and playback events and listeners
  52. * - Flex GUI controls
  53. *
  54. * TODO
  55. * 1. Follow the instructions below and complete the exercise
  56. * 2. Complete and run both Flex and Red5 projects
  57. *
  58. * Hint:
  59. * - Read the sections marked: !!! LAB EXERCISE !!!
  60. * - Complete the sections marked: *** YOUR CODE HERE ***
  61. * - Have fun!
  62. *
  63. * Note: This project is intentionally incomplete and should be finished by the student.
  64. * To help guide your work, this project includes a partial structure along with
  65. * embedded comments, hints and links. An accompanying in-class presentation
  66. * will provide the background information and instructions necessary to
  67. * complete this exercise.
  68. *
  69. * REFERENCES
  70. * - AS3 GUI controls: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/fl/controls/package-detail.html
  71. * - AS3 reference: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/package-summary.html
  72. */
  73. /**
  74. ************************************* !!! LAB EXERCISE !!! *************************************
  75. * This exercise consists of three parts:
  76. * 1. be familiar with red5 applications
  77. * 1.1. start/stop red5 server.
  78. * 1.2. deploy and run red5 applications
  79. * 1.3. debug red5 messages via the Console
  80. * 1.4. file structure for red5 applications
  81. * 1.5. basic configuration and property files for red5 applications "WEB-INF" contents
  82. *
  83. * 2. be familiar with simple flex applications
  84. * 2.1. file structure for flex applications i.e. ".as" and ".mxml"
  85. * 2.2. deploy flex applications
  86. *
  87. * 3. complete the exercise following the comments and hints to
  88. *
  89. * **(On the server-side/red5 application - "myStreamPublisher")**
  90. * 3.1. review the "myStreamPublisher" application basic file and class strcture.
  91. * 3.2. create a folder called "streams" under "WebContent" and add the sample ".flv" video files to the "streams" folder.
  92. * - Hints:
  93. * - The name of the video files will assemble the names of the streams broadcasted by the server.
  94. *
  95. * **(On the client-side/flex application - "myStreamPublisherClient")**
  96. * 3.3. complete "onCreationComplete" method.
  97. * 3.4. complete all call back methods as follows:
  98. * - complete the "onConnectionNetStatus" method to alert the user with network status
  99. * - complete the "onClickPlayBtn", "onClickPauseBtn", "onClickResumeBtn", and "onClickTogglePauseBtn" methods
  100. * 3.5. complete the "setupVideo" method to setup the stage to play the incomming streams from the server
  101. * 3.6. complete the "ns_onMetaData' method
  102. *
  103. * 4. Homework: Create your interactive TV streaming channel by using your gained knowledge from exercises "5" and "6", as follow:
  104. * - your application is a simple platform to view video streams and share live comments about them.
  105. * - build a new red5 project called "shareMyVideoView" and flex client called "shareMyVideoViewClient"
  106. * - the user can connect and disconnect to the streaming server at any time
  107. * - allow the user to choose and play any of 3 video streams
  108. * - Allow basic user functionality i.e. clearing the comment section, play, pause and close video stream
  109. * - the user can send share live comments about the played stream with other viewers
  110. * - Messages are seen by all connected users.
  111. * - categorize the comments based on the stream using color-coding.
  112. * - the user can set his/her name
  113. * - present the viewer information about the played stream i.e. duration, framerate, hight, with, video codec, and video data rate.
  114. * - make sure you have the right GUI "graphical user interface" for your client application
  115. * - feel free to add any important / cool feature
  116. *
  117. * */
  118. // network properties
  119. private var connection: NetConnection;
  120. private var inStream: NetStream;
  121. private var videoURL: String = "KMA_sample_video2.flv"; // Video name with or without extension (if *.flv)
  122. // device properties
  123. // video properties
  124. private var inVideo: Video;
  125. // wrapper flex components
  126. // you cannot add video directly to flex ui you have to have a wrapper
  127. // private var inVideoWrapper: UIComponent;
  128. public function applicationCode()
  129. {
  130. // ===================================================================================
  131. // *** YOUR CODE HERE ***
  132. var tf:TextField = new TextField();
  133. tf.text = "Constructor of applicationCode was called.";
  134. tf.width = 400;
  135. addChild(tf);
  136. onCreationComplete();
  137. // ===================================================================================
  138. }
  139. /*
  140. Called right after loading the flash container on the page. This is the first method to be called.
  141. Here goes all the instantiations and configurations of your client
  142. */
  143. public function onCreationComplete() : void {
  144. /* -----------------------------------------------------------------------------------
  145. * !!! LAB EXERCISE !!!
  146. * ------------------------------------------------------------------------------------
  147. * TODO 3.3:
  148. * - establish the connection with the server-side application "myStreamPublisher" using the RTMP protocol
  149. * - add an event listner to listen to all NetStatusEvents
  150. * - review the "myStreamPublisherClient.mxml". You are provided with a number of play control buttons but you can
  151. * have your own if you like.
  152. * - add event listners to your play control buttons (play, pause, resume, and togglePause)
  153. * Hints:
  154. * - to add event listener use "addEventListener" method. You will need "MouseEvent.CLICK" and "NetStatusEvent.NET_STATUS"
  155. * - you have been provided with 4 button callback methods called onClickPlayBtn, onClickPauseBtn, onClickResumeBtn,
  156. * and onClickTogglePauseBtn
  157. */
  158. // ===================================================================================
  159. // *** YOUR CODE HERE ***
  160. var tf:TextField = new TextField();
  161. tf.text = "Event onCreationComplete was called.";
  162. tf.width = 400;
  163. tf.y = 10;
  164. addChild(tf);
  165. // Establish the connection with the server-side application (using the RTMP protocol)
  166. connection = new NetConnection();
  167. connection.connect("rtmp://localhost/Assignment6");
  168. connection.client = this;
  169. connection.addEventListener(NetStatusEvent.NET_STATUS, onConnectionNetStatus);
  170. // Create user interface
  171. drawPlayButton();
  172. drawPauseButton();
  173. drawResumeButton();
  174. drawTogglePauseButton();
  175. // ===================================================================================
  176. }
  177. //callback method for network status events
  178. public function onConnectionNetStatus(event:NetStatusEvent) : void {
  179. /* -----------------------------------------------------------------------------------
  180. * !!! LAB EXERCISE !!!
  181. * ------------------------------------------------------------------------------------
  182. * TODO 3.4: complete "onConnectionNetStatus" method
  183. * - Alert the user on successful conection or unsuccessful connection
  184. * - on successfull connection call the "setupVideo()" method.
  185. * - add a streaming status label to your interface to show the current playing status of the stream
  186. * (video playing, paused, resumed, and stream not found)
  187. * - add a general network status label to show the latest network event status to the user at all times.
  188. * Hints:
  189. * - use Alert.show("your message", "Information");
  190. * - a successful connection will have the following code "NetConnection.Connect.Success"
  191. * - network status code is returned in event.info.code object
  192. * - for playing and pauseing status review the "code property", see the following reference
  193. * - reference: http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/events/NetStatusEvent.html#info
  194. */
  195. // ===================================================================================
  196. // *** YOUR CODE HERE ***
  197. // Connection status
  198. var conStatusLabel:TextField = new TextField();
  199. conStatusLabel.width = 400;
  200. conStatusLabel.y = 20;
  201. addChild(conStatusLabel);
  202. if (event.info.code == "NetConnection.Connect.Success")
  203. {
  204. conStatusLabel.text = "Successful connection.";
  205. setupVideo(); // Setup video on successful connection
  206. }
  207. else if (event.info.code == "NetConnection.Connect.Failed")
  208. {
  209. conStatusLabel.text = "Unsuccessful connection.";
  210. }
  211. // Streaming status
  212. var strStatusLabel:TextField = new TextField();
  213. if (event.info.code == "NetStream.Play.Start")
  214. {
  215. strStatusLabel.text = "Playback has started.";
  216. }
  217. else if (event.info.code == "NetStream.Play.Stop")
  218. {
  219. strStatusLabel.text = "Playback has stopped.";
  220. }
  221. else if (event.info.code == "NetStream.Play.Failed")
  222. {
  223. strStatusLabel.text = "Playback failed.";
  224. }
  225. else if (event.info.code == "NetStream.Play.StreamNotFound")
  226. {
  227. strStatusLabel.text = "Stream could not be found.";
  228. }
  229. else if (event.info.code == "NetStream.Pause.Notify")
  230. {
  231. strStatusLabel.text = "Stream is paused.";
  232. }
  233. else if (event.info.code == "NetStream.Unpause.Notify")
  234. {
  235. strStatusLabel.text = "Stream is resumed.";
  236. }
  237. strStatusLabel.width = 400;
  238. strStatusLabel.y = 30;
  239. addChild(strStatusLabel);
  240. // General network connection status
  241. var genStatusLabel:TextField = new TextField();
  242. if (event.info.code == "NetConnection.Connect.Success")
  243. {
  244. genStatusLabel.text = "Connection opened."
  245. }
  246. else if (event.info.code == "NetConnection.Connect.Failed")
  247. {
  248. genStatusLabel.text = "Connection failed.";
  249. }
  250. else if (event.info.code == "NetConnection.Connect.Rejected")
  251. {
  252. genStatusLabel.text = "Connection rejected.";
  253. }
  254. else if (event.info.code == "NetConnection.Connect.Closed")
  255. {
  256. genStatusLabel.text = "Connection closed.";
  257. }
  258. genStatusLabel.width = 400;
  259. genStatusLabel.y = 40;
  260. addChild(genStatusLabel);
  261. // ===================================================================================
  262. }
  263. // "setupVideo" method to setup the stage to play the incomming streams from the server
  264. private function setupVideo():void{
  265. /* -----------------------------------------------------------------------------------
  266. * !!! LAB EXERCISE !!!
  267. * ------------------------------------------------------------------------------------
  268. * TODO 3.5: complete "setupVideo" method
  269. * - setup the input stream "inStream" using NetStream(connection)
  270. * - add an event listener to the "inStream"
  271. * - setup the incommping video "inVideo" using Video()
  272. * - attach the stream to the video using the "attachNetStream" method
  273. * - add the video as a child to the UIComponent "inVideoWrapper" by initialising
  274. * the "inVideoWrapper" using "UIComponent()"
  275. * then attach the video as a child, then add the wapper to the interface stage using
  276. * "this.addElement()" method
  277. */
  278. // ===================================================================================
  279. // *** YOUR CODE HERE ***
  280. var tf:TextField = new TextField();
  281. tf.text = "Method setupVideo was called.";
  282. tf.width = 400;
  283. tf.y = 80;
  284. addChild(tf);
  285. inStream = new NetStream(connection);
  286. inStream.addEventListener(NetStatusEvent.NET_STATUS, onConnectionNetStatus);
  287. inVideo = new Video();
  288. inVideo.attachNetStream(inStream);
  289. this.addChild(inVideo); // No video container here, we add to Sprite directly
  290. // ===================================================================================
  291. }
  292. // UI controls listeners
  293. // call this method on Play button click
  294. private function onClickPlayBtn(event:MouseEvent):void
  295. {
  296. /* -----------------------------------------------------------------------------------
  297. * !!! LAB EXERCISE !!!
  298. * ------------------------------------------------------------------------------------
  299. * TODO 3.4: complete "onClickPlayBtn" method
  300. * - set "inStream" buffer time
  301. * - play the sample stream in the "streams" folder in your servier-side application
  302. * Hints:
  303. * - when you play a live or recorded stream, you must set a buffer time for the stream to play correctly.
  304. * The buffer time must be at least .1 seconds, but it can be higher. Add the following line to your code
  305. * (ns is the name of the NetStream object)
  306. * - review closely the bufferTime property, mainly the differences between the recorded and live streaming buffers.
  307. * - "bufferTime" property specifies how long to buffer messages before starting to display the stream. 0.1 is the
  308. * default value. To play a server-side playlist, set bufferTime to at least 1 second. If you experience playback
  309. * issues, increase the length of bufferTime. Recorded content To avoid distortion when streaming pre-recorded
  310. * (not live) content, do not set the value of Netstream.bufferTime to 0.1
  311. * - to play video files on Flash Media Server, specify the name of the stream without a file extension
  312. * (for example, bolero). To play MP3 files, use mp3: before the stream name. To play the ID3 tags of MP3
  313. * files, use id3: before the stream name.
  314. * - review play(), close(), pause(), and resume() "NetStream" methods
  315. * - to play and resume video smoothly on red5, you might need to test with different buffer time to
  316. * optain best results. Try (0, 0.1, 5, and 30) and find out what is best?
  317. */
  318. // ===================================================================================
  319. // *** YOUR CODE HERE ***
  320. inStream.bufferTime = 30; // set stream buffer to 30 seconds
  321. inStream.play(videoURL);
  322. // Call event handler, if metadata is sent on stream
  323. inStream.client = {};
  324. inStream.client.onMetaData = ns_onMetaData;
  325. // ===================================================================================
  326. }
  327. // call this method on Pause button click
  328. private function onClickPauseBtn(event:MouseEvent):void
  329. {
  330. /* -----------------------------------------------------------------------------------
  331. * !!! LAB EXERCISE !!!
  332. * ------------------------------------------------------------------------------------
  333. * TODO 3.4: complete "onClickPauseBtn" method
  334. * - pause the incomming stream
  335. * Hints:
  336. * - Calling the pausing method does nothing if the video is already paused.
  337. */
  338. // ===================================================================================
  339. // *** YOUR CODE HERE ***
  340. inStream.pause();
  341. // ===================================================================================
  342. }
  343. // call this method on Resume button click
  344. private function onClickResumeBtn(event:MouseEvent):void
  345. {
  346. /* -----------------------------------------------------------------------------------
  347. * !!! LAB EXERCISE !!!
  348. * ------------------------------------------------------------------------------------
  349. * TODO 3.4: complete "onClickResumeBtn" method
  350. * - resume the incomming stream
  351. * Hints:
  352. * - Calling the resume method if the video is already playing, calling this method does nothing.
  353. */
  354. // ===================================================================================
  355. // *** YOUR CODE HERE ***
  356. inStream.resume();
  357. // ===================================================================================
  358. }
  359. // call this method on TogglePause button click
  360. private function onClickTogglePauseBtn(event:MouseEvent):void
  361. {
  362. /* -----------------------------------------------------------------------------------
  363. * !!! LAB EXERCISE !!!
  364. * ------------------------------------------------------------------------------------
  365. * TODO 3.4: complete "onClickTogglePauseBtn" method
  366. * - resume/pause the incomming stream
  367. * Hints:
  368. * - Use "togglePause" method
  369. * - The first time you call this method, it pauses play; the next time, it resumes play.
  370. * You could use this method to let users pause or resume playback by pressing a single button.
  371. */
  372. // ===================================================================================
  373. // *** YOUR CODE HERE ***
  374. inStream.togglePause();
  375. // ===================================================================================
  376. }
  377. /*Establishes a listener to respond when Flash Player receives descriptive information embedded in the video being played.
  378. For information about video file formats supported by Flash Media Server, see the www.adobe.com/go/learn_fms_fileformats_en.
  379. onMetaData is actually a property of the NetStream.client object. The property is listed in the Events section because it
  380. responds to a data event, either when streaming media using Flash Media Server or during FLV file playback. For more
  381. information, see the NetStream class description and the NetStream.client property. You cannot use the addEventListener()
  382. method, or any other EventDispatcher methods, to listen for or process onMetaData as an event. Define a single callback
  383. function and attach it to one of the following objects:
  384. The object that the client property of a NetStream instance references.
  385. An instance of a NetStream subclass. NetStream is a sealed class, which means that properties or methods cannot be added
  386. to a NetStream object at runtime. You can create a subclass of NetStream and define your event handler in the subclass.
  387. You can also make the subclass dynamic and add the event handler function to an instance of the subclass.
  388. */
  389. private function ns_onMetaData(item:Object):void {
  390. /* -----------------------------------------------------------------------------------
  391. * !!! LAB EXERCISE !!!
  392. * ------------------------------------------------------------------------------------
  393. * TODO 3.6: complete "ns_onMetaData" method.
  394. * - resize the video control based on the stream video size
  395. * - center the video instance of the the stage.
  396. * - create info panel to display all relevent information about the played stream to the user
  397. * i.e. duration, framerate, hight, with, video codec, and video data rate.
  398. * Hints:
  399. * - review http://livedocs.adobe.com/flex/3/html/help.html?content=Working_with_Video_17.html
  400. * - you will need to use the "stage" specially both properties "stageWidth" and "stageHeight"
  401. */
  402. // ===================================================================================
  403. // *** YOUR CODE HERE ***
  404. // Resize video to fit metadata from info object (item)
  405. inVideo.width = item["width"];
  406. inVideo.height = item["height"];
  407. // Center video control on user interface
  408. inVideo.x = this.x / 2;
  409. inVideo.y = this.y / 2;
  410. // Build string out of metadata
  411. var metaDataString:String;
  412. var key:String;
  413. for (key in item)
  414. {
  415. metaDataString += key + ": " + item[key] + ", ";
  416. }
  417. var tf:TextField = new TextField();
  418. tf.text = metaDataString;
  419. tf.width = 400;
  420. tf.height = 30; // Cannot press buttons below otherwise!!!
  421. tf.y = 270; // Display string below video
  422. addChild(tf);
  423. // ===================================================================================
  424. }
  425. // Helper method to draw play button
  426. private function drawPlayButton():void {
  427. var textLabel:TextField = new TextField();
  428. var button:Sprite = new Sprite();
  429. // Draw button
  430. button.graphics.clear();
  431. button.graphics.beginFill(0xD4D4D4); // grey color
  432. button.graphics.drawRoundRect(0, 320, 80, 25, 10, 10); // x, y, width, height, ellipseW, ellipseH
  433. button.graphics.endFill();
  434. // Create label
  435. textLabel.text = "Play";
  436. textLabel.x = 10;
  437. textLabel.y = 320;
  438. textLabel.selectable = false;
  439. // Add label to button and button to Sprite
  440. button.addChild(textLabel);
  441. addChild(button);
  442. // Add listener for click event
  443. button.addEventListener(MouseEvent.MOUSE_DOWN, onClickPlayBtn);
  444. }
  445. // Helper method to draw pause button
  446. private function drawPauseButton():void {
  447. var textLabel:TextField = new TextField();
  448. var button:Sprite = new Sprite();
  449. // Draw button
  450. button.graphics.clear();
  451. button.graphics.beginFill(0xD4D4D4); // grey color
  452. button.graphics.drawRoundRect(100, 320, 80, 25, 10, 10); // x, y, width, height, ellipseW, ellipseH
  453. button.graphics.endFill();
  454. // Create label
  455. textLabel.text = "Pause";
  456. textLabel.x = 110;
  457. textLabel.y = 320;
  458. textLabel.selectable = false;
  459. // Add label to button and button to Sprite
  460. button.addChild(textLabel);
  461. addChild(button);
  462. // Add listener for click event
  463. button.addEventListener(MouseEvent.MOUSE_DOWN, onClickPauseBtn);
  464. }
  465. // Helper method to draw resume button
  466. private function drawResumeButton():void {
  467. var textLabel:TextField = new TextField();
  468. var button:Sprite = new Sprite();
  469. // Draw button
  470. button.graphics.clear();
  471. button.graphics.beginFill(0xD4D4D4); // grey color
  472. button.graphics.drawRoundRect(200, 320, 80, 25, 10, 10); // x, y, width, height, ellipseW, ellipseH
  473. button.graphics.endFill();
  474. // Create label
  475. textLabel.text = "Resume";
  476. textLabel.x = 210;
  477. textLabel.y = 320;
  478. textLabel.selectable = false;
  479. // Add label to button and button to Sprite
  480. button.addChild(textLabel);
  481. addChild(button);
  482. // Add listener for click event
  483. button.addEventListener(MouseEvent.MOUSE_DOWN, onClickResumeBtn);
  484. }
  485. // Helper method to draw toggle pause button
  486. private function drawTogglePauseButton():void {
  487. var textLabel:TextField = new TextField();
  488. var button:Sprite = new Sprite();
  489. // Draw button
  490. button.graphics.clear();
  491. button.graphics.beginFill(0xD4D4D4); // grey color
  492. button.graphics.drawRoundRect(300, 320, 80, 25, 10, 10); // x, y, width, height, ellipseW, ellipseH
  493. button.graphics.endFill();
  494. // Create label
  495. textLabel.text = "Toggle pause";
  496. textLabel.x = 310;
  497. textLabel.y = 320;
  498. textLabel.selectable = false;
  499. // Add label to button and button to Sprite
  500. button.addChild(textLabel);
  501. addChild(button);
  502. // Add listener for click event
  503. button.addEventListener(MouseEvent.MOUSE_DOWN, onClickTogglePauseBtn);
  504. }
  505. }
  506. }