helloworld.lpr 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. program helloworld;
  2. {$mode objfpc}
  3. uses
  4. JS, Classes, SysUtils, Web, libkurento, node.events, browserapp, browserconsole;
  5. Type
  6. { TKurentoApp }
  7. TKurentoApp = class(TBrowserApplication)
  8. Private
  9. FURL : TJSHTMLInputElement;
  10. FVideoInput,
  11. FVideoOutput,
  12. FStartButton,
  13. FStopButton : TJSHTMLElement;
  14. FWebRTCPeer : TWebRtcPeer;
  15. FClient: TKurentoClient;
  16. FPipeLine : TKurentoMediaPipeline;
  17. FRTCEndPoint : TKurentoWebRtcEndPoint;
  18. FMyOffer: TKurentoOffer;
  19. // Helper routine to display offers.
  20. procedure DoError(aError: TJSError);
  21. // Helper routine to set needed ICE callbacks.
  22. procedure setIceCandidateCallbacks(webRtcPeer : TWebRtcPeer; webRtcEp : TKurentoWebRtcEndPoint; onerror : TErrorCallBack);
  23. // Here we start the ball rolling , we create the WebRTCPeer, and create an offer
  24. function DoStart(aEvent: TJSMouseEvent): boolean;
  25. function DoStop(aEvent: TJSMouseEvent): boolean;
  26. // When the offer is received, we create a Kurento client
  27. procedure OnOfferReceived(aError: TJSError; aOffer: TKurentoOffer);
  28. // When the kurento client is created, we use it to create a media pipeline
  29. procedure HaveClient(aError: TJSError; aClient: TKurentoClient);
  30. // When the pipeline is created, we use it to create an endpoint for it
  31. procedure HavePipeLine(aError: TJSError; aResult: TKurentoMediaObject);
  32. // When the endpoint was created, we handle ICE candidates, process the offer, and start gathering candidates
  33. // In the end, we connect. When the connect succeeds, we're all done.
  34. procedure HaveEndPoint(aError: TJSError; aResult: TKurentoMediaObject);
  35. // When the offer is processed, here we handle the answer.
  36. procedure OfferProcessed(aError: TJSError; aAnswer: TKurentoAnswer);
  37. // Helper routines to Show/Hide a spinner.
  38. procedure HideSpinner(Els: array of TJSHTMLElement);
  39. procedure ShowSpinner(Els: array of TJSHTMLElement);
  40. Public
  41. procedure DoRun; override;
  42. end;
  43. procedure TKurentoApp.OfferProcessed(aError: TJSError; aAnswer: TKurentoAnswer);
  44. begin
  45. if assigned(aError) then
  46. DoError(aError)
  47. else
  48. FWebRTCPeer.processAnswer(aAnswer,@DoError);
  49. end;
  50. Procedure TKurentoApp.HaveEndPoint(aError : TJSError; aResult : TKurentoMediaObject);
  51. begin
  52. Writeln('TKurentoApp.HaveEndPoint callback. Have error:',Assigned(aError));
  53. if assigned(aError) then
  54. DoError(aError)
  55. else
  56. begin
  57. FRTCEndPoint:= TKurentoWebRtcEndPoint(aResult);
  58. setIceCandidateCallbacks(FWebRTCPeer,FRTCEndPoint,@DoError);
  59. FRTCEndPoint.processOffer(FMyOffer,@OfferProcessed);
  60. FRTCEndPoint.gatherCandidates(@DoError);
  61. FRTCEndPoint.connect(FRTCEndPoint,Procedure(aError : TJSError)
  62. begin
  63. if Assigned(aError) then
  64. DoError(aError)
  65. else
  66. Writeln('We should be all set')
  67. end);
  68. end;
  69. end;
  70. Procedure TKurentoApp.HavePipeLine(aError : TJSError; aResult : TKurentoMediaObject);
  71. begin
  72. Writeln('TKurentoApp.HavePipeline callback. Have error:',Assigned(aError));
  73. if assigned(aError) then
  74. DoError(aError)
  75. else
  76. begin
  77. FPipeLine:=TKurentoMediaPipeline(aResult);
  78. FPipeLine.Create('WebRtcEndpoint',@HaveEndPoint);
  79. end;
  80. end;
  81. procedure TKurentoApp.HaveClient(aError: TJSError; aClient: TKurentoClient);
  82. begin
  83. Writeln('TKurentoApp.HaveClient callback. Have error:',Assigned(aError));
  84. if assigned(aError) then
  85. DoError(aError)
  86. else
  87. begin
  88. FClient:=aClient;
  89. FClient.create('MediaPipeline',@HavePipeLine);
  90. end;
  91. end;
  92. procedure TKurentoApp.OnOfferReceived(aError: TJSError; aOffer: TKurentoOffer);
  93. begin
  94. Writeln('TKurentoApp.OnOfferReceived callback. Have error:',Assigned(aError));
  95. if assigned(aError) then
  96. DoError(aError)
  97. else
  98. begin
  99. FMyOffer:=aOffer;
  100. KurentoClient(FURL.Value,@HaveClient);
  101. end;
  102. end;
  103. procedure TKurentoApp.setIceCandidateCallbacks(webRtcPeer : TWebRtcPeer; webRtcEp : TKurentoWebRtcEndPoint; onerror : TErrorCallBack);
  104. Type
  105. TIceCandidateCreateFunction = function(arg : string) : TKurentoIceCandidate;
  106. begin
  107. webRtcPeer.on_('icecandidate', Procedure(candidate : JSValue)
  108. var
  109. Cand :TKurentoIceCandidate;
  110. begin
  111. console.log('Local candidate:',String(candidate));
  112. cand:=TIceCandidateCreateFunction(TKurentoClientGlobal.getComplexType('IceCandidate'))(candidate);
  113. webRtcEp.addIceCandidate(cand, onerror)
  114. end
  115. );
  116. webRtcEp.on_('OnIceCandidate', Procedure(event : JSValue)
  117. var
  118. Cand :TKurentoIceCandidate;
  119. begin
  120. cand:=TKurentoIceCandidate(TJSObject(event)['candidate']);
  121. console.log('Remote candidate:',TJSJSON.Stringify(cand));
  122. webRtcPeer.addIceCandidate(cand, onerror);
  123. end
  124. );
  125. end;
  126. Procedure TKurentoApp.HideSpinner(Els : Array of TJSHTMLElement);
  127. Var
  128. El : TJSHTMLElement;
  129. begin
  130. For El in Els do
  131. begin
  132. El['src']:='';
  133. El['poster']:='img/webrtc.png';
  134. El.style.setProperty('background','');
  135. end;
  136. end;
  137. Procedure TKurentoApp.ShowSpinner(Els : Array of TJSHTMLElement);
  138. Var
  139. El : TJSHTMLElement;
  140. begin
  141. For El in Els do
  142. begin
  143. El['poster']:='img/transparent-1px.png';
  144. El.style.setProperty('background','center transparent url("img/spinner.gif") no-repeat');
  145. end;
  146. end;
  147. Procedure TKurentoApp.DoError(aError : TJSError);
  148. begin
  149. if Assigned(aError) then
  150. writeln('An error occurred: ',aError.Message);
  151. end;
  152. function TKurentoApp.DoStop(aEvent: TJSMouseEvent): boolean;
  153. begin
  154. if Assigned(FWebRTCPeer) then
  155. begin
  156. FWebRTCPeer.dispose;
  157. FWebRTCPeer:=Nil;
  158. end;
  159. if Assigned(FPipeLine) then
  160. begin
  161. FPipeLine.release();
  162. FPipeLine:=Nil;
  163. end;
  164. hideSpinner([FvideoInput, FvideoOutput]);
  165. end;
  166. function TKurentoApp.DoStart(aEvent: TJSMouseEvent): boolean;
  167. Var
  168. Opts : TWebRtcPeerOptions;
  169. begin
  170. Writeln('DoStart');
  171. Opts:=TWebRtcPeerOptions.New;
  172. Opts.localVideo:=FVideoInput;
  173. Opts.remoteVideo:=FVideoOutput;
  174. FWebRTCPeer:=TWebRtcPeer.WebRtcPeerSendRecv(Opts,procedure(aError : TJSError)
  175. begin
  176. Writeln('TWebRtcPeer.WebRtcPeerSendRecv callback. Have error:',Assigned(aError));
  177. if Assigned(aError) then
  178. DoError(aError)
  179. else
  180. FWebRTCPeer.generateOffer(@OnOfferReceived);
  181. end
  182. );
  183. end;
  184. procedure TKurentoApp.DoRun;
  185. begin
  186. Terminate; // Avoid a loop.
  187. FVideoInput:=getHTMLElement('videoInput');
  188. FVideoOutput:=getHTMLElement('videoOutput');
  189. FStartButton:=getHTMLElement('start');
  190. FStopButton:=getHTMLElement('stop');
  191. FURL:=TJSHTMLInputElement(getHTMLElement('edtServer'));
  192. FStartButton.OnCLick:=@DoStart;
  193. FStopButton.OnClick:=@DoStop;
  194. end;
  195. begin
  196. With TKurentoApp.Create(Nil) do
  197. begin
  198. Initialize;
  199. Run;
  200. end;
  201. end.