File:  [DVB] / libsoftmpeg / src / a_fusionsound.c
Revision 1.1: download - view: text, annotated - select for diffs
Wed Mar 17 14:23:06 2004 UTC (20 years, 2 months ago) by hunold
Branches: MAIN
CVS tags: HEAD
- rip out all fusionsound stuff from main audio.c, put it to a_fusionsound.c, put a lean api around it
- check for availble audio ouput "devices" in audio.c, support fusionsound, follow changes in audio.c
- add copyright headers to all of the new files
- make all functions static in v_directfb.c

/*
   (c) Copyright 2004  convergence GmbH

   All rights reserved.

   Written by Michael Hunold <hunold@convergence.de> and
	      Denis Oliver Kropp <dok@directfb.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include "audio.h"

static  struct a_fusionsound_data
{
	IDirectFB		*DirectFB;
	IFusionSound 		*sound;
	IFusionSoundStream 	*stream;
	IFusionSoundPlayback 	*playback;
	int			channels;
	int			initialized;
} priv;

static int init (struct audio_decoder *d, void *init_data)
{
	struct a_fusionsound_data *data = &priv;
	/* don't need any init data */

	if (DFB_OK != DirectFBCreate(&data->DirectFB)) {
		SOFTMPEG_ERROR("directfb master interface not available.\n");
		return -1;
	}

	if (DFB_OK != data->DirectFB->GetInterface(data->DirectFB, "IFusionSound", NULL, NULL, (void **) &data->sound)) {
		SOFTMPEG_ERROR("fusion sound interface not available.\n");
		return -1;
	}

	/* we rely on the logic later on to initialize FusionSound properly */
	
	data->initialized = 0;
	return 0;
}

static int volume (struct audio_decoder *d, float volume)
{
	struct a_fusionsound_data *data = &priv;

	if (data->initialized == 0) {
		AUDIO_OUTPUT("FusionSound playback not initialized (yet)\n");
		return -1;
	}

	data->playback->SetVolume(data->playback, volume);
	return 0;
}

static int apause (struct audio_decoder *d, int pause)
{
	struct a_fusionsound_data *data = &priv;
	int ret;
	
	if (data->initialized == 0) {
		AUDIO_OUTPUT("FusionSound playback not initialized (yet)\n");
		return -1;
	}

	if (pause != 0) {
		ret = data->playback->Stop(data->playback);
		if (ret != 0) {
			AUDIO_OUTPUT("warning: stopping audio playback failed.\n");
		} else {
			AUDIO_OUTPUT("stopped audio playback.\n");
		}
		return 1;
	}
	
	ret = data->playback->Continue(data->playback);
	if (ret != 0) {
		AUDIO_OUTPUT("warning: starting audio playback failed.\n");
	} else {
		AUDIO_OUTPUT("starting audio playback.\n");
	}

	return 0;
}

static int get_delay (struct audio_decoder *d, int *delay)
{
	struct a_fusionsound_data *data = &priv;
	DFBBoolean playing;
	int filled;
	int total;
	
	if (data->initialized == 0) {
		AUDIO_OUTPUT("FusionSound playback not initialized (yet)\n");
		return -1;
	}

	*delay = 0;

	data->stream->GetStatus(data->stream, &filled, &total, NULL, NULL, &playing);

	if (!playing) {
		AUDIO_OUTPUT("not playing / unexpected interrupt\n");
                return -1;
	}

	data->stream->GetPresentationDelay(data->stream, delay);

	return 0;
}

