/* aKode: Sun-Sink Copyright (C) 2005 Allan Sandfeld Jensen 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 #include #include #include #include #include #include #include #include "sun_sink.h" #include 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; iaudio_fd, buffer, channels*length*2); if (status == -1) { // if (errno == EAGAIN) continue; if (errno == EINTR) continue; return false; } } while(false); return true; } } // namespace