@@ -471,6 +471,10 @@ public static function checkForExecutable(string $executable): ?string
471471 /**
472472 * Plays a file/url on the voice stream.
473473 *
474+ * FFmpeg is used to decode the file, so any format ffmpeg supports is accepted
475+ * (e.g. WAV, OGG Opus, MP3, FLAC). Raw PCM files (.pcm) are NOT supported here
476+ * because ffmpeg cannot auto-detect the format — use {@see playPcmFile()} instead.
477+ *
474478 * @param string $file The file/url to play.
475479 * @param int $channels Deprecated, Discord only supports 2 channels.
476480 *
@@ -595,7 +599,42 @@ public function playRawStream($stream, int $channels = 2, int $audioRate = 48000
595599 }
596600
597601 /**
598- * Plays an Ogg Opus stream.
602+ * Plays a raw PCM file on the voice stream.
603+ *
604+ * This is a convenience wrapper around {@see playRawStream()} for files saved
605+ * as raw signed 16-bit little-endian PCM (e.g. recordings produced by
606+ * {@see record()} with {@see RecordingFormat::PCM}).
607+ *
608+ * @param string $path Absolute or relative path to the raw PCM file.
609+ * @param int $channels Number of audio channels (default: 2 = stereo).
610+ * @param int $audioRate Sample rate in Hz (default: 48000).
611+ *
612+ * @throws FileNotFoundException if the file does not exist.
613+ * @throws \RuntimeException if the file cannot be opened or audio is already playing.
614+ *
615+ * @return PromiseInterface
616+ */
617+ public function playPcmFile (string $ path , int $ channels = 2 , int $ audioRate = 48000 ): PromiseInterface
618+ {
619+ $ deferred = new Deferred ();
620+
621+ if (! file_exists ($ path )) {
622+ $ deferred ->reject (new FileNotFoundException ("Could not find the file \"{$ path }\". " ));
623+
624+ return $ deferred ->promise ();
625+ }
626+
627+ $ handle = fopen ($ path , 'rb ' );
628+ if ($ handle === false ) {
629+ $ deferred ->reject (new \RuntimeException ("Could not open file for reading: \"{$ path }\". " ));
630+
631+ return $ deferred ->promise ();
632+ }
633+
634+ return $ this ->playRawStream ($ handle , $ channels , $ audioRate );
635+ }
636+
637+ /**
599638 *
600639 * @param resource|Process|Stream $stream The Ogg Opus stream to be sent.
601640 *
@@ -644,6 +683,7 @@ public function playOggStream($stream): PromiseInterface
644683
645684 $ this ->buffer = new RealBuffer ();
646685 $ stream ->on ('data ' , fn ($ d ) => $ this ->buffer ->write ($ d ));
686+ $ stream ->on ('end ' , fn () => $ this ->buffer ->end ());
647687
648688 /** @var OggStream */
649689 $ ogg = null ;
0 commit comments