mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-09-18 21:24:49 +02:00
Rewrite video player to use duplex pipe for process communication
This commit is contained in:
@@ -389,16 +389,6 @@ namespace TweetDuck.Core{
|
|||||||
BrowserProcesses.Link(m.LParam.ToInt32(), processId);
|
BrowserProcesses.Link(m.LParam.ToInt32(), processId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (m.Msg == Program.VideoPlayerMessage){
|
|
||||||
int volume = m.WParam.ToInt32();
|
|
||||||
|
|
||||||
if (Handle == m.LParam && volume != Config.VideoPlayerVolume){
|
|
||||||
Config.VideoPlayerVolume = volume;
|
|
||||||
Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ using System.IO;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetLib.Communication;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Other.Management{
|
namespace TweetDuck.Core.Other.Management{
|
||||||
sealed class VideoPlayer : IDisposable{
|
sealed class VideoPlayer : IDisposable{
|
||||||
@@ -23,23 +24,32 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
public event EventHandler ProcessExited;
|
public event EventHandler ProcessExited;
|
||||||
|
|
||||||
private readonly Form owner;
|
private readonly Form owner;
|
||||||
private Process currentProcess;
|
|
||||||
private string lastUrl;
|
private string lastUrl;
|
||||||
|
|
||||||
|
private Process currentProcess;
|
||||||
|
private DuplexPipe.Server currentPipe;
|
||||||
|
private bool isClosing;
|
||||||
|
|
||||||
public VideoPlayer(Form owner){
|
public VideoPlayer(Form owner){
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.owner.FormClosing += owner_FormClosing;
|
this.owner.FormClosing += owner_FormClosing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Launch(string url){
|
public void Launch(string url){
|
||||||
Close();
|
if (Running){
|
||||||
|
Destroy();
|
||||||
|
isClosing = false;
|
||||||
|
}
|
||||||
|
|
||||||
lastUrl = url;
|
lastUrl = url;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
currentPipe = DuplexPipe.CreateServer();
|
||||||
|
currentPipe.DataIn += currentPipe_DataIn;
|
||||||
|
|
||||||
if ((currentProcess = Process.Start(new ProcessStartInfo{
|
if ((currentProcess = Process.Start(new ProcessStartInfo{
|
||||||
FileName = PlayerExe,
|
FileName = PlayerExe,
|
||||||
Arguments = $"{owner.Handle} {Program.UserConfig.VideoPlayerVolume} \"{url}\"",
|
Arguments = $"{owner.Handle} {Program.UserConfig.VideoPlayerVolume} \"{url}\" \"{currentPipe.GenerateToken()}\"",
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardOutput = true
|
RedirectStandardOutput = true
|
||||||
})) != null){
|
})) != null){
|
||||||
@@ -51,15 +61,61 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
currentProcess.OutputDataReceived += (sender, args) => Debug.WriteLine("VideoPlayer: "+args.Data);
|
currentProcess.OutputDataReceived += (sender, args) => Debug.WriteLine("VideoPlayer: "+args.Data);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentPipe.DisposeToken();
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Program.Reporter.HandleException("Video Playback Error", "Error launching video player.", true, e);
|
Program.Reporter.HandleException("Video Playback Error", "Error launching video player.", true, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void currentPipe_DataIn(object sender, DuplexPipe.PipeReadEventArgs e){
|
||||||
|
owner.InvokeSafe(() => {
|
||||||
|
switch(e.Key){
|
||||||
|
case "vol":
|
||||||
|
if (int.TryParse(e.Data, out int volume) && volume != Program.UserConfig.VideoPlayerVolume){
|
||||||
|
Program.UserConfig.VideoPlayerVolume = volume;
|
||||||
|
Program.UserConfig.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "rip":
|
||||||
|
currentPipe.Dispose();
|
||||||
|
currentPipe = null;
|
||||||
|
|
||||||
|
currentProcess.Dispose();
|
||||||
|
currentProcess = null;
|
||||||
|
|
||||||
|
isClosing = false;
|
||||||
|
TriggerProcessExitEventUnsafe();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void Close(){
|
public void Close(){
|
||||||
if (currentProcess != null){
|
if (currentProcess != null){
|
||||||
currentProcess.Exited -= process_Exited;
|
if (isClosing){
|
||||||
|
Destroy();
|
||||||
|
isClosing = false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
isClosing = true;
|
||||||
|
currentProcess.Exited -= process_Exited;
|
||||||
|
currentPipe.Write("die");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose(){
|
||||||
|
ProcessExited = null;
|
||||||
|
|
||||||
|
isClosing = true;
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Destroy(){
|
||||||
|
if (currentProcess != null){
|
||||||
try{
|
try{
|
||||||
currentProcess.Kill();
|
currentProcess.Kill();
|
||||||
}catch{
|
}catch{
|
||||||
@@ -68,16 +124,14 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
|
|
||||||
currentProcess.Dispose();
|
currentProcess.Dispose();
|
||||||
currentProcess = null;
|
currentProcess = null;
|
||||||
|
|
||||||
|
currentPipe.Dispose();
|
||||||
|
currentPipe = null;
|
||||||
|
|
||||||
owner.InvokeAsyncSafe(TriggerProcessExitEventUnsafe);
|
TriggerProcessExitEventUnsafe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose(){
|
|
||||||
ProcessExited = null;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void owner_FormClosing(object sender, FormClosingEventArgs e){
|
private void owner_FormClosing(object sender, FormClosingEventArgs e){
|
||||||
if (currentProcess != null){
|
if (currentProcess != null){
|
||||||
currentProcess.Exited -= process_Exited;
|
currentProcess.Exited -= process_Exited;
|
||||||
@@ -103,6 +157,9 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
|
|
||||||
currentProcess.Dispose();
|
currentProcess.Dispose();
|
||||||
currentProcess = null;
|
currentProcess = null;
|
||||||
|
|
||||||
|
currentPipe.Dispose();
|
||||||
|
currentPipe = null;
|
||||||
|
|
||||||
owner.InvokeAsyncSafe(TriggerProcessExitEventUnsafe);
|
owner.InvokeAsyncSafe(TriggerProcessExitEventUnsafe);
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,6 @@ namespace TweetDuck{
|
|||||||
|
|
||||||
public static uint WindowRestoreMessage;
|
public static uint WindowRestoreMessage;
|
||||||
public static uint SubProcessMessage;
|
public static uint SubProcessMessage;
|
||||||
public static uint VideoPlayerMessage;
|
|
||||||
|
|
||||||
private static readonly LockManager LockManager = new LockManager(Path.Combine(StoragePath, ".lock"));
|
private static readonly LockManager LockManager = new LockManager(Path.Combine(StoragePath, ".lock"));
|
||||||
private static bool HasCleanedUp;
|
private static bool HasCleanedUp;
|
||||||
@@ -77,7 +76,6 @@ namespace TweetDuck{
|
|||||||
|
|
||||||
WindowRestoreMessage = Comms.RegisterMessage("TweetDuckRestore");
|
WindowRestoreMessage = Comms.RegisterMessage("TweetDuckRestore");
|
||||||
SubProcessMessage = Comms.RegisterMessage("TweetDuckSubProcess");
|
SubProcessMessage = Comms.RegisterMessage("TweetDuckSubProcess");
|
||||||
VideoPlayerMessage = Comms.RegisterMessage("TweetDuckVideoPlayer");
|
|
||||||
|
|
||||||
if (!WindowsUtils.CheckFolderWritePermission(StoragePath)){
|
if (!WindowsUtils.CheckFolderWritePermission(StoragePath)){
|
||||||
FormMessage.Warning("Permission Error", "TweetDuck does not have write permissions to the storage folder: "+StoragePath, FormMessage.OK);
|
FormMessage.Warning("Permission Error", "TweetDuck does not have write permissions to the storage folder: "+StoragePath, FormMessage.OK);
|
||||||
|
@@ -797,7 +797,6 @@
|
|||||||
var playVideo = function(url){
|
var playVideo = function(url){
|
||||||
$('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
|
$('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
|
||||||
$TD.playVideo(null);
|
$TD.playVideo(null);
|
||||||
$(this).remove();
|
|
||||||
}).appendTo(app);
|
}).appendTo(app);
|
||||||
|
|
||||||
$TD.playVideo(url);
|
$TD.playVideo(url);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Video.Controls;
|
using TweetDuck.Video.Controls;
|
||||||
@@ -12,6 +13,7 @@ namespace TweetDuck.Video{
|
|||||||
|
|
||||||
private readonly IntPtr ownerHandle;
|
private readonly IntPtr ownerHandle;
|
||||||
private readonly string videoUrl;
|
private readonly string videoUrl;
|
||||||
|
private readonly DuplexPipe pipe;
|
||||||
|
|
||||||
private readonly ControlWMP player;
|
private readonly ControlWMP player;
|
||||||
private bool wasCursorInside;
|
private bool wasCursorInside;
|
||||||
@@ -20,11 +22,13 @@ namespace TweetDuck.Video{
|
|||||||
|
|
||||||
private WindowsMediaPlayer Player => player.Ocx;
|
private WindowsMediaPlayer Player => player.Ocx;
|
||||||
|
|
||||||
public FormPlayer(IntPtr handle, int volume, string url){
|
public FormPlayer(IntPtr handle, int volume, string url, string token){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.ownerHandle = handle;
|
this.ownerHandle = handle;
|
||||||
this.videoUrl = url;
|
this.videoUrl = url;
|
||||||
|
this.pipe = DuplexPipe.CreateClient(token);
|
||||||
|
this.pipe.DataIn += pipe_DataIn;
|
||||||
|
|
||||||
player = new ControlWMP{
|
player = new ControlWMP{
|
||||||
Dock = DockStyle.Fill
|
Dock = DockStyle.Fill
|
||||||
@@ -54,6 +58,18 @@ namespace TweetDuck.Video{
|
|||||||
Player.URL = videoUrl;
|
Player.URL = videoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pipe_DataIn(object sender, DuplexPipe.PipeReadEventArgs e){
|
||||||
|
switch(e.Key){
|
||||||
|
case "die":
|
||||||
|
timerSync.Stop();
|
||||||
|
Visible = false;
|
||||||
|
pipe.Write("rip");
|
||||||
|
|
||||||
|
Close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void player_PlayStateChange(int newState){
|
private void player_PlayStateChange(int newState){
|
||||||
WMPPlayState state = (WMPPlayState)newState;
|
WMPPlayState state = (WMPPlayState)newState;
|
||||||
|
|
||||||
@@ -134,7 +150,7 @@ namespace TweetDuck.Video{
|
|||||||
|
|
||||||
private void timerData_Tick(object sender, EventArgs e){
|
private void timerData_Tick(object sender, EventArgs e){
|
||||||
timerData.Stop();
|
timerData.Stop();
|
||||||
Comms.BroadcastMessage(Program.VideoPlayerMessage, new UIntPtr((uint)trackBarVolume.Value), ownerHandle);
|
pipe.Write("vol", trackBarVolume.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void progressSeek_MouseDown(object sender, MouseEventArgs e){
|
private void progressSeek_MouseDown(object sender, MouseEventArgs e){
|
||||||
|
@@ -13,9 +13,6 @@ namespace TweetDuck.Video{
|
|||||||
public const int CODE_OWNER_GONE = 5;
|
public const int CODE_OWNER_GONE = 5;
|
||||||
public const int CODE_USER_REQUESTED = 6;
|
public const int CODE_USER_REQUESTED = 6;
|
||||||
|
|
||||||
private static uint? message;
|
|
||||||
public static uint VideoPlayerMessage => message ?? (message = Comms.RegisterMessage("TweetDuckVideoPlayer")).Value;
|
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
private static int Main(string[] args){
|
private static int Main(string[] args){
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
@@ -24,17 +21,19 @@ namespace TweetDuck.Video{
|
|||||||
IntPtr ownerHandle;
|
IntPtr ownerHandle;
|
||||||
int defaultVolume;
|
int defaultVolume;
|
||||||
string videoUrl;
|
string videoUrl;
|
||||||
|
string pipeToken;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
ownerHandle = new IntPtr(int.Parse(args[0], NumberStyles.Integer, CultureInfo.InvariantCulture));
|
ownerHandle = new IntPtr(int.Parse(args[0], NumberStyles.Integer, CultureInfo.InvariantCulture));
|
||||||
defaultVolume = int.Parse(args[1], NumberStyles.Integer, CultureInfo.InvariantCulture);
|
defaultVolume = int.Parse(args[1], NumberStyles.Integer, CultureInfo.InvariantCulture);
|
||||||
videoUrl = new Uri(args[2], UriKind.Absolute).AbsoluteUri;
|
videoUrl = new Uri(args[2], UriKind.Absolute).AbsoluteUri;
|
||||||
|
pipeToken = args[3];
|
||||||
}catch{
|
}catch{
|
||||||
return CODE_INVALID_ARGS;
|
return CODE_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
Application.Run(new FormPlayer(ownerHandle, defaultVolume, videoUrl));
|
Application.Run(new FormPlayer(ownerHandle, defaultVolume, videoUrl, pipeToken));
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Console.Out.WriteLine(e.Message);
|
Console.Out.WriteLine(e.Message);
|
||||||
return CODE_LAUNCH_FAIL;
|
return CODE_LAUNCH_FAIL;
|
||||||
|
Reference in New Issue
Block a user