Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

audiodevice.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002  ** Copyright (C) 2000 Trolltech AS.  All rights reserved.
00003  **
00004  ** This file is part of Qtopia Environment.
00005  **
00006  ** This file may be distributed and/or modified under the terms of the
00007  ** GNU General Public License version 2 as published by the Free Software
00008  ** Foundation and appearing in the file LICENSE.GPL included in the
00009  ** packaging of this file.
00010  **
00011  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013  **
00014  ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015  **
00016  ** Contact info@trolltech.com if any conditions of this licensing are
00017  ** not clear to you.
00018  **
00019  **********************************************************************/
00020 // L.J.Potter added better error code Fri 02-15-2002 14:37:47
00021 
00022 
00023 #include "audiodevice.h"
00024 
00025 /* OPIE */
00026 #include <qpe/qpeapplication.h>
00027 #include <qpe/config.h>
00028 #include <opie2/odebug.h>
00029 
00030 #if !defined(QT_NO_COP)
00031 #include <qpe/qcopenvelope_qws.h>
00032 #endif
00033 
00034 /* QT */
00035 #include <qmessagebox.h>
00036 
00037 /* STD */
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <errno.h>
00041 
00042 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
00043 #include <fcntl.h>
00044 #include <sys/ioctl.h>
00045 #include <sys/soundcard.h>
00046 #include <sys/stat.h>
00047 #include <sys/time.h>
00048 #include <sys/types.h>
00049 #include <unistd.h>
00050 #endif
00051 
00052 #ifdef OPIE_SOUND_FRAGMENT_SHIFT
00053 static const int sound_fragment_shift = OPIE_SOUND_FRAGMENT_SHIFT;
00054 #else
00055 static const int sound_fragment_shift = 16;
00056 #endif
00057 static const int sound_fragment_bytes = (1<<sound_fragment_shift);
00058 //#endif
00059 
00060 
00061 class AudioDevicePrivate {
00062 public:
00063     int handle;
00064     unsigned int frequency;
00065     unsigned int channels;
00066     unsigned int bytesPerSample;
00067     unsigned int bufferSize;
00068 //#ifndef Q_OS_WIN32
00069     bool can_GETOSPACE;
00070     char* unwrittenBuffer;
00071     unsigned int unwritten;
00072 //#endif
00073 
00074     static int dspFd;
00075     static bool muted;
00076     static unsigned int leftVolume;
00077     static unsigned int rightVolume;
00078 };
00079 
00080 
00081 #ifdef Q_WS_QWS
00082 // This is for keeping the device open in-between playing files when
00083 // the device makes clicks and it starts to drive you insane! :)
00084 // Best to have the device not open when not using it though
00085 //#define KEEP_DEVICE_OPEN
00086 #endif
00087 
00088 
00089 int AudioDevicePrivate::dspFd = 0;
00090 bool AudioDevicePrivate::muted = FALSE;
00091 unsigned int AudioDevicePrivate::leftVolume = 0;
00092 unsigned int AudioDevicePrivate::rightVolume = 0;
00093 
00094 
00095 void AudioDevice::getVolume( unsigned int& leftVolume, unsigned int& rightVolume, bool &muted ) {
00096     muted = AudioDevicePrivate::muted;
00097     unsigned int volume;
00098 #ifdef QT_QWS_DEVFS
00099     int mixerHandle = open( "/dev/sound/mixer", O_RDWR );
00100 #else
00101     int mixerHandle = open( "/dev/mixer", O_RDWR );
00102 #endif
00103     if ( mixerHandle >= 0 ) {
00104         if(ioctl( mixerHandle, MIXER_READ(0), &volume )==-1)
00105             perror("ioctl(\"MIXER_READ\")");
00106         close( mixerHandle );
00107     } else
00108         perror("open(\"/dev/mixer\")");
00109     leftVolume  = ((volume & 0x00FF) << 16) / 101;
00110     rightVolume = ((volume & 0xFF00) <<  8) / 101;
00111 }
00112 
00113 
00114 void AudioDevice::setVolume( unsigned int leftVolume, unsigned int rightVolume, bool muted ) {
00115     AudioDevicePrivate::muted = muted;
00116     if ( muted ) {
00117         AudioDevicePrivate::leftVolume = leftVolume;
00118         AudioDevicePrivate::rightVolume = rightVolume;
00119         leftVolume = 0;
00120         rightVolume = 0;
00121     } else {
00122         leftVolume  = ( (int) leftVolume < 0 ) ? 0 : ((  leftVolume > 0xFFFF ) ? 0xFFFF :  leftVolume );
00123         rightVolume = ( (int)rightVolume < 0 ) ? 0 : (( rightVolume > 0xFFFF ) ? 0xFFFF : rightVolume );
00124     }
00125       // Volume can be from 0 to 100 which is 101 distinct values
00126     unsigned int rV = (rightVolume * 101) >> 16;
00127 
00128 # if 0
00129     unsigned int lV = (leftVolume  * 101) >> 16;
00130     unsigned int volume = ((rV << 8) & 0xFF00) | (lV & 0x00FF);
00131     int mixerHandle = 0;
00132 #ifdef QT_QWS_DEVFS
00133     if ( ( mixerHandle = open( "/dev/sound/mixer", O_RDWR ) ) >= 0 ) {
00134 #else
00135     if ( ( mixerHandle = open( "/dev/mixer", O_RDWR ) ) >= 0 ) {
00136 #endif
00137         if(ioctl( mixerHandle, MIXER_WRITE(0), &volume ) ==-1)
00138             perror("ioctl(\"MIXER_WRITE\")");
00139         close( mixerHandle );
00140     } else
00141         perror("open(\"/dev/mixer\")");
00142 
00143 # else
00144       // This is the way this has to be done now I guess, doesn't allow for
00145       // independant right and left channel setting, or setting for different outputs
00146     Config cfg("qpe"); // qtopia is "Sound"
00147     cfg.setGroup("Volume"); // qtopia is "Settings"
00148     cfg.writeEntry("VolumePercent",(int)rV); //qtopia is Volume
00149 # endif
00150 
00151 //#endif
00152 //    odebug << "setting volume to: 0x" << volume << "" << oendl;
00153 #if ( defined Q_WS_QWS || defined(_WS_QWS_) ) && !defined(QT_NO_COP)
00154       // Send notification that the volume has changed
00155     QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << muted;
00156 #endif
00157 }
00158 
00159 
00160 
00161 AudioDevice::AudioDevice( unsigned int f, unsigned int chs, unsigned int bps ) {
00162    //    odebug << "creating new audio device" << oendl;
00163 //     QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << TRUE;
00164     d = new AudioDevicePrivate;
00165     d->frequency = f;
00166     d->channels = chs;
00167     d->bytesPerSample = bps;
00168     //    odebug << "" << bps << "" << oendl;
00169     int format=0;
00170     if( bps == 8)  format  = AFMT_U8;
00171     else if( bps <= 0) format = AFMT_S16_LE;
00172     else format = AFMT_S16_LE;
00173     //    odebug << "AD- freq " << f << ", channels " << chs << ", b/sample " << bps << ", bitrate " << format << "" << oendl;
00174     connect( qApp, SIGNAL( volumeChanged(bool) ), this, SLOT( volumeChanged(bool) ) );
00175 
00176     int fragments = 0x10000 * 8 + sound_fragment_shift;
00177     int capabilities = 0;
00178 
00179 
00180 #ifdef KEEP_DEVICE_OPEN
00181     if ( AudioDevicePrivate::dspFd == 0 ) {
00182 #endif
00183 #ifdef QT_QWS_DEVFS
00184         if ( ( d->handle = ::open( "/dev/sound/dsp", O_WRONLY ) ) < 0 ) {
00185 #else
00186         if ( ( d->handle = ::open( "/dev/dsp", O_WRONLY ) ) < 0 ) {
00187 #endif
00188 
00189         perror("open(\"/dev/dsp\")");
00190         QString errorMsg=tr("Somethin's wrong with\nyour sound device.\nopen(\"/dev/dsp\")\n")+(QString)strerror(errno)+tr("\n\nClosing player now.");
00191         QMessageBox::critical(0, "Vmemo", errorMsg, tr("Abort"));
00192         exit(-1); //harsh?
00193         }
00194 #ifdef KEEP_DEVICE_OPEN
00195         AudioDevicePrivate::dspFd = d->handle;
00196     } else {
00197         d->handle = AudioDevicePrivate::dspFd;
00198     }
00199 #endif
00200 
00201     if(ioctl( d->handle, SNDCTL_DSP_GETCAPS, &capabilities )==-1)
00202         perror("ioctl(\"SNDCTL_DSP_GETCAPS\")");
00203     if(ioctl( d->handle, SNDCTL_DSP_SETFRAGMENT, &fragments )==-1)
00204         perror("ioctl(\"SNDCTL_DSP_SETFRAGMENT\")");
00205     if(ioctl( d->handle, SNDCTL_DSP_SETFMT, & format )==-1)
00206         perror("ioctl(\"SNDCTL_DSP_SETFMT\")");
00207     //    odebug << "freq " << d->frequency << "" << oendl;
00208     if(ioctl( d->handle, SNDCTL_DSP_SPEED, &d->frequency )==-1)
00209         perror("ioctl(\"SNDCTL_DSP_SPEED\")");
00210     //    odebug << "channels " << d->channels << "" << oendl;
00211     if ( ioctl( d->handle, SNDCTL_DSP_CHANNELS, &d->channels ) == -1 ) {
00212         d->channels = ( d->channels == 1 ) ? 2 : d->channels;
00213         if(ioctl( d->handle, SNDCTL_DSP_CHANNELS, &d->channels )==-1)
00214             perror("ioctl(\"SNDCTL_DSP_CHANNELS\")");
00215     }
00216 //   QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << FALSE;
00217 
00218     d->bufferSize = sound_fragment_bytes;
00219     d->unwrittenBuffer = new char[d->bufferSize];
00220     d->unwritten = 0;
00221     d->can_GETOSPACE = TRUE; // until we find otherwise
00222 
00223       //if ( chs != d->channels )       odebug << "Wanted " << chs << ", got " << d->channels << " channels" << oendl;
00224       //if ( f != d->frequency )        odebug << "wanted " << f << "Hz, got " << d->frequency << "Hz" << oendl;
00225       //if ( capabilities & DSP_CAP_BATCH )   odebug << "Sound card has local buffer" << oendl;
00226       //if ( capabilities & DSP_CAP_REALTIME )odebug << "Sound card has realtime sync" << oendl;
00227       //if ( capabilities & DSP_CAP_TRIGGER ) odebug << "Sound card has precise trigger" << oendl;
00228       //if ( capabilities & DSP_CAP_MMAP )    odebug << "Sound card can mmap" << oendl;
00229 
00230 }
00231 
00232 
00233 AudioDevice::~AudioDevice() {
00234    //    odebug << "destryo audiodevice" << oendl;
00235 //    QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << TRUE;
00236 
00237 # ifndef KEEP_DEVICE_OPEN
00238     close( d->handle );     // Now it should be safe to shut the handle
00239 # endif
00240     delete d->unwrittenBuffer;
00241     delete d;
00242 //   QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << FALSE;
00243 
00244 }
00245 
00246 
00247 void AudioDevice::volumeChanged( bool muted )
00248 {
00249     AudioDevicePrivate::muted = muted;
00250 }
00251 
00252 
00253 void AudioDevice::write( char *buffer, unsigned int length )
00254 {
00255     int t = ::write( d->handle, buffer, length );
00256     if ( t<0 ) t = 0;
00257     if ( t != (int)length) {
00258        //        odebug << "Ahhh!! memcpys 1" << oendl;
00259         memcpy(d->unwrittenBuffer,buffer+t,length-t);
00260         d->unwritten = length-t;
00261     }
00262 //#endif
00263 }
00264 
00265 
00266 unsigned int AudioDevice::channels() const
00267 {
00268     return d->channels;
00269 }
00270 
00271 
00272 unsigned int AudioDevice::frequency() const
00273 {
00274     return d->frequency;
00275 }
00276 
00277 
00278 unsigned int AudioDevice::bytesPerSample() const
00279 {
00280     return d->bytesPerSample;
00281 }
00282 
00283 
00284 unsigned int AudioDevice::bufferSize() const
00285 {
00286     return d->bufferSize;
00287 }
00288 
00289 unsigned int AudioDevice::canWrite() const
00290 {
00291     audio_buf_info info;
00292     if ( d->can_GETOSPACE && ioctl(d->handle,SNDCTL_DSP_GETOSPACE,&info) ) {
00293         d->can_GETOSPACE = FALSE;
00294         fcntl( d->handle, F_SETFL, O_NONBLOCK );
00295     }
00296     if ( d->can_GETOSPACE ) {
00297         int t = info.fragments * sound_fragment_bytes;
00298         return QMIN(t,(int)bufferSize());
00299     } else {
00300         if ( d->unwritten ) {
00301             int t = ::write( d->handle, d->unwrittenBuffer, d->unwritten );
00302             if ( t<0 ) t = 0;
00303             if ( (unsigned)t!=d->unwritten ) {
00304                 memcpy(d->unwrittenBuffer,d->unwrittenBuffer+t,d->unwritten-t);
00305                 d->unwritten -= t;
00306             } else {
00307                 d->unwritten = 0;
00308             }
00309         }
00310         if ( d->unwritten )
00311             return 0;
00312         else
00313             return d->bufferSize;
00314     }
00315 }
00316 
00317 
00318 int AudioDevice::bytesWritten() {
00319     int buffered = 0;
00320     if ( ioctl( d->handle, SNDCTL_DSP_GETODELAY, &buffered ) ) {
00321        //        odebug << "failed to get audio device position" << oendl;
00322         return -1;
00323     }
00324     return buffered;
00325 }
00326 

Generated on Sat Nov 5 16:15:34 2005 for OPIE by  doxygen 1.4.2