1
0
mirror of https://github.com/salvadordf/CEF4Delphi.git synced 2024-11-24 08:02:15 +02:00

Update to CEF 81.2.24

- Added code comments to the MediaRouter demo
- Added a Lazarus version of the MediaRouter demo
This commit is contained in:
Salvador Díaz Fau 2020-04-25 15:57:11 +02:00
parent 22b59eae73
commit a34ae44cb0
20 changed files with 1807 additions and 36 deletions

View File

@ -3,10 +3,10 @@ CEF4Delphi is an open source project created by Salvador D
CEF4Delphi is based on DCEF3, made by Henri Gourvest. The original license of DCEF3 still applies to CEF4Delphi. Read the license terms in the first lines of any *.pas file.
CEF4Delphi uses CEF 81.2.22 which includes Chromium 81.0.4044.113.
CEF4Delphi uses CEF 81.2.24 which includes Chromium 81.0.4044.113.
The CEF binaries used by CEF4Delphi are available for download at spotify :
* [32 bits](http://opensource.spotify.com/cefbuilds/cef_binary_81.2.22%2Bg23f4473%2Bchromium-81.0.4044.113_windows32.tar.bz2)
* [64 bits](http://opensource.spotify.com/cefbuilds/cef_binary_81.2.22%2Bg23f4473%2Bchromium-81.0.4044.113_windows64.tar.bz2)
* [32 bits](http://opensource.spotify.com/cefbuilds/cef_binary_81.2.24%2Bgc0b313d%2Bchromium-81.0.4044.113_windows32.tar.bz2)
* [64 bits](http://opensource.spotify.com/cefbuilds/cef_binary_81.2.24%2Bgc0b313d%2Bchromium-81.0.4044.113_windows64.tar.bz2)
CEF4Delphi was developed and tested on Delphi 10.3.3 and it has been tested in Delphi 7, Delphi XE, Delphi 10, Delphi 10.2 and Lazarus 2.0.8/FPC 3.0.4. CEF4Delphi includes VCL, FireMonkey (FMX) and Lazarus components.

View File

@ -6,7 +6,7 @@
<MainSource>MediaRouter.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>

View File

@ -45,7 +45,7 @@ object MediaRouterFrm: TMediaRouterFrm
Width = 250
Height = 727
Align = alLeft
Caption = ' Sinks available on this network '
Caption = ' Sinks on this network '
Padding.Left = 10
Padding.Top = 10
Padding.Right = 10
@ -114,16 +114,6 @@ object MediaRouterFrm: TMediaRouterFrm
Padding.Right = 2
Padding.Bottom = 10
TabOrder = 0
object SourceURNEdt: TEdit
Left = 65
Top = 10
Width = 392
Height = 21
Align = alClient
TabOrder = 0
Text = 'cast:<appId>?clientId=<clientId>'
OnChange = SourceURNEdtChange
end
object SourceLblPnl: TPanel
Left = 0
Top = 10
@ -131,7 +121,7 @@ object MediaRouterFrm: TMediaRouterFrm
Height = 21
Align = alLeft
BevelOuter = bvNone
TabOrder = 1
TabOrder = 0
object SourceURNLbl: TLabel
Left = 0
Top = 0
@ -144,6 +134,20 @@ object MediaRouterFrm: TMediaRouterFrm
ExplicitHeight = 13
end
end
object SourceURNCbx: TComboBox
Left = 65
Top = 10
Width = 392
Height = 21
Align = alClient
ItemIndex = 1
TabOrder = 1
Text = 'cast:CC1AD845?clientId=123456789'
Items.Strings = (
'cast:<appId>?clientId=<clientId>'
'cast:CC1AD845?clientId=123456789'
'cast:4F8B3483?clientId=123456789')
end
end
object MessageGbx: TGroupBox
Left = 20
@ -247,7 +251,7 @@ object MediaRouterFrm: TMediaRouterFrm
Width = 250
Height = 727
Align = alRight
Caption = ' Routes available '
Caption = ' Established routes '
Padding.Left = 10
Padding.Top = 10
Padding.Right = 10
@ -261,6 +265,7 @@ object MediaRouterFrm: TMediaRouterFrm
Align = alClient
ItemHeight = 13
TabOrder = 0
OnClick = RoutesLbxClick
end
object RoutesButtonPnl: TPanel
Left = 12

View File

@ -72,7 +72,6 @@ type
CreateRouteBtn: TButton;
CentralPnl: TPanel;
SourcePnl: TPanel;
SourceURNEdt: TEdit;
SourceLblPnl: TPanel;
SourceURNLbl: TLabel;
RoutesGbx: TGroupBox;
@ -90,6 +89,7 @@ type
NotifyRoutesBtn: TButton;
ClearLogPnl: TPanel;
ClearLogBtn: TButton;
SourceURNCbx: TComboBox;
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormCreate(Sender: TObject);
@ -115,6 +115,7 @@ type
procedure NotifyRoutesBtnClick(Sender: TObject);
procedure ClearLogBtnClick(Sender: TObject);
procedure MessageMemChange(Sender: TObject);
procedure RoutesLbxClick(Sender: TObject);
protected
// Variables to control when can we destroy the form safely
@ -162,16 +163,63 @@ uses
{$ENDIF}
uCEFMiscFunctions;
// This demo can use a MediaRouter to communicate with devices on the local
// network via the CAST and DIAL protocols.
// TChromium exposes all the ICefMediaObserver events and the ICefMediaRouter
// methods to show the available devices, to established communication routes
// and to send messages to those devices.
// Follow these steps to test this demo :
// STEP 1
// ------
// Turn on your ChromeCast receiver. It can be an Android TV or similar device
// like a Xiaomi MiBox. It must be on the same local network as the computer
// running this demo.
// STEP 2
// ------
// Run this demo and wait a few seconds. It will show all the available devices
// in the local network and the protocol used to communicate with them.
// In the case of the MiBox device it shows a DIAL and a CAST "sink" but after
// a couple of secods the list is updated and it only shows the CAST sink.
// STEP 3
// ------
// Select the CAST sink and click on the "Create route" button. This button will
// use the "Source URN" value to create the route and that value has a CAST URN
// with the "Application ID" of the "Default Media Receiver", which is CC1AD845.
// This ID can be used for tests.
// STEP 4
// ------
// The "Established routes" box will show the routes that you created.
// STEP 5
// ------
// Select the route, type the message and click on the "Send message" button.
// STEP 6
// ------
// Click on the "Terminate route" button.
// WARNING
// =======
// This demo has a known bug when you close the form and it will crash.
// References :
// ============
// https://bitbucket.org/chromiumembedded/cef/issues/2900/add-mediarouter-support-for-cast-receiver
// https://blog.oakbits.com/google-cast-protocol-overview.html
// https://developers.google.com/cast/docs/developers
// https://gist.github.com/jloutsenhizer/8855258
procedure CreateGlobalCEFApp;
begin
GlobalCEFApp := TCefApplication.Create;
GlobalCEFApp.LogFile := 'debug.log';
GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO; //LOGSEVERITY_VERBOSE;
{
GlobalCEFApp.FrameworkDirPath := 'c:\cef';
GlobalCEFApp.ResourcesDirPath := 'c:\cef';
GlobalCEFApp.LocalesDirPath := 'c:\cef\locales';
}
GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO;
end;
procedure TMediaRouterFrm.Chromium1AfterCreated(Sender: TObject;
@ -411,6 +459,8 @@ begin
if (FLog <> nil) and (FLog.Count > 0) then
begin
LogMem.Lines.AddStrings(FLog);
LogMem.SelLength := 0;
LogMem.SelStart := Length(LogMem.Text);
FLog.Clear;
end;
finally
@ -427,6 +477,11 @@ begin
UpdateButtons;
end;
procedure TMediaRouterFrm.RoutesLbxClick(Sender: TObject);
begin
UpdateButtons;
end;
procedure TMediaRouterFrm.RefreshRoutesMsg(var aMessage : TMessage);
begin
if FClosing then exit;
@ -572,7 +627,7 @@ var
TempURN, TempErrorMsg : string;
TempSource : ICefMediaSource;
begin
TempURN := trim(SourceURNEdt.Text);
TempURN := trim(SourceURNCbx.Text);
if (length(TempURN) = 0) then
begin
@ -619,6 +674,7 @@ begin
end;
end;
finally
TempSource := nil;
FMediaCS.Release;
if (length(TempErrorMsg) > 0) then AddLogEntry(TempErrorMsg);
end;
@ -682,7 +738,7 @@ begin
(length(trim(MessageMem.Lines.Text)) > 0);
CreateRouteBtn.Enabled := not(TerminateRouteBtn.Enabled) and
(length(trim(SourceURNEdt.Text)) > 0) and
(length(trim(SourceURNCbx.Text)) > 0) and
(SinksLbx.ItemIndex >= 0) and
(SinksLbx.Items.Count > 0);
end;

View File

@ -6,7 +6,7 @@
<MainSource>PopupBrowser.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>

View File

@ -232,6 +232,8 @@ begin
GlobalCEFApp.EnableHighDPISupport := True;
GlobalCEFApp.TouchEvents := STATE_ENABLED;
//GlobalCEFApp.EnableGPU := True;
GlobalCEFApp.LogFile := 'debug.log';
GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO;
// If you need transparency leave the GlobalCEFApp.BackgroundColor property
// with the default value or set the alpha channel to 0

View File

@ -0,0 +1,2 @@
rmdir /S /Q lib
rmdir /S /Q backup

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<General>
<Flags>
<MainUnitHasUsesSectionForAllUnits Value="False"/>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="MediaRouter"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
<Modes Count="0"/>
</RunParams>
<RequiredPackages Count="2">
<Item1>
<PackageName Value="CEF4Delphi_Lazarus"/>
</Item1>
<Item2>
<PackageName Value="LCL"/>
</Item2>
</RequiredPackages>
<Units Count="2">
<Unit0>
<Filename Value="MediaRouter.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="uMediaRouterFrm.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="MediaRouterFrm"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit1>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="..\..\..\bin\MediaRouter"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<SyntaxMode Value="Delphi"/>
</SyntaxOptions>
</Parsing>
<Linking>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,72 @@
// ************************************************************************
// ***************************** CEF4Delphi *******************************
// ************************************************************************
//
// CEF4Delphi is based on DCEF3 which uses CEF to embed a chromium-based
// browser in Delphi applications.
//
// The original license of DCEF3 still applies to CEF4Delphi.
//
// For more information about CEF4Delphi visit :
// https://www.briskbard.com/index.php?lang=en&pageid=cef
//
// Copyright © 2020 Salvador Diaz Fau. All rights reserved.
//
// ************************************************************************
// ************ vvvv Original license and comments below vvvv *************
// ************************************************************************
(*
* Delphi Chromium Embedded 3
*
* Usage allowed under the restrictions of the Lesser GNU General Public License
* or alternatively the restrictions of the Mozilla Public License 1.1
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* Unit owner : Henri Gourvest <hgourvest@gmail.com>
* Web site : http://www.progdigy.com
* Repository : http://code.google.com/p/delphichromiumembedded/
* Group : http://groups.google.com/group/delphichromiumembedded
*
* Embarcadero Technologies, Inc is not permitted to use or redistribute
* this source code without explicit permission.
*
*)
program MediaRouter;
{$MODE Delphi}
{$I cef.inc}
uses
{$IFDEF DELPHI16_UP}
Vcl.Forms,
WinApi.Windows,
{$ELSE}
Windows,
Forms,
LCLIntf, LCLType, LMessages, Interfaces,
{$ENDIF }
uCEFApplication,
uMediaRouterFrm in 'uMediaRouterFrm.pas' {MediaRouterFrm};
{.$R *.res}
{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
begin
CreateGlobalCEFApp;
if GlobalCEFApp.StartMainProcess then
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMediaRouterFrm, MediaRouterFrm);
Application.Run;
end;
DestroyGlobalCEFApp;
end.

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectSession>
<PathDelim Value="\"/>
<Version Value="11"/>
<BuildModes Active="Default"/>
<Units Count="2">
<Unit0>
<Filename Value="MediaRouter.lpr"/>
<IsPartOfProject Value="True"/>
<TopLine Value="42"/>
<CursorPos X="37" Y="66"/>
<UsageCount Value="20"/>
<Loaded Value="True"/>
<DefaultSyntaxHighlighter Value="Delphi"/>
</Unit0>
<Unit1>
<Filename Value="uMediaRouterFrm.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="MediaRouterFrm"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="1"/>
<TopLine Value="553"/>
<CursorPos X="29" Y="49"/>
<UsageCount Value="20"/>
<Loaded Value="True"/>
<LoadedDesigner Value="True"/>
<DefaultSyntaxHighlighter Value="Delphi"/>
</Unit1>
</Units>
<JumpHistory Count="1">
<Position1>
<Filename Value="MediaRouter.lpr"/>
<Caret Line="49" Column="11" TopLine="42"/>
</Position1>
</JumpHistory>
<RunParams>
<FormatVersion Value="2"/>
<Modes Count="0" ActiveMode=""/>
</RunParams>
</ProjectSession>
</CONFIG>

View File

@ -0,0 +1,409 @@
// ************************************************************************
// ***************************** CEF4Delphi *******************************
// ************************************************************************
//
// CEF4Delphi is based on DCEF3 which uses CEF3 to embed a chromium-based
// browser in Delphi applications.
//
// The original license of DCEF3 still applies to CEF4Delphi.
//
// For more information about CEF4Delphi visit :
// https://www.briskbard.com/index.php?lang=en&pageid=cef
//
// Copyright © 2017 Salvador Diaz Fau. All rights reserved.
//
// ************************************************************************
// ************ vvvv Original license and comments below vvvv *************
// ************************************************************************
(*
* Delphi Chromium Embedded 3
*
* Usage allowed under the restrictions of the Lesser GNU General Public License
* or alternatively the restrictions of the Mozilla Public License 1.1
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* Unit owner : Henri Gourvest <hgourvest@gmail.com>
* Web site : http://www.progdigy.com
* Repository : http://code.google.com/p/delphichromiumembedded/
* Group : http://groups.google.com/group/delphichromiumembedded
*
* Embarcadero Technologies, Inc is not permitted to use or redistribute
* this source code without explicit permission.
*
*)
// The complete list of compiler versions is here :
// http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Compiler_Versions
{$DEFINE DELPHI_VERSION_UNKNOW}
// Delphi 5
{$IFDEF VER130}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$ENDIF}
// Delphi 6
{$IFDEF VER140}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$ENDIF}
// Delphi 7
{$IFDEF VER150}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$ENDIF}
// Delphi 8
{$IFDEF VER160}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$ENDIF}
// Delphi 2005
{$IFDEF VER170}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$ENDIF}
{$IFDEF VER180}
{$UNDEF DELPHI_VERSION_UNKNOW}
// Delphi 2007
{$IFDEF VER185}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
// Delphi 2006
{$ELSE}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$ENDIF}
{$ENDIF}
// Delphi 2009
{$IFDEF VER200}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$ENDIF}
//Delphi 2010
{$IFDEF VER210}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$ENDIF}
// Delphi XE
{$IFDEF VER220}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$ENDIF}
// Delphi XE2 (First FireMonkey and 64bit compiler)
{$IFDEF VER230}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$ENDIF}
// Delphi XE3
{$IFDEF VER240}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$ENDIF}
// Delphi XE4
{$IFDEF VER250}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$ENDIF}
// Delphi XE5
{$IFDEF VER260}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$ENDIF}
// Delphi XE6
{$IFDEF VER270}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$DEFINE DELPHI20_UP}
{$ENDIF}
// Delphi XE7
{$IFDEF VER280}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$DEFINE DELPHI20_UP}
{$DEFINE DELPHI21_UP}
{$ENDIF}
// Delphi XE8
{$IFDEF VER290}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$DEFINE DELPHI20_UP}
{$DEFINE DELPHI21_UP}
{$DEFINE DELPHI22_UP}
{$ENDIF VER290}
// Rad Studio 10 - Delphi Seattle
{$IFDEF VER300}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$DEFINE DELPHI20_UP}
{$DEFINE DELPHI21_UP}
{$DEFINE DELPHI22_UP}
{$DEFINE DELPHI23_UP}
{$ENDIF}
// Rad Studio 10.1 - Delphi Berlin
{$IFDEF VER310}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$DEFINE DELPHI20_UP}
{$DEFINE DELPHI21_UP}
{$DEFINE DELPHI22_UP}
{$DEFINE DELPHI23_UP}
{$DEFINE DELPHI24_UP}
{$ENDIF}
// Rad Studio 10.2 - Delphi Tokyo
{$IFDEF VER320}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$DEFINE DELPHI20_UP}
{$DEFINE DELPHI21_UP}
{$DEFINE DELPHI22_UP}
{$DEFINE DELPHI23_UP}
{$DEFINE DELPHI24_UP}
{$DEFINE DELPHI25_UP}
{$ENDIF}
// Rad Studio 10.3 - Delphi Rio
{$IFDEF VER330}
{$UNDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$DEFINE DELPHI20_UP}
{$DEFINE DELPHI21_UP}
{$DEFINE DELPHI22_UP}
{$DEFINE DELPHI23_UP}
{$DEFINE DELPHI24_UP}
{$DEFINE DELPHI25_UP}
{$DEFINE DELPHI26_UP}
{$ENDIF}
{$IFDEF FPC}
{$DEFINE SUPPORTS_INLINE}
{$ELSE}
{$IFDEF DELPHI_VERSION_UNKNOW}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$DEFINE DELPHI8_UP}
{$DEFINE DELPHI9_UP}
{$DEFINE DELPHI10_UP}
{$DEFINE DELPHI11_UP}
{$DEFINE DELPHI12_UP}
{$DEFINE DELPHI14_UP}
{$DEFINE DELPHI15_UP}
{$DEFINE DELPHI16_UP}
{$DEFINE DELPHI17_UP}
{$DEFINE DELPHI18_UP}
{$DEFINE DELPHI19_UP}
{$DEFINE DELPHI20_UP}
{$DEFINE DELPHI21_UP}
{$DEFINE DELPHI22_UP}
{$DEFINE DELPHI23_UP}
{$DEFINE DELPHI24_UP}
{$DEFINE DELPHI25_UP}
{$DEFINE DELPHI26_UP}
{$ENDIF}
{$ENDIF}
{$IFDEF DELPHI9_UP}
{$DEFINE SUPPORTS_INLINE}
{$ENDIF}

