| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Copyright (C) 2019 F4EXB                                                      //
 | 
					
						
							|  |  |  | // written by Edouard Griffiths                                                  //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							| 
									
										
										
										
											2019-02-18 18:29:37 +01:00
										 |  |  | // In this version we will use a fixed constant bit rate of 64kbit/s.            //
 | 
					
						
							|  |  |  | // With a frame time of 20ms the encoder output size is always 160 bytes.        //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  | // This program is free software; you can redistribute it and/or modify          //
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by          //
 | 
					
						
							|  |  |  | // the Free Software Foundation as version 3 of the License, or                  //
 | 
					
						
							| 
									
										
										
										
											2019-04-11 14:32:15 +02:00
										 |  |  | // (at your option) any later version.                                           //
 | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,               //
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
					
						
							|  |  |  | // GNU General Public License V3 for more details.                               //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License             //
 | 
					
						
							|  |  |  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "opus/opus.h"
 | 
					
						
							|  |  |  | #include <QDebug>
 | 
					
						
							| 
									
										
										
										
											2019-02-19 02:07:26 +01:00
										 |  |  | #include <QMutexLocker>
 | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "audioopus.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioOpus::AudioOpus() : | 
					
						
							|  |  |  |     m_encoderState(0), | 
					
						
							| 
									
										
										
										
											2019-02-19 02:07:26 +01:00
										 |  |  |     m_encoderOK(false), | 
					
						
							|  |  |  |     m_mutex(QMutex::Recursive) | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     qDebug("AudioOpus::AudioOpus: libopus version %s", opus_get_version_string()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioOpus::~AudioOpus() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_encoderState) { | 
					
						
							|  |  |  |         opus_encoder_destroy(m_encoderState); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioOpus::setEncoder(int32_t fs, int nChannels) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int error; | 
					
						
							|  |  |  |     bool newInstance = true; | 
					
						
							| 
									
										
										
										
											2019-02-19 02:07:26 +01:00
										 |  |  |     QMutexLocker mutexLocker(&m_mutex); | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-19 08:41:23 +01:00
										 |  |  |     if (m_encoderState) { | 
					
						
							|  |  |  |         opus_encoder_destroy(m_encoderState); | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-19 08:41:23 +01:00
										 |  |  |     m_encoderState = opus_encoder_create(fs, nChannels, OPUS_APPLICATION_AUDIO, &error); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  |     if (error != OPUS_OK) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qWarning("AudioOpus::setEncoder: %s error: %s", newInstance ? "create" : "init", opus_strerror(error)); | 
					
						
							|  |  |  |         m_encoderOK = false; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qDebug("AudioOpus::setEncoder: fs: %d, nChannels: %d", fs, nChannels); | 
					
						
							|  |  |  |         m_encoderOK = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     error = opus_encoder_ctl(m_encoderState, OPUS_SET_BITRATE(m_bitrate)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (error != OPUS_OK) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qWarning("AudioOpus::setEncoder: set bitrate error: %s", opus_strerror(error)); | 
					
						
							|  |  |  |         m_encoderOK = false; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-18 18:29:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     error = opus_encoder_ctl(m_encoderState, OPUS_SET_VBR(0)); // force constant bit rate
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (error != OPUS_OK) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qWarning("AudioOpus::setEncoder: set constant bitrate error: %s", opus_strerror(error)); | 
					
						
							|  |  |  |         m_encoderOK = false; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int AudioOpus::encode(int frameSize, int16_t *in, uint8_t *out) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-19 02:07:26 +01:00
										 |  |  |     QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-19 11:53:26 +01:00
										 |  |  |     if (!m_encoderOK) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qWarning("AudioOpus::encode: encoder not initialized"); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  |     int nbBytes = opus_encode(m_encoderState, in, frameSize, out, m_maxPacketSize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (nbBytes < 0) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-18 18:29:37 +01:00
										 |  |  |         qWarning("AudioOpus::encode failed: %s", opus_strerror(nbBytes)); | 
					
						
							| 
									
										
										
										
											2019-02-18 02:07:30 +01:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return nbBytes; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |