From: Stefan Schweizer Date: Tue, 20 Mar 2007 21:50:17 +0000 (+0000) Subject: Fix Alsa issues thanks to David Grant in bug 167229 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=238f24d214898e433add6c8c266a7b7b71d9e673;p=gentoo.git Fix Alsa issues thanks to David Grant in bug 167229 Package-Manager: portage-2.1.2.2 --- diff --git a/media-sound/lastfmplayer/ChangeLog b/media-sound/lastfmplayer/ChangeLog index c3880c735daf..2b760b1cd56e 100644 --- a/media-sound/lastfmplayer/ChangeLog +++ b/media-sound/lastfmplayer/ChangeLog @@ -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; +files/13_alsa-r1.diff, + -lastfmplayer-1.1.3.ebuild, +lastfmplayer-1.1.3-r1.ebuild: + Fix Alsa issues thanks to David Grant in bug 167229 12 Feb 2007; Simon Stelling +files/lastfmplayer-1.1.3-pic.patch, lastfmplayer-1.1.3.ebuild: diff --git a/media-sound/lastfmplayer/Manifest b/media-sound/lastfmplayer/Manifest index 57e159d5d64d..2af4d2d8463a 100644 --- a/media-sound/lastfmplayer/Manifest +++ b/media-sound/lastfmplayer/Manifest @@ -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 index 000000000000..e5289d3966fa --- /dev/null +++ b/media-sound/lastfmplayer/files/13_alsa-r1.diff @@ -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 * ++ * 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 ++ ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#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 _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 * ++ * Erik Jaelevik, Last.fm Ltd * ++ * * ++ * 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 ++ ++#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 * ++ * Erik Jaelevik, Last.fm Ltd * ++ * * ++ * 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 ++#include "alsaaudio.h" ++ ++#include ++#include ++ ++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 @@ ++/*************************************************************************** ++ * Copyright (C) 2005 - 2006 by * ++ * Christian Muehlhaeuser, Last.fm Ltd * ++ * Erik Jaelevik, Last.fm Ltd * ++ * * ++ * 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. * ++ ***************************************************************************/ ++ ++/* Add C includes here */ ++ ++#if defined __cplusplus ++ /* Add C++ includes here */ ++ #include ++ #include ++ #include ++ #include ++#endif // __cplusplus +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 ++ * ++ * Licensed under GNU LGPL version 2. ++ */ ++ ++#include ++#include ++#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 ++ * ++ * 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 ) + { +- QObject* obj = loadService( "playback_rtaudio" ); ++ QObject* obj = loadService( "playback_alsaaudio" ); + g_playbackService = qobject_cast( obj ); + } + diff --git a/media-sound/lastfmplayer/files/digest-lastfmplayer-1.1.3 b/media-sound/lastfmplayer/files/digest-lastfmplayer-1.1.3-r1 similarity index 100% rename from media-sound/lastfmplayer/files/digest-lastfmplayer-1.1.3 rename to media-sound/lastfmplayer/files/digest-lastfmplayer-1.1.3-r1 diff --git a/media-sound/lastfmplayer/lastfmplayer-1.1.3.ebuild b/media-sound/lastfmplayer/lastfmplayer-1.1.3-r1.ebuild 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 d7f7f1823e7d..e733e3a771bc 100644 --- a/media-sound/lastfmplayer/lastfmplayer-1.1.3.ebuild +++ b/media-sound/lastfmplayer/lastfmplayer-1.1.3-r1.ebuild @@ -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"