AUD_FFMPEGReader::AUD_FFMPEGReader(boost::shared_ptr<AUD_Buffer> buffer) :
		m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1),
		m_membuffer(buffer),
		m_membufferpos(0)
{
	m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE));

	m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this,
									   read_packet, NULL, seek_packet);

	if(!m_aviocontext)
	{
		av_free(m_aviocontext);
		AUD_THROW(AUD_ERROR_FILE, fileopen_error);
	}

	m_formatCtx = avformat_alloc_context();
	m_formatCtx->pb = m_aviocontext;
	if(avformat_open_input(&m_formatCtx, "", NULL, NULL)!=0)
	{
		av_free(m_aviocontext);
		AUD_THROW(AUD_ERROR_FILE, streamopen_error);
	}

	try
	{
		init();
	}
	catch(AUD_Exception&)
	{
		avformat_close_input(&m_formatCtx);
		av_free(m_aviocontext);
		throw;
	}
}
Esempio n. 2
0
void FFMPEGWriter::close()
{
	int got_packet = true;

	while(got_packet)
	{
		AVPacket packet;

		packet.data = nullptr;
		packet.size = 0;

		av_init_packet(&packet);

		if(avcodec_encode_audio2(m_codecCtx, &packet, nullptr, &got_packet))
			AUD_THROW(FileException, "File end couldn't be written, audio encoding failed with ffmpeg.");

		if(got_packet)
		{
			packet.flags |= AV_PKT_FLAG_KEY;
			packet.stream_index = m_stream->index;
			if(av_write_frame(m_formatCtx, &packet))
			{
				av_free_packet(&packet);
				AUD_THROW(FileException, "Final frames couldn't be writen to the file with ffmpeg.");
			}
			av_free_packet(&packet);
		}
	}
}
Esempio n. 3
0
OpenALDevice::OpenALHandle::OpenALHandle(OpenALDevice* device, ALenum format, std::shared_ptr<IReader> reader, bool keep) :
	m_isBuffered(false), m_reader(reader), m_keep(keep), m_format(format),
	m_eos(false), m_loopcount(0), m_stop(nullptr), m_stop_data(nullptr), m_status(STATUS_PLAYING),
	m_device(device)
{
	DeviceSpecs specs = m_device->m_specs;
	specs.specs = m_reader->getSpecs();

	// OpenAL playback code
	alGenBuffers(CYCLE_BUFFERS, m_buffers);
	if(alGetError() != AL_NO_ERROR)
		AUD_THROW(DeviceException, "Buffer generation failed while staring playback with OpenAL.");

	try
	{
		m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
		int length;
		bool eos;

		for(m_current = 0; m_current < CYCLE_BUFFERS; m_current++)
		{
			length = m_device->m_buffersize;
			reader->read(length, eos, m_device->m_buffer.getBuffer());

			if(length == 0)
				break;

			alBufferData(m_buffers[m_current], m_format, m_device->m_buffer.getBuffer(), length * AUD_DEVICE_SAMPLE_SIZE(specs), specs.rate);

			if(alGetError() != AL_NO_ERROR)
				AUD_THROW(DeviceException, "Filling the buffer with data failed while starting playback with OpenAL.");
		}

		alGenSources(1, &m_source);
		if(alGetError() != AL_NO_ERROR)
			AUD_THROW(DeviceException, "Source generation failed while starting playback with OpenAL.");

		try
		{
			alSourceQueueBuffers(m_source, m_current, m_buffers);
			if(alGetError() != AL_NO_ERROR)
				AUD_THROW(DeviceException, "Buffer queuing failed while starting playback with OpenAL.");
		}
		catch(Exception&)
		{
			alDeleteSources(1, &m_source);
			throw;
		}
	}
	catch(Exception&)
	{
		alDeleteBuffers(CYCLE_BUFFERS, m_buffers);
		throw;
	}
	alSourcei(m_source, AL_SOURCE_RELATIVE, 1);
}
Esempio n. 4
0
AUD_OpenALDevice::AUD_OpenALHandle::AUD_OpenALHandle(AUD_OpenALDevice* device, ALenum format, AUD_Reference<AUD_IReader> reader, bool keep) :
	m_isBuffered(false), m_reader(reader), m_keep(keep), m_format(format), m_current(0),
	m_eos(false), m_loopcount(0), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING),
	m_device(device)
{
	AUD_DeviceSpecs specs = m_device->m_specs;
	specs.specs = m_reader->getSpecs();

	// OpenAL playback code
	alGenBuffers(CYCLE_BUFFERS, m_buffers);
	if(alGetError() != AL_NO_ERROR)
		AUD_THROW(AUD_ERROR_OPENAL, genbuffer_error);

	try
	{
		m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
		int length;
		bool eos;

		for(int i = 0; i < CYCLE_BUFFERS; i++)
		{
			length = m_device->m_buffersize;
			reader->read(length, eos, m_device->m_buffer.getBuffer());
			alBufferData(m_buffers[i], m_format, m_device->m_buffer.getBuffer(),
						 length * AUD_DEVICE_SAMPLE_SIZE(specs),
						 specs.rate);
			if(alGetError() != AL_NO_ERROR)
				AUD_THROW(AUD_ERROR_OPENAL, bufferdata_error);
		}

		alGenSources(1, &m_source);
		if(alGetError() != AL_NO_ERROR)
			AUD_THROW(AUD_ERROR_OPENAL, gensource_error);

		try
		{
			alSourceQueueBuffers(m_source, CYCLE_BUFFERS,
								 m_buffers);
			if(alGetError() != AL_NO_ERROR)
				AUD_THROW(AUD_ERROR_OPENAL, queue_error);
		}
		catch(AUD_Exception&)
		{
			alDeleteSources(1, &m_source);
			throw;
		}
	}
	catch(AUD_Exception&)
	{
		alDeleteBuffers(CYCLE_BUFFERS, m_buffers);
		throw;
	}
	alSourcei(m_source, AL_SOURCE_RELATIVE, 1);
}
Esempio n. 5
0
AUD_IReader* AUD_FileFactory::createReader() const
{
#ifdef WITH_SNDFILE
	try
	{
		if(m_buffer.get())
			return new AUD_SndFileReader(m_buffer);
		else
			return new AUD_SndFileReader(m_filename);
	}
	catch(AUD_Exception&) {}
#endif

#ifdef WITH_FFMPEG
	try
	{
		if(m_buffer.get())
			return new AUD_FFMPEGReader(m_buffer);
		else
			return new AUD_FFMPEGReader(m_filename);
	}
	catch(AUD_Exception&) {}
#endif

	AUD_THROW(AUD_ERROR_FILE, read_error);
}
Esempio n. 6
0
void AUD_SuperposeReader::read(int& length, bool& eos, sample_t* buffer)
{
	AUD_Specs specs = m_reader1->getSpecs();
	AUD_Specs s2 = m_reader2->getSpecs();
	if(!AUD_COMPARE_SPECS(specs, s2))
		AUD_THROW(AUD_ERROR_SPECS, specs_error);

	int samplesize = AUD_SAMPLE_SIZE(specs);

	m_buffer.assureSize(length * samplesize);

	int len1 = length;
	m_reader1->read(len1, eos, buffer);

	if(len1 < length)
		memset(buffer + len1 * specs.channels, 0, (length - len1) * samplesize);

	int len2 = length;
	bool eos2;
	sample_t* buf = m_buffer.getBuffer();
	m_reader2->read(len2, eos2, buf);

	for(int i = 0; i < len2 * specs.channels; i++)
		buffer[i] += buf[i];

	length = AUD_MAX(len1, len2);
	eos &= eos2;
}
Esempio n. 7
0
AUD_ReverseReader::AUD_ReverseReader(AUD_IReader* reader) :
		AUD_EffectReader(reader),
		m_length(reader->getLength()),
		m_position(0)
{
	if(m_length < 0 || !reader->isSeekable())
		AUD_THROW(AUD_ERROR_PROPS, props_error);
}
Esempio n. 8
0
AUD_NAMESPACE_BEGIN

