diff options
Diffstat (limited to 'akode/plugins/sun_sink/sun_sink.cpp')
-rw-r--r-- | akode/plugins/sun_sink/sun_sink.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/akode/plugins/sun_sink/sun_sink.cpp b/akode/plugins/sun_sink/sun_sink.cpp new file mode 100644 index 0000000..c8b6c57 --- /dev/null +++ b/akode/plugins/sun_sink/sun_sink.cpp @@ -0,0 +1,179 @@ +/* aKode: Sun-Sink + + Copyright (C) 2005 Allan Sandfeld Jensen <kde@carewolf.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <config.h> + +#include <sys/audioio.h> + +#include <sys/ioctl.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <alloca.h> + +#include <audioframe.h> +#include "sun_sink.h" + +#include <iostream> + +namespace aKode { + +extern "C" { SunSinkPlugin sun_sink; } + +struct SunSink::private_data +{ + private_data() : audio_fd(-1), device(0), valid(false) {}; + int audio_fd; + audio_info_t auinfo; + + const char *device; + AudioConfiguration config; + bool valid; +}; + + +SunSink::SunSink() +{ + d = new private_data; +} + +SunSink::~SunSink() +{ + close(); + delete d; +} + +bool SunSink::open() +{ + const char* device = getenv("AUDIODEV"); + if (!device) device = "/dev/audio"; + + if (::access(device, F_OK) != 0) { + std::cerr << "akode: Device not found: " << device << "\n"; + goto failed; + } + + d->device = device; + + d->audio_fd = ::open(d->device, O_WRONLY, 0); + + if (d->audio_fd == -1) { + std::cerr << "akode: No write access to " << device << "\n"; + goto failed; + } + d->valid = true; + return true; + +failed: + d->valid = false; + return false; +} + + +void SunSink::close() { + if (d->audio_fd != -1) ::close(d->audio_fd); + d->audio_fd = -1; + d->valid = false; +} + +int SunSink::setAudioConfiguration(const AudioConfiguration* config) +{ + d->config = *config; + + AUDIO_INITINFO(&d->auinfo) + + if (ioctl(d->audio_fd, AUDIO_GETINFO, &d->auinfo) < 0) + { + d->valid = false; + return -1; + } + + int width = config->sample_width; + if (width < 0 ) width = 16; + d->auinfo.play.precision = width; + + d->auinfo.play.encoding = AUDIO_ENCODING_LINEAR; + + d->auinfo.play.channels = config->channels; + d->auinfo.play.sample_rate = config->sample_rate; + + if (ioctl(d->audio_fd, AUDIO_SETINFO, &d->auinfo) < 0) + { + d->valid = false; + return -1; + } + + if (ioctl(d->audio_fd, AUDIO_GETINFO, &d->auinfo) < 0) + { + d->valid = false; + return -1; + } + + d->config.sample_width = d->auinfo.play.precision; + d->config.channels = d->auinfo.play.channels; + d->config.sample_rate = d->auinfo.play.sample_rate; + if (d->config.channels <= 2) d->config.channel_config = MonoStereo; + + if (d->config == *config) + return 0; + else + return 1; +} + +const AudioConfiguration* SunSink::audioConfiguration() const +{ + return &d->config; +} + +bool SunSink::writeFrame(AudioFrame* frame) +{ + if (!d->valid) return false; + + if ( frame->sample_width != d->config.sample_width + || frame->channels != d->config.channels ) + { + if (setAudioConfiguration(frame) < 0) + return false; + } + + int channels = d->config.channels; + int length = frame->length; + + int16_t *buffer = (int16_t*)alloca(length*channels*2); + int16_t** data = (int16_t**)frame->data; + for(int i = 0; i<length; i++) + for(int j=0; j<channels; j++) + buffer[i*channels+j] = data[j][i]; + +// std::cerr << "Writing frame\n"; + int status = 0; + do { + status = ::write(d->audio_fd, buffer, channels*length*2); + if (status == -1) { +// if (errno == EAGAIN) continue; + if (errno == EINTR) continue; + return false; + } + } while(false); + + return true; +} + +} // namespace |