Skip to content

Commit 2b16ab7

Browse files
committed
Update OpusFfi.php
1 parent 7e94e14 commit 2b16ab7

1 file changed

Lines changed: 54 additions & 44 deletions

File tree

src/Discord/Voice/Processes/OpusFfi.php

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,30 @@
1111
* with this source code in the LICENSE.md file.
1212
*/
1313

14-
namespace Discord\Voice\Processes;
14+
namespace Discord\Voice;
1515

1616
use FFI;
1717

1818
/**
1919
* Handles the decoding of Opus audio data using FFI (Foreign Function Interface).
2020
*
21-
* @since 10.19.0
21+
* @todo
22+
*
23+
* @property FFI $ffi
24+
* @method int opus_packet_get_nb_frames(mixed $packet, int $len)
25+
* @method int opus_packet_get_samples_per_frame(mixed $data, int $Fs)
26+
* @method mixed opus_decoder_create(int $Fs, int $channels, mixed $error)
27+
* @method int opus_decode(mixed $st, mixed $data, int $len, mixed $pcm, int $frame_size, int $decode_fec)
28+
* @method void opus_decoder_destroy(mixed $st)
2229
*/
23-
final class OpusFfi
30+
class OpusFFI
2431
{
25-
/**
26-
* Creates a FFI instance (code in C) to decode Opus audio data.
27-
* By using the libopus library, this function decodes Opus-encoded audio data
28-
* into PCM samples.
29-
* This is useful for processing audio data in Discord voice channels.
30-
* @param string|mixed $data
31-
*
32-
* @return string Returns the decoded PCM audio data as a string/binary.
33-
*/
34-
public static function decode($data): string
32+
protected FFI $ffi;
33+
34+
public function __construct()
3535
{
3636
// Load libopus and define needed functions/types
37-
// TODO: Move this to a separate file or class if needed.
38-
$ffi = FFI::cdef('
37+
$this->ffi = FFI::cdef('
3938
typedef struct OpusDecoder OpusDecoder;
4039
typedef short opus_int16;
4140
typedef int opus_int32;
@@ -47,51 +46,62 @@ public static function decode($data): string
4746
int opus_decode(OpusDecoder *st, const unsigned char *data, opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec);
4847
void opus_decoder_destroy(OpusDecoder *st);
4948
', 'libopus.so.0');
49+
}
5050

51-
// Parameters
52-
$sampleRate = 48000;
53-
$channels = 2;
54-
51+
/**
52+
* Creates a FFI instance (code in C) to decode Opus audio data.
53+
* By using the libopus library, this function decodes Opus-encoded audio data
54+
* into PCM samples.
55+
*
56+
* @param string|mixed $data The Opus-encoded audio data to decode.
57+
*
58+
* @return string The decoded PCM audio data as a string/binary.
59+
*/
60+
public function decode($data, int $channels = 2, int $audioRate = 48000): string
61+
{
5562
$dataLength = strlen($data);
63+
if ($dataLength < 0) {
64+
return '';
65+
}
5666

57-
$dataBuffer = $ffi->new("const unsigned char[$dataLength]", false);
67+
$dataBuffer = $this->ffi->new("const unsigned char[$dataLength]", false);
5868
FFI::memcpy($dataBuffer, $data, $dataLength);
5969

60-
$frames = $ffi->opus_packet_get_nb_frames($dataBuffer, $dataLength);
61-
$samplesPerFrame = $ffi->opus_packet_get_samples_per_frame($dataBuffer, $sampleRate);
70+
$frames = $this->opus_packet_get_nb_frames($dataBuffer, $dataLength);
71+
$samplesPerFrame = $this->opus_packet_get_samples_per_frame($dataBuffer, $audioRate);
6272
$frameSize = $frames * $samplesPerFrame;
6373

6474
// Create decoder
65-
$error = $ffi->new('int');
66-
$decoder = $ffi->opus_decoder_create($sampleRate, $channels, FFI::addr($error));
67-
68-
// Prepare input data (Opus-encoded)
69-
70-
if ($dataLength < 0) {
71-
$ffi->opus_decoder_destroy($decoder);
72-
73-
return '';
74-
}
75+
$error = $this->ffi->new('int');
76+
$decoder = $this->opus_decoder_create($audioRate, $channels, FFI::addr($error));
7577

7678
// Prepare output buffer for PCM samples
77-
$pcm = $ffi->new('opus_int16['.$frameSize * $channels * 2 .']', false);
79+
$pcm = $this->ffi->new('opus_int16['.$frameSize * $channels * 2 .']', false);
7880

7981
// Decode
80-
$ret = $ffi->opus_decode($decoder, $dataBuffer, $dataLength, $pcm, $frameSize, 0);
82+
$ret = $this->opus_decode($decoder, $dataBuffer, $dataLength, $pcm, $frameSize, 0);
8183

82-
if ($ret < 0) {
83-
$ffi->opus_decoder_destroy($decoder);
84+
// Clean up
85+
$this->opus_decoder_destroy($decoder);
8486

85-
// TODO: Handle decoding error
86-
return ''; // Or handle error
87+
if ($ret < 0) {
88+
/** @todo Handle decoding error */
89+
return '';
8790
}
8891

89-
// Get PCM bytes
90-
$pcm_bytes = FFI::string($pcm, $ret * $channels * 2); // 2 bytes per sample
91-
92-
// Clean up
93-
$ffi->opus_decoder_destroy($decoder);
92+
// 2 bytes per sample
93+
return FFI::string($pcm, $ret * $channels * 2);
94+
}
9495

95-
return $pcm_bytes;
96+
/**
97+
* Magic method to redirect method calls to the FFI instance.
98+
*
99+
* @param string $name
100+
* @param array $arguments
101+
* @return mixed
102+
*/
103+
public function __call(string $name, array $arguments)
104+
{
105+
return $this->ffi->$name(...$arguments);
96106
}
97107
}

0 commit comments

Comments
 (0)