ReverseReader::ReverseReader(std::shared_ptr<IReader> reader) :
    EffectReader(reader),
    m_length(reader->getLength()),
    m_position(0)
{
    if(m_length < 0 || !reader->isSeekable())
        AUD_THROW(StateException, "A reader has to be seekable and have finite length to be reversible.");
}
Esempio n. 9
0
void FFMPEGWriter::close()
{
#ifdef FFMPEG_OLD_CODE
	int got_packet = true;

	while(got_packet)
	{
		m_packet->data = nullptr;
		m_packet->size = 0;

		av_init_packet(m_packet);

		if(avcodec_encode_audio2(m_codecCtx, m_packet, nullptr, &got_packet))
			AUD_THROW(FileException, "File end couldn't be written, audio encoding failed with ffmpeg.");

		if(got_packet)
		{
			m_packet->flags |= AV_PKT_FLAG_KEY;
			m_packet->stream_index = m_stream->index;
			if(av_write_frame(m_formatCtx, m_packet))
			{
				av_free_packet(m_packet);
				AUD_THROW(FileException, "Final frames couldn't be writen to the file with ffmpeg.");
			}
			av_free_packet(m_packet);
		}
	}
#else
	if(avcodec_send_frame(m_codecCtx, nullptr) < 0)
		AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg.");

	while(avcodec_receive_packet(m_codecCtx, m_packet) == 0)
	{
		m_packet->stream_index = m_stream->index;

		if(av_write_frame(m_formatCtx, m_packet) < 0)
			AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg.");
	}
#endif
}
Esempio n. 10
0
AUD_SDLDevice::AUD_SDLDevice(AUD_DeviceSpecs specs, int buffersize)
{
	if(specs.channels == AUD_CHANNELS_INVALID)
		specs.channels = AUD_CHANNELS_STEREO;
	if(specs.format == AUD_FORMAT_INVALID)
		specs.format = AUD_FORMAT_S16;
	if(specs.rate == AUD_RATE_INVALID)
		specs.rate = AUD_RATE_44100;

	m_specs = specs;

	SDL_AudioSpec format, obtained;

	format.freq = m_specs.rate;
	if(m_specs.format == AUD_FORMAT_U8)
		format.format = AUDIO_U8;
	else
		format.format = AUDIO_S16SYS;
	format.channels = m_specs.channels;
	format.samples = buffersize;
	format.callback = AUD_SDLDevice::SDL_mix;
	format.userdata = this;

	if(SDL_OpenAudio(&format, &obtained) != 0)
		AUD_THROW(AUD_ERROR_SDL, open_error);

	m_specs.rate = (AUD_SampleRate)obtained.freq;
	m_specs.channels = (AUD_Channels)obtained.channels;
	if(obtained.format == AUDIO_U8)
		m_specs.format = AUD_FORMAT_U8;
	else if(obtained.format == AUDIO_S16LSB || obtained.format == AUDIO_S16MSB)
		m_specs.format = AUD_FORMAT_S16;
	else
	{
		SDL_CloseAudio();
		AUD_THROW(AUD_ERROR_SDL, format_error);
	}

	create();
}
Esempio n. 11
0
AUD_OpenALDevice::AUD_OpenALDevice(AUD_Specs specs, int buffersize)
{
	// cannot determine how many channels or which format OpenAL uses, but
	// it at least is able to play 16 bit stereo audio
	specs.channels = AUD_CHANNELS_STEREO;
	specs.format = AUD_FORMAT_S16;

	m_device = alcOpenDevice(NULL);

	if(!m_device)
		AUD_THROW(AUD_ERROR_OPENAL);

	// at least try to set the frequency
	ALCint attribs[] = { ALC_FREQUENCY, specs.rate, 0 };
	ALCint* attributes = attribs;
	if(specs.rate == AUD_RATE_INVALID)
		attributes = NULL;

	m_context = alcCreateContext(m_device, attributes);
	alcMakeContextCurrent(m_context);

	alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate);

	// check for specific formats and channel counts to be played back
	if(alIsExtensionPresent("AL_EXT_FLOAT32") == AL_TRUE)
		specs.format = AUD_FORMAT_FLOAT32;

	m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE;

	alGetError();

	m_converter = new AUD_ConverterFactory(specs); AUD_NEW("factory")

	m_specs = specs;
	m_buffersize = buffersize;
	m_playing = false;

	m_playingSounds = new std::list<AUD_OpenALHandle*>(); AUD_NEW("list")
	m_pausedSounds = new std::list<AUD_OpenALHandle*>(); AUD_NEW("list")
	m_bufferedFactories = new std::list<AUD_OpenALBufferedFactory*>();
	AUD_NEW("list")

	pthread_mutexattr_t attr;
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

	pthread_mutex_init(&m_mutex, &attr);

	pthread_mutexattr_destroy(&attr);
}
Esempio n. 12
0
AUD_SndFileReader::AUD_SndFileReader(std::string filename) :
	m_position(0)
{
	SF_INFO sfinfo;

	sfinfo.format = 0;
	m_sndfile = sf_open(filename.c_str(), SFM_READ, &sfinfo);

	if(!m_sndfile)
		AUD_THROW(AUD_ERROR_FILE, fileopen_error);

	m_specs.channels = (AUD_Channels) sfinfo.channels;
	m_specs.rate = (AUD_SampleRate) sfinfo.samplerate;
	m_length = sfinfo.frames;
	m_seekable = sfinfo.seekable;
}
Esempio n. 13
0
SndFileReader::SndFileReader(std::string filename) :
	m_position(0)
{
	SF_INFO sfinfo;

	sfinfo.format = 0;
	m_sndfile = sf_open(filename.c_str(), SFM_READ, &sfinfo);

	if(!m_sndfile)
		AUD_THROW(FileException, "The file couldn't be opened with libsndfile.");

	m_specs.channels = (Channels) sfinfo.channels;
	m_specs.rate = (SampleRate) sfinfo.samplerate;
	m_length = sfinfo.frames;
	m_seekable = sfinfo.seekable;
}
Esempio n. 14
0
AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_Reference<AUD_IReader> reader,
											 AUD_Specs specs) :
		AUD_ResampleReader(reader, specs.rate),
		m_channels(reader->getSpecs().channels),
		m_position(0)
{
	int error;
	m_src = src_callback_new(src_callback,
							 SRC_SINC_MEDIUM_QUALITY,
							 m_channels,
							 &error,
							 this);

	if(!m_src)
	{
		// XXX printf("%s\n", src_strerror(error));
		AUD_THROW(AUD_ERROR_SRC, state_error);
	}
}
Esempio n. 15
0
AUD_NAMESPACE_BEGIN

