Fix Alsa issues thanks to David Grant <davidgrant@gmail.com> in bug 167229
authorStefan Schweizer <genstef@gentoo.org>
Tue, 20 Mar 2007 21:50:17 +0000 (21:50 +0000)
committerStefan Schweizer <genstef@gentoo.org>
Tue, 20 Mar 2007 21:50:17 +0000 (21:50 +0000)
Package-Manager: portage-2.1.2.2

media-sound/lastfmplayer/ChangeLog
media-sound/lastfmplayer/Manifest
media-sound/lastfmplayer/files/13_alsa-r1.diff [new file with mode: 0644]
media-sound/lastfmplayer/files/digest-lastfmplayer-1.1.3-r1 [moved from media-sound/lastfmplayer/files/digest-lastfmplayer-1.1.3 with 100% similarity]
media-sound/lastfmplayer/lastfmplayer-1.1.3-r1.ebuild [moved from media-sound/lastfmplayer/lastfmplayer-1.1.3.ebuild with 93% similarity]

index c3880c735daf03e0c68c6e3e4b2f9711b091fda0..2b760b1cd56ef2b57b9599f0015a96e69a5ae57b 100644 (file)
@@ -1,6 +1,12 @@
 # ChangeLog for media-sound/lastfmplayer
 # Copyright 1999-2007 Gentoo Foundation; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/media-sound/lastfmplayer/ChangeLog,v 1.12 2007/02/12 13:55:38 blubb Exp $
+# $Header: /var/cvsroot/gentoo-x86/media-sound/lastfmplayer/ChangeLog,v 1.13 2007/03/20 21:50:17 genstef Exp $
+
+*lastfmplayer-1.1.3-r1 (20 Mar 2007)
+
+  20 Mar 2007; <stefan@gentoo.org> +files/13_alsa-r1.diff,
+  -lastfmplayer-1.1.3.ebuild, +lastfmplayer-1.1.3-r1.ebuild:
+  Fix Alsa issues thanks to David Grant <davidgrant@gmail.com> in bug 167229
 
   12 Feb 2007; Simon Stelling <blubb@gentoo.org>
   +files/lastfmplayer-1.1.3-pic.patch, lastfmplayer-1.1.3.ebuild:
index 57e159d5d64d56c60a6e1cfd964d1041fa036278..2af4d2d8463af99dc0af5c870e9450448bd17c61 100644 (file)
@@ -1,3 +1,7 @@
+AUX 13_alsa-r1.diff 73384 RMD160 7f85545a1008183a6c84b67eb06e618ade7011db SHA1 8ae27d2a74c932a2d3ef1ae12b6a0407d297991e SHA256 5ec8a053ed07316eb345499f47aa68ec56c36f808586be610ffdbd30ea09110c
+MD5 28158673ebb7244a4b45a03824156dee files/13_alsa-r1.diff 73384
+RMD160 7f85545a1008183a6c84b67eb06e618ade7011db files/13_alsa-r1.diff 73384
+SHA256 5ec8a053ed07316eb345499f47aa68ec56c36f808586be610ffdbd30ea09110c files/13_alsa-r1.diff 73384
 AUX lastfm.protocol 159 RMD160 863935a9ee6f66f5c901f39182278346117f80b3 SHA1 827723dfcc15714fa676671ec6656d352419208a SHA256 c0f82b00703ed8c307e448ae49f173e30801a06ea2eb7a82d21a6b3f75f25093
 MD5 fb5e9996204c9704722582e18e15fb1a files/lastfm.protocol 159
 RMD160 863935a9ee6f66f5c901f39182278346117f80b3 files/lastfm.protocol 159
@@ -16,14 +20,14 @@ EBUILD lastfmplayer-1.0.0.1_p2113.ebuild 2909 RMD160 5d1b9f5ec1bfa5478340a4642c5
 MD5 35d2b802066475c80e71fdef3ac94cd3 lastfmplayer-1.0.0.1_p2113.ebuild 2909
 RMD160 5d1b9f5ec1bfa5478340a4642c53bc2a0f03da0d lastfmplayer-1.0.0.1_p2113.ebuild 2909
 SHA256 9cfb87a38978a6a7a0ec684be23f316292524dcaa330a068a1a00aac046aec88 lastfmplayer-1.0.0.1_p2113.ebuild 2909
-EBUILD lastfmplayer-1.1.3.ebuild 1860 RMD160 426494aceb44262ddd759f42fd6157f0abe93131 SHA1 a4c4dfc1ca012d3f80074b0fe977fac82b3b176f SHA256 0ced51e396d328c787c92edb0b19ea833395769fd2320c7a6016c024e97efed3
-MD5 3a90f98db08d918beb940365f2a2d224 lastfmplayer-1.1.3.ebuild 1860
-RMD160 426494aceb44262ddd759f42fd6157f0abe93131 lastfmplayer-1.1.3.ebuild 1860
-SHA256 0ced51e396d328c787c92edb0b19ea833395769fd2320c7a6016c024e97efed3 lastfmplayer-1.1.3.ebuild 1860
-MISC ChangeLog 2720 RMD160 811638e8dd84c8bafc79610eac0c3941835b00d6 SHA1 7d00be9c5b2a81241606952af5cc9f29ba275d5f SHA256 b6596eee10f390659d37ce5f04d18ef3a8774a28bbaa6be1e7d2b4c3eaf8a01b
-MD5 ef458aac1e686649ddd3c78f32f3e77d ChangeLog 2720
-RMD160 811638e8dd84c8bafc79610eac0c3941835b00d6 ChangeLog 2720
-SHA256 b6596eee10f390659d37ce5f04d18ef3a8774a28bbaa6be1e7d2b4c3eaf8a01b ChangeLog 2720
+EBUILD lastfmplayer-1.1.3-r1.ebuild 1932 RMD160 28c1f9e2328664ca020981eafa66c934385d78bc SHA1 05da84d910b72a5af777e89c9a916e7406c44bd7 SHA256 7802d20bb4737af2f51ed512a5c72ae920d8839bc0c8dd6ae77428ebd18fa438
+MD5 ee313a73ab4fba7db4e6dc652564e82e lastfmplayer-1.1.3-r1.ebuild 1932
+RMD160 28c1f9e2328664ca020981eafa66c934385d78bc lastfmplayer-1.1.3-r1.ebuild 1932
+SHA256 7802d20bb4737af2f51ed512a5c72ae920d8839bc0c8dd6ae77428ebd18fa438 lastfmplayer-1.1.3-r1.ebuild 1932
+MISC ChangeLog 2958 RMD160 1e8dcfd7164368996e25f8dd9d2f2063b5b1ae45 SHA1 53aa13ea46efe9d83bb3f985c334c2e9ecdff391 SHA256 284efaee2d1b7afc5469b4d66a9aaee86ac0f07a51c781b95327de01e05371ab
+MD5 df836e76d3f878dfe9e91aded196605d ChangeLog 2958
+RMD160 1e8dcfd7164368996e25f8dd9d2f2063b5b1ae45 ChangeLog 2958
+SHA256 284efaee2d1b7afc5469b4d66a9aaee86ac0f07a51c781b95327de01e05371ab ChangeLog 2958
 MISC metadata.xml 251 RMD160 d7ccc9e1d41d94cb971d83931a8ece9a684f6fc6 SHA1 1a65ae8b81af34d32b85ed8a18e1df5caef40ff3 SHA256 c87b81ca4913491f67f603b92fa806fb2af4f29d1fec96891731d2ac7490cb2b
 MD5 99b44433affea389a5ec121d625af495 metadata.xml 251
 RMD160 d7ccc9e1d41d94cb971d83931a8ece9a684f6fc6 metadata.xml 251
@@ -31,6 +35,6 @@ SHA256 c87b81ca4913491f67f603b92fa806fb2af4f29d1fec96891731d2ac7490cb2b metadata
 MD5 fd123671a9e7c9d43238d7a160030201 files/digest-lastfmplayer-1.0.0.1_p2113 286
 RMD160 f314831eaa27bc6b6b40b1a0cddcc48ba3a94a9b files/digest-lastfmplayer-1.0.0.1_p2113 286
 SHA256 38616aa5a2814055010380fd603e5e190c8494d53fcf83ac9f0a314e37aed135 files/digest-lastfmplayer-1.0.0.1_p2113 286
