# playSoundClip Repeatedly

**URL:** <https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345>\
**Category:** Ignition\
**Tags:** ignition79, ignition81, vision\
**Created:** [August 29, 2024, 7:55pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345 "2024-08-29T19:55:35Z")\
**Posts on this page:** 17\
**Page:** 2

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [September 3, 2024, 1:21pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/21 "2024-09-03T13:21:44Z")

</div>

Ya, that took care of it. Both

```python
not initialChange

```

and

```python
previousValue.value is not None

```

worked and produced the same result. I didn't think to put the initial change back in there, since I had to remove it previously to get it to start working.

Thanks

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [September 4, 2024, 4:43pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/22 "2024-09-04T16:43:22Z")

</div>

So, I went with the recursion solution here, but I've seen that there is a Java max recursion depth. Assuming that the alarms are never acknowledged and the count remains non-0 "forever" - what would be the best way to handle that?

I've added a try, except to my recursive call, but what happens at the point that the last call hits that max recursion error? I'd imagine that it just stops.

```python
if EN and area == 0:
		if count > 0:
			fileNames = options.getColumnAsList(1)
			if selection and selection in fileNames:
				wavFile = path + '\\' + selection + '.wav'
				system.util.playSoundClip(wavFile, volume/100.0, True)
				
				try:
					playAlarmSoundLoop()
				except:
					system.gui.errorBox(count+' Unacked Alarms. Please Ack', 'Unacked Alarms Error')
					return
				
			else:
				return
		else:
			return
	else:
		return

```

Simple solution for now, is just throw an error box.

---

<div class="post-metadata">

**Author:** ![Zach\_Larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zach_larson/32/54388_2.png) [@Zach\_Larson](https://forum.inductiveautomation.com/u/Zach_Larson)\
**Post date:** [September 4, 2024, 4:57pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/23 "2024-09-04T16:57:55Z")

</div>

> [@pturmel](#):
>
> A wave file has a close correlation between size and duration. Estimate duration, add a partial second, save that timestamp for deferring interim status checks.
> 
> (Use a client timer script to check conditions.)

Whenever in doubt, I think review any post that PTurmel has given you.

It is efficient, eliminates waits.

---

<div class="post-metadata">

**Author:** ![michael.flagler](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/michael.flagler/32/26272_2.png) [@michael.flagler](https://forum.inductiveautomation.com/u/michael.flagler)\
**Post date:** [September 4, 2024, 5:28pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/24 "2024-09-04T17:28:28Z")

</div>

I believe you need to be calling the `playAlarmSoundLoop` function asynchronously instead of synchronously/directly like you're doing. I would think that would escape this recursion, but I personally don't know that for certain.

```python
system.util.invokeAsynchronous(playAlarmSoundLoop)

```

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [September 4, 2024, 6:11pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/25 "2024-09-04T18:11:32Z")

</div>

The first call is async. Does each successive call need to be async as well?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 4, 2024, 6:17pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/26 "2024-09-04T18:17:22Z")

</div>

Each async call will reset the stack depth. Recursive calls on the same thread = the same stack.

---

<div class="post-metadata">

**Author:** ![michael.flagler](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/michael.flagler/32/26272_2.png) [@michael.flagler](https://forum.inductiveautomation.com/u/michael.flagler)\
**Post date:** [September 4, 2024, 6:17pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/27 "2024-09-04T18:17:37Z")

</div>

Yes, as that should essentially put that call on a separate thread and the current thread would close out.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [September 4, 2024, 6:18pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/28 "2024-09-04T18:18:54Z")

</div>

How does the current thread close out if the recursive call never returns? Is the thread able to detect the recursion and close?

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [September 5, 2024, 2:01pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/29 "2024-09-05T14:01:52Z")

</div>

> [@amarks](#):
>
> ```python
> if EN and area == 0:
> if count > 0:
> fileNames = options.getColumnAsList(1)
> if selection and selection in fileNames:
> wavFile[...]
> 
> ```

I would negate the if statements to reduce nesting depth:

```python
if not EN or area != 0:
	return
elif count <= 0:
	return
fileNames = options.getColumnAsList(1)
if selection and selection in fileNames:
	wavFile [...]

```

---

<div class="post-metadata">

**Author:** ![michael.flagler](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/michael.flagler/32/26272_2.png) [@michael.flagler](https://forum.inductiveautomation.com/u/michael.flagler)\
**Post date:** [September 5, 2024, 2:15pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/30 "2024-09-05T14:15:03Z")

</div>

When you call something asynchronously, the current thread/script doesn't wait for a return. If you needed it to return something you'd have to pass a return function that would be called separately once the called function returns, but in this case, you just need to fire and forget, so it fires off the call and exits/returns.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [September 5, 2024, 2:23pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/31 "2024-09-05T14:23:02Z")

</div>

I understand that the thread doesn't _wait_ for the return. I guess I don't understand threading. Wouldn't you end up with thousands of threads that are waiting to close? How does the thread know when to close?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 5, 2024, 2:26pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/32 "2024-09-05T14:26:04Z")

</div>

The thread dies when whatever function it was executing stops (when execution reaches the end).

---

<div class="post-metadata">

**Author:** ![Zach\_Larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zach_larson/32/54388_2.png) [@Zach\_Larson](https://forum.inductiveautomation.com/u/Zach_Larson)\
**Post date:** [September 6, 2024, 7:23pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/33 "2024-09-06T19:23:09Z")

</div>

Why choose asynchronous and recursion over triggers?

You could reduce the overhead, eliminate race conditions, and never risk overflow by triggering the next at the end.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [September 6, 2024, 7:34pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/34 "2024-09-06T19:34:46Z")

</div>

and where would that "end" be?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 6, 2024, 8:07pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/35 "2024-09-06T20:07:18Z")

</div>

When the code runs out? You're passing a defined function to `system.util.invokeAsynchronous`. When it's run out of instructions to run, it'll stop. As long as you're not doing something like `while(True):` inside your script, it'll die as normal.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [September 6, 2024, 8:18pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/36 "2024-09-06T20:18:36Z")

</div>

ok, so the invokeAsync call will start the new call but the thread that called it will just continue on in the code, not waiting for the return to continue execution - so it'll hit the end of the script in this case.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 6, 2024, 8:21pm UTC](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345/37 "2024-09-06T20:21:50Z")

</div>

Yes. That's the whole point of the "asynchronous" part - it doesn't block the flow of execution through the _calling_ script.

[Previous page](https://forum.inductiveautomation.com/t/playsoundclip-repeatedly/95345.md?page=1)