OpenALReader::OpenALReader(Specs specs, int buffersize) :
	m_specs(specs),
	m_position(0),
	m_device(nullptr)
{
	if((specs.channels != CHANNELS_MONO) && (specs.channels != CHANNELS_STEREO))
		specs.channels = CHANNELS_MONO;

	m_device = alcCaptureOpenDevice(nullptr, specs.rate,
									specs.channels == CHANNELS_MONO ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16,
									buffersize * specs.channels * 2);

	if(!m_device)
		AUD_THROW(DeviceException, "The capture device couldn't be opened with OpenAL.");

	alcCaptureStart(m_device);
}
Esempio n. 16
0
AUD_SuperposeReader::AUD_SuperposeReader(AUD_IReader* reader1, AUD_IReader* reader2) :
	m_reader1(reader1), m_reader2(reader2)
{
	try
	{
		AUD_Specs s1, s2;
		s1 = reader1->getSpecs();
		s2 = reader2->getSpecs();
		if(memcmp(&s1, &s2, sizeof(AUD_Specs)))
			AUD_THROW(AUD_ERROR_SPECS, specs_error);
	}
	catch(AUD_Exception&)
	{
		delete reader1;
		delete reader2;

		throw;
	}
}
Esempio n. 17
0
OpenALDevice::OpenALDevice(DeviceSpecs specs, int buffersize, std::string name) :
	m_playing(false), m_buffersize(buffersize)
{
	// cannot determine how many channels or which format OpenAL uses, but
	// it at least is able to play 16 bit stereo audio
	specs.format = FORMAT_S16;

	if(name.empty())
		m_device = alcOpenDevice(nullptr);
	else
		m_device = alcOpenDevice(name.c_str());

	if(!m_device)
		AUD_THROW(DeviceException, "The audio device couldn't be opened with OpenAL.");

	// at least try to set the frequency
	ALCint attribs[] = { ALC_FREQUENCY, (ALCint)specs.rate, 0 };
	ALCint* attributes = attribs;
	if(specs.rate == RATE_INVALID)
		attributes = nullptr;

	m_context = alcCreateContext(m_device, attributes);
	alcMakeContextCurrent(m_context);

	alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate);

	// check for specific formats and channel counts to be played back
	if(alIsExtensionPresent("AL_EXT_FLOAT32") == AL_TRUE)
		specs.format = FORMAT_FLOAT32;

	m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE;

	if((!m_useMC && specs.channels > CHANNELS_STEREO) ||
			specs.channels == CHANNELS_STEREO_LFE ||
			specs.channels == CHANNELS_SURROUND5)
		specs.channels = CHANNELS_STEREO;

	alGetError();
	alcGetError(m_device);

	m_specs = specs;
}
AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) :
	m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1),
	m_formatCtx(NULL),
	m_aviocontext(NULL),
	m_membuf(NULL)
{
	// open file
	if(avformat_open_input(&m_formatCtx, filename.c_str(), NULL, NULL)!=0)
		AUD_THROW(AUD_ERROR_FILE, fileopen_error);

	try
	{
		init();
	}
	catch(AUD_Exception&)
	{
		avformat_close_input(&m_formatCtx);
		throw;
	}
}
Esempio n. 19
0
AUD_Reference<AUD_IWriter> AUD_FileWriter::createWriter(std::string filename,AUD_DeviceSpecs specs,
														AUD_Container format, AUD_Codec codec, unsigned int bitrate)
{
#ifdef WITH_SNDFILE
	try
	{
		return new AUD_SndFileWriter(filename, specs, format, codec, bitrate);
	}
	catch(AUD_Exception&) {}
#endif

#ifdef WITH_FFMPEG
	try
	{
		return new AUD_FFMPEGWriter(filename, specs, format, codec, bitrate);
	}
	catch(AUD_Exception&) {}
#endif

	AUD_THROW(AUD_ERROR_SPECS, write_error);
}
Esempio n. 20
0
void AUD_SRCResampleReader::read(int& length, bool& eos, sample_t* buffer)
{
	AUD_Specs specs = m_reader->getSpecs();

	double factor = double(m_rate) / double(specs.rate);

	specs.rate = m_rate;

	int size = length;

	m_buffer.assureSize(length * AUD_SAMPLE_SIZE(specs));

	if(specs.channels != m_channels)
	{
		src_delete(m_src);

		m_channels = specs.channels;

		int error;
		m_src = src_callback_new(src_callback,
								 SRC_SINC_MEDIUM_QUALITY,
								 m_channels,
								 &error,
								 this);

		if(!m_src)
		{
			// XXX printf("%s\n", src_strerror(error));
			AUD_THROW(AUD_ERROR_SRC, state_error);
		}
	}

	m_eos = false;

	length = src_callback_read(m_src, factor, length, buffer);

	m_position += length;

	eos = m_eos && (length < size);
}
Esempio n. 21
0
AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_IReader* reader,
											 AUD_Specs specs) :
		AUD_EffectReader(reader),
		m_sspecs(reader->getSpecs()),
		m_factor(double(specs.rate) / double(m_sspecs.rate)),
		m_tspecs(specs),
		m_position(0)
{
	m_tspecs.channels = m_sspecs.channels;

	int error;
	m_src = src_callback_new(src_callback,
							 SRC_SINC_MEDIUM_QUALITY,
							 m_sspecs.channels,
							 &error,
							 this);

	if(!m_src)
	{
		// XXX printf("%s\n", src_strerror(error));
		AUD_THROW(AUD_ERROR_SRC, state_error);
	}
}
Esempio n. 22
0
AUD_SndFileReader::AUD_SndFileReader(AUD_Reference<AUD_Buffer> buffer) :
	m_position(0),
	m_membuffer(buffer),
	m_memoffset(0)
{
	m_vio.get_filelen = vio_get_filelen;
	m_vio.read = vio_read;
	m_vio.seek = vio_seek;
	m_vio.tell = vio_tell;
	m_vio.write = NULL;

	SF_INFO sfinfo;

	sfinfo.format = 0;
	m_sndfile = sf_open_virtual(&m_vio, SFM_READ, &sfinfo, this);

	if(!m_sndfile)
		AUD_THROW(AUD_ERROR_FILE, fileopen_error);

	m_specs.channels = (AUD_Channels) sfinfo.channels;
	m_specs.rate = (AUD_SampleRate) sfinfo.samplerate;
	m_length = sfinfo.frames;
	m_seekable = sfinfo.seekable;
}
Esempio n. 23
0
SndFileReader::SndFileReader(std::shared_ptr<Buffer> buffer) :
	m_position(0),
	m_membuffer(buffer),
	m_memoffset(0)
{
	m_vio.get_filelen = vio_get_filelen;
	m_vio.read = vio_read;
	m_vio.seek = vio_seek;
	m_vio.tell = vio_tell;
	m_vio.write = nullptr;

	SF_INFO sfinfo;

	sfinfo.format = 0;
	m_sndfile = sf_open_virtual(&m_vio, SFM_READ, &sfinfo, this);

	if(!m_sndfile)
		AUD_THROW(FileException, "The buffer couldn't be read with libsndfile.");

	m_specs.channels = (Channels) sfinfo.channels;
	m_specs.rate = (SampleRate) sfinfo.samplerate;
	m_length = sfinfo.frames;
	m_seekable = sfinfo.seekable;
}
Esempio n. 24
0
AUD_NAMESPACE_BEGIN

