piwave 2.1.1__py3-none-any.whl → 2.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- piwave/piwave.py +43 -13
- {piwave-2.1.1.dist-info → piwave-2.1.3.dist-info}/METADATA +5 -2
- {piwave-2.1.1.dist-info → piwave-2.1.3.dist-info}/RECORD +6 -6
- {piwave-2.1.1.dist-info → piwave-2.1.3.dist-info}/WHEEL +0 -0
- {piwave-2.1.1.dist-info → piwave-2.1.3.dist-info}/licenses/LICENSE +0 -0
- {piwave-2.1.1.dist-info → piwave-2.1.3.dist-info}/top_level.txt +0 -0
piwave/piwave.py
CHANGED
|
@@ -90,7 +90,6 @@ class PiWave:
|
|
|
90
90
|
Log.config(silent=silent)
|
|
91
91
|
|
|
92
92
|
self._validate_environment()
|
|
93
|
-
atexit.register(self.cleanup)
|
|
94
93
|
|
|
95
94
|
discover_backends()
|
|
96
95
|
|
|
@@ -326,6 +325,28 @@ class PiWave:
|
|
|
326
325
|
self._stop_current_process()
|
|
327
326
|
return False
|
|
328
327
|
|
|
328
|
+
def _playback_worker_wrapper(self):
|
|
329
|
+
# wrapper for non-blocking playback
|
|
330
|
+
try:
|
|
331
|
+
wav_file = self._convert_to_wav(self.current_file)
|
|
332
|
+
if not wav_file:
|
|
333
|
+
Log.error(f"Failed to convert {self.current_file}")
|
|
334
|
+
self.is_playing = False
|
|
335
|
+
return
|
|
336
|
+
|
|
337
|
+
if not os.path.exists(wav_file):
|
|
338
|
+
Log.error(f"File not found: {wav_file}")
|
|
339
|
+
self.is_playing = False
|
|
340
|
+
return
|
|
341
|
+
|
|
342
|
+
self._play_file(wav_file)
|
|
343
|
+
except Exception as e:
|
|
344
|
+
Log.error(f"Playback error: {e}")
|
|
345
|
+
if self.on_error:
|
|
346
|
+
self.on_error(e)
|
|
347
|
+
finally:
|
|
348
|
+
self.is_playing = False
|
|
349
|
+
|
|
329
350
|
|
|
330
351
|
def _play_live(self, audio_source, sample_rate: int, channels: int, chunk_size: int) -> bool:
|
|
331
352
|
if self.is_playing or self.is_live_streaming:
|
|
@@ -443,11 +464,9 @@ class PiWave:
|
|
|
443
464
|
def _stop_current_process(self):
|
|
444
465
|
if self.current_process:
|
|
445
466
|
try:
|
|
446
|
-
Log.info("Stopping current process...")
|
|
447
467
|
os.killpg(os.getpgid(self.current_process.pid), signal.SIGTERM)
|
|
448
468
|
self.current_process.wait(timeout=5)
|
|
449
469
|
except (ProcessLookupError, subprocess.TimeoutExpired):
|
|
450
|
-
Log.warning("Forcing kill of current process")
|
|
451
470
|
try:
|
|
452
471
|
os.killpg(os.getpgid(self.current_process.pid), signal.SIGKILL)
|
|
453
472
|
except ProcessLookupError:
|
|
@@ -483,18 +502,14 @@ class PiWave:
|
|
|
483
502
|
self._log_debug("Playback worker finished")
|
|
484
503
|
|
|
485
504
|
|
|
486
|
-
def
|
|
487
|
-
Log.warning("Interrupt received, stopping playback...")
|
|
488
|
-
self.stop()
|
|
489
|
-
os._exit(0)
|
|
490
|
-
|
|
491
|
-
def play(self, source, sample_rate: int = 44100, channels: int = 2, chunk_size: int = 4096):
|
|
505
|
+
def play(self, source, sample_rate: int = 44100, channels: int = 2, chunk_size: int = 4096, blocking: bool = False):
|
|
492
506
|
"""Play audio from file or live source.
|
|
493
507
|
|
|
494
508
|
:param source: Either a file path (str) or live audio source (generator/callable/file-like)
|
|
495
509
|
:param sample_rate: Sample rate for live audio (ignored for files)
|
|
496
510
|
:param channels: Channels for live audio (ignored for files)
|
|
497
511
|
:param chunk_size: Chunk size for live audio (ignored for files)
|
|
512
|
+
:param blocking: If the playback should be blocking or not (ignored for live, always non-blocking)
|
|
498
513
|
:return: True if playback/streaming started successfully
|
|
499
514
|
:rtype: bool
|
|
500
515
|
|
|
@@ -506,7 +521,23 @@ class PiWave:
|
|
|
506
521
|
# autodetect if source is live or file
|
|
507
522
|
if isinstance(source, str):
|
|
508
523
|
# file (string)
|
|
509
|
-
|
|
524
|
+
if blocking:
|
|
525
|
+
return self._play_file(source)
|
|
526
|
+
else:
|
|
527
|
+
if self.is_playing:
|
|
528
|
+
self.stop()
|
|
529
|
+
|
|
530
|
+
self.current_file = source
|
|
531
|
+
self.is_playing = True
|
|
532
|
+
self.stop_event.clear()
|
|
533
|
+
|
|
534
|
+
self.playback_thread = threading.Thread(
|
|
535
|
+
target=self._playback_worker_wrapper,
|
|
536
|
+
daemon=True
|
|
537
|
+
)
|
|
538
|
+
self.playback_thread.start()
|
|
539
|
+
return True
|
|
540
|
+
|
|
510
541
|
else:
|
|
511
542
|
# live
|
|
512
543
|
return self._play_live(source, sample_rate, channels, chunk_size)
|
|
@@ -520,7 +551,8 @@ class PiWave:
|
|
|
520
551
|
Example:
|
|
521
552
|
>>> pw.stop()
|
|
522
553
|
"""
|
|
523
|
-
|
|
554
|
+
|
|
555
|
+
if not self.is_playing and not self.is_live_streaming and not self.current_process:
|
|
524
556
|
return
|
|
525
557
|
|
|
526
558
|
Log.warning("Stopping...")
|
|
@@ -786,8 +818,6 @@ class PiWave:
|
|
|
786
818
|
|
|
787
819
|
Log.info("Cleanup completed")
|
|
788
820
|
|
|
789
|
-
def __del__(self):
|
|
790
|
-
self.cleanup()
|
|
791
821
|
|
|
792
822
|
def send(self, file_path: str):
|
|
793
823
|
"""Alias for the play method.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: piwave
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
4
4
|
Summary: A python module to broadcast radio waves with your Raspberry Pi.
|
|
5
5
|
Home-page: https://github.com/douxxtech/piwave
|
|
6
6
|
Author: Douxx
|
|
@@ -518,8 +518,11 @@ status = pw.get_status()
|
|
|
518
518
|
##### `cleanup()`
|
|
519
519
|
Clean up resources and temporary files.
|
|
520
520
|
|
|
521
|
+
> [!WARNING]
|
|
522
|
+
> Always clean up behind you! Dropped support of auto-cleanup on version > 2.1.2
|
|
523
|
+
|
|
521
524
|
```python
|
|
522
|
-
pw.cleanup()
|
|
525
|
+
pw.cleanup()
|
|
523
526
|
```
|
|
524
527
|
|
|
525
528
|
### Backend Management
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
piwave/__init__.py,sha256=jz2r-qclltKTxJjlGnqhAwIlUgjvRTR31f4hjTHP5NA,230
|
|
2
2
|
piwave/__main__.py,sha256=ygl6F8VmOZjsnnUbAbzLoA7_1qv18ruG6TW4EocSaQE,3927
|
|
3
3
|
piwave/logger.py,sha256=lPG3cz3ByqC1p1UKpwlv3R9KgiAb0zzyu6c3bhTpST0,2766
|
|
4
|
-
piwave/piwave.py,sha256=
|
|
4
|
+
piwave/piwave.py,sha256=f3v0n3RBr7sxQ7D1jXunAmplxe0D-6_mdaDLJmGwVpM,32423
|
|
5
5
|
piwave/backends/__init__.py,sha256=DUbdyYf2V2XcDB05vmFWEkuJ292YTNiNJjzh1raJ5Cg,3756
|
|
6
6
|
piwave/backends/base.py,sha256=amjdR3pwx-0XN2ngpwfYNt74j5kWrW1cI0zMOTMU-q8,7668
|
|
7
7
|
piwave/backends/fm_transmitter.py,sha256=6CuYpkCgb40PEpemMlbTkQ6Gq8qFe3C1TSSLLnwXXX4,1338
|
|
8
8
|
piwave/backends/pi_fm_rds.py,sha256=l1y9JUKjw-d9lh9X7HLQNEwbNVO-whYlzaYnqEfRviI,1429
|
|
9
|
-
piwave-2.1.
|
|
10
|
-
piwave-2.1.
|
|
11
|
-
piwave-2.1.
|
|
12
|
-
piwave-2.1.
|
|
13
|
-
piwave-2.1.
|
|
9
|
+
piwave-2.1.3.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
|
10
|
+
piwave-2.1.3.dist-info/METADATA,sha256=opQ0LdqJda66i1iaOGccjdw0gdZT9b7CKwDC1Ym_xWM,20612
|
|
11
|
+
piwave-2.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
+
piwave-2.1.3.dist-info/top_level.txt,sha256=xUbZ7Rk6OymSdDxmb9bfO8N-avJ9VYxP41GnXfwKYi8,7
|
|
13
|
+
piwave-2.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|