Error while setting volume on SoundEffectInstance - silverlight

I am seeing an error be reported quite frequently in my application. I know where it is happening, I just don't know why. The app plays sound effects (not background music), I am using Xna.Audio and I have a timer to call FrameworkDispatcher.Update() in regular intervals. I am using SoundEffect.CreateInstance so I can I have the sound effect loop. It looks like an error happens when changing the volume. I don't know WHY though. Are there known instances when this can fail?
Function ::: Offset
xxx_RaiseException ::: 32
WatsonUnhandledManagedException ::: 300
Dbg_NotifyManagedException ::: 136
FirstPassException ::: 1044
TransitionStub ::: 0
Microsoft.Xna.Framework.Helpers.ThrowExceptionFromErrorCode ::: 76
Microsoft.Xna.Framework.Audio.SoundEffectInstance.set_Volume ::: 232
Microsoft.Xna.Framework.Audio.SoundEffectInstance..ctor ::: 232
Microsoft.Xna.Framework.Audio.SoundEffect.CreateInstance ::: 192
AgiliTrain.PhoneyTools.Media.SoundEffectPlayer..ctor ::: 96
WildSafari.ClassicModeGame.animalVisibleTimer_Tick ::: 344
...snip....
For those asking, here is more code. The SoundEffectPlayer takes a SoundEffect, creates an instance, and kicks off the XNA FrameworkDispatcher (via the GameTimer). This code is taken from PhoneyTools, so go check out the codeplex project if you need more context. When I want to play an effect, I just new up a SoundEffectPlayer, and pass in what I want.
public class SoundEffectPlayer
{
GameTimer _xnaTimer = new GameTimer();
SoundEffectInstance _effect = null;
public float _duration;
public SoundEffectPlayer(SoundEffect effect, bool loop)
{
_effect = effect.CreateInstance();
_effect.IsLooped = loop;
_duration = (float)effect.Duration.TotalSeconds;
}
public void Play(float volume)
{
_xnaTimer.Start();
_effect.Play();
_effect.Volume = volume;
}
public void Stop()
{
_effect.Stop(true);
_xnaTimer.Stop();
}
}
public class GameTimer
{
DispatcherTimer _timer = new DispatcherTimer()
{
Interval = TimeSpan.FromMilliseconds(50),
};
public GameTimer()
{
_timer.Tick += new EventHandler(_timer_Tick);
}
void _timer_Tick(object sender, EventArgs e)
{
FrameworkDispatcher.Update();
}
public void Start()
{
if (!_timer.IsEnabled) _timer.Start();
}
public void Stop()
{
if (_timer.IsEnabled) _timer.Stop();
}
}

