1 module opus.encoder; 2 3 const int OPUS_OK = 0; 4 5 enum Application { 6 VOIP = 2048, 7 AUDIO = 2049, 8 LOWDELAY = 2051, 9 } 10 11 enum Bandwidth { 12 NARROWBAND = 1101, 13 MEDIUMBAND = 1102, 14 WIDEBAND = 1103, 15 SUPERWIDEBAND = 1104, 16 FULLBAND = 1105, 17 } 18 19 enum CTL { 20 SET_BITRATE_REQUEST = 4002, 21 SET_BANDWIDTH_REQUEST = 4008, 22 SET_INBAND_FEC_REQUEST = 4012, 23 SET_PACKET_LOSS_PERC_REQUEST = 4014, 24 } 25 26 extern (C) { 27 struct OpusEncoder {}; 28 29 OpusEncoder* opus_encoder_create(int, int, int, int*); 30 void opus_encoder_destroy(OpusEncoder*); 31 int opus_encode(OpusEncoder*, const short*, int, ubyte*, int); 32 int opus_encoder_ctl(OpusEncoder*, int request, ...); 33 } 34 35 /// Encoder is a wrapper around opus encoding 36 class Encoder { 37 OpusEncoder* encoder; 38 39 private { 40 int sampleRate; 41 int channels; 42 Application app; 43 } 44 45 this(int sampleRate=48000, int channels=2, Application app = Application.VOIP) { 46 this.sampleRate = sampleRate; 47 this.channels = channels; 48 this.app = app; 49 50 int error; 51 this.encoder = opus_encoder_create(sampleRate, channels, app, &error); 52 assert(error == OPUS_OK); 53 } 54 55 ~this() { 56 if (this.encoder) { 57 opus_encoder_destroy(this.encoder); 58 this.encoder = null; 59 } 60 } 61 62 /// Encodes an array of PCM data into raw opus 63 ubyte[] encode(immutable short[] pcm, int frameSize) { 64 ubyte[] data = new ubyte[]((frameSize * this.channels) * 2); 65 int size = opus_encode(this.encoder, &pcm[0], frameSize, &data[0], cast(int)data.length); 66 return data[0..size]; 67 } 68 69 /// Sets the bitrate for this encoder (in kbps) 70 void setBitrate(int kbps) { 71 assert(opus_encoder_ctl(this.encoder, CTL.SET_BITRATE_REQUEST, kbps * 1024) == OPUS_OK); 72 } 73 74 /// Sets the bandwidth for this encoder 75 void setBandwidth(Bandwidth bw) { 76 assert(opus_encoder_ctl(this.encoder, CTL.SET_BANDWIDTH_REQUEST, cast(int)bw) == OPUS_OK); 77 } 78 79 /// Sets whether inband FEC (forward error correction) is enabled for this encoder 80 void setInbandFEC(bool enabled) { 81 assert(opus_encoder_ctl(this.encoder, CTL.SET_INBAND_FEC_REQUEST, cast(int)enabled) == OPUS_OK); 82 } 83 84 /// Sets the predicted packet loss percent for FEC (if enabled) 85 void setPacketLossPercent(int percent) { 86 assert(opus_encoder_ctl(this.encoder, CTL.SET_PACKET_LOSS_PERC_REQUEST, percent) == OPUS_OK); 87 } 88 } 89 90 unittest { 91 Encoder enc = new Encoder(); 92 enc.setInbandFEC(true); 93 enc.setPacketLossPercent(30); 94 enc.setBandwidth(Bandwidth.FULLBAND); 95 enc.setBitrate(128); 96 enc.destroy(); 97 }