-MD5 6657a20eaa2d2330819948b39f61b44e files/digest-lastfmplayer-1.1.3 256
-RMD160 eb29f6d2e05b76d63cf8ba7e0c56ce3e0fc013b5 files/digest-lastfmplayer-1.1.3 256
-SHA256 7cf053b4971e3bd4505ef93741f9a673cd565a6ee07e6f5cc68755526a60c2cd files/digest-lastfmplayer-1.1.3 256
+MD5 6657a20eaa2d2330819948b39f61b44e files/digest-lastfmplayer-1.1.3-r1 256
+RMD160 eb29f6d2e05b76d63cf8ba7e0c56ce3e0fc013b5 files/digest-lastfmplayer-1.1.3-r1 256
+SHA256 7cf053b4971e3bd4505ef93741f9a673cd565a6ee07e6f5cc68755526a60c2cd files/digest-lastfmplayer-1.1.3-r1 256
diff --git a/media-sound/lastfmplayer/files/13_alsa-r1.diff b/media-sound/lastfmplayer/files/13_alsa-r1.diff
new file mode 100644 (file)
index 0000000..e5289d3
--- /dev/null
@@ -0,0 +1,2186 @@
+diff -urN last.fm-1.1.3.orig/LastFM.pro last.fm-1.1.3/LastFM.pro
+--- last.fm-1.1.3.orig/LastFM.pro      2007-03-18 20:57:23.000000000 -0700
++++ last.fm-1.1.3/LastFM.pro   2007-03-18 20:59:36.000000000 -0700
+@@ -5,8 +5,19 @@
+            src/webservice/ src/settingsservice/ \
+            src/httpinput/ \
+            src/mp3transcode/ \
+-           src/rtaudioplayback/ \
+            src/metadataextension/ src/sidebarextension/ src/searchextension/ src/userinfoextension/ \
+            src/mediadevices/itunes/
+ TRANSLATIONS = i18n/lastfm_jp_JP.ts
++
++win32 {
++    SUBDIRS += src/rtaudioplayback/
++}
++
++unix:!linux-g++ {
++    SUBDIRS += src/rtaudioplayback/
++}
++
++unix:linux-g++ {
++    SUBDIRS += src/alsaplayback/
++}
+diff -urN last.fm-1.1.3.orig/src/alsaplayback/alsaaudio.cpp last.fm-1.1.3/src/alsaplayback/alsaaudio.cpp
+--- last.fm-1.1.3.orig/src/alsaplayback/alsaaudio.cpp  1969-12-31 16:00:00.000000000 -0800
++++ last.fm-1.1.3/src/alsaplayback/alsaaudio.cpp       2007-03-18 20:57:28.000000000 -0700
+@@ -0,0 +1,851 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by John Stamp                                      *
++ *   jstamp@users.sourceforge.net                                          *
++ *                                                                         *
++ *   Large portions of this code are shamelessly copied from audio.c:      *
++ *   The XMMS ALSA output plugin                                           *
++ *   Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org>           *
++ *   Copyright (C) 1998-2003  Peter Alm, Mikael Alm, Olle Hallnas,         *
++ *                            Thomas Nilsson and 4Front Technologies       *
++ *   Copyright (C) 1999-2006  Haavard Kvaalen                              *
++ *   Copyright (C) 2005       Takashi Iwai                                 *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program 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 General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
++ ***************************************************************************/
++#include "alsaaudio.h"
++#include "Loqqer.h"
++#include <qendian.h>
++
++#include <QDebug>
++
++#define MIN( a, b )  ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
++#define MAX_BUFFER_SIZE 5
++
++QMutex AlsaAudio::mutex;
++pthread_t AlsaAudio::audio_thread;
++
++QByteArray AlsaAudio::audioData;
++snd_output_t* AlsaAudio::logs = NULL;
++bool AlsaAudio::going = false;
++snd_pcm_t *AlsaAudio::alsa_pcm = NULL;
++
++int AlsaAudio::hw_period_size_in = 0;
++snd_format* AlsaAudio::inputf = NULL;
++snd_format* AlsaAudio::outputf = NULL;
++float AlsaAudio::volume = 1.0;
++
++convert_func_t         AlsaAudio::alsa_convert_func = NULL;
++convert_channel_func_t AlsaAudio::alsa_stereo_convert_func =NULL;
++convert_freq_func_t    AlsaAudio::alsa_frequency_convert_func =NULL;
++xmms_convert_buffers   *AlsaAudio::convertb = NULL;
++bool AlsaAudio::use_mmap = false;
++
++
++AlsaAudio::AlsaAudio()
++{
++    maxBufferSize = 0;
++}
++
++
++AlsaAudio::~AlsaAudio()
++{
++}
++
++
++/******************************************************************************
++    Device Detection
++******************************************************************************/
++
++int AlsaAudio::getCards( void )
++{
++    int card = -1;
++    int err = 0;
++    _devices.clear();
++
++    if ( ( err = snd_card_next( &card ) ) != 0 )
++    {
++        LOGL( 1, "AlsaAudio::getCards() failed: " << snd_strerror( -err ) );
++        return -1;
++    }
++
++    while ( card > -1 )
++    {
++        getDevicesForCard( card );
++        if ( ( err = snd_card_next( &card ) ) != 0 )
++        {
++            LOGL( 1, "AlsaAudio::getCards() failed: " << snd_strerror( -err ) );
++            return -1;
++        }
++    }
++    return _devices.size();
++}
++
++
++void AlsaAudio::getDevicesForCard( int card )
++{
++    int pcm_device = -1, err;
++    snd_pcm_info_t *pcm_info;
++    snd_ctl_t *ctl;
++    char devName[64], *card_name;
++
++    sprintf( devName, "hw:%i", card );
++
++    if ( ( err = snd_ctl_open( &ctl, devName, 0 ) ) < 0 )
++    {
++        LOGL( 1, "AlsaAudio::getDevicesForCard() failed: " << snd_strerror( -err ) );
++        return;
++    }
++
++    if ( ( err = snd_card_get_name( card, &card_name ) ) != 0 )
++    {
++        LOGL( 1, "AlsaAudio::getDevicesForCard() failed: " << snd_strerror( -err ) );
++        card_name = "Unknown soundcard";
++    }
++
++    // Each card has its own default device
++    // But test, just to be sure it's there
++    AlsaDeviceInfo dev;
++    dev.name = QString( "%1: Default Device (default:%2)" ).arg( card_name ).arg( card );
++    dev.device = QString( "default:%1" ).arg( card );
++    snd_pcm_t *test_pcm;
++    err = snd_pcm_open( &test_pcm, dev.device.toStdString().c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK );
++    if ( err >= 0 )
++        snd_pcm_close( test_pcm );
++    if ( err == 0 || err == -EBUSY )
++        _devices.push_back( dev );
++
++    snd_pcm_info_alloca( &pcm_info );
++
++    for ( ;; )
++    {
++        char device[64], descr[128];
++        if ( ( err = snd_ctl_pcm_next_device( ctl, &pcm_device ) ) < 0 )
++        {
++            LOGL( 1, "AlsaAudio::getDevicesForCard() failed: " << snd_strerror( -err ) );
++            pcm_device = -1;
++        }
++        if ( pcm_device < 0 )
++            break;
++
++        snd_pcm_info_set_device( pcm_info, pcm_device );
++        snd_pcm_info_set_subdevice( pcm_info, 0 );
++        snd_pcm_info_set_stream( pcm_info, SND_PCM_STREAM_PLAYBACK );
++
++        if ( ( err = snd_ctl_pcm_info( ctl, pcm_info ) ) < 0 )
++        {
++            if ( err != -ENOENT )
++                LOGL( 1, "AlsaAudio::getDevicesForCard: snd_ctl_pcm_info() failed ("
++                         << card << ":" << pcm_device << "): " << snd_strerror( -err ) );
++            continue;
++        }
++
++        sprintf( device, "hw:%d,%d", card, pcm_device );
++        sprintf( descr, "%s: %s (%s)", card_name,
++                                       snd_pcm_info_get_name( pcm_info ),
++                                       device );
++        dev.name = descr;
++        dev.device = device;
++        _devices.push_back( dev );
++    }
++
++    snd_ctl_close( ctl );
++}
++
++
++AlsaDeviceInfo AlsaAudio::getDeviceInfo( int device )
++{
++    return _devices[device];
++}
++
++
++/******************************************************************************
++    Device Setup
++******************************************************************************/
++
++bool AlsaAudio::alsaSetup( QString device, snd_pcm_uframes_t periodSize, uint periodCount, snd_format *f )
++{
++    int err, hw_period_size;
++    snd_pcm_hw_params_t *hwparams;
++    snd_pcm_sw_params_t *swparams;
++    snd_pcm_uframes_t alsa_buffer_size, alsa_period_size;
++    snd_pcm_access_mask_t *mask;
++
++#ifndef QT_NO_DEBUG
++    qDebug() << "AlsaAudio::alsaSetup()";
++    snd_output_stdio_attach( &logs, stderr, 0 );
++#endif
++
++    alsa_convert_func = NULL;
++    alsa_stereo_convert_func = NULL;
++    alsa_frequency_convert_func = NULL;
++
++    free( outputf );
++    outputf = snd_format_from_xmms( f->xmms_format, f->rate, f->channels );
++
++#ifndef QT_NO_DEBUG
++    qDebug() << "Opening device:" << device;
++#endif
++    // FIXME: Can snd_pcm_open() return EAGAIN?
++    if ( ( err = snd_pcm_open( &alsa_pcm, device.toStdString().c_str(),
++                 SND_PCM_STREAM_PLAYBACK,
++                 SND_PCM_NONBLOCK ) ) < 0 )
++    {
++        LOGL( 1, "AlsaAudio::alsaSetup(): Failed to open pcm device (" << device << "): " << snd_strerror( -err ) );
++        alsa_pcm = NULL;
++        free( outputf );
++        outputf = NULL;
++        return false;
++    }
++
++#ifndef QT_NO_DEBUG
++    snd_pcm_info_t *info;
++    int alsa_card, alsa_device, alsa_subdevice;
++
++    snd_pcm_info_alloca( &info );
++    snd_pcm_info( alsa_pcm, info );
++    alsa_card = snd_pcm_info_get_card( info );
++    alsa_device = snd_pcm_info_get_device( info );
++    alsa_subdevice = snd_pcm_info_get_subdevice( info );
++    qDebug() << "Card:" << alsa_card << "Device:" << alsa_device << "Subdevice:" << alsa_subdevice;
++#endif
++
++    snd_pcm_hw_params_alloca( &hwparams );
++
++    if ( ( err = snd_pcm_hw_params_any( alsa_pcm, hwparams ) ) < 0 )
++    {
++        LOGL( 1, "AlsaAudio::alsaSetup(): No configuration available for playback: " << snd_strerror( -err ) );
++        return false;
++    }
++
++    // First try to set up mmapped access
++    mask = (snd_pcm_access_mask_t*)alloca(snd_pcm_access_mask_sizeof());
++    snd_pcm_access_mask_none(mask);
++    snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
++    snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
++    snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
++
++#ifndef QT_NO_DEBUG
++    qDebug() << "Trying to set mmapped write mode";
++#endif
++    if ( ( err = snd_pcm_hw_params_set_access_mask( alsa_pcm, hwparams, mask ) ) < 0 )
++    {
++        use_mmap = false;
++#ifndef QT_NO_DEBUG
++        qDebug() << "Setting mmapped write mode failed: " << snd_strerror( -err ) << "\n Trying normal write mode";
++#endif
++        if ( ( err = snd_pcm_hw_params_set_access( alsa_pcm, hwparams,
++               SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
++        {
++            LOGL( 1, "AlsaAudio::alsaSetup(): Cannot set normal write mode: " << snd_strerror( -err ) );
++            return false;
++        }
++    }
++    else
++        use_mmap = true;
++
++    if ( ( err = snd_pcm_hw_params_set_format( alsa_pcm, hwparams, outputf->format ) ) < 0 )
++    {
++        //Try if one of these format work (one of them should work
++        //on almost all soundcards)
++
++        snd_pcm_format_t formats[] = { SND_PCM_FORMAT_S16_LE,
++                                       SND_PCM_FORMAT_S16_BE,
++                                       SND_PCM_FORMAT_U8
++                                     };
++        uint i;
++
++        for ( i = 0; i < sizeof( formats ) / sizeof( formats[0] ); i++ )
++        {
++            if ( snd_pcm_hw_params_set_format( alsa_pcm, hwparams, formats[i] ) == 0 )
++            {
++                outputf->format = formats[i];
++                break;
++            }
++        }
++        if ( outputf->format != f->format )
++        {
++            outputf->xmms_format = (AFormat)format_from_alsa( outputf->format );
++#ifndef QT_NO_DEBUG
++            qDebug() << "Converting format from" << f->xmms_format << "to" << outputf->xmms_format;
++#endif
++            if ( outputf->xmms_format < 0 )
++                return -1;
++            alsa_convert_func = xmms_convert_get_func( outputf->xmms_format, f->xmms_format );
++            if ( alsa_convert_func == NULL )
++            {
++                LOGL( 1, "Format translation needed, but not available.  Input: " << f->xmms_format << "; Output: " << outputf->xmms_format );
++                return false;
++            }
++        }
++        else
++        {
++            LOGL( 1, "AlsaAudio::alsaSetup(): Sample format not available for playback: " << snd_strerror( -err ) );
++            return false;
++        }
++    }
++
++    snd_pcm_hw_params_set_channels_near( alsa_pcm, hwparams, &outputf->channels );
++    if ( outputf->channels != f->channels )
++    {
++#ifndef QT_NO_DEBUG
++        qDebug() << "Converting channels from" << f->channels << "to" << outputf->channels;
++#endif
++        alsa_stereo_convert_func =
++                xmms_convert_get_channel_func( outputf->xmms_format,
++                                               outputf->channels,
++                                               f->channels );
++        if ( alsa_stereo_convert_func == NULL )
++        {
++            LOGL( 1, "No stereo conversion available.  Format: " << outputf->xmms_format << "; Input Channels: " << f->channels << "; Output Channels: " << outputf->channels );
++            return false;
++        }
++    }
++
++    snd_pcm_hw_params_set_rate_near( alsa_pcm, hwparams, &outputf->rate, 0 );
++    if ( outputf->rate == 0 )
++    {
++        LOGL( 1, "AlsaAudio::alsaSetup: No usable samplerate available." );
++        return false;
++    }
++    if ( outputf->rate != f->rate )
++    {
++        LOGL( 3, "Converting samplerate from " << f->rate << "  to " << outputf->rate );
++        if ( outputf->channels < 1 || outputf->channels > 2 )
++        {
++            LOGL( 1, "Unsupported number of channels: " << outputf->channels << ". Resample function not available" );
++            alsa_frequency_convert_func = NULL;
++            return false;
++        }
++        alsa_frequency_convert_func =
++                xmms_convert_get_frequency_func( outputf->xmms_format,
++                                                 outputf->channels );
++        if ( alsa_frequency_convert_func == NULL )
++        {
++            LOGL( 1, "Resample function not available.  Format " << outputf->xmms_format );
++            return false;
++        }
++    }
++
++    outputf->sample_bits = snd_pcm_format_physical_width( outputf->format );
++    outputf->bps = ( outputf->rate * outputf->sample_bits * outputf->channels ) >> 3;
++
++    if ( ( err = snd_pcm_hw_params_set_period_size_near( alsa_pcm, hwparams,
++                                                         &periodSize, NULL ) ) < 0 )
++    {
++        LOGL( 1, "AlsaAudio::alsaSetup(): Set period size failed: " << snd_strerror( -err ) );
++        return false;
++    }
++
++    if ( ( err = snd_pcm_hw_params_set_periods_near( alsa_pcm, hwparams,
++         &periodCount, 0 ) ) < 0 )
++    {
++        LOGL( 1, "AlsaAudio::alsaSetup(): Set period count failed: " << snd_strerror( -err ) );
++        return false;
++    }
++
++    if ( snd_pcm_hw_params( alsa_pcm, hwparams ) < 0 )
++    {
++#ifndef QT_NO_DEBUG
++        snd_pcm_hw_params_dump( hwparams, logs );
++#endif
++        LOGL( 1, "AlsaAudio::alsaSetup(): Unable to install hw params" );
++        return false;
++    }
++
++    if ( ( err = snd_pcm_hw_params_get_buffer_size( hwparams, &alsa_buffer_size ) ) < 0 )
++    {
++        LOGL( 1, "AlsaAudio::alsaSetup(): snd_pcm_hw_params_get_buffer_size() failed: " << snd_strerror( -err ) );
++        return false;
++    }
++
++    if ( ( err = snd_pcm_hw_params_get_period_size( hwparams, &alsa_period_size, 0 ) ) < 0 )
++    {
++        LOGL( 1, "AlsaAudio::alsaSetup(): snd_pcm_hw_params_get_period_size() failed: " << snd_strerror( -err ) );
++        return false;
++    }
++    snd_pcm_sw_params_alloca( &swparams );
++    snd_pcm_sw_params_current( alsa_pcm, swparams );
++
++    if ( ( err = snd_pcm_sw_params_set_start_threshold( alsa_pcm,
++         swparams, alsa_buffer_size - alsa_period_size ) < 0 ) )
++        LOGL( 1, "AlsaAudio::alsaSetup(): setting start threshold failed: " << snd_strerror( -err ) );
++    if ( snd_pcm_sw_params( alsa_pcm, swparams ) < 0 )
++    {
++        LOGL( 1, "AlsaAudio::alsaSetup(): Unable to install sw params" );
++        return false;
++    }
++
++#ifndef QT_NO_DEBUG
++    snd_pcm_sw_params_dump( swparams, logs );
++    snd_pcm_dump( alsa_pcm, logs );
++#endif
++    hw_period_size = snd_pcm_frames_to_bytes( alsa_pcm, alsa_period_size );
++    if ( inputf->bps != outputf->bps )
++    {
++        int align = ( inputf->sample_bits * inputf->channels ) / 8;
++        hw_period_size_in = ( (quint64)hw_period_size * inputf->bps +
++                            outputf->bps/2 ) / outputf->bps;
++        hw_period_size_in -= hw_period_size_in % align;
++    }
++    else
++    {
++        hw_period_size_in = hw_period_size;
++    }
++
++#ifndef QT_NO_DEBUG
++    qDebug() << "Device setup: period size:" << hw_period_size;
++    qDebug() << "bits per sample:" <<  snd_pcm_format_physical_width( outputf->format ) <<
++            "frame size:" <<  snd_pcm_frames_to_bytes( alsa_pcm, 1 ) <<
++            "Bps:" << outputf->bps;
++#endif
++    return true;
++}
++
++bool AlsaAudio::alsaOpen( QString device, AFormat format, unsigned int rate, unsigned int channels, unsigned int buffer_time, unsigned int period_time )
++{
++#ifndef QT_NO_DEBUG
++    qDebug() << "Opening device";
++#endif
++    inputf = snd_format_from_xmms( format, rate, channels );
++
++    // We'll be using this in alsaWrite
++    maxBufferSize = inputf->bps * MAX_BUFFER_SIZE;
++    // And clear the buffer, just in case
++    clearBuffer();
++
++    if ( alsaSetup( device, buffer_time, period_time, inputf ) == false )
++    {
++        alsaClose();
++        return false;
++    }
++
++    going = true;
++    convertb = xmms_convert_buffers_new();
++
++    AlsaAudio* aaThread = new AlsaAudio();
++#ifndef QT_NO_DEBUG
++    qDebug() << "Starting thread";
++#endif
++    pthread_create( &audio_thread, NULL, &alsa_loop, (void*)aaThread );
++
++    return true;
++}
++
++void AlsaAudio::clearBuffer( void )
++{
++    mutex.lock();
++    audioData.clear();
++    mutex.unlock();
++}
++
++/******************************************************************************
++    Play Interface
++******************************************************************************/
++
++void AlsaAudio::alsaWrite( const QByteArray* inputData )
++{
++    if ( ( audioData.size() + inputData->size() ) < maxBufferSize )
++    {
++        mutex.lock();
++#ifndef QT_NO_DEBUG
++    qDebug( "max buffer size: %d; buffer data: %d; input data: %d", maxBufferSize, audioData.size(), inputData->size() );
++#endif
++        audioData.append( *inputData );
++        mutex.unlock();
++    }
++    else
++    {
++        mutex.lock();
++        int inSize = maxBufferSize - audioData.size();
++#ifndef QT_NO_DEBUG
++    qDebug( "max buffer size: %d; buffer data: %d; input data: %d; truncated to: %d", 
++            maxBufferSize, audioData.size(), inputData->size(), inSize );
++#endif
++        audioData.append( inputData->left( inSize ) );
++        mutex.unlock();
++        LOGL( 1, "Max data buffer size reached.  Bytes dropped: " << inSize );
++    }
++}
++
++
++int AlsaAudio::bufferSize( void )
++{
++    return audioData.size();
++}
++
++void AlsaAudio::setVolume ( float vol )
++{
++    volume = vol;
++}
++
++
++void AlsaAudio::alsaClose( void )
++{
++    if ( !going )
++        return;
++
++#ifndef QT_NO_DEBUG
++    qDebug() << "Closing device";
++#endif
++
++    going = false;
++
++    pthread_join( audio_thread, NULL );
++
++    xmms_convert_buffers_destroy( convertb );
++    convertb = NULL;
++    free( inputf );
++    inputf = NULL;
++    free( outputf );
++    outputf = NULL;
++
++#ifndef QT_NO_DEBUG
++    snd_output_close( logs );
++    qDebug() << "Device closed";
++#endif
++}
++
++
++/******************************************************************************
++    Play Thread
++******************************************************************************/
++
++void* AlsaAudio::alsa_loop( void* pthis )
++{
++  AlsaAudio* aaThread = (AlsaAudio*)pthis;
++  aaThread->run();
++  return NULL;
++}
++
++
++void AlsaAudio::run( void )
++{
++    int npfds = snd_pcm_poll_descriptors_count( alsa_pcm );
++    struct pollfd *pfds;
++    unsigned short *revents;
++
++    if ( npfds <= 0 )
++        goto _error;
++    pfds = (struct pollfd*)malloc( sizeof( *pfds ) * npfds );
++    revents = (unsigned short*)malloc( sizeof( *revents ) * npfds );
++    while ( going && alsa_pcm )
++    {
++        if ( audioData.size() > hw_period_size_in )
++        {
++            snd_pcm_poll_descriptors( alsa_pcm, pfds, npfds );
++            if ( poll( pfds, npfds, 10 ) > 0 )
++            {
++                // need to check revents.  poll() with
++                // dmix returns a postive value even
++                // if no data is available
++                int i;
++                snd_pcm_poll_descriptors_revents( alsa_pcm, pfds,
++                        npfds, revents );
++                for ( i = 0; i < npfds; i++ )
++                    if ( revents[i] & POLLOUT )
++                {
++                    pumpThreadData();
++                    break;
++                }
++            }
++        }
++        else
++        {
++            struct timespec req;
++            req.tv_sec = 0;
++            req.tv_nsec = 10000000;
++            nanosleep( &req, NULL );
++        }
++    }
++    free( pfds );
++    free( revents );
++
++ _error:
++    alsa_close_pcm();
++    mutex.lock();
++    audioData.clear();
++    mutex.unlock();
++#ifndef QT_NO_DEBUG
++    qDebug() << "Exiting thread";
++#endif
++    pthread_exit( NULL );
++}
++
++
++/* transfer audio data from thread buffer to h/w */
++void AlsaAudio::pumpThreadData( void )
++{
++    int length, cnt, avail, datSize;
++
++    datSize = audioData.size();
++    length = MIN( hw_period_size_in, datSize );
++    avail = snd_pcm_frames_to_bytes( alsa_pcm, getAvailableFrames() );
++    length = MIN( length, avail );
++    while ( length > 0 )
++    {
++        cnt = MIN( length, datSize );
++        convertData( audioData.left( cnt ).data(), cnt );
++        mutex.lock();
++        audioData.remove( 0, cnt );
++        mutex.unlock();
++        length -= cnt;
++    }
++}
++
++
++/* update and get the available space on h/w buffer (in frames) */
++snd_pcm_sframes_t AlsaAudio::getAvailableFrames( void )
++{
++    snd_pcm_sframes_t ret;
++
++    if ( alsa_pcm == NULL )
++        return 0;
++
++    while ( ( ret = snd_pcm_avail_update( alsa_pcm ) ) < 0 )
++    {
++        ret = alsa_handle_error( ret );
++        if ( ret < 0 )
++        {
++            LOGL( 1, "alsa_get_avail(): snd_pcm_avail_update() failed: " << snd_strerror( -ret ) );
++            return 0;
++        }
++        return 0;
++    }
++    return ret;
++}
++
++
++/* transfer data to audio h/w; length is given in bytes
++ *
++ * data can be modified via rate conversion or
++ * software volume before passed to audio h/w
++ */
++void AlsaAudio::convertData( void* data, int length )
++{
++    if ( alsa_convert_func != NULL )
++        length = alsa_convert_func( convertb, &data, length );
++    if ( alsa_stereo_convert_func != NULL )
++        length = alsa_stereo_convert_func( convertb, &data, length );
++    if ( alsa_frequency_convert_func != NULL )
++    {
++        length = alsa_frequency_convert_func( convertb, &data, length,
++                                              inputf->rate,
++                                              outputf->rate );
++    }
++
++    adjustVolume( data, length, outputf->xmms_format );
++
++    writeToCard( (char*)data, length );
++}
++
++
++#define VOLUME_ADJUST( type, endian )                                       \
++do {                                                                        \
++    type *ptr = (type*)data;                                                \
++    for ( i = 0; i < length; i += 2 )                                       \
++    {                                                                       \
++        *ptr = qTo##endian( (type)( qFrom##endian( *ptr ) * volume  ) );    \
++        ptr++;                                                              \
++    }                                                                       \
++} while ( 0 )
++
++#define VOLUME_ADJUST8( type )           \
++do {                                     \
++    type *ptr = (type*)data;             \
++    for ( i = 0; i < length; i++ )       \
++    {                                    \
++        *ptr = (type)( *ptr * volume );  \
++        ptr++;                           \
++    }                                    \
++} while ( 0 )
++
++void AlsaAudio::adjustVolume( void* data, int length, AFormat fmt )
++{
++    int i;
++    if ( volume == 1.0 )
++        return;
++
++    switch ( fmt )
++    {
++        case FMT_S16_LE:
++            VOLUME_ADJUST( qint16, LittleEndian );
++            break;
++        case FMT_U16_LE:
++            VOLUME_ADJUST( quint16, LittleEndian );
++            break;
++        case FMT_S16_BE:
++            VOLUME_ADJUST( qint16, BigEndian );
++            break;
++        case FMT_U16_BE:
++            VOLUME_ADJUST( quint16, BigEndian );
++            break;
++        case FMT_S8:
++            VOLUME_ADJUST8( qint8 );
++            break;
++        case FMT_U8:
++            VOLUME_ADJUST8( quint8 );
++            break;
++        default:
++            LOGL( 1, "AlsaAudio::adjustVolume(): unhandled format: " << fmt );
++            break;
++    }
++}
++
++
++/* transfer data to audio h/w via normal write */
++void AlsaAudio::writeToCard( char *data, int length )
++{
++    snd_pcm_sframes_t written_frames;
++
++    while ( length > 0 )
++    {
++        int frames = snd_pcm_bytes_to_frames( alsa_pcm, length );
++
++        if ( use_mmap )
++        {
++            written_frames = snd_pcm_mmap_writei( alsa_pcm, data, frames );
++        }
++        else
++            written_frames = snd_pcm_writei( alsa_pcm, data, frames );
++
++        if ( written_frames > 0 )
++        {
++            int written = snd_pcm_frames_to_bytes( alsa_pcm, written_frames );
++            length -= written;
++            data += written;
++        }
++        else
++        {
++            int err = alsa_handle_error( (int)written_frames );
++            if ( err < 0 )
++            {
++                LOGL( 1, "AlsaAudio::writeToCard(): write error: " << snd_strerror( -err ) );
++                break;
++            }
++        }
++    }
++}
++
++
++/* handle generic errors */
++int AlsaAudio::alsa_handle_error( int err )
++{
++    switch ( err )
++    {
++        case -EPIPE:
++            return xrun_recover();
++        case -ESTRPIPE:
++            return suspend_recover();
++    }
++
++    return err;
++}
++
++
++/* close PCM and release associated resources */
++void AlsaAudio::alsa_close_pcm( void )
++{
++    if ( alsa_pcm )
++    {
++        int err;
++        snd_pcm_drop( alsa_pcm );
++        if ( ( err = snd_pcm_close( alsa_pcm ) ) < 0 )
++            LOGL( 1, "alsa_pcm_close() failed: " << snd_strerror( -err ) );
++        alsa_pcm = NULL;
++    }
++}
++
++
++int AlsaAudio::format_from_alsa( snd_pcm_format_t fmt )
++{
++    uint i;
++    for ( i = 0; i < sizeof( format_table ) / sizeof( format_table[0] ); i++ )
++        if ( format_table[i].alsa == fmt )
++            return format_table[i].xmms;
++    LOGL( 1, "Unsupported format: " << snd_pcm_format_name( fmt ) );
++    return -1;
++}
++
++struct snd_format * AlsaAudio::snd_format_from_xmms( AFormat fmt, int rate, int channels )
++{
++    struct snd_format *f = (struct snd_format*)malloc( sizeof( struct snd_format ) );
++    uint i;
++
++    f->xmms_format = fmt;
++    f->format = SND_PCM_FORMAT_UNKNOWN;
++
++    for ( i = 0; i < sizeof( format_table ) / sizeof( format_table[0] ); i++ )
++    {
++        if ( format_table[i].xmms == fmt )
++        {
++            f->format = format_table[i].alsa;
++            break;
++        }
++    }
++
++    /* Get rid of _NE */
++    for ( i = 0; i < sizeof( format_table ) / sizeof( format_table[0] ); i++ )
++    {
++        if ( format_table[i].alsa == f->format )
++        {
++            f->xmms_format = format_table[i].xmms;
++            break;
++        }
++    }
++
++    f->rate = rate;
++    f->channels = channels;
++    f->sample_bits = snd_pcm_format_physical_width( f->format );
++    f->bps = ( rate * f->sample_bits * channels ) >> 3;
++
++    return f;
++}
++
++
++int AlsaAudio::xrun_recover( void )
++{
++
++#ifndef QT_NO_DEBUG
++    snd_pcm_status_t *alsa_status;
++    snd_pcm_status_alloca( &alsa_status );
++    if ( snd_pcm_status( alsa_pcm, alsa_status ) < 0 )
++    {
++        qDebug() << "AlsaAudio::xrun_recover(): snd_pcm_status() failed";
++    }
++    else
++    {
++        snd_pcm_status_dump( alsa_status, logs );
++        qDebug() << "Status:\n" << logs;
++    }
++#endif
++
++    return snd_pcm_prepare( alsa_pcm );
++}
++
++int AlsaAudio::suspend_recover( void )
++{
++    int err;
++
++    while ( ( err = snd_pcm_resume( alsa_pcm ) ) == -EAGAIN )
++        /* wait until suspend flag is released */
++        sleep( 1 );
++    if ( err < 0 )
++    {
++        LOGL( 3, "alsa_handle_error(): snd_pcm_resume() failed." );
++        return snd_pcm_prepare( alsa_pcm );
++    }
++    return err;
++}
+diff -urN last.fm-1.1.3.orig/src/alsaplayback/alsaaudio.h last.fm-1.1.3/src/alsaplayback/alsaaudio.h
+--- last.fm-1.1.3.orig/src/alsaplayback/alsaaudio.h    1969-12-31 16:00:00.000000000 -0800
++++ last.fm-1.1.3/src/alsaplayback/alsaaudio.h 2007-03-18 20:57:28.000000000 -0700
+@@ -0,0 +1,121 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by John Stamp                                      *
++ *   jstamp@users.sourceforge.net                                          *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program 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 General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
++ ***************************************************************************/
++#ifndef ALSAAUDIO_H
++#define ALSAAUDIO_H
++
++#include <alsa/asoundlib.h>
++#include <QByteArray>
++#include <QList>
++#include <QString>
++#include <QMutex>
++#include "xconvert.h"
++
++struct AlsaDeviceInfo {
++    QString name;
++    QString device;
++};
++
++struct snd_format {
++    unsigned int rate;
++    unsigned int channels;
++    snd_pcm_format_t format;
++    AFormat xmms_format;
++    int sample_bits;
++    int bps;
++};
++
++static const struct {
++    AFormat xmms;
++    snd_pcm_format_t alsa;
++} format_table[] =
++                   { { FMT_S16_LE, SND_PCM_FORMAT_S16_LE },
++                     { FMT_S16_BE, SND_PCM_FORMAT_S16_BE },
++                     { FMT_S16_NE, SND_PCM_FORMAT_S16    },
++                     { FMT_U16_LE, SND_PCM_FORMAT_U16_LE },
++                     { FMT_U16_BE, SND_PCM_FORMAT_U16_BE },
++                     { FMT_U16_NE, SND_PCM_FORMAT_U16    },
++                     { FMT_U8,     SND_PCM_FORMAT_U8     },
++                     { FMT_S8,     SND_PCM_FORMAT_S8     },
++                   };
++
++class AlsaAudio {
++public:
++    AlsaAudio();
++
++    ~AlsaAudio();
++
++    int getCards();
++    AlsaDeviceInfo getDeviceInfo( int device );
++
++    bool alsaOpen( QString device, AFormat format, unsigned int rate,
++                   unsigned int channels, unsigned int buffer_time,
++                   unsigned int period_time );
++    void alsaWrite( const QByteArray* inputData );
++
++    void alsaClose( void );
++
++    void setVolume ( float vol );
++    int bufferSize( void );
++    void clearBuffer( void );
++
++private:
++    QList<AlsaDeviceInfo> _devices;
++
++    int maxBufferSize;
++
++    // The following static variables are configured in either
++    // alsaOpen or alsaSetup and used later in the audio thread
++    static int hw_period_size_in;
++    static snd_output_t *logs;
++    static bool going;
++    static snd_pcm_t *alsa_pcm;
++    static snd_format* inputf;
++    static snd_format* outputf;
++    static float volume;
++    static QByteArray audioData;
++    static convert_func_t alsa_convert_func;
++    static convert_channel_func_t alsa_stereo_convert_func;
++    static convert_freq_func_t alsa_frequency_convert_func;
++    static xmms_convert_buffers *convertb;
++    static pthread_t audio_thread;
++    static QMutex mutex;
++    static bool use_mmap;
++
++    void getDevicesForCard( int card );
++    bool alsaSetup( QString device, snd_pcm_uframes_t periodSize, uint periodCount, snd_format *f );
++
++    static void* alsa_loop( void* );
++    void run( void );
++    void pumpThreadData( void );
++    void convertData( void* data, int length );
++    void adjustVolume( void* data, int length, AFormat fmt );
++    void writeToCard( char *data, int length );
++
++    snd_pcm_sframes_t getAvailableFrames( void );
++    int alsa_handle_error( int err );
++    int xrun_recover( void );
++    int suspend_recover( void );
++    int format_from_alsa( snd_pcm_format_t fmt );
++    snd_format* snd_format_from_xmms( AFormat fmt, int rate, int channels );
++
++    void alsa_close_pcm( void );
++};
++
++#endif
+diff -urN last.fm-1.1.3.orig/src/alsaplayback/alsaplayback.cpp last.fm-1.1.3/src/alsaplayback/alsaplayback.cpp
+--- last.fm-1.1.3.orig/src/alsaplayback/alsaplayback.cpp       1969-12-31 16:00:00.000000000 -0800
++++ last.fm-1.1.3/src/alsaplayback/alsaplayback.cpp    2007-03-18 20:57:28.000000000 -0700
+@@ -0,0 +1,205 @@
++/***************************************************************************
++ *   Copyright (C) 2005 - 2006 by                                          *
++ *      Christian Muehlhaeuser, Last.fm Ltd <chris@last.fm>                *
++ *      Erik Jaelevik, Last.fm Ltd <erik@last.fm>                          *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program 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 General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Steet, Fifth Floor, Boston, MA  02111-1307, USA.          *
++ ***************************************************************************/
++
++#include <QtGui>
++
++#include "alsaplayback.h"
++#include "containerutils.h"
++#include "Loqqer.h"
++
++float AlsaPlayback::m_volume = 0.5;
++
++
++AlsaPlayback::AlsaPlayback() :
++    m_audio( 0 ),
++    m_timer( new QTimer( this ) )
++{
++    gLogger.Init( savePath( "playback.log" ), false );
++    gLogger.SetLevel( 4 );
++
++    LOGL( 3, "Initialising AlsaAudio Playback" );
++    initAudio();
++
++    connect( m_timer, SIGNAL( timeout() ), this, SLOT( checkBuffer() ) );
++}
++
++AlsaPlayback::~AlsaPlayback()
++{
++    delete m_audio;
++}
++
++void
++AlsaPlayback::setVolume( int volume )
++{
++    if ( m_audio )
++        m_audio->setVolume( (float)volume / 100.0 );
++}
++
++
++QStringList
++AlsaPlayback::soundSystems()
++{
++    QStringList l;
++    l << "Alsa";
++    return l;
++}
++
++
++QStringList
++AlsaPlayback::devices()
++{
++#ifndef QT_NO_DEBUG
++    qDebug() << "Querying audio devices";
++#endif
++    QStringList l;
++
++    if ( !m_audio )
++        return l;
++
++    int cards = m_audio->getCards();
++#ifndef QT_NO_DEBUG
++    qDebug() << "Device nums:" << cards;
++#endif
++
++    for ( int i = 0; i < cards; i++ )
++    {
++        AlsaDeviceInfo info;
++        info = m_audio->getDeviceInfo( i );
++#ifndef QT_NO_DEBUG
++        qDebug() << "Device name:" << info.name ;
++#endif
++
++        l << info.name;
++    }
++
++    return l;
++}
++
++
++void
++AlsaPlayback::startPlayback()
++{
++    int channels = 2;
++    int sampleRate = 44100;
++    int periodSize = 1024;  // According to mplayer, these two are good defaults.
++    int periodCount = 16;   // They create a buffer size of 16384 frames.
++    QString cardDevice;
++
++    if ( !m_audio )
++    {
++        LOGL( 1, "No AlsaAudio instance available." );
++        goto _error;
++    }
++
++    cardDevice = internalSoundCardID();
++
++    if ( !m_audio->alsaOpen( cardDevice, FMT_S16_LE, sampleRate, channels, periodSize, periodCount ) )
++        goto _error;
++
++    if ( !m_timer->isActive() )
++        m_timer->start( 15 );
++
++    return;
++
++_error:
++    // We need to send a stop signal to m_iInput here, otherwise
++    // it will keep running and filling up the buffers even though
++    // there is no available device.
++    emit stop();
++    QMessageBox::critical( qApp->activeWindow(), tr("Audio Error"), tr("No soundcard available."));
++    return;
++}
++
++
++void
++AlsaPlayback::stopPlayback()
++{
++    if ( !m_audio )
++    {
++        return;
++    }
++
++    m_timer->stop();
++    m_audio->alsaClose();
++}
++
++
++void
++AlsaPlayback::initAudio()
++{
++    m_audio = new AlsaAudio();
++
++    if ( m_audio )
++    {
++        LOGL( 1, "AlsaAudio successfully initialised." );
++    }
++    else
++    {
++        LOGL( 1, "Initialising AlsaAudio failed." );
++    }
++}
++
++
++void
++AlsaPlayback::dataAvailable( const QByteArray &buffer )
++{
++    m_audio->alsaWrite( &buffer );
++}
++
++
++void
++AlsaPlayback::clearBuffers()
++{
++    m_audio->clearBuffer();
++}
++
++
++void
++AlsaPlayback::checkBuffer()
++{
++    // NOTE: this is wavedata! 16kb of wavedata aprox. equals 1.6kb of mp3
++    if ( m_audio->bufferSize() < 16384 * 12 )
++        emit needData();
++}
++
++
++QString
++AlsaPlayback::internalSoundCardID()
++{
++    if ( !m_audio )
++        return "";
++
++    int cards = m_audio->getCards();
++
++    int cardnum = settingsService()->soundCard();
++
++    if ( cardnum < cards )
++    {
++        AlsaDeviceInfo info;
++        info = m_audio->getDeviceInfo( cardnum );
++        return info.device;
++    }
++    else
++        return "default";
++}
++
++
++Q_EXPORT_PLUGIN2( playback, AlsaPlayback )
+diff -urN last.fm-1.1.3.orig/src/alsaplayback/alsaplayback.h last.fm-1.1.3/src/alsaplayback/alsaplayback.h
+--- last.fm-1.1.3.orig/src/alsaplayback/alsaplayback.h 1969-12-31 16:00:00.000000000 -0800
++++ last.fm-1.1.3/src/alsaplayback/alsaplayback.h      2007-03-18 20:57:28.000000000 -0700
+@@ -0,0 +1,71 @@
++/***************************************************************************
++ *   Copyright (C) 2005 - 2006 by                                          *
++ *      Christian Muehlhaeuser, Last.fm Ltd <chris@last.fm>                *
++ *      Erik Jaelevik, Last.fm Ltd <erik@last.fm>                          *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program 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 General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Steet, Fifth Floor, Boston, MA  02111-1307, USA.          *
++ ***************************************************************************/
++
++#ifndef ALSAPLAYBACK_H
++#define ALSAPLAYBACK_H
++
++#include <playbackinterface.h>
++#include "alsaaudio.h"
++
++#include <QObject>
++#include <QTimer>
++
++class AlsaPlayback : public PlaybackInterface
++{
++    Q_OBJECT
++    Q_INTERFACES( PlaybackInterface )
++
++    public:
++        AlsaPlayback();
++        ~AlsaPlayback();
++
++        void initAudio();
++        float volume() { return m_volume; }
++
++        QStringList soundSystems();
++        QStringList devices();
++
++        static float m_volume;
++
++    signals:
++        void needData();
++        void stop();    // connected to m_iInput::stop()
++
++    public slots:
++        void dataAvailable( const QByteArray &buffer );
++        void clearBuffers();
++
++        void startPlayback();
++        void stopPlayback();
++
++        void setVolume( int volume );
++
++    private:
++        AlsaAudio *m_audio;
++        QTimer *m_timer;
++
++        QString internalSoundCardID();
++
++    private slots:
++        void checkBuffer();
++};
++
++#endif
+diff -urN last.fm-1.1.3.orig/src/alsaplayback/alsaplayback.pro last.fm-1.1.3/src/alsaplayback/alsaplayback.pro
+--- last.fm-1.1.3.orig/src/alsaplayback/alsaplayback.pro       1969-12-31 16:00:00.000000000 -0800
++++ last.fm-1.1.3/src/alsaplayback/alsaplayback.pro    2007-03-18 20:57:28.000000000 -0700
+@@ -0,0 +1,19 @@
++TEMPLATE      = lib
++CONFIG       += plugin
++INCLUDEPATH  += ../ ../libLastFMTools
++LOGGERDIR     = ../build
++LIBS         += -L../../bin -lLastFMTools -lasound
++OBJECTS_DIR = ../build
++MOC_DIR = ../build
++UI_DIR = ../build
++TARGET  = playback_alsaaudio
++DESTDIR = ../../bin/services
++
++include(../../definitions.pro.inc)
++
++HEADERS       = alsaplayback.h alsaaudio.h xconvert.h
++SOURCES       = alsaplayback.cpp alsaaudio.cpp xconvert.c
++
++LIBS += $$LOGGERDIR/Loqqer.o
++
++QT += gui xml network
+diff -urN last.fm-1.1.3.orig/src/alsaplayback/precompiled.h last.fm-1.1.3/src/alsaplayback/precompiled.h
+--- last.fm-1.1.3.orig/src/alsaplayback/precompiled.h  1969-12-31 16:00:00.000000000 -0800
++++ last.fm-1.1.3/src/alsaplayback/precompiled.h       2007-03-18 20:57:28.000000000 -0700
+@@ -0,0 +1,30 @@
++/***************************************************************************\r
++ *   Copyright (C) 2005 - 2006 by                                          *\r
++ *      Christian Muehlhaeuser, Last.fm Ltd <chris@last.fm>                *\r
++ *      Erik Jaelevik, Last.fm Ltd <erik@last.fm>                          *\r
++ *                                                                         *\r
++ *   This program is free software; you can redistribute it and/or modify  *\r
++ *   it under the terms of the GNU General Public License as published by  *\r
++ *   the Free Software Foundation; either version 2 of the License, or     *\r
++ *   (at your option) any later version.                                   *\r
++ *                                                                         *\r
++ *   This program is distributed in the hope that it will be useful,       *\r
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
++ *   GNU General Public License for more details.                          *\r
++ *                                                                         *\r
++ *   You should have received a copy of the GNU General Public License     *\r
++ *   along with this program; if not, write to the                         *\r
++ *   Free Software Foundation, Inc.,                                       *\r
++ *   51 Franklin Steet, Fifth Floor, Boston, MA  02111-1307, USA.          *\r
++ ***************************************************************************/\r
++\r
++/* Add C includes here */\r
++\r
++#if defined __cplusplus\r
++    /* Add C++ includes here */\r
++    #include <QtCore>\r
++    #include <QtGui>\r
++    #include <QtNetwork>\r
++    #include <QtXml>\r
++#endif // __cplusplus\r
+diff -urN last.fm-1.1.3.orig/src/alsaplayback/xconvert.c last.fm-1.1.3/src/alsaplayback/xconvert.c
+--- last.fm-1.1.3.orig/src/alsaplayback/xconvert.c     1969-12-31 16:00:00.000000000 -0800
++++ last.fm-1.1.3/src/alsaplayback/xconvert.c  2007-03-18 20:57:28.000000000 -0700
+@@ -0,0 +1,771 @@
++/*
++ *  Copyright (C) 2001-2003  Haavard Kvaalen <havardk@xmms.org>
++ *
++ *  Licensed under GNU LGPL version 2.
++ */
++
++#include <stdlib.h>
++#include <stdint.h>
++#include "xconvert.h"
++
++// These are adapted from defines in gtypes.h and glibconfig.h
++#ifndef FALSE
++#define FALSE    ( 0 )
++#endif
++
++#ifndef TRUE
++#define TRUE    ( !FALSE )
++#endif
++
++# define GUINT16_SWAP_LE_BE( val )                          \
++    ( ( uint16_t )                                          \
++        (                                                   \
++            ( uint16_t ) ( ( uint16_t ) ( val ) >> 8 ) |    \
++            ( uint16_t ) ( ( uint16_t ) ( val ) << 8 )      \
++        )                                                   \
++    )
++
++# define GINT16_SWAP_LE_BE( val )    ( ( int16_t ) GUINT16_SWAP_LE_BE ( val ) )
++
++#ifdef WORDS_BIGENDIAN
++
++# define IS_BIG_ENDIAN TRUE
++
++# define GINT16_TO_BE( val )       ( ( int16_t ) ( val ) )
++# define GINT16_FROM_BE( val )     ( ( int16_t ) ( val ) )
++# define GUINT16_TO_BE( val )      ( ( uint16_t ) ( val ) )
++# define GUINT16_FROM_BE( val )    ( ( uint16_t ) ( val ) )
++
++# define GUINT16_TO_LE( val )      ( GUINT16_SWAP_LE_BE ( val ) )
++# define GUINT16_FROM_LE( val )    ( GUINT16_SWAP_LE_BE ( val ) )
++# define GINT16_TO_LE( val )       ( ( int16_t ) GUINT16_SWAP_LE_BE ( val ) )
++# define GINT16_FROM_LE( val )     ( ( int16_t ) GUINT16_SWAP_LE_BE ( val ) )
++
++#else
++
++# define IS_BIG_ENDIAN FALSE
++
++# define GINT16_TO_LE( val )       ( ( int16_t ) ( val ) )
++# define GINT16_FROM_LE( val )     ( ( int16_t ) ( val ) )
++# define GUINT16_TO_LE( val )      ( ( uint16_t ) ( val ) )
++# define GUINT16_FROM_LE( val )    ( ( uint16_t ) ( val ) )
++
++# define GUINT16_TO_BE( val )      ( GUINT16_SWAP_LE_BE ( val ) )
++# define GUINT16_FROM_BE( val )    ( GUINT16_SWAP_LE_BE ( val ) )
++# define GINT16_TO_BE( val )       ( ( int16_t ) GUINT16_SWAP_LE_BE ( val ) )
++# define GINT16_FROM_BE( val )     ( ( int16_t ) GUINT16_SWAP_LE_BE ( val ) )
++
++#endif
++
++
++struct buffer {
++    void *buffer;
++    uint size;
++};
++
++struct xmms_convert_buffers {
++    struct buffer format_buffer, stereo_buffer, freq_buffer;
++};
++
++struct xmms_convert_buffers* xmms_convert_buffers_new( void )
++{
++    return calloc( 1, sizeof( struct xmms_convert_buffers ) );
++}
++
++static void* convert_get_buffer( struct buffer *buffer, size_t size )
++{
++    if ( size > 0 && size <= buffer->size )
++        return buffer->buffer;
++
++    buffer->size = size;
++    buffer->buffer = realloc( buffer->buffer, size );
++    return buffer->buffer;
++}
++
++void xmms_convert_buffers_free( struct xmms_convert_buffers* buf )
++{
++    convert_get_buffer( &buf->format_buffer, 0 );
++    convert_get_buffer( &buf->stereo_buffer, 0 );
++    convert_get_buffer( &buf->freq_buffer, 0 );
++}
++
++void xmms_convert_buffers_destroy( struct xmms_convert_buffers* buf )
++{
++    if ( !buf )
++        return;
++    xmms_convert_buffers_free( buf );
++    free( buf );
++}
++
++static int convert_swap_endian( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint16_t *ptr = *data;
++    int i;
++    for ( i = 0; i < length; i += 2, ptr++ )
++        *ptr = GUINT16_SWAP_LE_BE( *ptr );
++
++    return i;
++}
++
++static int convert_swap_sign_and_endian_to_native( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint16_t *ptr = *data;
++    int i;
++    for ( i = 0; i < length; i += 2, ptr++ )
++        *ptr = GUINT16_SWAP_LE_BE( *ptr ) ^ 1 << 15;
++
++    return i;
++}
++
++static int convert_swap_sign_and_endian_to_alien( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint16_t *ptr = *data;
++    int i;
++    for ( i = 0; i < length; i += 2, ptr++ )
++        *ptr = GUINT16_SWAP_LE_BE( *ptr ^ 1 << 15 );
++
++    return i;
++}
++
++static int convert_swap_sign16( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int16_t *ptr = *data;
++    int i;
++    for ( i = 0; i < length; i += 2, ptr++ )
++        *ptr ^= 1 << 15;
++
++    return i;
++}
++
++static int convert_swap_sign8( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int8_t *ptr = *data;
++    int i;
++    for ( i = 0; i < length; i++ )
++        *ptr++ ^= 1 << 7;
++
++    return i;
++}
++
++static int convert_to_8_native_endian( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int8_t *output = *data;
++    int16_t *input = *data;
++    int i;
++    for ( i = 0; i < length / 2; i++ )
++        *output++ = *input++ >> 8;
++
++    return i;
++}
++
++static int convert_to_8_native_endian_swap_sign( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int8_t *output = *data;
++    int16_t *input = *data;
++    int i;
++    for ( i = 0; i < length / 2; i++ )
++        *output++ = ( *input++ >> 8 ) ^ ( 1 << 7 );
++
++    return i;
++}
++
++
++static int convert_to_8_alien_endian( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int8_t *output = *data;
++    int16_t *input = *data;
++    int i;
++    for ( i = 0; i < length / 2; i++ )
++        *output++ = *input++ & 0xff;
++
++    return i;
++}
++
++static int convert_to_8_alien_endian_swap_sign( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int8_t *output = *data;
++    int16_t *input = *data;
++    int i;
++    for ( i = 0; i < length / 2; i++ )
++        *output++ = ( *input++ & 0xff ) ^ ( 1 << 7 );
++
++    return i;
++}
++
++static int convert_to_16_native_endian( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint8_t *input = *data;
++    uint16_t *output;
++    int i;
++    *data = convert_get_buffer( &buf->format_buffer, length * 2 );
++    output = *data;
++    for ( i = 0; i < length; i++ )
++        *output++ = *input++ << 8;
++
++    return i * 2;
++}
++
++static int convert_to_16_native_endian_swap_sign( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint8_t *input = *data;
++    uint16_t *output;
++    int i;
++    *data = convert_get_buffer( &buf->format_buffer, length * 2 );
++    output = *data;
++    for ( i = 0; i < length; i++ )
++        *output++ = ( *input++ << 8 ) ^ ( 1 << 15 );
++
++    return i * 2;
++}
++
++
++static int convert_to_16_alien_endian( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint8_t *input = *data;
++    uint16_t *output;
++    int i;
++    *data = convert_get_buffer( &buf->format_buffer, length * 2 );
++    output = *data;
++    for ( i = 0; i < length; i++ )
++        *output++ = *input++;
++
++    return i * 2;
++}
++
++static int convert_to_16_alien_endian_swap_sign( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint8_t *input = *data;
++    uint16_t *output;
++    int i;
++    *data = convert_get_buffer( &buf->format_buffer, length * 2 );
++    output = *data;
++    for ( i = 0; i < length; i++ )
++        *output++ = *input++ ^ ( 1 << 7 );
++
++    return i * 2;
++}
++
++static AFormat unnativize( AFormat fmt )
++{
++    if ( fmt == FMT_S16_NE )
++    {
++        if ( IS_BIG_ENDIAN )
++            return FMT_S16_BE;
++        else
++            return FMT_S16_LE;
++    }
++    if ( fmt == FMT_U16_NE )
++    {
++        if ( IS_BIG_ENDIAN )
++            return FMT_U16_BE;
++        else
++            return FMT_U16_LE;
++    }
++    return fmt;
++}
++
++convert_func_t xmms_convert_get_func( AFormat output, AFormat input )
++{
++    output = unnativize( output );
++    input = unnativize( input );
++
++    if ( output == input )
++        return NULL;
++
++    if ( ( output == FMT_U16_BE && input == FMT_U16_LE ) ||
++         ( output == FMT_U16_LE && input == FMT_U16_BE ) ||
++         ( output == FMT_S16_BE && input == FMT_S16_LE ) ||
++         ( output == FMT_S16_LE && input == FMT_S16_BE ) )
++        return convert_swap_endian;
++
++    if ( ( output == FMT_U16_BE && input == FMT_S16_BE ) ||
++         ( output == FMT_U16_LE && input == FMT_S16_LE ) ||
++         ( output == FMT_S16_BE && input == FMT_U16_BE ) ||
++         ( output == FMT_S16_LE && input == FMT_U16_LE ) )
++        return convert_swap_sign16;
++
++    if ( ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_BE && input == FMT_S16_LE ) ||
++           ( output == FMT_S16_BE && input == FMT_U16_LE ) ) ) ||
++        ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_LE && input == FMT_S16_BE ) ||
++           ( output == FMT_S16_LE && input == FMT_U16_BE ) ) ) )
++        return convert_swap_sign_and_endian_to_native;
++
++    if ( ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_BE && input == FMT_S16_LE ) ||
++           ( output == FMT_S16_BE && input == FMT_U16_LE ) ) ) ||
++        ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_LE && input == FMT_S16_BE ) ||
++           ( output == FMT_S16_LE && input == FMT_U16_BE ) ) ) )
++        return convert_swap_sign_and_endian_to_alien;
++
++    if ( ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U8 && input == FMT_U16_BE ) ||
++           ( output == FMT_S8 && input == FMT_S16_BE ) ) ) ||
++        ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U8 && input == FMT_U16_LE ) ||
++           ( output == FMT_S8 && input == FMT_S16_LE ) ) ) )
++        return convert_to_8_native_endian;
++
++    if ( ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U8 && input == FMT_S16_BE ) ||
++           ( output == FMT_S8 && input == FMT_U16_BE ) ) ) ||
++        ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U8 && input == FMT_S16_LE ) ||
++           ( output == FMT_S8 && input == FMT_U16_LE ) ) ) )
++        return convert_to_8_native_endian_swap_sign;
++
++    if ( ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U8 && input == FMT_U16_BE ) ||
++           ( output == FMT_S8 && input == FMT_S16_BE ) ) ) ||
++        ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U8 && input == FMT_U16_LE ) ||
++           ( output == FMT_S8 && input == FMT_S16_LE ) ) ) )
++        return convert_to_8_alien_endian;
++
++    if ( ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U8 && input == FMT_S16_BE ) ||
++           ( output == FMT_S8 && input == FMT_U16_BE ) ) ) ||
++        ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U8 && input == FMT_S16_LE ) ||
++           ( output == FMT_S8 && input == FMT_U16_LE ) ) ) )
++        return convert_to_8_alien_endian_swap_sign;
++
++    if ( ( output == FMT_U8 && input == FMT_S8 ) ||
++         ( output == FMT_S8 && input == FMT_U8 ) )
++        return convert_swap_sign8;
++
++    if ( ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_BE && input == FMT_U8 ) ||
++           ( output == FMT_S16_BE && input == FMT_S8 ) ) ) ||
++        ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_LE && input == FMT_U8 ) ||
++           ( output == FMT_S16_LE && input == FMT_S8 ) ) ) )
++        return convert_to_16_native_endian;
++
++    if ( ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_BE && input == FMT_S8 ) ||
++           ( output == FMT_S16_BE && input == FMT_U8 ) ) ) ||
++        ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_LE && input == FMT_S8 ) ||
++           ( output == FMT_S16_LE && input == FMT_U8 ) ) ) )
++        return convert_to_16_native_endian_swap_sign;
++
++    if ( ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_BE && input == FMT_U8 ) ||
++           ( output == FMT_S16_BE && input == FMT_S8 ) ) ) ||
++        ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_LE && input == FMT_U8 ) ||
++           ( output == FMT_S16_LE && input == FMT_S8 ) ) ) )
++        return convert_to_16_alien_endian;
++
++    if ( ( !IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_BE && input == FMT_S8 ) ||
++           ( output == FMT_S16_BE && input == FMT_U8 ) ) ) ||
++        ( IS_BIG_ENDIAN &&
++         ( ( output == FMT_U16_LE && input == FMT_S8 ) ||
++           ( output == FMT_S16_LE && input == FMT_U8 ) ) ) )
++        return convert_to_16_alien_endian_swap_sign;
++
++    //g_warning( "Translation needed, but not available.\n"
++    //      "Input: %d; Output %d.", input, output );
++    return NULL;
++}
++
++static int convert_mono_to_stereo( struct xmms_convert_buffers* buf, void **data, int length, int b16 )
++{
++    int i;
++    void *outbuf = convert_get_buffer( &buf->stereo_buffer, length * 2 );
++
++    if ( b16 )
++    {
++        uint16_t *output = outbuf, *input = *data;
++        for ( i = 0; i < length / 2; i++ )
++        {
++            *output++ = *input;
++            *output++ = *input;
++            input++;
++        }
++    }
++    else
++    {
++        uint8_t *output = outbuf, *input = *data;
++        for ( i = 0; i < length; i++ )
++        {
++            *output++ = *input;
++            *output++ = *input;
++            input++;
++        }
++    }
++    *data = outbuf;
++
++    return length * 2;
++}
++
++static int convert_mono_to_stereo_8( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    return convert_mono_to_stereo( buf, data, length, FALSE );
++}
++
++static int convert_mono_to_stereo_16( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    return convert_mono_to_stereo( buf, data, length, TRUE );
++}
++
++static int convert_stereo_to_mono_u8( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint8_t *output = *data, *input = *data;
++    int i;
++    for ( i = 0; i < length / 2; i++ )
++    {
++        uint16_t tmp;
++        tmp = *input++;
++        tmp += *input++;
++        *output++ = tmp / 2;
++    }
++    return length / 2;
++}
++static int convert_stereo_to_mono_s8( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int8_t *output = *data, *input = *data;
++    int i;
++    for ( i = 0; i < length / 2; i++ )
++    {
++        int16_t tmp;
++        tmp = *input++;
++        tmp += *input++;
++        *output++ = tmp / 2;
++    }
++    return length / 2;
++}
++static int convert_stereo_to_mono_u16le( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint16_t *output = *data, *input = *data;
++    int i;
++    for ( i = 0; i < length / 4; i++ )
++    {
++        uint32_t tmp;
++        uint16_t stmp;
++        tmp = GUINT16_FROM_LE( *input );
++        input++;
++        tmp += GUINT16_FROM_LE( *input );
++        input++;
++        stmp = tmp / 2;
++        *output++ = GUINT16_TO_LE( stmp );
++    }
++    return length / 2;
++}
++
++static int convert_stereo_to_mono_u16be( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    uint16_t *output = *data, *input = *data;
++    int i;
++    for ( i = 0; i < length / 4; i++ )
++    {
++        uint32_t tmp;
++        uint16_t stmp;
++        tmp = GUINT16_FROM_BE( *input );
++        input++;
++        tmp += GUINT16_FROM_BE( *input );
++        input++;
++        stmp = tmp / 2;
++        *output++ = GUINT16_TO_BE( stmp );
++    }
++    return length / 2;
++}
++
++static int convert_stereo_to_mono_s16le( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int16_t *output = *data, *input = *data;
++    int i;
++    for ( i = 0; i < length / 4; i++ )
++    {
++        int32_t tmp;
++        int16_t stmp;
++        tmp = GINT16_FROM_LE( *input );
++        input++;
++        tmp += GINT16_FROM_LE( *input );
++        input++;
++        stmp = tmp / 2;
++        *output++ = GINT16_TO_LE( stmp );
++    }
++    return length / 2;
++}
++
++static int convert_stereo_to_mono_s16be( struct xmms_convert_buffers* buf, void **data, int length )
++{
++    int16_t *output = *data, *input = *data;
++    int i;
++    for ( i = 0; i < length / 4; i++ )
++    {
++        int32_t tmp;
++        int16_t stmp;
++        tmp = GINT16_FROM_BE( *input );
++        input++;
++        tmp += GINT16_FROM_BE( *input );
++        input++;
++        stmp = tmp / 2;
++        *output++ = GINT16_TO_BE( stmp );
++    }
++    return length / 2;
++}
++
++convert_channel_func_t xmms_convert_get_channel_func( AFormat fmt, int output, int input )
++{
++    fmt = unnativize( fmt );
++
++    if ( output == input )
++        return NULL;
++
++    if ( input == 1 && output == 2 )
++        switch ( fmt )
++        {
++            case FMT_U8:
++            case FMT_S8:
++                return convert_mono_to_stereo_8;
++            case FMT_U16_LE:
++            case FMT_U16_BE:
++            case FMT_S16_LE:
++            case FMT_S16_BE:
++                return convert_mono_to_stereo_16;
++            default:
++                //g_warning( "Unknown format: %d"
++                //      "No conversion available.", fmt );
++                return NULL;
++        }
++    if ( input == 2 && output == 1 )
++        switch ( fmt )
++        {
++            case FMT_U8:
++                return convert_stereo_to_mono_u8;
++            case FMT_S8:
++                return convert_stereo_to_mono_s8;
++            case FMT_U16_LE:
++                return convert_stereo_to_mono_u16le;
++            case FMT_U16_BE:
++                return convert_stereo_to_mono_u16be;
++            case FMT_S16_LE:
++                return convert_stereo_to_mono_s16le;
++            case FMT_S16_BE:
++                return convert_stereo_to_mono_s16be;
++            default:
++                //g_warning( "Unknown format: %d.  "
++                //      "No conversion available.", fmt );
++                return NULL;
++        }
++
++    //g_warning( "Input has %d channels, soundcard uses %d channels\n"
++    //      "No conversion is available", input, output );
++    return NULL;
++}
++
++
++#define RESAMPLE_STEREO( sample_type, bswap )                   \
++do {                                                            \
++    const int shift = sizeof ( sample_type );                   \
++        int i, in_samples, out_samples, x, delta;               \
++    sample_type *inptr = *data, *outptr;                        \
++    uint nlen = ( ( ( length >> shift ) * ofreq ) / ifreq );    \
++    void *nbuf;                                                 \
++    if ( nlen == 0 )                                            \
++        break;                                                  \
++    nlen <<= shift;                                             \
++    if ( bswap )                                                \
++        convert_swap_endian( NULL, data, length );              \
++    nbuf = convert_get_buffer( &buf->freq_buffer, nlen );       \
++    outptr = nbuf;                                              \
++    in_samples = length >> shift;                               \
++        out_samples = nlen >> shift;                            \
++    delta = ( in_samples << 12 ) / out_samples;                 \
++    for ( x = 0, i = 0; i < out_samples; i++ )                  \
++    {                                                           \
++        int x1, frac;                                           \
++        x1 = ( x >> 12 ) << 12;                                 \
++        frac = x - x1;                                          \
++        *outptr++ =                                             \
++            ( ( inptr[( x1 >> 12 ) << 1] *                      \
++              ( ( 1<<12 ) - frac ) +                            \
++              inptr[( ( x1 >> 12 ) + 1 ) << 1] *                \
++              frac ) >> 12 );                                   \
++        *outptr++ =                                             \
++            ( ( inptr[( ( x1 >> 12 ) << 1 ) + 1] *              \
++              ( ( 1<<12 ) - frac ) +                            \
++              inptr[( ( ( x1 >> 12 ) + 1 ) << 1 ) + 1] *        \
++              frac ) >> 12 );                                   \
++        x += delta;                                             \
++    }                                                           \
++    if ( bswap )                                                \
++        convert_swap_endian( NULL, &nbuf, nlen );               \
++    *data = nbuf;                                               \
++    return nlen;                                                \
++} while ( 0 )
++
++
++#define RESAMPLE_MONO( sample_type, bswap )                     \
++do {                                                            \
++    const int shift = sizeof ( sample_type ) - 1;               \
++        int i, x, delta, in_samples, out_samples;               \
++    sample_type *inptr = *data, *outptr;                        \
++    uint nlen = ( ( ( length >> shift ) * ofreq ) / ifreq );    \
++    void *nbuf;                                                 \
++    if ( nlen == 0 )                                            \
++        break;                                                  \
++    nlen <<= shift;                                             \
++    if ( bswap )                                                \
++        convert_swap_endian( NULL, data, length );              \
++    nbuf = convert_get_buffer( &buf->freq_buffer, nlen );       \
++    outptr = nbuf;                                              \
++    in_samples = length >> shift;                               \
++        out_samples = nlen >> shift;                            \
++    delta = ( ( length >> shift ) << 12 ) / out_samples;        \
++    for ( x = 0, i = 0; i < out_samples; i++ )                  \
++    {                                                           \
++        int x1, frac;                                           \
++        x1 = ( x >> 12 ) << 12;                                 \
++        frac = x - x1;                                          \
++        *outptr++ =                                             \
++            ( ( inptr[x1 >> 12] * ( ( 1<<12 ) - frac ) +        \
++              inptr[( x1 >> 12 ) + 1] * frac ) >> 12 );         \
++        x += delta;                                             \
++    }                                                           \
++    if ( bswap )                                                \
++        convert_swap_endian( NULL, &nbuf, nlen );               \
++    *data = nbuf;                                               \
++    return nlen;                                                \
++} while ( 0 )
++
++static int convert_resample_stereo_s16ne( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_STEREO( int16_t, FALSE );
++    return 0;
++}
++
++static int convert_resample_stereo_s16ae( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_STEREO( int16_t, TRUE );
++    return 0;
++}
++
++static int convert_resample_stereo_u16ne( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_STEREO( uint16_t, FALSE );
++    return 0;
++}
++
++static int convert_resample_stereo_u16ae( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_STEREO( uint16_t, TRUE );
++    return 0;
++}
++
++static int convert_resample_mono_s16ne( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_MONO( int16_t, FALSE );
++    return 0;
++}
++
++static int convert_resample_mono_s16ae( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_MONO( int16_t, TRUE );
++    return 0;
++}
++
++static int convert_resample_mono_u16ne( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_MONO( uint16_t, FALSE );
++    return 0;
++}
++
++static int convert_resample_mono_u16ae( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_MONO( uint16_t, TRUE );
++    return 0;
++}
++
++static int convert_resample_stereo_u8( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_STEREO( uint8_t, FALSE );
++    return 0;
++}
++
++static int convert_resample_mono_u8( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_MONO( uint8_t, FALSE );
++    return 0;
++}
++
++static int convert_resample_stereo_s8( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_STEREO( int8_t, FALSE );
++    return 0;
++}
++
++static int convert_resample_mono_s8( struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq )
++{
++    RESAMPLE_MONO( int8_t, FALSE );
++    return 0;
++}
++
++
++convert_freq_func_t xmms_convert_get_frequency_func( AFormat fmt, int channels )
++{
++    fmt = unnativize( fmt );
++    //g_message( "fmt %d, channels: %d", fmt, channels );
++
++    if ( channels < 1 || channels > 2 )
++    {
++        //g_warning( "Unsupported number of channels: %d.  "
++        //      "Resample function not available", channels );
++        return NULL;
++    }
++    if ( (  IS_BIG_ENDIAN && fmt == FMT_U16_BE ) ||
++         ( !IS_BIG_ENDIAN && fmt == FMT_U16_LE ) )
++    {
++        if ( channels == 1 )
++            return convert_resample_mono_u16ne;
++        else
++            return convert_resample_stereo_u16ne;
++    }
++    if ( (  IS_BIG_ENDIAN && fmt == FMT_S16_BE ) ||
++         ( !IS_BIG_ENDIAN && fmt == FMT_S16_LE ) )
++    {
++        if ( channels == 1 )
++            return convert_resample_mono_s16ne;
++        else
++            return convert_resample_stereo_s16ne;
++    }
++    if ( ( !IS_BIG_ENDIAN && fmt == FMT_U16_BE ) ||
++         (  IS_BIG_ENDIAN && fmt == FMT_U16_LE ) )
++    {
++        if ( channels == 1 )
++            return convert_resample_mono_u16ae;
++        else
++            return convert_resample_stereo_u16ae;
++    }
++    if ( ( !IS_BIG_ENDIAN && fmt == FMT_S16_BE ) ||
++         (  IS_BIG_ENDIAN && fmt == FMT_S16_LE ) )
++    {
++        if ( channels == 1 )
++            return convert_resample_mono_s16ae;
++        else
++            return convert_resample_stereo_s16ae;
++    }
++    if ( fmt == FMT_U8 )
++    {
++        if ( channels == 1 )
++            return convert_resample_mono_u8;
++        else
++            return convert_resample_stereo_u8;
++    }
++    if ( fmt == FMT_S8 )
++    {
++        if ( channels == 1 )
++            return convert_resample_mono_s8;
++        else
++            return convert_resample_stereo_s8;
++    }
++    //g_warning( "Resample function not available"
++    //      "Format %d.", fmt );
++    return NULL;
++}
+diff -urN last.fm-1.1.3.orig/src/alsaplayback/xconvert.h last.fm-1.1.3/src/alsaplayback/xconvert.h
+--- last.fm-1.1.3.orig/src/alsaplayback/xconvert.h     1969-12-31 16:00:00.000000000 -0800
++++ last.fm-1.1.3/src/alsaplayback/xconvert.h  2007-03-18 20:57:28.000000000 -0700
+@@ -0,0 +1,39 @@
++/*
++ *  Copyright (C) 2003  Haavard Kvaalen <havardk@xmms.org>
++ *
++ *  Licensed under GNU LGPL version 2.
++ */
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef enum
++{
++    FMT_U8, FMT_S8, FMT_U16_LE, FMT_U16_BE, FMT_U16_NE, FMT_S16_LE, FMT_S16_BE, FMT_S16_NE
++}
++AFormat;
++
++struct xmms_convert_buffers;
++
++struct xmms_convert_buffers* xmms_convert_buffers_new(void);
++/*
++ * Free the data assosiated with the buffers, without destroying the
++ * context.  The context can be reused.
++ */
++void xmms_convert_buffers_free(struct xmms_convert_buffers* buf);
++void xmms_convert_buffers_destroy(struct xmms_convert_buffers* buf);
++
++
++typedef int (*convert_func_t)(struct xmms_convert_buffers* buf, void **data, int length);
++typedef int (*convert_channel_func_t)(struct xmms_convert_buffers* buf, void **data, int length);
++typedef int (*convert_freq_func_t)(struct xmms_convert_buffers* buf, void **data, int length, int ifreq, int ofreq);
++
++
++convert_func_t xmms_convert_get_func(AFormat output, AFormat input);
++convert_channel_func_t xmms_convert_get_channel_func(AFormat fmt, int output, int input);
++convert_freq_func_t xmms_convert_get_frequency_func(AFormat fmt, int channels);
++
++#ifdef __cplusplus
++}
++#endif
+diff -urN last.fm-1.1.3.orig/src/container.cpp last.fm-1.1.3/src/container.cpp
+--- last.fm-1.1.3.orig/src/container.cpp       2007-03-18 20:57:23.000000000 -0700
++++ last.fm-1.1.3/src/container.cpp    2007-03-18 20:57:28.000000000 -0700
+@@ -517,6 +517,7 @@
+     connect( m_iInput,      SIGNAL( newData( QByteArray ) ),  m_iTranscode, SLOT( dataAvailable( QByteArray ) ) );
+     connect( m_iTranscode,  SIGNAL( newData( QByteArray ) ),  m_iPlayback,  SLOT( dataAvailable( QByteArray ) ) );
+     connect( m_iPlayback,   SIGNAL( needData() ),             m_iInput,     SLOT( requestData() ) );
++    connect( m_iPlayback,   SIGNAL( stop() ),                 m_iInput,     SLOT( stopStreaming() ) );
+     // Auto updater
+     connect( &m_updater, SIGNAL( updateCheckDone( bool, bool, QString ) ),
+diff -urN last.fm-1.1.3.orig/src/libLastFMTools/containerutils.cpp last.fm-1.1.3/src/libLastFMTools/containerutils.cpp
+--- last.fm-1.1.3.orig/src/libLastFMTools/containerutils.cpp   2007-03-18 20:57:23.000000000 -0700
++++ last.fm-1.1.3/src/libLastFMTools/containerutils.cpp        2007-03-18 20:57:28.000000000 -0700
+@@ -288,7 +288,7 @@
+ {
+     if ( g_playbackService == NULL )
+     {\r
+-        QObject* obj = loadService( "playback_rtaudio" );\r
++        QObject* obj = loadService( "playback_alsaaudio" );\r
+         g_playbackService = qobject_cast<PlaybackInterface*>( obj );\r
+     }
+     
similarity index 93%
rename from media-sound/lastfmplayer/lastfmplayer-1.1.3.ebuild
rename to media-sound/lastfmplayer/lastfmplayer-1.1.3-r1.ebuild
index d7f7f1823e7d67ce054b9322f6d0c682aec75e85..e733e3a771bc50a5d3be443428b38bf372bbb2f0 100644 (file)
@@ -1,6 +1,6 @@
 # Copyright 1999-2007 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/media-sound/lastfmplayer/lastfmplayer-1.1.3.ebuild,v 1.2 2007/02/12 13:55:38 blubb Exp $
+# $Header: /var/cvsroot/gentoo-x86/media-sound/lastfmplayer/lastfmplayer-1.1.3-r1.ebuild,v 1.1 2007/03/20 21:50:17 genstef Exp $
 
 inherit eutils versionator
 
@@ -19,6 +19,11 @@ S="${WORKDIR}/${MY_P}"
 DEPEND=">=x11-libs/qt-4.2
        media-libs/alsa-lib"
 
+src_unpack() {
+       unpack ${A}
+       epatch ${FILESDIR}/13_alsa-r1.diff
+}
+
 src_compile() {
        ./configure
        emake -j1 qmake_all || die "emake qmake_all failed"