void FFMPEGWriter::encode()
{
	sample_t* data = m_input_buffer.getBuffer();

	if(m_deinterleave)
	{
		m_deinterleave_buffer.assureSize(m_input_buffer.getSize());

		sample_t* dbuf = m_deinterleave_buffer.getBuffer();
		// deinterleave
		int single_size = sizeof(sample_t);
		for(int channel = 0; channel < m_specs.channels; channel++)
		{
			for(int i = 0; i < m_input_buffer.getSize() / AUD_SAMPLE_SIZE(m_specs); i++)
			{
				std::memcpy(((data_t*)dbuf) + (m_input_samples * channel + i) * single_size,
							((data_t*)data) + ((m_specs.channels * i) + channel) * single_size, single_size);
			}
		}

		// convert first
		if(m_input_size)
			m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(dbuf), m_input_samples * m_specs.channels);
		else
			std::memcpy(data, dbuf, m_input_buffer.getSize());
	}
	else
		// convert first
		if(m_input_size)
			m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_samples * m_specs.channels);

	AVPacket packet;

	packet.data = nullptr;
	packet.size = 0;

	av_init_packet(&packet);

	AVFrame* frame = av_frame_alloc();
	av_frame_unref(frame);
	int got_packet;

	frame->nb_samples = m_input_samples;
	frame->format = m_codecCtx->sample_fmt;
	frame->channel_layout = m_codecCtx->channel_layout;

	if(avcodec_fill_audio_frame(frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0)
		AUD_THROW(FileException, "File couldn't be written, filling the audio frame failed with ffmpeg.");

	AVRational sample_time = { 1, static_cast<int>(m_specs.rate) };
	frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time);

	if(avcodec_encode_audio2(m_codecCtx, &packet, frame, &got_packet))
	{
		av_frame_free(&frame);
		AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg.");
	}

	if(got_packet)
	{
		packet.flags |= AV_PKT_FLAG_KEY;
		packet.stream_index = m_stream->index;
		if(av_write_frame(m_formatCtx, &packet) < 0)
		{
			av_free_packet(&packet);
			av_frame_free(&frame);
			AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg.");
		}
		av_free_packet(&packet);
	}

	av_frame_free(&frame);
}
Esempio n. 25
0
FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate) :
	m_position(0),
	m_specs(specs),
	m_input_samples(0),
	m_deinterleave(false)
{
	static const char* formats[] = { nullptr, "ac3", "flac", "matroska", "mp2", "mp3", "ogg", "wav" };

	if(avformat_alloc_output_context2(&m_formatCtx, nullptr, formats[format], filename.c_str()) < 0)
		AUD_THROW(FileException, "File couldn't be written, format couldn't be found with ffmpeg.");

	m_outputFmt = m_formatCtx->oformat;

	if(!m_outputFmt) {
		avformat_free_context(m_formatCtx);
		AUD_THROW(FileException, "File couldn't be written, output format couldn't be found with ffmpeg.");
	}

	m_outputFmt->audio_codec = AV_CODEC_ID_NONE;

	switch(codec)
	{
	case CODEC_AAC:
		m_outputFmt->audio_codec = AV_CODEC_ID_AAC;
		break;
	case CODEC_AC3:
		m_outputFmt->audio_codec = AV_CODEC_ID_AC3;
		break;
	case CODEC_FLAC:
		m_outputFmt->audio_codec = AV_CODEC_ID_FLAC;
		break;
	case CODEC_MP2:
		m_outputFmt->audio_codec = AV_CODEC_ID_MP2;
		break;
	case CODEC_MP3:
		m_outputFmt->audio_codec = AV_CODEC_ID_MP3;
		break;
	case CODEC_OPUS:
		m_outputFmt->audio_codec = AV_CODEC_ID_OPUS;
		break;
	case CODEC_PCM:
		switch(specs.format)
		{
		case FORMAT_U8:
			m_outputFmt->audio_codec = AV_CODEC_ID_PCM_U8;
			break;
		case FORMAT_S16:
			m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
			break;
		case FORMAT_S24:
			m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE;
			break;
		case FORMAT_S32:
			m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE;
			break;
		case FORMAT_FLOAT32:
			m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE;
			break;
		case FORMAT_FLOAT64:
			m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE;
			break;
		default:
			m_outputFmt->audio_codec = AV_CODEC_ID_NONE;
			break;
		}
		break;
	case CODEC_VORBIS:
		m_outputFmt->audio_codec = AV_CODEC_ID_VORBIS;
		break;
	default:
		m_outputFmt->audio_codec = AV_CODEC_ID_NONE;
		break;
	}

	try
	{
		if(m_outputFmt->audio_codec == AV_CODEC_ID_NONE)
			AUD_THROW(FileException, "File couldn't be written, audio codec not found with ffmpeg.");

		AVCodec* codec = avcodec_find_encoder(m_outputFmt->audio_codec);
		if(!codec)
			AUD_THROW(FileException, "File couldn't be written, audio encoder couldn't be found with ffmpeg.");

		m_stream = avformat_new_stream(m_formatCtx, codec);
		if(!m_stream)
			AUD_THROW(FileException, "File couldn't be written, stream creation failed with ffmpeg.");

		m_stream->id = m_formatCtx->nb_streams - 1;

		m_codecCtx = m_stream->codec;

		switch(m_specs.format)
		{
		case FORMAT_U8:
			m_convert = convert_float_u8;
			m_codecCtx->sample_fmt = AV_SAMPLE_FMT_U8;
			break;
		case FORMAT_S16:
			m_convert = convert_float_s16;
			m_codecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
			break;
		case FORMAT_S32:
			m_convert = convert_float_s32;
			m_codecCtx->sample_fmt = AV_SAMPLE_FMT_S32;
			break;
		case FORMAT_FLOAT64:
			m_convert = convert_float_double;
			m_codecCtx->sample_fmt = AV_SAMPLE_FMT_DBL;
			break;
		default:
			m_convert = convert_copy<sample_t>;
			m_codecCtx->sample_fmt = AV_SAMPLE_FMT_FLT;
			break;
		}

		if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
			m_codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;

		bool format_supported = false;

		for(int i = 0; codec->sample_fmts[i] != -1; i++)
		{
			if(av_get_alt_sample_fmt(codec->sample_fmts[i], false) == m_codecCtx->sample_fmt)
			{
				m_deinterleave = av_sample_fmt_is_planar(codec->sample_fmts[i]);
				m_codecCtx->sample_fmt = codec->sample_fmts[i];
				format_supported = true;
			}
		}

		if(!format_supported)
		{
			int chosen_index = 0;
			auto chosen = av_get_alt_sample_fmt(codec->sample_fmts[chosen_index], false);
			for(int i = 1; codec->sample_fmts[i] != -1; i++)
			{
				auto fmt = av_get_alt_sample_fmt(codec->sample_fmts[i], false);
				if((fmt > chosen && chosen < m_codecCtx->sample_fmt) || (fmt > m_codecCtx->sample_fmt && fmt < chosen))
				{
					chosen = fmt;
					chosen_index = i;
				}
			}

			m_codecCtx->sample_fmt = codec->sample_fmts[chosen_index];
			m_deinterleave = av_sample_fmt_is_planar(m_codecCtx->sample_fmt);
			switch(av_get_alt_sample_fmt(m_codecCtx->sample_fmt, false))
			{
			case AV_SAMPLE_FMT_U8:
				specs.format = FORMAT_U8;
				m_convert = convert_float_u8;
				break;
			case AV_SAMPLE_FMT_S16:
				specs.format = FORMAT_S16;
				m_convert = convert_float_s16;
				break;
			case AV_SAMPLE_FMT_S32:
				specs.format = FORMAT_S32;
				m_convert = convert_float_s32;
				break;
			case AV_SAMPLE_FMT_FLT:
				specs.format = FORMAT_FLOAT32;
				m_convert = convert_copy<sample_t>;
				break;
			case AV_SAMPLE_FMT_DBL:
				specs.format = FORMAT_FLOAT64;
				m_convert = convert_float_double;
				break;
			default:
				AUD_THROW(FileException, "File couldn't be written, sample format not supported with ffmpeg.");
			}
		}

		m_codecCtx->sample_rate = 0;

		if(codec->supported_samplerates)
		{
			for(int i = 0; codec->supported_samplerates[i]; i++)
			{
				if(codec->supported_samplerates[i] == m_specs.rate)
				{
					m_codecCtx->sample_rate = codec->supported_samplerates[i];
					break;
				}
				else if((codec->supported_samplerates[i] > m_codecCtx->sample_rate && m_specs.rate > m_codecCtx->sample_rate) ||
						(codec->supported_samplerates[i] < m_codecCtx->sample_rate && m_specs.rate < codec->supported_samplerates[i]))
				{
					m_codecCtx->sample_rate = codec->supported_samplerates[i];
				}
			}
		}

		if(m_codecCtx->sample_rate == 0)
			m_codecCtx->sample_rate = m_specs.rate;

		m_specs.rate = m_codecCtx->sample_rate;

		m_codecCtx->codec_id = m_outputFmt->audio_codec;
		m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
		m_codecCtx->bit_rate = bitrate;
		m_codecCtx->channels = m_specs.channels;
		m_stream->time_base.num = m_codecCtx->time_base.num = 1;
		m_stream->time_base.den = m_codecCtx->time_base.den = m_codecCtx->sample_rate;

		if(avcodec_open2(m_codecCtx, codec, nullptr) < 0)
			AUD_THROW(FileException, "File couldn't be written, encoder couldn't be opened with ffmpeg.");

		int samplesize = std::max(int(AUD_SAMPLE_SIZE(m_specs)), AUD_DEVICE_SAMPLE_SIZE(m_specs));

		if((m_input_size = m_codecCtx->frame_size))
			m_input_buffer.resize(m_input_size * samplesize);

		if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE))
			AUD_THROW(FileException, "File couldn't be written, file opening failed with ffmpeg.");

		avformat_write_header(m_formatCtx, nullptr);
	}
	catch(Exception&)
	{
		avformat_free_context(m_formatCtx);
		throw;
	}
}
Esempio n. 26
0
AUD_OpenALDevice::AUD_OpenALDevice(AUD_DeviceSpecs specs, int buffersize)
{
	// cannot determine how many channels or which format OpenAL uses, but
	// it at least is able to play 16 bit stereo audio
	specs.channels = AUD_CHANNELS_STEREO;
	specs.format = AUD_FORMAT_S16;

#if 0
	if(alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE)
	{
		ALCchar* devices = const_cast<ALCchar*>(alcGetString(NULL, ALC_DEVICE_SPECIFIER));
		printf("OpenAL devices (standard is: %s):\n", alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER));

		while(*devices)
		{
			printf("%s\n", devices);
			devices += strlen(devices) + 1;
		}
	}
