1 /*
2 * speexio.cpp - A coder encoder for raw audio and speex.
3 *
4 * Copyright (c) 2008 by Detlev Casanova <detlev.casanova@gmail.com>
5 *
6 * Kopete (c) by the Kopete developers <kopete-devel@kde.org>
7 *
8 * *************************************************************************
9 * * *
10 * * This program is free software; you can redistribute it and/or modify *
11 * * it under the terms of the GNU General Public License as published by *
12 * * the Free Software Foundation; either version 2 of the License, or *
13 * * (at your option) any later version. *
14 * * *
15 * *************************************************************************
16 */
17
18 #include "speexio.h"
19 #include "jabber_protocol_debug.h"
20
21 class SpeexIO::Private
22 {
23 public:
24 void *encoder;
25 void *decoder;
26 SpeexBits encBits;
27 SpeexBits decBits;
28 int samplingRate;
29 int bitRate;
30 int frameSize;
31
32 QByteArray speexData; //encoded data
33 QByteArray rawData; //decoded date
34 };
35
SpeexIO()36 SpeexIO::SpeexIO()
37 : AbstractIO()
38 , d(new Private())
39 {
40 speex_bits_init(&d->encBits);
41 speex_bits_init(&d->decBits);
42
43 d->samplingRate = -1;
44 d->frameSize = 0;
45 d->bitRate = 0;
46 qCDebug(JABBER_PROTOCOL_LOG) << "SpeexIO : created.";
47 }
48
~SpeexIO()49 SpeexIO::~SpeexIO()
50 {
51 speex_bits_destroy(&d->encBits);
52 speex_encoder_destroy(d->encoder);
53
54 speex_bits_destroy(&d->decBits);
55 speex_decoder_destroy(d->decoder);
56 delete d;
57 qCDebug(JABBER_PROTOCOL_LOG) << "Destroyed SpeexIO";
58 }
59
setSamplingRate(int sr)60 void SpeexIO::setSamplingRate(int sr)
61 {
62 if (d->samplingRate != -1) {
63 //FIXME:this should simply change the current sampling rate (SPEEX_SET_SAMPLING_RATE)
64 //FIXME:is that possible ?
65 qCDebug(JABBER_PROTOCOL_LOG) << "Sampling rate already set... Abort";
66 return;
67 }
68
69 switch (sr) {
70 case 8000:
71 d->encoder = speex_encoder_init(&speex_nb_mode);
72 d->decoder = speex_decoder_init(&speex_nb_mode);
73 break;
74 case 16000:
75 d->encoder = speex_encoder_init(&speex_wb_mode);
76 d->decoder = speex_decoder_init(&speex_wb_mode);
77 break;
78 // Currently not supported, this is not for internet payloads anyway.
79 /* case 32000 :
80 d->encoder = speex_encoder_init(&speex_uwb_mode);
81 d->decoder = speex_decoder_init(&speex_uwb_mode);
82 break;
83 */
84 default:
85 return;
86 }
87
88 d->samplingRate = sr;
89
90 qCDebug(JABBER_PROTOCOL_LOG) << "encoder and decoder initiated.";
91 }
92
setQuality(int q)93 int SpeexIO::setQuality(int q)
94 {
95 if (d->samplingRate == -1) {
96 return -1;
97 }
98
99 int qualityEnc = q;
100 if (0 != speex_encoder_ctl(d->encoder, SPEEX_SET_QUALITY, &qualityEnc)) {
101 return -1;
102 }
103
104 int qualityDec = q;
105 if (0 != speex_decoder_ctl(d->decoder, SPEEX_SET_QUALITY, &qualityDec)) {
106 return -1;
107 }
108
109 if (qualityEnc != qualityDec) {
110 return -1;
111 }
112
113 return qualityDec;
114 }
115
116 // Returns a frame size in samples.
frameSize()117 int SpeexIO::frameSize()
118 {
119 if (d->samplingRate == -1) {
120 return -1;
121 }
122
123 if (d->frameSize != 0) { //if frameSize != 0, we already got it, no need to get it again.
124 return d->frameSize;
125 }
126
127 int fs;
128 //Encoder and decoder frame size are the same.
129 if (0 != speex_encoder_ctl(d->encoder, SPEEX_GET_FRAME_SIZE, &fs)) {
130 return -1;
131 }
132
133 return d->frameSize = fs;
134 }
135
136 // Returns a frame size in bytes.
frameSizeBytes()137 int SpeexIO::frameSizeBytes()
138 {
139 return d->samplingRate == 8000 ? 160 * 2 : 320 * 2;
140 }
141
start()142 bool SpeexIO::start()
143 {
144 if (d->samplingRate == -1) {
145 return false;
146 }
147 return true;
148 }
149
encode(const QByteArray & rawData)150 void SpeexIO::encode(const QByteArray &rawData)
151 {
152 d->speexData.clear();
153
154 if (d->samplingRate == -1 || rawData.size() == 0) {
155 return;
156 }
157
158 speex_bits_reset(&d->encBits);
159 int ret = speex_encode_int(d->encoder, (short *)rawData.data(), &d->encBits);
160 if (ret == 0) {
161 qCDebug(JABBER_PROTOCOL_LOG) << "Error encoding speex data : frame needs not be transmitted";
162 return;
163 }
164
165 int maxSize = speex_bits_nbytes(&d->encBits);
166 d->speexData.resize(maxSize);
167
168 int nbBytes = speex_bits_write(&d->encBits, (char *)d->speexData.data(), maxSize);
169
170 emit encoded();
171 }
172
encodedData() const173 QByteArray SpeexIO::encodedData() const
174 {
175 return d->speexData;
176 }
177
decode(const QByteArray & speexData)178 void SpeexIO::decode(const QByteArray &speexData)
179 {
180 d->rawData.clear();
181
182 if (d->samplingRate == -1 || speexData.size() == 0) {
183 return;
184 }
185
186 speex_bits_read_from(&d->decBits, (char *)speexData.data(), speexData.size());
187
188 if (frameSizeBytes() == -1) {
189 return;
190 }
191
192 d->rawData.resize(frameSizeBytes());
193 int ret = speex_decode_int(d->decoder, &d->decBits, (short *)d->rawData.data());
194 if (ret != 0) {
195 qCDebug(JABBER_PROTOCOL_LOG) << "Error decoding speex data :" << (ret == -1 ? "end of stream" : "corrupt stream");
196 return;
197 }
198
199 emit decoded();
200 }
201
decodedData() const202 QByteArray SpeexIO::decodedData() const
203 {
204 return d->rawData;
205 }
206
tsValue()207 int SpeexIO::tsValue()
208 {
209 return d->samplingRate / 50;
210 }
211