* #27819: audiofile: use sndfile for .au, .al and .ul files

This commit is contained in:
Tristan Matthews
2013-08-09 14:17:40 -04:00
parent e384241388
commit c8ddbdcf77
3 changed files with 37 additions and 69 deletions

View File

@ -39,7 +39,6 @@
#include <sndfile.hh>
#include "audiofile.h"
#include "audio/codecs/audiocodec.h"
#include "audio/samplerateconverter.h"
#include "client/callmanager.h"
#include "manager.h"
@ -64,61 +63,49 @@ AudioFile::onBufferFinish()
updatePlaybackScale_++;
}
RawFile::RawFile(const std::string& name, sfl::AudioCodec *codec, unsigned int sampleRate)
: AudioFile(name, sampleRate), audioCodec_(codec)
RawFile::RawFile(const std::string& name, unsigned int sampleRate)
: AudioFile(name, sampleRate)
{
if (filepath_.empty())
throw AudioFileException("Unable to open audio file: filename is empty");
bool hasHeader = false;
const unsigned fileSampleRate = 8000;
int format = SF_FORMAT_RAW | SF_FORMAT_ULAW;
std::fstream file;
file.open(filepath_.c_str(), std::fstream::in);
if (!file.is_open())
throw AudioFileException("Unable to open audio file");
file.seekg(0, std::ios::end);
size_t length = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> fileBuffer(length);
file.read(&fileBuffer[0], length);
file.close();
const unsigned int frameSize = audioCodec_->getFrameSize();
const unsigned int bitrate = audioCodec_->getBitRate() * 1000 / 8;
const unsigned int audioRate = audioCodec_->getClockRate();
const unsigned int encFrameSize = frameSize * bitrate / audioRate;
const unsigned int decodedSize = length * (frameSize / encFrameSize);
AudioBuffer * buffer = new AudioBuffer(decodedSize);
unsigned bufpos = 0;
unsigned char *filepos = reinterpret_cast<unsigned char *>(&fileBuffer[0]);
while (length >= encFrameSize) {
bufpos += audioCodec_->decode(buffer->getData(), filepos, encFrameSize, bufpos);
filepos += encFrameSize;
length -= encFrameSize;
if (filepath_.find(".al") != std::string::npos)
format = SF_FORMAT_RAW | SF_FORMAT_ALAW;
else if (filepath_.find(".au") != std::string::npos) {
format = SF_FORMAT_AU;
hasHeader = true;
}
if (sampleRate == audioRate) {
SndfileHandle fileHandle(filepath_.c_str(), SFM_READ, format, hasHeader ? 0 : 1, hasHeader ? 0 : 8000);
if (!fileHandle)
throw AudioFileException("Unable to open audio file");
// get # of bytes in file
const size_t fileSize = fileHandle.seek(0, SEEK_END);
fileHandle.seek(0, SEEK_SET);
const size_t nbFrames = hasHeader ? fileHandle.frames() : fileSize * fileHandle.channels();
std::vector<SFLAudioSample> temp(nbFrames);
fileHandle.read(&*temp.begin(), nbFrames);
AudioBuffer * buffer = new AudioBuffer(nbFrames, fileHandle.channels(), fileSampleRate);
buffer->deinterleave(&*temp.begin(), nbFrames, fileHandle.channels());
if (sampleRate == fileHandle.samplerate()) {
delete buffer_;
buffer_ = buffer;
} else {
double factord = (double) sampleRate / audioRate;
const size_t channels = buffer->channels();
// FIXME: it looks like buffer and buffer_ are leaked in this case
if (channels > 2)
throw AudioFileException("WaveFile: unsupported number of channels");
double factord = (double) sampleRate / fileHandle.samplerate();
size_t samples = buffer->samples();
size_t size = channels * samples;
size_t size = fileHandle.channels() * samples;
float* floatBufferIn = new float[size];
buffer->interleaveFloat(floatBufferIn);
int samplesOut = ceil(factord * samples);
int sizeOut = samplesOut * channels;
int sizeOut = samplesOut * fileHandle.channels();
SRC_DATA src_data;
src_data.data_in = floatBufferIn;
@ -129,13 +116,13 @@ RawFile::RawFile(const std::string& name, sfl::AudioCodec *codec, unsigned int s
float* floatBufferOut = new float[sizeOut];
src_data.data_out = floatBufferOut;
src_simple(&src_data, SRC_SINC_BEST_QUALITY, channels);
src_simple(&src_data, SRC_SINC_BEST_QUALITY, fileHandle.channels());
samplesOut = src_data.output_frames_gen;
sizeOut = samplesOut * channels;
sizeOut = samplesOut * fileHandle.channels();
SFLAudioSample *scratch = new SFLAudioSample[sizeOut];
src_float_to_short_array(floatBufferOut, scratch, src_data.output_frames_gen);
buffer->deinterleave(scratch, samplesOut, channels);
buffer->deinterleave(scratch, samplesOut, fileHandle.channels());
delete buffer_;
buffer_ = buffer;

View File

@ -37,10 +37,6 @@
#include <stdexcept>
#include "audio/audioloop.h"
namespace sfl {
class AudioCodec;
}
class AudioFileException : public std::runtime_error {
public:
AudioFileException(const std::string &str) :
@ -71,16 +67,7 @@ class AudioFile : public AudioLoop {
class RawFile : public AudioFile {
public:
/**
* Constructor
*/
RawFile(const std::string& name, sfl::AudioCodec* codec, unsigned int sampleRate = 8000);
private:
NON_COPYABLE(RawFile);
/** Your preferred codec */
sfl::AudioCodec* audioCodec_;
RawFile(const std::string& name, unsigned int sampleRate = 8000);
};
class WaveFile : public AudioFile {

View File

@ -1866,16 +1866,10 @@ void
ManagerImpl::updateAudioFile(const std::string &file, int sampleRate)
{
try {
if (file.find(".wav") != std::string::npos)
if (file.find(".wav") != std::string::npos) {
audiofile_.reset(new WaveFile(file, sampleRate));
else {
sfl::AudioCodec *codec;
if (file.find(".ul") != std::string::npos or file.find(".au") != std::string::npos)
codec = audioCodecFactory.getCodec(PAYLOAD_CODEC_ULAW);
else
throw AudioFileException("Couldn't guess an appropriate decoder");
audiofile_.reset(new RawFile(file, static_cast<sfl::AudioCodec *>(codec), sampleRate));
} else {
audiofile_.reset(new RawFile(file, sampleRate));
}
} catch (const AudioFileException &e) {
ERROR("Exception: %s", e.what());