#endif

	m_device = alcOpenDevice(NULL);

	if(!m_device)
		AUD_THROW(AUD_ERROR_OPENAL, open_error);

	// at least try to set the frequency
	ALCint attribs[] = { ALC_FREQUENCY, specs.rate, 0 };
	ALCint* attributes = attribs;
	if(specs.rate == AUD_RATE_INVALID)
		attributes = NULL;

	m_context = alcCreateContext(m_device, attributes);
	alcMakeContextCurrent(m_context);

	alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate);

	// check for specific formats and channel counts to be played back
	if(alIsExtensionPresent("AL_EXT_FLOAT32") == AL_TRUE)
		specs.format = AUD_FORMAT_FLOAT32;

	m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE;

	alGetError();
	alcGetError(m_device);

	m_specs = specs;
	m_buffersize = buffersize;
	m_playing = false;

//	m_bufferedFactories = new std::list<AUD_OpenALBufferedFactory*>();

	pthread_mutexattr_t attr;
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

	pthread_mutex_init(&m_mutex, &attr);

	pthread_mutexattr_destroy(&attr);

	start(false);
}
Esempio n. 27
0
JackDevice::JackDevice(std::string name, DeviceSpecs specs, int buffersize) :
	m_synchronizer(this)
{
	if(specs.channels == CHANNELS_INVALID)
		specs.channels = CHANNELS_STEREO;

	// jack uses floats
	m_specs = specs;
	m_specs.format = FORMAT_FLOAT32;

	jack_options_t options = JackNullOption;
	jack_status_t status;

	// open client
	m_client = AUD_jack_client_open(name.c_str(), options, &status);
	if(m_client == nullptr)
		AUD_THROW(DeviceException, "Connecting to the JACK server failed.");

	// set callbacks
	AUD_jack_set_process_callback(m_client, JackDevice::jack_mix, this);
	AUD_jack_on_shutdown(m_client, JackDevice::jack_shutdown, this);
	AUD_jack_set_sync_callback(m_client, JackDevice::jack_sync, this);

	// register our output channels which are called ports in jack
	m_ports = new jack_port_t*[m_specs.channels];

	try
	{
		char portname[64];
		for(int i = 0; i < m_specs.channels; i++)
		{
			sprintf(portname, "out %d", i+1);
			m_ports[i] = AUD_jack_port_register(m_client, portname, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
			if(m_ports[i] == nullptr)
				AUD_THROW(DeviceException, "Registering output port with JACK failed.");
		}
	}
	catch(Exception&)
	{
		AUD_jack_client_close(m_client);
		delete[] m_ports;
		throw;
	}

	m_specs.rate = (SampleRate)AUD_jack_get_sample_rate(m_client);

	buffersize *= sizeof(sample_t);
	m_ringbuffers = new jack_ringbuffer_t*[specs.channels];
	for(unsigned int i = 0; i < specs.channels; i++)
		m_ringbuffers[i] = AUD_jack_ringbuffer_create(buffersize);
	buffersize *= specs.channels;
	m_deinterleavebuf.resize(buffersize);
	m_buffer.resize(buffersize);

	create();

	m_valid = true;
	m_sync = 0;
	m_syncFunc = nullptr;
	m_nextState = m_state = AUD_jack_transport_query(m_client, nullptr);

	// activate the client
	if(AUD_jack_activate(m_client))
	{
		AUD_jack_client_close(m_client);
		delete[] m_ports;
		for(unsigned int i = 0; i < specs.channels; i++)
			AUD_jack_ringbuffer_free(m_ringbuffers[i]);
		delete[] m_ringbuffers;
		destroy();

		AUD_THROW(DeviceException, "Client activation with JACK failed.");
	}

	const char** ports = AUD_jack_get_ports(m_client, nullptr, nullptr,
										JackPortIsPhysical | JackPortIsInput);
	if(ports != nullptr)
	{
		for(int i = 0; i < m_specs.channels && ports[i]; i++)
			AUD_jack_connect(m_client, AUD_jack_port_name(m_ports[i]), ports[i]);

		AUD_jack_free(ports);
	}

	m_mixingThread = std::thread(&JackDevice::updateRingBuffers, this);
}
void AUD_FFMPEGReader::init()
{
	m_position = 0;
	m_pkgbuf_left = 0;

	if(avformat_find_stream_info(m_formatCtx, NULL) < 0)
		AUD_THROW(AUD_ERROR_FFMPEG, streaminfo_error);

	// find audio stream and codec
	m_stream = -1;

	for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
	{
		if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
			&& (m_stream < 0))
		{
			m_stream=i;
			break;
		}
	}

	if(m_stream == -1)
		AUD_THROW(AUD_ERROR_FFMPEG, noaudio_error);

	m_codecCtx = m_formatCtx->streams[m_stream]->codec;

	// get a decoder and open it
	AVCodec *aCodec = avcodec_find_decoder(m_codecCtx->codec_id);
	if(!aCodec)
		AUD_THROW(AUD_ERROR_FFMPEG, nodecoder_error);

	if(avcodec_open2(m_codecCtx, aCodec, NULL) < 0)
		AUD_THROW(AUD_ERROR_FFMPEG, codecopen_error);

	// XXX this prints file information to stdout:
	//dump_format(m_formatCtx, 0, NULL, 0);

	m_specs.channels = (AUD_Channels) m_codecCtx->channels;
	m_tointerleave = av_sample_fmt_is_planar(m_codecCtx->sample_fmt);

	switch(av_get_packed_sample_fmt(m_codecCtx->sample_fmt))
	{
	case AV_SAMPLE_FMT_U8:
		m_convert = AUD_convert_u8_float;
		m_specs.format = AUD_FORMAT_U8;
		break;
	case AV_SAMPLE_FMT_S16:
		m_convert = AUD_convert_s16_float;
		m_specs.format = AUD_FORMAT_S16;
		break;
	case AV_SAMPLE_FMT_S32:
		m_convert = AUD_convert_s32_float;
		m_specs.format = AUD_FORMAT_S32;
		break;
	case AV_SAMPLE_FMT_FLT:
		m_convert = AUD_convert_copy<float>;
		m_specs.format = AUD_FORMAT_FLOAT32;
		break;
	case AV_SAMPLE_FMT_DBL:
		m_convert = AUD_convert_double_float;
		m_specs.format = AUD_FORMAT_FLOAT64;
		break;
	default:
		AUD_THROW(AUD_ERROR_FFMPEG, format_error);
	}

	m_specs.rate = (AUD_SampleRate) m_codecCtx->sample_rate;
}
Esempio n. 29
0
AUD_JackDevice::AUD_JackDevice(std::string name, AUD_DeviceSpecs specs, int buffersize)
{
	if(specs.channels == AUD_CHANNELS_INVALID)
		specs.channels = AUD_CHANNELS_STEREO;

	// jack uses floats
	m_specs = specs;
	m_specs.format = AUD_FORMAT_FLOAT32;

	jack_options_t options = JackNullOption;
	jack_status_t status;

	// open client
	m_client = jack_client_open(name.c_str(), options, &status);
	if(m_client == NULL)
		AUD_THROW(AUD_ERROR_JACK, clientopen_error);

	// set callbacks
	jack_set_process_callback(m_client, AUD_JackDevice::jack_mix, this);
	jack_on_shutdown(m_client, AUD_JackDevice::jack_shutdown, this);
	jack_set_sync_callback(m_client, AUD_JackDevice::jack_sync, this);

	// register our output channels which are called ports in jack
	m_ports = new jack_port_t*[m_specs.channels];

	try
	{
		char portname[64];
		for(int i = 0; i < m_specs.channels; i++)
		{
			sprintf(portname, "out %d", i+1);
			m_ports[i] = jack_port_register(m_client, portname,
											JACK_DEFAULT_AUDIO_TYPE,
											JackPortIsOutput, 0);
			if(m_ports[i] == NULL)
				AUD_THROW(AUD_ERROR_JACK, port_error);
		}
	}
	catch(AUD_Exception&)
	{
		jack_client_close(m_client);
		delete[] m_ports;
		throw;
	}

	m_specs.rate = (AUD_SampleRate)jack_get_sample_rate(m_client);

	buffersize *= sizeof(sample_t);
	m_ringbuffers = new jack_ringbuffer_t*[specs.channels];
	for(unsigned int i = 0; i < specs.channels; i++)
		m_ringbuffers[i] = jack_ringbuffer_create(buffersize);
	buffersize *= specs.channels;
	m_deinterleavebuf.resize(buffersize);
	m_buffer.resize(buffersize);

	create();

	m_valid = true;
	m_sync = 0;
	m_syncFunc = NULL;
	m_nextState = m_state = jack_transport_query(m_client, NULL);

	pthread_mutex_init(&m_mixingLock, NULL);
	pthread_cond_init(&m_mixingCondition, NULL);

	// activate the client
	if(jack_activate(m_client))
	{
		jack_client_close(m_client);
		delete[] m_ports;
		for(unsigned int i = 0; i < specs.channels; i++)
			jack_ringbuffer_free(m_ringbuffers[i]);
		delete[] m_ringbuffers;
		pthread_mutex_destroy(&m_mixingLock);
		pthread_cond_destroy(&m_mixingCondition);
		destroy();

		AUD_THROW(AUD_ERROR_JACK, activate_error);
	}

	const char** ports = jack_get_ports(m_client, NULL, NULL,
										JackPortIsPhysical | JackPortIsInput);
	if(ports != NULL)
	{
		for(int i = 0; i < m_specs.channels && ports[i]; i++)
			jack_connect(m_client, jack_port_name(m_ports[i]), ports[i]);

		free(ports);
	}

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	pthread_create(&m_mixingThread, &attr, runMixingThread, this);

	pthread_attr_destroy(&attr);
}
Esempio n. 30
0
AUD_NAMESPACE_BEGIN