View File

@ -0,0 +1,316 @@
object MediaRouterFrm: TMediaRouterFrm
Left = 363
Height = 757
Top = 75
Width = 1029
Caption = 'Media Router'
ClientHeight = 757
ClientWidth = 1029
Color = clBtnFace
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
OnDestroy = FormDestroy
OnShow = FormShow
Position = poScreenCenter
LCLVersion = '2.0.8.0'
object CEFWindowParent1: TCEFWindowParent
Left = 184
Height = 0
Top = 56
Width = 0
TabOrder = 0
Visible = False
Enabled = False
end
object MainPnl: TPanel
Left = 0
Height = 757
Top = 0
Width = 1029
Align = alClient
BevelOuter = bvNone
ClientHeight = 757
ClientWidth = 1029
TabOrder = 1
object SinksGbx: TGroupBox
Left = 0
Height = 757
Top = 0
Width = 250
Align = alLeft
Caption = ' Sinks on this network '
ClientHeight = 739
ClientWidth = 246
TabOrder = 0
object SinksLbx: TListBox
Left = 0
Height = 679
Top = 0
Width = 246
Align = alClient
ItemHeight = 0
OnClick = SinksLbxClick
TabOrder = 0
end
object SinksButtonsPnl: TPanel
Left = 0
Height = 60
Top = 679
Width = 246
Align = alBottom
BevelOuter = bvNone
ClientHeight = 60
ClientWidth = 246
TabOrder = 1
object CreateRouteBtn: TButton
Left = 0
Height = 27
Top = 0
Width = 246
Align = alTop
Caption = 'Create route'
Enabled = False
OnClick = CreateRouteBtnClick
TabOrder = 0
end
object NotifySinksBtn: TButton
Left = 0
Height = 27
Top = 33
Width = 246
Align = alBottom
Caption = 'Notify sinks'
OnClick = NotifySinksBtnClick
TabOrder = 1
end
end
end
object CentralPnl: TPanel
Left = 250
Height = 757
Top = 0
Width = 529
Align = alClient
BevelOuter = bvNone
ClientHeight = 757
ClientWidth = 529
TabOrder = 1
object SourcePnl: TPanel
Left = 0
Height = 21
Top = 0
Width = 529
Align = alTop
BevelOuter = bvNone
ClientHeight = 21
ClientWidth = 529
TabOrder = 0
object SourceLblPnl: TPanel
Left = 0
Height = 21
Top = 0
Width = 65
Align = alLeft
BevelOuter = bvNone
ClientHeight = 21
ClientWidth = 65
TabOrder = 0
object SourceURNLbl: TLabel
Left = 0
Height = 21
Top = 0
Width = 65
Align = alClient
Caption = 'Source URN'
Layout = tlCenter
ParentColor = False
end
end
object SourceURNCbx: TComboBox
Left = 65
Height = 21
Top = 0
Width = 464
Align = alClient
ItemHeight = 13
ItemIndex = 1
Items.Strings = (
'cast:<appId>?clientId=<clientId>'
'cast:CC1AD845?clientId=123456789'
'cast:4F8B3483?clientId=123456789'
)
TabOrder = 1
Text = 'cast:CC1AD845?clientId=123456789'
end
end
object MessageGbx: TGroupBox
Left = 0
Height = 430
Top = 327
Width = 529
Align = alClient
Caption = ' Message '
ClientHeight = 412
ClientWidth = 525
TabOrder = 1
object SendMessagePnl: TPanel
Left = 0
Height = 27
Top = 385
Width = 525
Align = alBottom
BevelOuter = bvNone
ClientHeight = 27
ClientWidth = 525
TabOrder = 0
object SendMsgBtn: TButton
Left = 0
Height = 27
Top = 0
Width = 525
Align = alClient
Caption = 'Send message'
OnClick = SendMsgBtnClick
TabOrder = 0
end
end
object MessageMem: TMemo
Left = 0
Height = 385
Top = 0
Width = 525
Align = alClient
OnChange = MessageMemChange
ScrollBars = ssBoth
TabOrder = 1
end
end
object LogGbx: TGroupBox
Left = 0
Height = 296
Top = 21
Width = 529
Align = alTop
Caption = ' Log '
ClientHeight = 278
ClientWidth = 525
TabOrder = 2
object LogMem: TMemo
Left = 0
Height = 251
Top = 0
Width = 525
Align = alClient
ReadOnly = True
ScrollBars = ssBoth
TabOrder = 0
end
object ClearLogPnl: TPanel
Left = 0
Height = 27
Top = 251
Width = 525
Align = alBottom
BevelOuter = bvNone
ClientHeight = 27
ClientWidth = 525
TabOrder = 1
object ClearLogBtn: TButton
Left = 0
Height = 27
Top = 0
Width = 525
Align = alClient
Caption = 'Clear log'
OnClick = ClearLogBtnClick
TabOrder = 0
end
end
end
object SpacerPnl: TPanel
Left = 0
Height = 10
Top = 317
Width = 529
Align = alTop
BevelOuter = bvNone
TabOrder = 3
end
end
object RoutesGbx: TGroupBox
Left = 779
Height = 757
Top = 0
Width = 250
Align = alRight
Caption = ' Established routes '
ClientHeight = 739
ClientWidth = 246
TabOrder = 2
object RoutesLbx: TListBox
Left = 0
Height = 679
Top = 0
Width = 246
Align = alClient
ItemHeight = 0
OnClick = RoutesLbxClick
TabOrder = 0
end
object RoutesButtonPnl: TPanel
Left = 0
Height = 60
Top = 679
Width = 246
Align = alBottom
BevelOuter = bvNone
ClientHeight = 60
ClientWidth = 246
TabOrder = 1
object TerminateRouteBtn: TButton
Left = 0
Height = 27
Top = 0
Width = 246
Align = alTop
Caption = 'Terminate route'
Enabled = False
OnClick = TerminateRouteBtnClick
TabOrder = 0
end
object NotifyRoutesBtn: TButton
Left = 0
Height = 27
Top = 33
Width = 246
Align = alBottom
Caption = 'Notify routes'
OnClick = NotifyRoutesBtnClick
TabOrder = 1
end
end
end
end
object Chromium1: TChromium
OnMediaRouteCreateFinished = Chromium1MediaRouteCreateFinished
OnAfterCreated = Chromium1AfterCreated
OnBeforeClose = Chromium1BeforeClose
OnClose = Chromium1Close
OnSinks = Chromium1Sinks
OnRoutes = Chromium1Routes
OnRouteStateChanged = Chromium1RouteStateChanged
OnRouteMessageReceived = Chromium1RouteMessageReceived
left = 72
top = 56
end
object Timer1: TTimer
Enabled = False
Interval = 300
OnTimer = Timer1Timer
left = 72
top = 136
end
end

View File

@ -0,0 +1,774 @@
// ************************************************************************
// ***************************** CEF4Delphi *******************************
// ************************************************************************
//
// CEF4Delphi is based on DCEF3 which uses CEF to embed a chromium-based
// browser in Delphi applications.
//
// The original license of DCEF3 still applies to CEF4Delphi.
//
// For more information about CEF4Delphi visit :
// https://www.briskbard.com/index.php?lang=en&pageid=cef
//
// Copyright © 2020 Salvador Diaz Fau. All rights reserved.
//
// ************************************************************************
// ************ vvvv Original license and comments below vvvv *************
// ************************************************************************
(*
* Delphi Chromium Embedded 3
*
* Usage allowed under the restrictions of the Lesser GNU General Public License
* or alternatively the restrictions of the Mozilla Public License 1.1
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* Unit owner : Henri Gourvest <hgourvest@gmail.com>
* Web site : http://www.progdigy.com
* Repository : http://code.google.com/p/delphichromiumembedded/
* Group : http://groups.google.com/group/delphichromiumembedded
*
* Embarcadero Technologies, Inc is not permitted to use or redistribute
* this source code without explicit permission.
*
*)
unit uMediaRouterFrm;
{$MODE Delphi}
{$I cef.inc}
interface
uses
LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics, Menus,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Types, ComCtrls, ClipBrd,
ActiveX, ShlObj, SyncObjs,
uCEFChromium, uCEFWindowParent, uCEFInterfaces, uCEFApplication, uCEFTypes, uCEFConstants,
uCEFWinControl, uCEFSentinel, uCEFChromiumCore;
const
MEDIA_ROUTER_PENDING_LOG_LINES = WM_APP + $B00;
MEDIA_ROUTER_REFRESH_SINKS = WM_APP + $B01;
MEDIA_ROUTER_REFRESH_ROUTES = WM_APP + $B02;
MEDIA_ROUTER_UPDATE_BUTTONS = WM_APP + $B03;
type
TMediaRouterFrm = class(TForm)
Chromium1: TChromium;
CEFWindowParent1: TCEFWindowParent;
Timer1: TTimer;
MainPnl: TPanel;
SinksGbx: TGroupBox;
SinksLbx: TListBox;
SinksButtonsPnl: TPanel;
CreateRouteBtn: TButton;
CentralPnl: TPanel;
SourcePnl: TPanel;
SourceLblPnl: TPanel;
SourceURNLbl: TLabel;
RoutesGbx: TGroupBox;
RoutesLbx: TListBox;
RoutesButtonPnl: TPanel;
TerminateRouteBtn: TButton;
MessageGbx: TGroupBox;
SendMessagePnl: TPanel;
SendMsgBtn: TButton;
MessageMem: TMemo;
LogGbx: TGroupBox;
LogMem: TMemo;
SpacerPnl: TPanel;
NotifySinksBtn: TButton;
NotifyRoutesBtn: TButton;
ClearLogPnl: TPanel;
ClearLogBtn: TButton;
SourceURNCbx: TComboBox;
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
procedure Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
procedure Chromium1Close(Sender: TObject; const browser: ICefBrowser; var aAction: TCefCloseBrowserAction);
procedure Chromium1Sinks(Sender: TObject; const sinks: TCefMediaSinkArray);
procedure Chromium1Routes(Sender: TObject; const routes: TCefMediaRouteArray);
procedure Chromium1RouteStateChanged(Sender: TObject; const route: ICefMediaRoute; state: TCefMediaRouteConnectionState);
procedure Chromium1RouteMessageReceived(Sender: TObject; const route: ICefMediaRoute; const message_: ustring);
procedure Chromium1MediaRouteCreateFinished(Sender: TObject; result: Integer; const error: ustring; const route: ICefMediaRoute);
procedure Timer1Timer(Sender: TObject);
procedure SourceURNEdtChange(Sender: TObject);
procedure SinksLbxClick(Sender: TObject);
procedure CreateRouteBtnClick(Sender: TObject);
procedure TerminateRouteBtnClick(Sender: TObject);
procedure SendMsgBtnClick(Sender: TObject);
procedure NotifySinksBtnClick(Sender: TObject);
procedure NotifyRoutesBtnClick(Sender: TObject);
procedure ClearLogBtnClick(Sender: TObject);
procedure MessageMemChange(Sender: TObject);
procedure RoutesLbxClick(Sender: TObject);
protected
// Variables to control when can we destroy the form safely
FCanClose : boolean; // Set to True in TChromium.OnBeforeClose
FClosing : boolean; // Set to True in the CloseQuery event.
FMediaCS : TCriticalSection;
FLog : TStringList;
FSinks : TCefMediaSinkInfoArray;
FRoutes : TCefMediaRouteInfoArray;
procedure BrowserDestroyMsg(var aMessage : TMessage); message CEF_DESTROY;
procedure PendingLogLinesMsg(var aMessage : TMessage); message MEDIA_ROUTER_PENDING_LOG_LINES;
procedure RefreshSinksMsg(var aMessage : TMessage); message MEDIA_ROUTER_REFRESH_SINKS;
procedure RefreshRoutesMsg(var aMessage : TMessage); message MEDIA_ROUTER_REFRESH_ROUTES;
procedure UpdateButtonsMsg(var aMessage : TMessage); message MEDIA_ROUTER_UPDATE_BUTTONS;
procedure DestroySinksArray;
procedure DestroyRoutesArray;
procedure DestroyAllArrays;
procedure CopySinksArray(const aSinks : TCefMediaSinkArray);
procedure CopyRoutesArray(const aRoutes : TCefMediaRouteArray);
procedure UpdateAvailableSinks;
procedure UpdateAvailableRoutes;
procedure UpdateButtons;
procedure AppendPendingLogStrings;
procedure AddLogEntry(const aMessage1, aMessage2 : string; aRec : boolean); overload;
procedure AddLogEntry(const aMessage1 : string; const aMessage2 : string = ''); overload;
end;
var
MediaRouterFrm: TMediaRouterFrm;
procedure CreateGlobalCEFApp;
implementation
{$R *.lfm}
uses
{$IFDEF DELPHI16_UP}
System.Math,
{$ELSE}
Math,
{$ENDIF}
uCEFMiscFunctions;
// This demo can use a MediaRouter to communicate with devices on the local
// network via the CAST and DIAL protocols.
// TChromium exposes all the ICefMediaObserver events and the ICefMediaRouter
// methods to show the available devices, to established communication routes
// and to send messages to those devices.
// Follow these steps to test this demo :
// STEP 1
// ------
// Turn on your ChromeCast receiver. It can be an Android TV or similar device
// like a Xiaomi MiBox. It must be on the same local network as the computer
// running this demo.
// STEP 2
// ------
// Run this demo and wait a few seconds. It will show all the available devices
// in the local network and the protocol used to communicate with them.
// In the case of the MiBox device it shows a DIAL and a CAST "sink" but after
// a couple of secods the list is updated and it only shows the CAST sink.
// STEP 3
// ------
// Select the CAST sink and click on the "Create route" button. This button will
// use the "Source URN" value to create the route and that value has a CAST URN
// with the "Application ID" of the "Default Media Receiver", which is CC1AD845.
// This ID can be used for tests.
// STEP 4
// ------
// The "Established routes" box will show the routes that you created.
// STEP 5
// ------
// Select the route, type the message and click on the "Send message" button.
// STEP 6
// ------
// Click on the "Terminate route" button.
// WARNING
// =======
// This demo has a known bug when you close the form and it will crash.
// References :
// ============
// https://bitbucket.org/chromiumembedded/cef/issues/2900/add-mediarouter-support-for-cast-receiver
// https://blog.oakbits.com/google-cast-protocol-overview.html
// https://developers.google.com/cast/docs/developers
// https://gist.github.com/jloutsenhizer/8855258
procedure CreateGlobalCEFApp;
begin
GlobalCEFApp := TCefApplication.Create;
GlobalCEFApp.LogFile := 'debug.log';
GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO;
end;
procedure TMediaRouterFrm.Chromium1AfterCreated(Sender: TObject;
const browser: ICefBrowser);
begin
AddLogEntry('Browser initialized.');
end;
procedure TMediaRouterFrm.Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
procedure TMediaRouterFrm.Chromium1Close(Sender: TObject;
const browser: ICefBrowser; var aAction: TCefCloseBrowserAction);
begin
PostMessage(Handle, CEF_DESTROY, 0, 0);
aAction := cbaDelay;
end;
procedure TMediaRouterFrm.Chromium1MediaRouteCreateFinished(Sender: TObject;
result: Integer; const error: ustring; const route: ICefMediaRoute);
var
TempMsg, TempID : string;
begin
TempMsg := '';
try
FMediaCS.Acquire;
if (result = CEF_MRCR_OK) then
begin
TempMsg := 'Route created';
if (route <> nil) then TempID := 'Route ID : ' + route.ID;
end
else
TempMsg := error;
finally
FMediaCS.Release;
if (length(TempMsg) > 0) then AddLogEntry(TempID, TempMsg);
PostMessage(Handle, MEDIA_ROUTER_UPDATE_BUTTONS, 0, 0);
end;
end;
procedure TMediaRouterFrm.Chromium1RouteMessageReceived(Sender: TObject;
const route: ICefMediaRoute; const message_: ustring);
var
TempID : string;
begin
if (route <> nil) then
TempID := 'Route ID : ' + route.ID;
AddLogEntry(TempID, 'Message contents : ' + message_, True);
end;
procedure TMediaRouterFrm.Chromium1Routes(Sender: TObject;
const routes: TCefMediaRouteArray);
begin
CopyRoutesArray(routes);
end;
procedure TMediaRouterFrm.Chromium1RouteStateChanged(Sender: TObject;
const route: ICefMediaRoute; state: TCefMediaRouteConnectionState);
var
TempMsg, TempID : string;
begin
if (route <> nil) then TempID := 'Route ID : ' + route.ID;
case state of
CEF_MRCS_CONNECTING : TempMsg := 'Route state : Connecting.';
CEF_MRCS_CONNECTED : TempMsg := 'Route state : Connected.';
CEF_MRCS_CLOSED : TempMsg := 'Route state : Closed.';
CEF_MRCS_TERMINATED : TempMsg := 'Route state : Terminated.';
else TempMsg := 'Route state : Unknown.';
end;
TempMsg := TempMsg + ' ' + dateTimeToStr(now);
AddLogEntry(TempID, TempMsg);
end;
procedure TMediaRouterFrm.Chromium1Sinks(Sender: TObject;
const sinks: TCefMediaSinkArray);
begin
CopySinksArray(sinks);
end;
procedure TMediaRouterFrm.ClearLogBtnClick(Sender: TObject);
begin
LogMem.Lines.Clear;
end;
procedure TMediaRouterFrm.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
CanClose := FCanClose;
if not(FClosing) then
begin
FClosing := True;
Visible := False;
DestroyAllArrays;
Chromium1.CloseBrowser(True);
end;
end;
procedure TMediaRouterFrm.FormCreate(Sender: TObject);
begin
FCanClose := False;
FClosing := False;
FSinks := nil;
FRoutes := nil;
FMediaCS := TCriticalSection.Create;
FLog := TStringList.Create;
end;
procedure TMediaRouterFrm.FormDestroy(Sender: TObject);
begin
FLog.Free;
FMediaCS.Free;
end;
procedure TMediaRouterFrm.FormShow(Sender: TObject);
begin
UpdateButtons;
if not(Chromium1.CreateBrowser(CEFWindowParent1)) then
Timer1.Enabled := True;
end;
procedure TMediaRouterFrm.MessageMemChange(Sender: TObject);
begin
UpdateButtons;
end;
procedure TMediaRouterFrm.NotifyRoutesBtnClick(Sender: TObject);
begin
Chromium1.NotifyCurrentRoutes;
end;
procedure TMediaRouterFrm.NotifySinksBtnClick(Sender: TObject);
begin
Chromium1.NotifyCurrentSinks;
end;
procedure TMediaRouterFrm.SendMsgBtnClick(Sender: TObject);
var
TempMsg, TempID : string;
begin
TempMsg := '';
try
FMediaCS.Acquire;
if (RoutesLbx.Items.Count > 0) and
(FRoutes <> nil) and
(RoutesLbx.ItemIndex >= 0) and
(RoutesLbx.ItemIndex < length(FRoutes)) and
(MessageMem.Lines.Count > 0) then
begin
TempMsg := trim(MessageMem.Lines.Text);
if (length(TempMsg) > 0) and
(FRoutes[RoutesLbx.ItemIndex].RouteIntf <> nil) then
try
TempID := 'Route ID : ' + FRoutes[RoutesLbx.ItemIndex].RouteIntf.ID;
FRoutes[RoutesLbx.ItemIndex].RouteIntf.SendRouteMessage(TempMsg);
TempMsg := 'Message contents : ' + TempMsg;
except
on e : exception do
if CustomExceptionHandler('TMediaRouterFrm.SendMsgBtnClick', e) then raise;
end;
end;
finally
FMediaCS.Release;
if (length(TempMsg) > 0) then AddLogEntry(TempID, TempMsg, False);
end;
end;
procedure TMediaRouterFrm.SinksLbxClick(Sender: TObject);
begin
UpdateButtons;
end;
procedure TMediaRouterFrm.SourceURNEdtChange(Sender: TObject);
begin
UpdateButtons;
end;
procedure TMediaRouterFrm.TerminateRouteBtnClick(Sender: TObject);
begin
try
FMediaCS.Acquire;
if (RoutesLbx.Items.Count > 0) and
(FRoutes <> nil) and
(RoutesLbx.ItemIndex >= 0) and
(RoutesLbx.ItemIndex < length(FRoutes)) and
(FRoutes[RoutesLbx.ItemIndex].RouteIntf <> nil) then
try
FRoutes[RoutesLbx.ItemIndex].RouteIntf.Terminate;
except
on e : exception do
if CustomExceptionHandler('TMediaRouterFrm.TerminateRouteBtnClick', e) then raise;
end;
finally
FMediaCS.Release;
UpdateButtons;
end;
end;
procedure TMediaRouterFrm.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
if not(Chromium1.CreateBrowser(CEFWindowParent1)) and not(Chromium1.Initialized) then
Timer1.Enabled := True;
end;
procedure TMediaRouterFrm.BrowserDestroyMsg(var aMessage : TMessage);
begin
CEFWindowParent1.Free;
end;
procedure TMediaRouterFrm.PendingLogLinesMsg(var aMessage : TMessage);
begin
if FClosing then exit;
AppendPendingLogStrings;
end;
procedure TMediaRouterFrm.AppendPendingLogStrings;
begin
try
FMediaCS.Acquire;
if (FLog <> nil) and (FLog.Count > 0) then
begin
LogMem.Lines.AddStrings(FLog);
LogMem.SelLength := 0;
LogMem.SelStart := Length(LogMem.Text);
FLog.Clear;
end;
finally
FMediaCS.Release;
end;
end;
procedure TMediaRouterFrm.RefreshSinksMsg(var aMessage : TMessage);
begin
if FClosing then exit;
UpdateAvailableSinks;
AppendPendingLogStrings;
UpdateButtons;
end;
procedure TMediaRouterFrm.RoutesLbxClick(Sender: TObject);
begin
UpdateButtons;
end;
procedure TMediaRouterFrm.RefreshRoutesMsg(var aMessage : TMessage);
begin
if FClosing then exit;
UpdateAvailableRoutes;
AppendPendingLogStrings;
UpdateButtons;
end;
procedure TMediaRouterFrm.UpdateButtonsMsg(var aMessage : TMessage);
begin
if FClosing then exit;
AppendPendingLogStrings;
UpdateButtons;
end;
procedure TMediaRouterFrm.DestroyAllArrays;
begin
try
FMediaCS.Acquire;
DestroyRoutesArray;
DestroySinksArray;
finally
FMediaCS.Release;
end;
end;
procedure TMediaRouterFrm.DestroySinksArray;
var
i : integer;
begin
if (FSinks <> nil) then
begin
i := pred(length(FSinks));
while (i >= 0) do
begin
FSinks[i].SinkIntf := nil;
dec(i);
end;
Finalize(FSinks);
FSinks := nil;
end;
end;
procedure TMediaRouterFrm.DestroyRoutesArray;
var
i : integer;
begin
if (FRoutes <> nil) then
begin
i := pred(length(FRoutes));
while (i >= 0) do
begin
FRoutes[i].RouteIntf := nil;
dec(i);
end;
Finalize(FRoutes);
FRoutes := nil;
end;
end;
procedure TMediaRouterFrm.CopySinksArray(const aSinks : TCefMediaSinkArray);
var
i, TempLen : integer;
begin
try
FMediaCS.Acquire;
FLog.Add('Sinks available : ' + inttostr(length(aSinks)));
FLog.Add('------------------------------------------');
DestroySinksArray;
if (aSinks <> nil) then
begin
TempLen := length(aSinks);
SetLength(FSinks, TempLen);
i := 0;
while (i < TempLen) do
begin
FSinks[i].ID := aSinks[i].ID;
FSinks[i].Name := aSinks[i].Name;
FSinks[i].Description := aSinks[i].Description;
FSinks[i].Valid := aSinks[i].IsValid;
FSinks[i].SinkIntf := aSinks[i];
if aSinks[i].IsCastSink then
FSinks[i].SinkType := mtCast
else
if aSinks[i].IsDialSink then
FSinks[i].SinkType := mtDial
else
FSinks[i].SinkType := mtUnknown;
inc(i);
end;
end;
finally
PostMessage(Handle, MEDIA_ROUTER_REFRESH_SINKS, 0, 0);
FMediaCS.Release;
end;
end;
procedure TMediaRouterFrm.CopyRoutesArray(const aRoutes : TCefMediaRouteArray);
var
i, TempLen : integer;
begin
try
FMediaCS.Acquire;
FLog.Add('Routes available : ' + inttostr(length(aRoutes)));
FLog.Add('------------------------------------------');
DestroyRoutesArray;
if (aRoutes <> nil) then
begin
TempLen := length(aRoutes);
SetLength(FRoutes, TempLen);
i := 0;
while (i < TempLen) do
begin
FRoutes[i].ID := aRoutes[i].ID;
FRoutes[i].SourceID := aRoutes[i].GetSource.ID;
FRoutes[i].SinkID := aRoutes[i].GetSink.ID;
FRoutes[i].RouteIntf := aRoutes[i];
inc(i);
end;
end;
finally
PostMessage(Handle, MEDIA_ROUTER_REFRESH_ROUTES, 0, 0);
FMediaCS.Release;
end;
end;
procedure TMediaRouterFrm.CreateRouteBtnClick(Sender: TObject);
var
TempURN, TempErrorMsg : string;
TempSource : ICefMediaSource;
begin
TempURN := trim(SourceURNCbx.Text);
if (length(TempURN) = 0) then
begin
AddLogEntry('Invalid URN');
exit;
end;
TempErrorMsg := '';
try
try
FMediaCS.Acquire;
if (FSinks <> nil) and
(SinksLbx.Items.Count > 0) and
(SinksLbx.ItemIndex >= 0) and
(SinksLbx.ItemIndex < length(FSinks)) then
begin
TempSource := Chromium1.GetSource(TempURN);
if (TempSource <> nil) and TempSource.IsValid then
begin
if (FSinks[SinksLbx.ItemIndex].SinkIntf <> nil) and
FSinks[SinksLbx.ItemIndex].SinkIntf.IsValid then
begin
if FSinks[SinksLbx.ItemIndex].SinkIntf.IsCompatibleWith(TempSource) then
Chromium1.CreateRoute(TempSource, FSinks[SinksLbx.ItemIndex].SinkIntf)
else
TempErrorMsg := 'The selected Sink is not compatible with the Media Source.';
end
else
TempErrorMsg := 'The selected Sink is not valid.';
end
else
TempErrorMsg := 'The Media Source is not valid.';
end
else
TempErrorMsg := 'The sinks list is outdated.';
except
on e : exception do
begin
TempErrorMsg := e.Message;
if CustomExceptionHandler('TMediaRouterFrm.CreateRouteBtnClick', e) then raise;
end;
end;
finally
TempSource := nil;
FMediaCS.Release;
if (length(TempErrorMsg) > 0) then AddLogEntry(TempErrorMsg);
end;
end;
procedure TMediaRouterFrm.UpdateAvailableSinks;
var
i : integer;
begin
try
FMediaCS.Acquire;
SinksLbx.Items.Clear;
if (FSinks <> nil) then
begin
i := 0;
while (i < length(FSinks)) do
begin
case FSinks[i].SinkType of
mtCast : SinksLbx.Items.Add(FSinks[i].Name + ' (CAST)');
mtDial : SinksLbx.Items.Add(FSinks[i].Name + ' (DIAL)');
else SinksLbx.Items.Add(FSinks[i].Name + ' (UNKNOWN)');
end;
inc(i);
end;
end;
finally
FMediaCS.Release;
end;
end;
procedure TMediaRouterFrm.UpdateAvailableRoutes;
var
i : integer;
begin
try
FMediaCS.Acquire;
RoutesLbx.Items.Clear;
if (FRoutes <> nil) then
begin
i := 0;
while (i < length(FRoutes)) do
begin
RoutesLbx.Items.Add('ID : ' + quotedstr(FRoutes[i].ID));
inc(i);
end;
end;
finally
FMediaCS.Release;
end;
end;
procedure TMediaRouterFrm.UpdateButtons;
begin
TerminateRouteBtn.Enabled := (RoutesLbx.ItemIndex >= 0) and
(RoutesLbx.Items.Count > 0);
SendMsgBtn.Enabled := TerminateRouteBtn.Enabled and
(length(trim(MessageMem.Lines.Text)) > 0);
CreateRouteBtn.Enabled := not(TerminateRouteBtn.Enabled) and
(length(trim(SourceURNCbx.Text)) > 0) and
(SinksLbx.ItemIndex >= 0) and
(SinksLbx.Items.Count > 0);
end;
procedure TMediaRouterFrm.AddLogEntry(const aMessage1, aMessage2 : string; aRec : boolean);
begin
try
FMediaCS.Acquire;
if aRec then
FLog.Add('Message received ' + dateTimeToStr(now))
else
FLog.Add('Message sent ' + dateTimeToStr(now));
FLog.Add(aMessage1);
if (length(aMessage2) > 0) then FLog.Add(aMessage2);
FLog.Add('------------------------------------------');
finally
PostMessage(Handle, MEDIA_ROUTER_PENDING_LOG_LINES, 0, 0);
FMediaCS.Release;
end;
end;
procedure TMediaRouterFrm.AddLogEntry(const aMessage1, aMessage2 : string);
begin
try
FMediaCS.Acquire;
FLog.Add(aMessage1);
if (length(aMessage2) > 0) then FLog.Add(aMessage2);
FLog.Add('------------------------------------------');
finally
PostMessage(Handle, MEDIA_ROUTER_PENDING_LOG_LINES, 0, 0);
FMediaCS.Release;
end;
end;
end.

