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