SndFileWriter::SndFileWriter(std::string filename, DeviceSpecs specs,
									 Container format, Codec codec, unsigned int bitrate) :
	m_position(0), m_specs(specs)
{
	SF_INFO sfinfo;

	sfinfo.channels = specs.channels;
	sfinfo.samplerate = int(specs.rate);

	switch(format)
	{
	case CONTAINER_FLAC:
		sfinfo.format = SF_FORMAT_FLAC;
		switch(specs.format)
		{
		case FORMAT_S16:
			sfinfo.format |= SF_FORMAT_PCM_16;
			break;
		case FORMAT_S24:
			sfinfo.format |= SF_FORMAT_PCM_24;
			break;
		case FORMAT_S32:
			sfinfo.format |= SF_FORMAT_PCM_32;
			break;
		case FORMAT_FLOAT32:
			sfinfo.format |= SF_FORMAT_FLOAT;
			break;
		case FORMAT_FLOAT64:
			sfinfo.format |= SF_FORMAT_DOUBLE;
			break;
		default:
			sfinfo.format = 0;
			break;
		}
		break;
	case CONTAINER_OGG:
		if(codec == CODEC_VORBIS)
			sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS;
		else
			sfinfo.format = 0;
		break;
	case CONTAINER_WAV:
		sfinfo.format = SF_FORMAT_WAV;
		switch(specs.format)
		{
		case FORMAT_U8:
			sfinfo.format |= SF_FORMAT_PCM_U8;
			break;
		case FORMAT_S16:
			sfinfo.format |= SF_FORMAT_PCM_16;
			break;
		case FORMAT_S24:
			sfinfo.format |= SF_FORMAT_PCM_24;
			break;
		case FORMAT_S32:
			sfinfo.format |= SF_FORMAT_PCM_32;
			break;
		case FORMAT_FLOAT32:
			sfinfo.format |= SF_FORMAT_FLOAT;
			break;
		case FORMAT_FLOAT64:
			sfinfo.format |= SF_FORMAT_DOUBLE;
			break;
		default:
			sfinfo.format = 0;
			break;
		}
		break;
	default:
		sfinfo.format = 0;
		break;
	}

	if(sfinfo.format == 0)
		AUD_THROW(FileException, "This format couldn't be written with libsndfile.");

	m_sndfile = sf_open(filename.c_str(), SFM_WRITE, &sfinfo);

	if(!m_sndfile)
		AUD_THROW(FileException, "The file couldn't be written with libsndfile.");
}