Trying to help out, although i don't have a valid fix...
The setter property for SoundEffectInstance is not as simple as one might think:
set
{
lock (this.voiceHandleLock)
{
if (this.IsDisposed)
{
throw new ObjectDisposedException(base.GetType().Name, FrameworkResources.ObjectDisposedException);
}
if ((value < 0f) || (value > 1f))
{
throw new ArgumentOutOfRangeException("value");
}
Helpers.ThrowExceptionFromErrorCode(SoundEffectUnsafeNativeMethods.SetVolume(this.voiceHandle, value));
this.currentVolume = value;
}
}
Basically the part we're after comes in the line before last.
If the call from SoundEffectUnsafeNativeMethods.SetVolume returns any code smaller than 0, the exception you're getting will be triggered.
Here's what's happening inside the unsafe method:
public static unsafe int modopt(IsLong) SetVolume(uint soundEffectInstanceHandle, float volume)
{
lock (SoundEffectSubsystemSyncObject)
{
if ((soundEffectInstanceHandle != 0) && (soundEffectInstanceHandle != uint.MaxValue))
{
CHandleTable* tablePtr = ?g_pTable#CHandleTable##0PAV1#A;
KernelSoundEffectInstance* instancePtr = CHandleTable.LookUp<class Microsoft::Xna::Framework::Audio::KernelSoundEffectInstance>((CHandleTable modopt(IsConst)* modopt(IsConst) modopt(IsConst)) ?g_pTable#CHandleTable##0PAV1#A, soundEffectInstanceHandle, 0);
if (instancePtr == null)
{
return -2147024809;
}
return **(((int*) instancePtr))[0x34](instancePtr, volume);
}
return -2147024809;
}
}
You can try to surround the creation of _effect.CreateInstance with try...catch and rethrow a more comprehensive and helpful exception that will contain for example, information about the SoundEffect object which you're trying to create (basically you can note down all of its field's values for inspection. (not sure that what you get from MS is only a stack trace or the actual exception messaage).
It seems that on WP7, the call to set the volume goes to some OS pointer table that does some magic behind the scenes and looks for the sound effect handle in this table.
If for some reason it is not found or something similar (don't know why, maybe we can take it with XNA developers), it will throw this exception you're getting.
I know this is not a solution but maybe this is a step in the right direction.

Generally, the exception should not be thrown for the situation you are describing, as long as you built the XNA compatibility layer as it should be (details here).
However, I noticed that you are using PhoneyTools.Media.SoundEffectPlayer - what for? It might be the cause of the problem in your situation.
Also, you seem to have ambiguous references - effect and _effect - which one are you working with when playing content?

Related

in flink processFunction, all mapstate is empty in onTimer() function

I want implements the aggregationFunction by the processKeyedFunction, because the default aggregationFunction does not support rich function,
Besides, I tryed the aggreagationFunction + processWindowFunction(https://ci.apache.org/projects/flink/flink-docs-stable/dev/stream/operators/windows.html), but it also cannot satisfy my needs, so I have to use the basic processKeyedFunction to implement the aggregationFunction, the detail of my problem is as followed:
in processFunction, , I define a windowState for stage the aggregation value of elements, the code is as followed:
public void open(Configuration parameters) throws Exception {
followCacheMap = FollowSet.getInstance();
windowState = getRuntimeContext().getMapState(windowStateDescriptor);
currentTimer = getRuntimeContext().getState(new ValueStateDescriptor<Long>(
"timer",
Long.class
));
in processElement() function, I use the windowState (which is a MapState initiate in open function) to aggregate the window element, and register the first timeServie to clear current window state, the code is as followed:
#Override
public void processElement(FollowData value, Context ctx, Collector<FollowData> out) throws Exception
{
if ( (currentTimer==null || (currentTimer.value() ==null) || (long)currentTimer.value()==0 ) && value.getClickTime() != null) {
currentTimer.update(value.getClickTime() + interval);
ctx.timerService().registerEventTimeTimer((long)currentTimer.value());
}
windowState = doMyAggregation(value);
}
in onTimer() function, first, I register the next timeService in next One minute, and clear the window State
#Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<FollowData> out) throws Exception {
currentTimer.update(timestamp + interval); // interval is 1 minute
ctx.timerService().registerEventTimeTimer((long)currentTimer.value());
out.collect(windowState);
windowState.clear();
}
but when the program is running , I found that all the windowState in onTimer is empty, but it is not empyt in processElement() function, I don't know why this happens, maybe the execution logic is different, how can I fix this,
Thanks in advance !
new added code about doMyAggregation() part
windowState is a MapState , key is "mykey", value is an self-defined Object AggregateFollow
public class AggregateFollow {
private String clicked;
private String unionid;
private ArrayList allFollows;
private int enterCnt;
private Long clickTime;
}
and the doMyAggregation(value) function is pretty much like this , the function of doMyAggregation is to get all the value whose source field is 'follow', but if there are no values whose field is 'click' during 1 minute, the 'follow' value should be obsolete, in a word , it's like a join operation of 'follow' data and 'click' data,
AggregateFollow acc = windowState.get(windowkey);
String flag = acc.getClicked();
ArrayList<FollowData> followDataList = acc.getAllFollows();
if ("0".equals(flag)) {
if ("follow".equals(value.getSource())) {
followDataList.add(value);
acc.setAllFollows(followDataList);
}
if ("click".equals(value.getSource())) {
String unionid = value.getUnionid();
clickTime = value.getClickTime();
if (followDataList.size() > 0) {
ArrayList listNew = new ArrayList();
for (FollowData followData : followDataList) {
followData.setUnionid(unionid);
followData.setClickTime(clickTime);
followData.setSource("joined_flag"); //
}
acc.setAllFollows(listNew);
}
acc.setClicked("1");
acc.setUnionid(unionid);
acc.setClickTime(clickTime);
windowState.put(windowkey, acc);
}
} else if ("1".equals(flag)) {
if ("follow".equals(value.getSource())) {
value.setUnionid(acc.getUnionid());
value.setClickTime(acc.getClickTime());
value.setSource("joined_flag");
followDataList.add(value);
acc.setAllFollows(followDataList);
windowState.put(windowkey, acc);
}
}
because of performance problem, original windowAPI is not a valid choice for me, the only way here I think is to use processFunction + ontimer and Guava Cache ,
Thanks a lot
If windowState is empty, it would be helpful to see what doMyAggregation(value) is doing.
It's difficult to debug this, or propose good alternatives, without more context, but out.collect(windowState) isn't going to work as intended. What you might want to do instead would be to iterate over this MapState and collect each key/value pair it contains to the output.
I changed the type of windowState from MapState to ValueState, and the problem is solved, maybe it is a bug or something, can anyone can explain this?

issues with BackGround worker across classes

this is my first question in this forum, hope it will not be duplicated somewhere because i have searched for the respons for almost 4 weeks without making any progress.
here is my situation,
im developing an application that need to do a lot of background operation, for that reason i creat 2 BKW, the first one used to load data from a DB and put it inside an observable collection , 'no need to report progress or support cancelation for this one' :
private Boolean loadTestSteps()
{
// Create a background worker thread that don't report progress and does not
// support cancelation
BackgroundWorker wk_LoadTestSteps = new BackgroundWorker();
wk_LoadTestSteps.DoWork += new DoWorkEventHandler(wk_LoadTestSteps_DoWork);
wk_LoadTestSteps.RunWorkerAsync();
return true;
}
observable collection class :
public class clsTestStep : DependencyObject
{
public static DependencyProperty TestStepProperty = DependencyProperty.Register(
"TestStep", typeof(String), typeof(clsTestStep));
public string TestStep
{
get { return (string)GetValue(TestStepProperty); }
set { SetValue(TestStepProperty, value); }
} and so on for the rest of items....
now the main backGround that should do the longer operation and in the same time report the progress to the main UI ,declared like so
private void InitializeBackGroundWork()
{
_wk_StartTest = new BackgroundWorker();
// Create a background worker thread that ReportsProgress &
// SupportsCancellation
// Hook up the appropriate events.
_wk_StartTest.DoWork += new DoWorkEventHandler(_wk_StartTest_DoWork);
_wk_StartTest.ProgressChanged += new ProgressChangedEventHandler
(_wk_StartTest_ProgressChanged);
_wk_StartTest.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(_wk_StartTest_RunWorkerCompleted);
_wk_StartTest.WorkerReportsProgress = true;
_wk_StartTest.WorkerSupportsCancellation = true;
_wk_StartTest.RunWorkerAsync();
}
in the do work events, exactly in the foreach loop i encontered an error saying : you cannot access this object because another thread own it :
void _wk_StartTest_DoWork(object sender, DoWorkEventArgs e)
{
//Loop through each test step and perform Test
foreach (clsTestStep item in _testStep)
{
Thread.Sleep(200);
temp[0] = item.TestStep;
temp[1] = item.Delay.ToString();
temp[2] = item.NumberRepetition.ToString();
temp[3] = item.Mode.ToString();
//Report % of Progress, Test step Name,and the paragraph from Class PerformTest
_wk_StartTest.ReportProgress(counter,
temp[0]);
counter += 1;
_performTest.Fdispatcher(temp, out _paragraph);
//_si.PgBarMax = Convert.ToDouble(_testStep.Count);
}
//Report completion on operation completed
_wk_StartTest.ReportProgress(counter);
}
what im missing here please, because my head is gonna explod from searching !!!
It sounds like your ObservableCollection is created and so owned by an other thread so your _wk_StartTest_DoWork method can't access it.
Where your _testStep variable comes from ?
By the way, in a multithread environment when many thread access the same data you should prefer the use of ConcurrentBag class instead of an ObservableCollection. ConcurrentBag is thread safe.
for the ones that may enconter this kind of problem ^^
finnaly i have found a way to acess class even if its not owned by the current thread here a nice article explaining step by step how to do this here

Remove a ScreenSpaceLines3D Object from a ViewPort?

I am making a 3D Game with WPF in VB, and I am using a ScrennSpaceLines3D Object I found
http://3dtools.codeplex.com/releases/view/2058
but when I try to remove a line I added to the viewport by using
mainViewport.Children.RemoveAt(i)
it gives a NullExceptionError. I have read that this is because it does not totally come off the rendering queue. There have been fixes for c#, but I have yet to find one that works with VB. Is there a way to make this work or possibly draw a line in 3D space some other way? I find it quite ridiculous that VB doesn't even have a way to easily draw 3D lines...
Remove ScreenSpaceLines3D :
foreach (ScreenSpaceLines3D line3D in lines3DList)
{
lines3D.Points.Clear(); // Very importante
_viewport3D.Children.Remove(lines3D);
}
I'm a bit late to the party but i'm having the same issues.
The access violation occurs because each instance registers an event handler to the Rendering event of the composition target
public ScreenSpaceLines3D()
{
...
CompositionTarget.Rendering += OnRender; // <-- this line
}
but forgets to remove it when the instance is removed from the scene.
So to fix this you need to touch the source code:
public ScreenSpaceLines3D()
{
...
// event registration removed
}
private bool AttachedToCompositionTargetRendering { get; set; }
protected override void OnVisualParentChanged(DependencyObject oldParent)
{
base.OnVisualParentChanged(oldParent);
var parent = VisualTreeHelper.GetParent(this);
if (parent == null)
{
if (AttachedToCompositionTargetRendering)
{
CompositionTarget.Rendering -= OnRender;
AttachedToCompositionTargetRendering = false;
}
}
else
{
if (!AttachedToCompositionTargetRendering)
{
CompositionTarget.Rendering += OnRender;
AttachedToCompositionTargetRendering = true;
}
}
}

Making smooth effect in WPF manually in C# with DispatcherTimer

I'm trying to make pretty effect with not using Storyboard or another ready/already done stuff in WPF.
I want to make smooth effect, where on some event (like click) the UI element resizes for 2-3 seconds and bluring with changing color. All these items I want to make in smooth pretty way.
I have prepared such class to render each frame of my effect:
public static class ApplicationHelper
{
[SecurityPermissionAttribute(SecurityAction.Demand,
Flags=SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents(DispatcherPriority priority)
{
DispatcherFrame frame = new DispatcherFrame();
DispatcherOperation oper = Dispatcher.CurrentDispatcher.
BeginInvoke(priority,
new DispatcherOperationCallback(ExitFrameOperation),
frame);
Dispatcher.PushFrame(frame);
if (oper.Status != DispatcherOperationStatus.Completed)
{
oper.Abort();
}
}
private static object ExitFrameOperation(object obj)
{
((DispatcherFrame)obj).Continue = false;
return null;
}
[SecurityPermissionAttribute(SecurityAction.Demand,
Flags=SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
DoEvents(DispatcherPriority.Background);
}
}
Here I'm trying to make it work with DispatcherTimer:
void vb1_click(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 0, 0, 500);
dt.Tick += new System.EventHandler(dt_Tick);
dt.Start();
}
void dt_Tick(object sender, System.EventArgs e)
{
for(int i = 0; i < 20; i++)
{
this.vb2_blur_eff.Radius = (double)i;
ApplicationHelper.DoEvents();
}
}
The main problem is, that when I'm launcing it, I'm only waiting and at the final time ( when must last frame be rendered ) , I'm getting in a very quick speed all frames, but perviously there was nothing.
How to solve it and make perfect smooth effect in pure C# way with not using some ready/done stuff?
Thank you!
The ApplicationHelper.DoEvents() in dt_Tick probably does nothing, since there are no events to process. At least not the ones you're probably expecting.
If I'm not mistaken, your code will just quickly set the Radius to 0, then 1, 2, and so on in quick succession, and finally to 19. All of that will happen every 500 milliseconds (on every Tick, that is).
I think you might believe that each Tick will only set Radius to one value and then wait for the next Tick, but it does not. Every Tick will set the Radius to all the values, ending at 19. That is one possible explanation for what you're experiencing.
I would also like to comment on the DoEvents approach. It's most likely a bad idea. Whenever I see a DoEvents I get chills up my spine. (It reminds me of some seriously bad Visual Basic 5/6 code I stumbled across 10-15 years ago.) As I see it, an event handler should return control of the GUI thread as quickly as possible. If the operation takes a not insignificant amount of time, then you should delegate that work to a worker thread. And nowadays, you have plenty of options for writing asynchronous code.

OnPropertyChanged reaction different the first time and the second time

I have got a collection of viewModels(InputViewModel) in an other viewModel(ScenarioManager).
each InputviewModel has an instance of a Class(RestOfInput) which contains properties able to raise the OnPropertyChanged.
when one of these properties changes the event is handled by this method (in InputViewModel) :
public void TestAfterChanges(object sender, PropertyChangedEventArgs e)
{
MessageBox.Show("not ref");
bool isInTheList = false;
RestOfInput roi = sender as RestOfInput;
string prop = e.PropertyName;
if (prop!="NameFile")
{
Difference d = new Difference();
d.Length = prop;
d.Value1 = reference.RoI.getValueByPropertyName(prop);
d.Value2 = roi.getValueByPropertyName(prop);
foreach (Difference diff in _ListOfDifferences)
{
if (diff.Length==prop)
{
if ( (Math.Abs(d.Value2-d.Value1)>0.001*d.Value1))
{
//replace by le new one
_ListOfDifferences.Insert(_ListOfDifferences.IndexOf(diff), d);
_ListOfDifferences.Remove(diff);
}
else
{
//if change make the field value equal to the ref then remove from difference list
_ListOfDifferences.Remove(diff);
}
isInTheList = true;
}
}
if ((Math.Abs(d.Value2 - d.Value1) > 0.001 * d.Value1) && isInTheList==false)
{
_ListOfDifferences.Add(d);
}
}
}
this method gives just a summary of the differences between this particular case and the reference case.
Now if the reference case changes I have to update all the cases and the event is handled
in ScenarioManager :
public void refCaseChanging(object sender, PropertyChangedEventArgs e)
{
MessageBox.Show("ref");
string propname = e.PropertyName;
foreach (InputViewModel item in _casesList)
{
if (item!=inpVM)
{
item.RoI.OnPropertyChanged(propname);
}
}
}
inpVM is the reference case.
Then I have this behavior :
-if I change a field in a case which is not the reference case : everything is ok.
-if I change a particular field in the reference case : the first time, everything is ok.
But the second time, only the reference case and the first case (in the collection) which is not the reference case are updated>
It is like the foreach loop is broken..
Any explications.
If the message is not clear please tell me ( not easy to explain ;) )
An exception could explain that processing stops (although one expects that it would be caught and displayed somewehre).
Have you tried to ask VS to halt your program when an exception is thrown ? (if you have never done this before, go to Debug / Exceptions and check the check box for CLR exceptions)

Resources