View File

@ -22,8 +22,8 @@
<ResourceBaseClass Value="Form"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="1"/>
<TopLine Value="544"/>
<CursorPos X="38" Y="555"/>
<TopLine Value="22"/>
<CursorPos X="37" Y="48"/>
<UsageCount Value="21"/>
<Bookmarks Count="3">
<Item0 Y="840" ID="1"/>

View File

@ -15,7 +15,7 @@ object MiniBrowserFrm: TMiniBrowserFrm
OnDestroy = FormDestroy
OnShow = FormShow
Position = poScreenCenter
LCLVersion = '2.0.6.0'
LCLVersion = '2.0.8.0'
object Splitter1: TSplitter
Left = 1179
Height = 663

View File

@ -45,7 +45,7 @@ uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Menus,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Types, ComCtrls, ClipBrd, ActiveX, ShlObj,
uCEFChromium, uCEFWindowParent, uCEFInterfaces, uCEFApplication, uCEFTypes, uCEFConstants,
uCEFWinControl, uCEFChromiumEvents, uCEFSentinel;
uCEFWinControl, uCEFChromiumEvents;
const
MINIBROWSER_SHOWDEVTOOLS = WM_APP + $101;

View File

@ -21,7 +21,7 @@
</CompilerOptions>
<Description Value="CEF4Delphi is an open source project created by Salvador Díaz Fau to embed Chromium-based browsers in applications made with Delphi or Lazarus/FPC."/>
<License Value="MPL 1.1"/>
<Version Major="81" Minor="2" Release="22"/>
<Version Major="81" Minor="2" Release="24"/>
<Files Count="154">
<Item1>
<Filename Value="..\source\uCEFAccessibilityHandler.pas"/>

View File

@ -62,7 +62,7 @@ uses
const
CEF_SUPPORTED_VERSION_MAJOR = 81;
CEF_SUPPORTED_VERSION_MINOR = 2;
CEF_SUPPORTED_VERSION_RELEASE = 22;
CEF_SUPPORTED_VERSION_RELEASE = 24;
CEF_SUPPORTED_VERSION_BUILD = 0;
CEF_CHROMEELF_VERSION_MAJOR = 81;

View File

@ -1276,8 +1276,8 @@ end;
procedure TChromiumCore.DestroyMediaObserver;
begin
FRegistration := nil;
FMediaObserver := nil;
FRegistration := nil;
end;
procedure TChromiumCore.CreateMediaObserver;

View File

@ -2,9 +2,9 @@
"UpdateLazPackages" : [
{
"ForceNotify" : true,
"InternalVersion" : 124,
"InternalVersion" : 125,
"Name" : "cef4delphi_lazarus.lpk",
"Version" : "81.2.22.0"
"Version" : "81.2.24.0"
}
],
"UpdatePackageData" : {