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
[email protected]
https://lists.sourceforge.net/lists/listinfo/alsa-user