static int reconfigure (struct audio_decoder *d, unsigned int buffer_size, unsigned int sample_rate, unsigned int channels)
{
	struct a_fusionsound_data *data = &priv;
	FSStreamDescription sd;

	data->initialized = 0;

	if (NULL != data->stream) {
		data->stream->Release(data->stream);
		data->stream = NULL;
	}

	SOFTMPEG_DEBUG("changing audio configuration: buffer_size:%d, sample_rate:%d, channels:%d\n",buffer_size, sample_rate, channels);

	if (sample_rate != 48000 && sample_rate != 44100 && sample_rate != 32000) {
		AUDIO_OUTPUT("unsupported sample_rate %d\n",sample_rate);
		return -1;
	}
	
	if (channels != 2 && channels != 1) {
		AUDIO_OUTPUT("unsupported number of channels %d\n",channels);
		return -1;
	}

	if (buffer_size < sample_rate) {
		AUDIO_OUTPUT("buffer size smaller than sample rate.\n");
		return -1;
	}

	sd.flags = (FSSDF_BUFFERSIZE | FSSDF_SAMPLEFORMAT | FSSDF_SAMPLERATE | FSSDF_CHANNELS | FSSDF_PREBUFFER);

	sd.buffersize   = buffer_size;
	sd.sampleformat = FSSF_S16;
	sd.samplerate   = sample_rate;
	sd.channels     = channels;
	sd.prebuffer    = -1; /* Disables automatic playback. */

	data->sound->CreateStream(data->sound, &sd, &data->stream);
	if (NULL == data->stream) {
		SOFTMPEG_ERROR("fusion sound stream init failed\n");
		data->stream = NULL;
		return -1;
	}

	data->stream->GetPlayback(data->stream, &data->playback);
	if (NULL == data->playback) {
		SOFTMPEG_ERROR("fusion sound get playback interface failed\n");
		data->stream->Release(data->stream);
		data->stream = NULL;
		return -1;
	}
	
	data->channels = channels;

	data->initialized = 1;
	volume(d, 0.0);
 
	return 0;
}

static int get_status (struct audio_decoder *d, int *filled, int *total, int *playing)
{
	struct a_fusionsound_data *data = &priv;
	DFBBoolean p;
	int ret;
	
	if (NULL == data->stream) {
		AUDIO_OUTPUT("stream not available.\n");
		return -1;
	}

	ret = data->stream->GetStatus(data->stream, filled, total, NULL, NULL, &p);
	if (ret != 0) {
		AUDIO_OUTPUT("status not available.\n");
		return -1;
	}
	
	if (p == DFB_TRUE) {
		*playing = 1;
	} else {
		*playing = 0;
	}
	
	return 0;
}

static int awrite (struct audio_decoder *d, struct audio_buffer *output, int *filled, int *total)
{
	struct a_fusionsound_data *data = &priv;
	DFBBoolean playing;
	int ret;
	
	if (data->initialized == 0) {
		AUDIO_OUTPUT("FusionSound playback not initialized (yet)\n");
		return -1;
	}

	ret = data->stream->Write(data->stream, (uint32_t *) output->buf, output->len / (data->channels*2));
	if (ret) {
		SOFTMPEG_DFB_ERROR( "IFusionSoundStream::Write()", ret );
		return -1;
	}

	ret = data->stream->GetStatus(data->stream, filled, total, NULL, NULL, &playing);
	if (ret) {
		SOFTMPEG_DFB_ERROR( "IFusionSoundStream::GetStatus()", ret );
		return -1;
	}

	if (playing == DFB_TRUE) {
		return 1;
	}
	
	return 0;
}

static int flush (struct audio_decoder *d)
{
	struct a_fusionsound_data *data = &priv;

	if (data->initialized == 0) {
		AUDIO_OUTPUT("FusionSound playback not initialized (yet)\n");
		return -1;
	}

	data->stream->Flush(data->stream);
	volume(d, 0.0);

	return 0;
}

struct audio_operations a_fusionsound_ops = 
{
	.init 		= &init,
	.pause		= &apause,
	.volume		= &volume,
	.get_delay	= &get_delay,
	.reconfigure	= &reconfigure,
	.get_status	= &get_status,
	.write		= &awrite,
	.flush		= &flush,
	.priv		= &priv,
};

LinuxTV legacy CVS <linuxtv.org/cvs>