Hi, Have written a thread to repeatedly play wav sounds with
varying delays in between the sound being played. Unfortunately the sound
is being clipped (cut off) at the beginning of when the sound is being
played. It is not too clear to me what api calls need to be implemented
(or what api calls have been implemented wrongly) in order to sort this problem
out. This particular piece of code works on some other hardware
but doesn’t work on this particular hardware (Freescale MCIMX31 with
ARMv6 compatible processor (v61) with Logitech V10 Notebook speakers (USB -
connected to USB port on MCIMX31)). The code does work on Cirrus EP9315
Arm 920T processor with the same USB speakers connected to the USB port (this
device is a slower device). When I attempt to play wav files with the alsa-utils test
application ‘aplay’ I am able to play mono wavs ok but stereo wavs
are clipped or cut-off in exactly the same way as the sound being played in the
thread. The thread is playing mono wavs not stereo wavs (the mono wav
sounds are also cut off). Some other hardware details are as follows:- /proc/asound/devices 0: [ 0] : control 16: [ 0- 0]: digital audio playback 33: : timer /proc/asound/card0/pcm0p/info card: 0 device: 0 subdevice: 0 stream: PLAYBACK id: USB Audio name: USB Audio subname: subdevice #0 class: 0 subclass: 0 subdevices_count: 1 subdevices_avail: 1 Devices are as follows:- crw-rw---- 1 root
audio 14, 4 audio crw-rw---- 1 root audio
14, 3 dsp Kernel configuration is as follows:- CONFIG_SND CONFIG_SND_PCM_OSS CONFIG_SND_VERBOSE_PROCFS CONFIG_SND_VERBOSE_PRINTK CONFIG_SND_USB_AUDIO Dmesg output:- usbcore: registered new interface driver usbhid drivers/hid/usbhid/hid-core.c: v2.6:USB HID core driver Advanced Linux Sound Architecture Driver Version 1.0.14 (Thu
May 31 09:03:25 2007 UTC). usbcore: registered new interface driver snd-usb-audio ALSA device list:
#0:
Logitech
Logitech Speaker at usb-fsl-ehci.2-1, full spe Sound thread code attached. Cheers, Geoff Crowther |
#ifndef SOUNDTHREAD_H #define SOUNDTHREAD_H #include <QThread> #include <QMutex> #ifdef Q_OS_LINUX #include <alsa/asoundlib.h> typedef struct { u_int32_t dwSize ; u_int16_t wFormatTag ; u_int16_t wChannels ; u_int32_t dwSamplesPerSec ; u_int32_t dwAvgBytesPerSec ; u_int16_t wBlockAlign ; u_int16_t wBitsPerSample ; } WAVEFORMAT ; #endif typedef enum SoundType { ABOVEGRADESOUND, ONGRADESOUND, BELOWGRADESOUND, OUTSIDEEXTENTSSOUND, HITREFSOUND, BUCKETSENSORINPLANESOUND, HEIGHTHIGHALARM, HEIGHTLOWALARM, BUCKETINLASERSOUND }; typedef enum Position { ABOVE_HIGH_EXTENTS, BELOW_HIGH_EXTENT_ABOVE_DEADBAND, BELOW_HIGH_DEADBAND_ABOVE_LOW_DEADBAND, BELOW_LOW_DEADBAND_ABOVE_LOW_EXTENTS, BELOW_LOW_EXTENTS, SENSORS_OFFLINE, REF_COMPLETE_SUCCESS_POS, REF_COMPLETE_FAILURE_POS, HEIGHT_ALARM_POS, DEPTH_ALARM_POS, BUCKET_IN_LASER_POS }; typedef enum SoundStateTransition { ABOVEEXTENTS, ABOVEGRADE, ONGRADE, BELOWGRADE, BELOWEXTENTS, SENSORSOFFLINE, REFCOMPLETESUCCESS, REFCOMPLETEFAILURE, HEIGHTALARM, DEPTHALARM, BUCKETINLASER, ABOVEEXTENTS_TO_ABOVEGRADE, ABOVEEXTENTS_TO_ONGRADE, ABOVEEXTENTS_TO_BELOWGRADE, ABOVEEXTENTS_TO_BELOWEXTENTS, ABOVEEXTENTS_TO_SENSORSOFFLINE, ABOVEEXTENTS_TO_REFCOMPLETEFAILURE, ABOVEEXTENTS_TO_REFCOMPLETESUCCESS, ABOVEEXTENTS_TO_HEIGHTALARM, ABOVEEXTENTS_TO_DEPTHALARM, ABOVEEXTENTS_TO_BUCKETINLASER, ABOVEGRADE_TO_ABOVEEXTENTS, ABOVEGRADE_TO_ONGRADE, ABOVEGRADE_TO_BELOWGRADE, ABOVEGRADE_TO_BELOWEXTENTS, ABOVEGRADE_TO_SENSORSOFFLINE, ABOVEGRADE_TO_REFCOMPLETEFAILURE, ABOVEGRADE_TO_REFCOMPLETESUCCESS, ABOVEGRADE_TO_HEIGHTALARM, ABOVEGRADE_TO_DEPTHALARM, ABOVEGRADE_TO_BUCKETINLASER, ONGRADE_TO_ABOVEEXTENTS, ONGRADE_TO_ABOVEGRADE, ONGRADE_TO_BELOWGRADE, ONGRADE_TO_BELOWEXTENTS, ONGRADE_TO_SENSORSOFFLINE, ONGRADE_TO_REFCOMPLETESUCCESS, ONGRADE_TO_REFCOMPLETEFAILURE, ONGRADE_TO_HEIGHTALARM, ONGRADE_TO_DEPTHALARM, ONGRADE_TO_BUCKETINLASER, BELOWGRADE_TO_ABOVEEXTENTS, BELOWGRADE_TO_ABOVEGRADE, BELOWGRADE_TO_ONGRADE, BELOWGRADE_TO_BELOWEXTENTS, BELOWGRADE_TO_SENSORSOFFLINE, BELOWGRADE_TO_REFCOMPLETESUCCESS, BELOWGRADE_TO_REFCOMPLETEFAILURE, BELOWGRADE_TO_HEIGHTALARM, BELOWGRADE_TO_DEPTHALARM, BELOWGRADE_TO_BUCKETINLASER, BELOWEXTENTS_TO_ABOVEEXTENTS, BELOWEXTENTS_TO_ABOVEGRADE, BELOWEXTENTS_TO_ONGRADE, BELOWEXTENTS_TO_BELOWGRADE, BELOWEXTENTS_TO_SENSORSOFFLINE, BELOWEXTENTS_TO_HEIGHTALARM, BELOWEXTENTS_TO_DEPTHALARM, BELOWEXTENTS_TO_REFCOMPLETESUCCESS, BELOWEXTENTS_TO_REFCOMPLETEFAILURE, BELOWEXTENTS_TO_BUCKETINLASER, SENSORSOFFLINE_TO_ABOVEEXTENTS, SENSORSOFFLINE_TO_ABOVEGRADE, SENSORSOFFLINE_TO_ONGRADE, SENSORSOFFLINE_TO_BELOWGRADE, SENSORSOFFLINE_TO_BELOWEXTENTS, SENSORSOFFLINE_TO_REFCOMPLETESUCCESS, SENSORSOFFLINE_TO_REFCOMPLETEFAILURE, SENSORSOFFLINE_TO_HEIGHTALARM, SENSORSOFFLINE_TO_DEPTHALARM, SENSORSOFFLINE_TO_BUCKETINLASER, REFCOMPLETESUCCESS_TO_ABOVEEXTENTS, REFCOMPLETESUCCESS_TO_ABOVEGRADE, REFCOMPLETESUCCESS_TO_ONGRADE, REFCOMPLETESUCCESS_TO_BELOWGRADE, REFCOMPLETESUCCESS_TO_BELOWEXTENTS, REFCOMPLETESUCCESS_TO_SENSORSOFFLINE, REFCOMPLETESUCCESS_TO_REFCOMPLETEFAILURE, REFCOMPLETESUCCESS_TO_HEIGHTALARM, REFCOMPLETESUCCESS_TO_DEPTHALARM, REFCOMPLETESUCCESS_TO_BUCKETINLASER, REFCOMPLETEFAILURE_TO_ABOVEEXTENTS, REFCOMPLETEFAILURE_TO_ABOVEGRADE, REFCOMPLETEFAILURE_TO_ONGRADE, REFCOMPLETEFAILURE_TO_BELOWGRADE, REFCOMPLETEFAILURE_TO_BELOWEXTENTS, REFCOMPLETEFAILURE_TO_SENSORSOFFLINE, REFCOMPLETEFAILURE_TO_REFCOMPLETESUCCESS, REFCOMPLETEFAILURE_TO_DEPTHALARM, REFCOMPLETEFAILURE_TO_HEIGHTALARM, REFCOMPLETEFAILURE_TO_BUCKETINLASER, DEPTHALARM_TO_SENSORSOFFLINE, DEPTHALARM_TO_ABOVEEXTENTS, DEPTHALARM_TO_ABOVEGRADE, DEPTHALARM_TO_ONGRADE, DEPTHALARM_TO_BELOWGRADE, DEPTHALARM_TO_BELOWEXTENTS, DEPTHALARM_TO_REFCOMPLETESUCCESS, DEPTHALARM_TO_REFCOMPLETEFAILURE, DEPTHALARM_TO_HEIGHTALARM, DEPTHALARM_TO_BUCKETINLASER, HEIGHTALARM_TO_SENSORSOFFLINE, HEIGHTALARM_TO_ABOVEEXTENTS, HEIGHTALARM_TO_ABOVEGRADE, HEIGHTALARM_TO_ONGRADE, HEIGHTALARM_TO_BELOWGRADE, HEIGHTALARM_TO_BELOWEXTENTS, HEIGHTALARM_TO_REFCOMPLETESUCCESS, HEIGHTALARM_TO_REFCOMPLETEFAILURE, HEIGHTALARM_TO_DEPTHALARM, HEIGHTALARM_TO_BUCKETINLASER, BUCKETINLASER_TO_SENSORSOFFLINE, BUCKETINLASER_TO_ABOVEEXTENTS, BUCKETINLASER_TO_ABOVEGRADE, BUCKETINLASER_TO_ONGRADE, BUCKETINLASER_TO_BELOWGRADE, BUCKETINLASER_TO_BELOWEXTENTS, BUCKETINLASER_TO_REFCOMPLETESUCCESS, BUCKETINLASER_TO_REFCOMPLETEFAILURE, BUCKETINLASER_TO_HEIGHTALARM, BUCKETINLASER_TO_DEPTHALARM }; class QSoundThread : public QThread { Q_OBJECT public: QSoundThread( const QString& filename, QObject* parent=0) ; virtual ~QSoundThread(); virtual void run(); bool Initialise(const QString & soundfile); const QString & GetWaveFile(){ return Path; } void SetThreadDelay(int delay); bool is_available; bool isAvailable() { return is_available ; } void ExitThread(); bool SoundAvailable() { return !SoundNotAvailable; } private: QMutex mutex_soundfile; QMutex mutex_threaddelay; QString Path; int threaddelay; int dummythreaddelay; bool exitthread; bool SoundNotAvailable; #ifdef Q_OS_LINUX // ALSA parameters snd_pcm_t *handle; snd_pcm_sframes_t frames; char *device ; // playback device snd_pcm_uframes_t chunk_size, buffer_size; size_t bits_per_sample, bits_per_frame, chunk_bytes; // File parser int fd; // Open file descriptor or -1 char* findchunk(char* pstart, char* fourcc, size_t n); WAVEFORMAT waveformat ; u_long samples, datastart; #endif }; #endif // SOUNDTHREAD_H
#include "SoundThread.h" #include <QThread> #include <QtDebug> #include <QSound> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "Formats.h" #ifdef Q_OS_LINUX #include <sys/time.h> #include <alsa/asoundlib.h> #include <malloc.h> #if WORDS_BIGENDIAN #define SwapLE16(x) ((((u_int16_t)x)<<8)|(((u_int16_t)x)>>8)) #define SwapLE32(x) ((((u_int32_t)x)<<24)|((((u_int32_t)x)<<8)&0x00FF0000) \ |((((u_int32_t)x)>>8)&0x0000FF00)|(((u_int32_t)x)>>24)) #else #define SwapLE16(x) (x) #define SwapLE32(x) (x) #endif #endif #define BUFFERSIZE 1024 QSoundThread::QSoundThread( const QString& filename, QObject* parent) : QThread(parent) { SoundNotAvailable = false; Path = filename; dummythreaddelay = threaddelay = 300; is_available= Initialise(filename); if(!is_available) { //Speakers not plugged in exitthread = true; SoundNotAvailable = true; return; } exitthread = false; #ifdef Q_OS_LINUX snd_pcm_close(handle); close(fd); #endif } QSoundThread::~QSoundThread() { } bool QSoundThread::Initialise(const QString & soundfile) { Path.clear(); Path += soundfile; if (SoundNotAvailable) return false; #ifdef _WIN32 if (QSound::isAvailable()) return true ; #endif mutex_soundfile.lock(); exitthread = false; mutex_soundfile.unlock(); #ifdef Q_OS_LINUX char buffer [ BUFFERSIZE ] ; //device = strdup("plughw:0,0"); // playback device device = strdup("default"); // playback device char* ptr ; u_long databytes ; snd_pcm_format_t format; snd_pcm_hw_params_t *params; int err; if ( (fd = open(Path.toLatin1().constData(),O_RDONLY)) < 0 ) { qWarning("Error Opening WAV file %s",Path.toLatin1().constData()); return false; } if ( lseek(fd,0L,SEEK_SET) != 0L ) { qWarning("Error nRewinding WAV file %s",Path.toLatin1().constData()); return false; // Wav file must be seekable device } read (fd, buffer, BUFFERSIZE) ; if (findchunk (buffer, "RIFF", BUFFERSIZE) != buffer) { qWarning("Bad format: Cannot find RIFF file marker"); return false; } if (! findchunk (buffer, "WAVE", BUFFERSIZE)) { qWarning("Bad format: Cannot find WAVE file marker"); return false; } ptr = findchunk (buffer, "fmt ", BUFFERSIZE) ; if (! ptr) { qWarning("Bad format: Cannot find 'fmt' file marker"); return false; } ptr += 4 ; // Move past "fmt ". memcpy (&waveformat, ptr, sizeof (WAVEFORMAT)) ; waveformat.dwSize = SwapLE32(waveformat.dwSize); waveformat.wFormatTag = SwapLE16(waveformat.wFormatTag) ; waveformat.wChannels = SwapLE16(waveformat.wChannels) ; waveformat.dwSamplesPerSec = SwapLE32(waveformat.dwSamplesPerSec) ; waveformat.dwAvgBytesPerSec = SwapLE32(waveformat.dwAvgBytesPerSec) ; waveformat.wBlockAlign = SwapLE16(waveformat.wBlockAlign) ; waveformat.wBitsPerSample = SwapLE16(waveformat.wBitsPerSample) ; qDebug("waveformat.dwSize %i", waveformat.dwSize); qDebug("waveformat.wFormatTag %i", waveformat.wFormatTag); qDebug("waveformat.wChannels %i", waveformat.wChannels); qDebug("waveformat.dwSamplesPerSec %i",waveformat.dwSamplesPerSec); qDebug("waveformat.dwAvgBytesPerSec %i", waveformat.dwAvgBytesPerSec); qDebug("waveformat.wBlockAlign %i",waveformat.wBlockAlign); qDebug("waveformat.wBitsPerSample %i",waveformat.wBitsPerSample); ptr = findchunk (buffer, "data", BUFFERSIZE) ; if (! ptr) { qWarning("Bad format: unable to find 'data' file marker"); return false; } ptr += 4 ; // Move past "data". memcpy (&databytes, ptr, sizeof (u_long)) ; samples = databytes / waveformat.wBlockAlign ; datastart = ((u_long) (ptr + 4)) - ((u_long) (&(buffer[0]))) ; switch (waveformat.wBitsPerSample) { case 8: format = SND_PCM_FORMAT_U8 ; break; case 16: format = SND_PCM_FORMAT_S16_LE ; break; case 32 : format = SND_PCM_FORMAT_S32_LE; break; default : qWarning("Bad format: %i bits per seconds",waveformat.wBitsPerSample ); return false; break; } // qDebug("%s - format :%d, %i Hz, %i channels",Path.toLatin1(),waveformat.wBitsPerSample, waveformat.dwSamplesPerSec,waveformat.wChannels); //ALSA pain snd_pcm_hw_params_alloca(¶ms); if ((err = snd_pcm_open (&handle, device,SND_PCM_STREAM_PLAYBACK,SND_PCM_ASYNC)) < 0) { qWarning("cannot open audio device %s (%s)", device,snd_strerror (err)); return false; } if ((err = snd_pcm_nonblock(handle, 1))< 0) { qWarning("nonblock setting error: %s", snd_strerror(err)); return false; } // Init hwparams with full configuration space if (snd_pcm_hw_params_any(handle, params) < 0) { qFatal("Can not configure this PCM device."); return false; } err = snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { qFatal("Access type not available"); return false; } err = snd_pcm_hw_params_set_format(handle, params, format); if (err < 0) { qFatal("Sample format not available"); return false; } err = snd_pcm_hw_params_set_channels(handle, params, waveformat.wChannels); if (err < 0) { qFatal("Channels count not available"); return false; } err = snd_pcm_hw_params_set_rate_near(handle, params,&waveformat.dwSamplesPerSec, 0); if (err < 0) { qFatal("Unable to set rate : %d", waveformat.dwSamplesPerSec); return false; } assert(err >= 0); err = snd_pcm_hw_params(handle, params); if (err < 0) { qFatal("Unable to install hw params:"); return false; } chunk_size = 0; buffer_size=0; snd_pcm_hw_params_get_buffer_size(params, &buffer_size); snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); bits_per_sample = snd_pcm_format_physical_width(format); bits_per_frame = bits_per_sample * waveformat.wChannels; chunk_bytes = chunk_size * bits_per_frame / 8; qDebug("bits_per_sample %i", bits_per_sample); qDebug("bits_per_frame %i", bits_per_frame); qDebug("chunk_size %i", chunk_size); qDebug("chunk_bytes %i", chunk_bytes); return true; #endif } void QSoundThread::ExitThread() { mutex_soundfile.lock(); exitthread = true; mutex_soundfile.unlock(); wait(-1); #ifdef Q_OS_LINUX snd_pcm_close(handle); close(fd); #endif } void QSoundThread::run() { bool flag; #ifdef Q_OS_LINUX int err; // start playback err=lseek(fd,datastart,SEEK_SET); int count,f; char *buffer2; buffer2 = (char *)malloc (buffer_size); #else //_WIN32 QSound soundtoplay(Path); #endif while(1) //thread { #ifdef Q_OS_LINUX while ((count = read (fd, buffer2,buffer_size))) { f=count*8/bits_per_frame; //f = count; qDebug("bits_per_frame is %i, count is %i", bits_per_frame, count); while ((frames = snd_pcm_writei(handle, buffer2, f)) < 0) { snd_pcm_prepare(handle); } } snd_pcm_drain(handle); #elif _WIN32 soundtoplay.play(); #else qWarning("Platform has no sound configured"); #endif mutex_threaddelay.lock(); threaddelay = dummythreaddelay; //don't want to block on the sleep mutex_threaddelay.unlock(); msleep(threaddelay); mutex_soundfile.tryLock(); flag = exitthread; mutex_soundfile.unlock(); #ifdef Q_OS_LINUX if(fd >= 0 && !flag) { err=lseek(fd,datastart,SEEK_SET); } else { free(buffer2); err=lseek(fd,datastart,SEEK_SET); #else if(!flag) { } else { #endif mutex_soundfile.tryLock(); exitthread = false; mutex_soundfile.unlock(); return; } } } void QSoundThread::SetThreadDelay(int delay) { mutex_threaddelay.lock(); dummythreaddelay = delay; mutex_threaddelay.unlock(); } #ifdef Q_OS_LINUX char* QSoundThread::findchunk (char* pstart, char* fourcc, size_t n) { char *pend; int k, test; pend = pstart + n; while (pstart < pend) { if (*pstart == *fourcc) // found match for first char { test = TRUE ; for (k = 1 ; fourcc [k] != 0 ; k++) test = (test ? ( pstart [k] == fourcc [k] ) : FALSE) ; if (test) return pstart ; } ; // if pstart ++ ; } ; // while lpstart return NULL ; } // findchuck #endif
------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________ Alsa-user mailing list Alsa-user@xxxxxxxxxxxxxxxxxxxxx https://lists.sourceforge.net/lists/listinfo/alsa-user