I am using the following code to jump to a particular time location in the video
private void button1_Click(object sender, EventArgs e)
{
var replay = new Uri(#"Test.wmv");
var converted_url = replay.AbsoluteUri;
axVLCPlugin21.playlist.add(converted_url);
axVLCPlugin21.playlist.play();
axVLCPlugin21.input.time = 10000; // Jump to 10th second
}
Which works fine. But when the video is being written simultaneously while being displayed the code doesn't work and the video starts from zeroth second without throwing an error. Can someone suggest what's wrong or how to debug the code?
Related
I have a Windows forms application that I am trying to add accessibility to and have run into an issue with the speech synthesizer where it appears that the SpeechAsyncCancelAll runs in the user interface thread. Performance is totally dependent on the power of the PC.
This can be reproduced with a very simple application in Windows forms.
Create a form and add a numeric up down control. Then use this code:
using System.Windows.Forms;
using System.Speech;
using System.Speech.Synthesis;
namespace WindowsFormsApp8
{
public partial class Form1 : Form
{
SpeechSynthesizer _speech = new SpeechSynthesizer();
public Form1()
{
InitializeComponent();
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(numericUpDown1.Value.ToString());
}
}
}
On my development machine which is very powerful it runs without a problem and very fast when you hold down the up arrow. Each value is cancelled so you do not hear anything as the control increments and when you stop pressing the up arrow it announces the last value properly.
However, the minute this is run on a lesser PC, even a core i9 hexacore machine, the repeat on the increment slows to a crawl.
It looks to me that this is running on the user interface thread.
Any suggestions?
Thanks
Don't get yourself tricked by the "Async" in the name of the SpeakAsyncCancelAll() method name. As one can see in the source code of the SpeechSynthesizer and VoiceSynthesis classes, there is quite some synchronous code involved in order to communicate with a background thread that does the actual voice synthesis. This code is actually quite heavy in that it uses multiple lock statements.
A best practice solution for this situation (multiple successive user interactions could create a series of code reactions but in the end we only want the last one) is to not directly start the reaction, but start a timer and only perform the reaction if there was no other user interaction in the meantime.
public partial class Form1 : Form
{
private SpeechSynthesizer _speech = new SpeechSynthesizer();
public Form1()
{
InitializeComponent();
timer1.Interval = 500;
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
// Reset timer
timer1.Stop();
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(numericUpDown1.Value.ToString());
}
}
You should allow the user to configure the timer interval to chose a good compromise based on their system performance and their individual usage patterns. People who need audio assistance often consider for good reasons a too long delay between user activity and an audio response as wasting their time. So it is important that users can configure such a delay to best fit their individual needs.
Let's assume you have taken Neil's excellent comment into consideration, and checked the repeat rate of the NumericUpDown control on the other PCs "without" calling the speech engine. Good.
Your code looks right. The SpeakAsyncCancelAll and SpeakAsync do not block and are "expected" to be running on a background thread. When I attempted to reproduce the problem (not a shocker) your code works fine on my PC using the test condition you describe. That being the case, maybe you could try a couple of variations on the slim chance that something makes a difference and yields some kind of clue by ruling out some unlikely issues.
Variation 1
Capture the "text to say" and post the work using BeginInvoke. This ensures that nothing could possibly be interfering with the ValueChanged or MouseDown messages from pumping in the message queue.
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
// Make 100% sure that the up-down ctrl is decoupled from speak call.
var say = $"{numericUpDown1.Value}";
// Ruling out an unlikely problem
BeginInvoke((MethodInvoker)delegate
{
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(say);
});
}
Variation 2
Since you have a suspicion that something is running on the UI thread that shouldn't be, go ahead and give explicit instructions to post it on a background Task. At least we can rule that out.
private void numericUpDown2_ValueChanged(object sender, EventArgs e)
{
// Make 100% sure that the up-down ctrl is decoupled from speak call.
var say = $"{numericUpDown2.Value}";
// Ruling out an unlikely problem
Task.Run(() =>
{
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(say);
});
}
Variation 3 - Inspired by NineBerry's answer (added to test code project repo)
/// <summary>
/// Watchdog timer inspired by NineBerry.
/// https://stackoverflow.com/a/74975629/5438626
/// Please accept THAT answer if this solves your issue.
/// </summary>
int _changeCount = 0;
private void numericUpDown3_ValueChanged(object sender, EventArgs e)
{
var captureCount = ++_changeCount;
var say = $"{numericUpDown3.Value}";
Task
.Delay(TimeSpan.FromMilliseconds(250))
.GetAwaiter()
.OnCompleted(() =>
{
if(captureCount.Equals(_changeCount))
{
Debug.WriteLine(say);
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(say);
}
});
}
Well the above answers do not solve the issue. However, all the tested computers were dell computers. By default when the OS is installed, Dell installs a sound utility called MaxWaves which allows different audio enhancements. Although all options are off in this utility, it appears that it buffers the sound and when an Async.CancelAll() call comes, it blocks until the sound duration is complete. Therefore everything appears to slow to a crawl.
Uninstalling this utility as well as disabling it as a service corrects the problem.
Everything now works correctly. Thank you for your answers.
I have the latest version of CefSharp installed and when I call ViewSource(), it opens up a notepad window with the source code. But when I call GetSourceAsync() the code is very different and missing the HTML I need in the var html that is shown in the Notepad window. The only work around would be to somehow copy the contents of the code in Notepad into my app and use it. Does anyone know how to get the html as shown in the NotePad window? I'm running the application in the Windows 7 Pro operating system using Visual Studio 2017 Express. Here is my code...
private void WebBrowserFrameLoadEndedAsync(object sender, FrameLoadEndEventArgs e)
{
chromeBrowser.ViewSource();
chromeBrowser.GetSourceAsync().ContinueWith(taskHtml =>
{
var html = taskHtml.Result;
});
}
}
Here is the web page that the browser goes to...
chromeBrowser = new ChromiumWebBrowser("https://www.amazon.com/product-reviews/B084RCFDJ3/ref=acr_search_hist_5?ie=UTF8&filterByStar=five_star&reviewerType=all_reviews#reviews-filter-bar");
It turns out, I was searching the source for the wrong phrase. So now I just call the following...
string source = await chromeBrowser.GetBrowser().MainFrame.GetSourceAsync();
I've gone into detail on the difference between GetSource and ViewSource further down.
Some important things to note about FrameLoadEnd.
Is called for every frame, if your page has multiple frames then it will be called multiple times
It's called when the initial resources have finished loading, if your website is dynamically created/rendered then your call maybe happening too early.
//FrameLoadEnd is called for every frame, if your page has multiple frames then it will be called multiple times.
private async void BrowserFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
{
var frame = e.Frame;
var source = await frame.GetSourceAsync();
}
//To only get the main frame source
private async void BrowserFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
{
var frame = e.Frame;
if (frame.IsMain)
{
var source = await frame.GetSourceAsync();
}
}
// If your website dynamically generates content then you might need to wait a
// little longer for it to render. Introduce a fixed wait period, this can be
// problematic for a number of reasons.
private async void BrowserFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
{
var frame = e.Frame;
if (frame.IsMain)
{
// Wait a little bit of time for the page to load
await System.Threading.Tasks.Task.Delay(500);
var source = await frame.GetSourceAsync();
}
}
Explanation of the difference in behaviour
Firstly ViewSource() returns immediately, Notepad is being launched after the GetSourceAsync call has completed.
Both methods send a GetSource message to the render process which returns a ReadOnlySharedMemoryRegion. When you read the data from the shared memory section ends up with a different snapshot in time.
void CefFrameHostImpl::ViewSource() {
SendCommandWithResponse(
"GetSource",
base::BindOnce(&ViewTextCallback, CefRefPtr<CefFrameHostImpl>(this)));
}
void CefFrameHostImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
SendCommandWithResponse("GetSource",
base::BindOnce(&StringVisitCallback, visitor));
}
CEF Source reference.
The CefFrameHostImpl::GetSource method which GetSourceAsync calls completes very quickly as it simply creates a string from the shared memory section.
The CefFrameHostImpl::ViewSource method whilst returns immediately is much slower and takes additional processing to create a file on disk, write that string, spawn notepad.
HTML Source is always a snapshot of source for a given point in time. For static web pages, time makes no difference, for dynamically rendered/updated websites a few hundred milliseconds can mean you get entirely different source.
When the shared ReadOnlySharedMemoryRegion is converted into a string means there is a subtle difference in the source you end up getting.
I'm currently using this method to play a .wav file:
private void button5_Click(object sender, System.EventArgs e)
{
System.Media.SoundPlayer player = new System.Media.SoundPlayer(Properties.Resources.Song1);
player.PlaySync();
}
It's playing the .wav file for like a second, then it stops and a few seconds later after stopping, the program freezes and closes itself without showing any errors.
Did anyone experience this too and if so, (how) did you solve it?
I'm using axWindowsMediaPlayer playlist, and have some problem - after one video end's - next playing without any pause. I cant pause or stop it even with
private void axWindowsMediaPlayer1_MediaChange(object sender, AxWMPLib._WMPOCXEvents_MediaChangeEvent e)
{
if (axWindowsMediaPlayer1.playState == WMPLib.WMPPlayState.wmppsMediaEnded)
{axWindowsMediaPlayer1.Ctlcontrols.pause(); }}
It doesn't do anything, but must stop the player. What can I do with this? Or even disable AUTOplaying next playlist file, that's would be even better.
Thx a lot for help!
I believe you should be working with the object passed into the method and additionally the PlayStateChange event like so:
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 8)
{
e.Ctlcontrols.pause();
}
}
}
UPDATE: Also I would suggest that you use the axWindowsMediaPlayer1_PlayStateChanged() event rather than Media change as this may be where the issue is occurring.
The '8' is to signify "Media Ended" which if you know how to access it another way then you of course can. If you want to use WMPLib.WMPPlayState.wmppsMediaEnded I'm sure it would yeild the same result.
Hello I am working on a WPF platform targeting .NET framework 4.5.2. I am writing a downloader for my application. Here is the code:
private void Download(Dictionary<int, FileAndLinkClass> MyLinks)
{
ApplicationDownloadThread = new Thread(() =>
{
foreach (KeyValuePair<int, FileAndLinkClass> item in MyLinks)
{
fileNo++;
WebClient myWebClient = new WebClient();
myWebClient.DownloadProgressChanged += MyWebClient_DownloadProgressChanged;
myWebClient.DownloadFileCompleted += MyWebClient_DownloadFileCompleted;
// Download the Web resource and save it into the current filesystem folder.
string downloadedFileAdress = System.IO.Path.Combine(fileLocation, $"{item.Value.FileName}");
myWebClient.DownloadFileAsync(new Uri(item.Value.Link), downloadedFileAdress);
while (myWebClient.IsBusy)
{
}
}
});
ApplicationDownloadThread.IsBackground = false;
ApplicationDownloadThread.Start();
//UnZipAndCreateUpdatePackage(MyLinks);
}
Now I want at button click the download must be paused and at another button click the download must be resumed. I tried working with .set() property of an AutoReset event and .Reset() property of the same but it didn't work.
I need help. My button click code are:
private AutoResetEvent waitHandle = new AutoResetEvent(true);
private void StartDownloadBtn_Click(object sender, RoutedEventArgs e)
{
waitHandle.Set();
}
private void StopDownloadBtn_Click(object sender, RoutedEventArgs e)
{
waitHandle.Reset();
}
I have also tried this link How to pause/suspend a thread then continue it?. nothing happens
I've also gone through Adding pause and continue ability in my downloader but I failed to incorporate the solution in my above code as I am also updating the download progress on the UI.
Well I did some more digging, apparently if for you Adding pause and continue ability in my downloader wasn't clear as the it uses byte stream data in the class. Maybe you could check out the link below, it also provides a VS solution on WPF for the downloading .zip file extensions with pause/resume/stop capabilities. Please let me know if you need some more help.
Link to CodeProject article:
C# .NET Background File Downloader