Update of /cvsroot/playerstage/code/player/server/drivers/audio
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3976
Modified Files:
Makefile.am alsa.cc alsa.h
Added Files:
audio_sample.cc audio_sample.h
Log Message:
Rewrote alsa driver to be far more flexible. Added recording functionality.
--- NEW FILE: audio_sample.cc ---
/*
* Player - One Hell of a Robot Server
* Copyright (C) 2003
* Brian Gerkey
*
*
* 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 <libplayercore/playercore.h>
#include "audio_sample.h"
#include <stdlib.h>
////////////////////////////////////////////////////////////////////////////////
// Class functions
////////////////////////////////////////////////////////////////////////////////
// Constructor
AudioSample::AudioSample (void)
{
// Set the sample type to none
type = SAMPLE_TYPE_NONE;
// Blank wave data
numChannels = 0;
sampleRate = 0;
byteRate = 0;
blockAlign = 0;
bitsPerSample = 0;
numFrames = 0;
// Blank storage variables
position = 0;
waveFile = NULL;
filePath = NULL;
headerSize = 0;
dataLength = 0;
data = NULL;
}
// Destructor
AudioSample::~AudioSample (void)
{
if (waveFile != NULL)
{
if (type != SAMPLE_TYPE_FILE)
PLAYER_WARN ("file descriptor not NULL for non-file
sample");
fclose (waveFile);
}
if (filePath != NULL)
{
if (type != SAMPLE_TYPE_FILE)
PLAYER_WARN ("file path not NULL for non-file sample");
free (filePath);
}
if (data != NULL)
{
if (type != SAMPLE_TYPE_MEM)
PLAYER_WARN ("data not NULL for non-mem sample");
delete[] data;
}
}
////////////////////////////////////////////////////////////////////////////////
// Data management functions
////////////////////////////////////////////////////////////////////////////////
// Set the position of reading in the data
void AudioSample::SetDataPosition (uint32_t newPosition)
{
// If the new position is beyond the end of the data, set it to the end
if ((newPosition * blockAlign) > dataLength)
position = dataLength;
else
// Otherwise just set it to the new position
position = newPosition * blockAlign;
}
uint32_t AudioSample::GetDataPosition (void) const
{
return position / blockAlign;
}
uint32_t AudioSample::GetDataLength (void) const
{
if (type == SAMPLE_TYPE_FILE || type == SAMPLE_TYPE_MEM)
return dataLength / blockAlign;
else // SAMPLE_TYPE_NONE or some other value that type really
shouldn't be
return 0;
}
// Get a block of wave data
// count: The number of _frames_ to get (not bytes!)
// buffer: The buffer to store the frames in (must allocate enough)
// Returns: the number of frames actually stored in buffer
int AudioSample::GetData (int count, uint8_t *buffer)
{
int bytesCopied = 0;
if (buffer == NULL)
{
// Can't copy to a NULL buffer
PLAYER_WARN ("Can't copy data into a null buffer");
return -1;
}
// Number of bytes to copy is number of frames to copy * frame size
int bytesCount = count * blockAlign;
if (type == SAMPLE_TYPE_NONE)
{
PLAYER_WARN ("Attempt to get data from an empty sample");
return -1;
}
else if (type == SAMPLE_TYPE_FILE)
{
// Seek to the position to get data from in the file (offset by
header size)
// (Have to do this in case SetDataPosition was used since the
last read)
if (fseek (waveFile, headerSize + position, SEEK_SET) != 0)
{
PLAYER_ERROR1 ("Error seeking to current position in
wave file: %s", strerror (errno));
return -1;
}
// Number of bytes to copy shouldn't take us beyond the end of
the array
int bytesToCopy = (position + bytesCount) > dataLength ?
(dataLength - position) : bytesCount;
// Read into the buffer provided the number of bytes to copy
if ((bytesCopied = fread (buffer, 1, bytesToCopy, waveFile)) ==
0)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading wave data");
else
PLAYER_ERROR1 ("Error reading wave data from
file: %s", strerror (errno));
return 0;
}
else if (bytesCopied < bytesToCopy)
{
printf ("Error reading wave data from file (didn't get
enough bytes): %s\n", strerror (errno));
// Return what we got, driver will assume end of data
and move to next sample in queue
}
}
else if (type == SAMPLE_TYPE_MEM)
{
// If there is no data, return 0 (end of sample)
if (dataLength == 0)
return 0;
// Number of bytes to copy shouldn't take us beyond the end of
the array
int bytesToCopy = (position + bytesCount) > dataLength ?
(dataLength - position) : bytesCount;
// Copy from data[position] to data[position + bytesToCopy]
memcpy (buffer, &data[position], bytesToCopy);
bytesCopied = bytesToCopy;
}
// Update position with the new position (old position + length
actually read)
position += bytesCopied;
// Return the number of frames actually copied
return bytesCopied / blockAlign;
}
// Clears the entire sample, making it a SAMPLE_TYPE_NONE
void AudioSample::ClearSample (void)
{
// For FILE type, need to close the file and remove the file name string
if (type == SAMPLE_TYPE_FILE)
{
if (waveFile != NULL)
fclose (waveFile);
if (filePath != NULL)
free (filePath);
}
// For MEM type, need to delete any stored data
else if (type == SAMPLE_TYPE_MEM)
{
if (data != NULL)
delete[] data;
}
// Do nothing for SAMPLE_TYPE_NONE
// In both cases, set everything to 0
// Set the sample type to none
type = SAMPLE_TYPE_NONE;
// Blank wave data
numChannels = 0;
sampleRate = 0;
byteRate = 0;
blockAlign = 0;
bitsPerSample = 0;
numFrames = 0;
// Blank storage variables
position = 0;
waveFile = NULL;
filePath = NULL;
headerSize = 0;
dataLength = 0;
data = NULL;
}
// Fills the data with a constant silence value
// time: The length of time to fill
bool AudioSample::FillSilence (uint32_t time)
{
// First, make sure this sample is empty
if (type != SAMPLE_TYPE_NONE)
{
PLAYER_ERROR ("Tried to set non-empty sample to silence");
return false;
}
// Next, create a data buffer
dataLength = static_cast<uint32_t> ((static_cast<double> (time) /
1000.0f) * byteRate);
if ((data = new uint8_t[dataLength]) == NULL)
{
PLAYER_ERROR ("Failed to allocate memory for wave data");
return false;
}
// Set the wave data to zero
memset (data, 0, dataLength);
numFrames = dataLength / blockAlign;
// Set type to MEM
type = SAMPLE_TYPE_MEM;
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Data conversion functions
////////////////////////////////////////////////////////////////////////////////
// Copies the data from a loaded wave file to the player struct for wave data
// If the wave data doesn't match one of the possible formats supported by the
// player format flags, the copy isn't performed and an error is returned
bool AudioSample::ToPlayer (player_audio_wav_t *dest)
{
if (type == SAMPLE_TYPE_NONE || data == NULL)
{
PLAYER_WARN ("No sample to convert to player format");
return false;
}
// Set the format flags
dest->format = PLAYER_AUDIO_FORMAT_RAW;
if (numChannels == 2)
dest->format |= PLAYER_AUDIO_STEREO;
else if (numChannels != 1)
{
PLAYER_ERROR ("Cannot convert wave to player struct: wrong
number of channels");
return false;
}
switch (sampleRate)
{
case 11025:
dest->format |= PLAYER_AUDIO_FREQ_11k;
break;
case 22050:
dest->format |= PLAYER_AUDIO_FREQ_22k;
break;
case 44100:
dest->format |= PLAYER_AUDIO_FREQ_44k;
break;
case 48000:
dest->format |= PLAYER_AUDIO_FREQ_48k;
break;
default:
PLAYER_ERROR ("Cannot convert wave to player struct:
wrong sample rate");
return false;
}
switch (bitsPerSample)
{
case 8:
dest->format |= PLAYER_AUDIO_8BIT;
break;
case 16:
dest->format |= PLAYER_AUDIO_16BIT;
break;
case 24:
dest->format |= PLAYER_AUDIO_24BIT;
break;
default:
PLAYER_ERROR ("Cannot convert wave to player struct:
wrong format (bits per sample)");
return false;
}
// Copy at most PLAYER_AUDIO_WAV_BUFFER_SIZE bytes of data
uint32_t bytesToCopy = PLAYER_AUDIO_WAV_BUFFER_SIZE;
if (dataLength < bytesToCopy)
bytesToCopy = dataLength;
if (type == SAMPLE_TYPE_FILE)
{
// Remember the current data position
uint32_t currentPos = GetDataPosition ();
// Move to the start of the wave
SetDataPosition (0);
// Grab some data, put it in the player struct
GetData (bytesToCopy, dest->data);
// Move back to where we were
SetDataPosition (currentPos);
}
else
{
// Just copy. Nice and easy.
memcpy (&dest->data, data, bytesToCopy);
}
dest->data_count = bytesToCopy;
return true;
}
bool AudioSample::FromPlayer (const player_audio_wav_t *source)
{
// Set format information
if ((source->format & PLAYER_AUDIO_FORMAT_BITS) !=
PLAYER_AUDIO_FORMAT_RAW)
{
// Can't handle non-raw data
PLAYER_ERROR ("Cannot play non-raw audio data");
return false;
}
// Clean out any existing data
ClearSample ();
if (source->format & PLAYER_AUDIO_STEREO)
numChannels = 2;
else
numChannels = 1;
if ((source->format & PLAYER_AUDIO_FREQ) == PLAYER_AUDIO_FREQ_11k)
sampleRate = 11025;
else if ((source->format & PLAYER_AUDIO_FREQ) == PLAYER_AUDIO_FREQ_22k)
sampleRate = 22050;
else if ((source->format & PLAYER_AUDIO_FREQ) == PLAYER_AUDIO_FREQ_44k)
sampleRate = 44100;
else if ((source->format & PLAYER_AUDIO_FREQ) == PLAYER_AUDIO_FREQ_48k)
sampleRate = 48000;
if ((source->format & PLAYER_AUDIO_BITS) == PLAYER_AUDIO_8BIT)
{
bitsPerSample = 8;
}
else if ((source->format & PLAYER_AUDIO_BITS) == PLAYER_AUDIO_16BIT)
{
bitsPerSample = 16;
}
else if ((source->format & PLAYER_AUDIO_BITS) == PLAYER_AUDIO_24BIT)
{
bitsPerSample = 24;
}
// Calculate the other format info
blockAlign = numChannels * (bitsPerSample / 8);
byteRate = sampleRate * blockAlign;
// Allocate memory for the data if necessary
if ((data = new uint8_t[source->data_count]) == NULL)
{
PLAYER_ERROR ("Failed to allocate memory for wave data");
return false;
}
// Copy the wave data across
memcpy (data, source->data, source->data_count);
dataLength = source->data_count;
numFrames = dataLength / blockAlign;
// Set type to MEM
type = SAMPLE_TYPE_MEM;
return true;
}
////////////////////////////////////////////////////////////////////////////////
// File management functions
////////////////////////////////////////////////////////////////////////////////
// Load a wave file from disc
// filePath: The path to the file to load
// Returns: true for success, false otherwise
bool AudioSample::LoadFile (const char *fileName)
{
char tag[5];
uint16_t tempUShort = 0;
uint32_t tempUInt = 0, subChunk1Size = 0;
// First of all, make sure this sample is empty
ClearSample ();
// Try to open the wave file
if ((waveFile = fopen (fileName, "r")) == NULL)
{
PLAYER_ERROR1 ("Couldn't open wave file for reading: %s",
strerror (errno));
return false;
}
// Wave file should be in the format (header, format chunk, data
chunk), where:
// header = 4+4+4 bytes: "RIFF", size, "WAVE"
// format = 4+4+2+2+4+4+2+2[+2] bytes:
// "fmt ", size, 1, numChannels, sampleRate, byteRate,
blockAlign,
// bitsPerSample, [extraParamsSize] (not present for PCM)
// data = 4+4+? bytes: "data", size, data bytes...
// Read the header - first the RIFF tag
if (fgets (tag, 5, waveFile) == NULL)
{
PLAYER_ERROR ("Error reading tag from wave file");
return false;
}
if (strcmp (tag, "RIFF") != 0)
{
PLAYER_ERROR ("Bad WAV format: missing RIFF tag");
return false;
}
// Get the size of the file
if (fread (&tempUInt, 4, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV header");
else
PLAYER_ERROR ("Error reading WAV header");
return false;
}
// Check the file size isn't stupid - should at least have size of all
// chunks (excluding 2 fields already done)
if (tempUInt < 36)
{
PLAYER_ERROR ("WAV file too short: missing chunk information");
return false;
}
// Next tag should say "WAVE"
if (fgets (tag, 5, waveFile) == NULL)
{
PLAYER_ERROR ("Error reading tag from wave file");
return false;
}
if (strcmp (tag, "WAVE") != 0)
{
PLAYER_ERROR ("Bad WAV format: missing WAVE tag");
return false;
}
// Next is the format information chunk, starting with a "fmt " tag
if (fgets (tag, 5, waveFile) == NULL)
{
PLAYER_ERROR ("Error reading tag from wave file");
return false;
}
if (strcmp (tag, "fmt ") != 0)
{
PLAYER_ERROR ("Bad WAV format: missing fmt tag");
return false;
}
// Followed by size of this chunk - should be 16, may be 18 if not quite
// following the format correctly
if (fread (&subChunk1Size, 4, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV format");
else
PLAYER_ERROR ("Error reading WAV format");
return false;
}
if (subChunk1Size != 16 && subChunk1Size != 18)
{
PLAYER_ERROR ("WAV file too short: missing chunk information");
return false;
}
// Audio format is next - if not 1, can't read this file cause it isn't
PCM
if (fread (&tempUShort, 2, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV format");
else
PLAYER_ERROR ("Error reading WAV format");
return false;
}
if (tempUShort != 1)
{
PLAYER_ERROR ("WAV file not in PCM format");
return false;
}
// Having got this far, we can now start reading data we want to keep
// Read the number of channels
if (fread (&numChannels, 2, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV num channels");
else
PLAYER_ERROR ("Error reading WAV num channels");
ClearSample ();
return false;
}
// Read the sample rate
if (fread (&sampleRate, 4, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV sample rate");
else
PLAYER_ERROR ("Error reading WAV sample rate");
ClearSample ();
return false;
}
// Read the byte rate
if (fread (&byteRate, 4, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV byte rate");
else
PLAYER_ERROR ("Error reading WAV byte rate");
ClearSample ();
return false;
}
// Read the block align
if (fread (&blockAlign, 2, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV block align");
else
PLAYER_ERROR ("Error reading WAV block align");
ClearSample ();
return false;
}
// Read the bits per sample
if (fread (&bitsPerSample, 2, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV bits per
sample");
else
PLAYER_ERROR ("Error reading WAV bits per sample");
ClearSample ();
return false;
}
// If the size of this chunk was 18, get those extra two bytes
if (subChunk1Size == 18)
{
if (fread (&tempUShort, 2, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading blank 2
bytes");
else
PLAYER_ERROR ("Error reading WAV blank 2
bytes");
ClearSample ();
return false;
}
}
// On to the data chunk, again starting with a tag
if (fgets (tag, 5, waveFile) == NULL)
{
PLAYER_ERROR ("Error reading tag from wave file");
ClearSample ();
return false;
}
if (strcmp (tag, "data") != 0)
{
PLAYER_ERROR ("Bad WAV format: missing data tag");
ClearSample ();
return false;
}
// Size of the wave data
if (fread (&dataLength, 4, 1, waveFile) != 1)
{
if (feof (waveFile))
PLAYER_ERROR ("End of file reading WAV data size");
else
PLAYER_ERROR ("Error reading WAV data size");
ClearSample ();
return false;
}
// The file pointer is now positioned at the start of the data.
// Store the header size (for moving around the wave file easily later
on).
headerSize = ftell (waveFile);
// Also store the file path
filePath = strdup (fileName);
// Go to the end of the file and get position in order to get the length
// of the file, subtract headerSize to get the position
fseek (waveFile, 0, SEEK_END);
dataLength = ftell (waveFile) - headerSize;
// Back to the start of the data again
fseek (waveFile, headerSize, SEEK_SET);
// Calculate the number of frames in the data
numFrames = dataLength / (numChannels * (bitsPerSample / 8));
// Set type
type = SAMPLE_TYPE_FILE;
return true;
}
void AudioSample::CloseFile (void)
{
// Just clear the sample, that'll close the file and clean up anything
else
ClearSample ();
}
////////////////////////////////////////////////////////////////////////////////
// Wave format functions
////////////////////////////////////////////////////////////////////////////////
// Checks if the format information of this sample is the same as rhs
// rhs: A pointer to an AudioSample
// Returns: true if same, false if different or rhs is NULL
bool AudioSample::SameFormat (const AudioSample *rhs)
{
if (!rhs || type == SAMPLE_TYPE_NONE)
return false;
if (numChannels == rhs->GetNumChannels () &&
sampleRate == rhs->GetSampleRate () &&
bitsPerSample == rhs->GetBitsPerSample ())
return true;
return false;
}
// Copies the format of rhs
// rhs: A pointer to an AudioSample whose format should be copied
void AudioSample::CopyFormat (const AudioSample *rhs)
{
if (!rhs || type == SAMPLE_TYPE_NONE)
return;
numChannels = rhs->GetNumChannels ();
sampleRate = rhs->GetSampleRate ();
byteRate = rhs->GetByteRate ();
blockAlign = rhs->GetBlockAlign ();
bitsPerSample = rhs->GetBitsPerSample ();
}
////////////////////////////////////////////////////////////////////////////////
// Other useful functions
////////////////////////////////////////////////////////////////////////////////
void AudioSample::PrintWaveInfo (void)
{
if (type == SAMPLE_TYPE_FILE)
printf ("File sample, path: %s\n", filePath);
else if (type == SAMPLE_TYPE_MEM)
printf ("Memory sample\n");
else
printf ("Empty sample\n");
printf ("Num channels:\t%d\n", numChannels);
printf ("Sample rate:\t%d\n", sampleRate);
printf ("Byte rate:\t%d\n", byteRate);
printf ("Block align:\t%d\n", blockAlign);
printf ("Format:\t\t");
switch (bitsPerSample)
{
case 8:
printf ("Unsigned 8 bit\n");
break;
case 16:
printf ("Signed 16 bit little-endian\n");
break;
case 24:
if ((blockAlign / numChannels) == 3)
printf ("Signed 24 bit 3-byte little-endian\n");
else
printf ("Signed 24 bit little-endian\n");
break;
case 32:
printf ("Signed 32 bit little-endian\n");
break;
default:
printf ("Unplayable format: %d bit\n", bitsPerSample);
}
printf ("Num frames:\t%d\n", numFrames);
printf ("Data length:\t%d\n", dataLength);
if (type == SAMPLE_TYPE_FILE)
printf ("Data starts at:\t%d\n", headerSize);
}
Index: alsa.h
===================================================================
RCS file: /cvsroot/playerstage/code/player/server/drivers/audio/alsa.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** alsa.h 18 Jun 2006 06:59:08 -0000 1.4
--- alsa.h 16 Jul 2006 02:50:08 -0000 1.5
***************
*** 23,57 ****
#include <alsa/asoundlib.h>
////////////////////////////////////////////////////////////////////////////////
! // Detailed description of wave data
! // This is more advanced than the player wave data structure: it can store
! // actual sample rate values, etc, making it more flexible and so useful for
! // locally loaded wave data
! typedef struct WaveData
{
! uint16_t numChannels; // Number of channels in the data
! uint32_t sampleRate; // Number of samples per second
! uint32_t byteRate; // Number of bytes per second
! uint16_t blockAlign; // Number of bytes for one sample over all
channels (i.e. frame size)
! uint16_t bitsPerSample; // Number of bits per sample (eg 8, 16, 24, ...)
! uint32_t numFrames; // Number of frames (divide by
sampleRate to get time)
! uint32_t dataLength; // Length of data in bytes
! uint8_t *data;
! } WaveData;
////////////////////////////////////////////////////////////////////////////////
! // Describes an audio sample
! typedef int SampleType;
! const SampleType SAMPLE_TYPE_LOCAL = 0; // Local samples are
stored in a file
! const SampleType SAMPLE_TYPE_REMOTE = 1; // Remote samples are stored in
memory
!
! typedef struct AudioSample
{
! SampleType type; // Type of sample - local file
or stored in memory
! char *localPath; // Path to local file if local
! WaveData *memData; // Stored audio data if sample
is memory
! int index; // Index of sample
! struct AudioSample *next; // Next sample in the linked list
! } AudioSample;
////////////////////////////////////////////////////////////////////////////////
--- 23,45 ----
#include <alsa/asoundlib.h>
+ #include "audio_sample.h"
+
////////////////////////////////////////////////////////////////////////////////
! // Describes a prestored sample for playing with PLAYER_AUDIO_SAMPLE_PLAY_CMD
! typedef struct StoredSample
{
! AudioSample *sample;
! int index; // Index of sample
! struct StoredSample *next; // Next sample in the linked list
! } StoredSample;
////////////////////////////////////////////////////////////////////////////////
! // An item on the queue of waves to play
! typedef struct QueueItem
{
! AudioSample *sample; // Audio sample at this position in the queue
! bool temp; // If true, the AudioSample
will be deleted after playback completes
! struct QueueItem *next; // Next item in the queue
! } QueueItem;
////////////////////////////////////////////////////////////////////////////////
***************
*** 76,80 ****
long minCapVol, curCapVol, maxCapVol; // min, current and max
volume levels for capture
long minComVol, curComVol, maxComVol; // min, current and max
volume levels for common
! bool playMute, capMute, comMute; // Current mute
status
char *name; // Name of the
element
ElemCap caps; // Capabilities
--- 64,68 ----
long minCapVol, curCapVol, maxCapVol; // min, current and max
volume levels for capture
long minComVol, curComVol, maxComVol; // min, current and max
volume levels for common
! int playSwitch, capSwitch, comSwitch; // Current switch status
char *name; // Name of the
element
ElemCap caps; // Capabilities
***************
*** 82,85 ****
--- 70,81 ----
////////////////////////////////////////////////////////////////////////////////
+ // State of the playback system
+ typedef uint8_t PBState;
+ const PBState PB_STATE_STOPPED = 0; // Not playing anything
+ const PBState PB_STATE_PLAYING = 1; // Playing
+ const PBState PB_STATE_DRAIN = 2; // Draining current wave
+ const PBState PB_STATE_RECORDING = 3; // Recording
+
+
////////////////////////////////////////////////////////////////////////////////
// The class for the driver
class Alsa : public Driver
***************
*** 96,109 ****
private:
// Driver options
! bool block; // If
should block while playing or return immediatly
! char *device; // Name of the
mixer device to attach to
! // uint32_t pbRate; // Sample rate
for playback
! // int pbNumChannels; // Number of
sound channels for playback
! AudioSample *samplesHead, *samplesTail; // Stored samples
// ALSA variables
! snd_pcm_t *pcmHandle; // Handle to the PCM
device
! snd_pcm_stream_t pbStream; // Stream for playback
! char *pcmName; // Name of the
sound interface
snd_mixer_t *mixerHandle; // Mixer for
controlling volume levels
MixerElement *mixerElements; // Elements of the mixer
--- 92,125 ----
private:
// Driver options
! bool useQueue; // If should
use a queue for playback or just stop currently playing
! char *pbDevice; // Name of the
playback device
! char *mixerDevice; // Name of the
mixer device
! char *recDevice; // Name of the
record device
! uint32_t cfgPBPeriodTime; // Length of a playback
period in milliseconds (configured value)
! uint32_t cfgPBBufferTime; // Length of the
playback buffer in milliseconds (configured value)
! uint32_t silenceTime; // Length of silence to
put between samples in the queue
! uint32_t cfgRecBufferTime; // Length of the record
buffer in milliseconds (configured value)
! uint32_t cfgRecPeriodTime; // Length of a record
period in milliseconds (configured value)
! uint8_t recNumChannels; // Number of channels
for recording
! uint32_t recSampleRate; // Sample rate for
recording
! uint8_t recBits; // Sample bits
for recording
// ALSA variables
! // Playback
! snd_pcm_t *pbHandle; // Handle to the PCM
device for playback
! int numPBFDs; // Number of
playback file descriptors
! struct pollfd *pbFDs; // Playback file
descriptors for polling
! uint32_t actPBBufferTime; // Length of the
playback buffer in microseconds (actual value)
! uint32_t actPBPeriodTime; // Length of a playback
period in microseconds (actual value)
! snd_pcm_uframes_t pbPeriodSize; // Size of a playback period
(used for filling the buffer)
! uint8_t *periodBuffer; // A buffer used to
copy data from samples to the playback buffer
! // Record
! snd_pcm_t *recHandle; // Handle to the PCM
device for recording
! int numRecFDs; // Number of
record file descriptors
! struct pollfd *recFDs; // Record file
descriptors for polling
! uint32_t actRecBufferTime; // Length of the record
buffer in microseconds (actual value)
! uint32_t actRecPeriodTime; // Length of a record
period in microseconds (actual value)
! snd_pcm_uframes_t recPeriodSize; // Size of a record
period (used for filling the buffer)
! // Mixer
snd_mixer_t *mixerHandle; // Mixer for
controlling volume levels
MixerElement *mixerElements; // Elements of the mixer
***************
*** 111,139 ****
// Other driver data
! int nextSampleIdx; // Next free
index to store a sample at
!
! // Command and request handling
! int HandleWavePlayCmd (player_audio_wav_t *waveData);
! int HandleSamplePlayCmd (player_audio_sample_item_t *data);
! int HandleMixerChannelCmd (player_audio_mixer_channel_list_t
*data);
! int HandleSampleLoadReq (player_audio_sample_t *data,
MessageQueue *resp_queue);
! int HandleSampleRetrieveReq (player_audio_sample_t *data,
MessageQueue *resp_queue);
! int HandleMixerChannelListReq
(player_audio_mixer_channel_list_detail_t *data, MessageQueue *resp_queue);
! int HandleMixerChannelLevelReq
(player_audio_mixer_channel_list_t *data, MessageQueue *resp_queue);
// Internal functions
virtual void Main (void);
- bool AddSample (AudioSample *newSample);
- bool AddFileSample (const char *path);
- bool AddMemorySample (player_audio_wav_t *sampleData);
- AudioSample* GetSampleAtIndex (int index);
- WaveData* LoadWaveFromFile (char *fileName);
- bool WaveDataToPlayer (WaveData *source, player_audio_wav_t
*dest);
- bool PlayerToWaveData (player_audio_wav_t *source, WaveData
*dest);
- void PrintWaveData (WaveData *wave);
! // Sound functions
! bool SetHWParams (WaveData *wave);
! bool PlayWave (WaveData *wave);
// Mixer functions
--- 127,173 ----
// Other driver data
! int nextSampleIdx; // Next
free index to store a sample at
! StoredSample *samplesHead, *samplesTail; // Stored
samples
! QueueItem *queueHead, *queueTail; // Queue of audio data
waiting to play
! PBState playState; // Playback
state
! PBState recState; // Record state
! // AudioSample *recData; // Somewhere to store
recorded data before it goes to the client
! player_audio_wav_t *recData; // Somewhere to store recorded
data before it goes to the client
// Internal functions
virtual void Main (void);
! // Stored sample functions
! bool AddStoredSample (StoredSample *newSample);
! bool AddStoredSample (player_audio_wav_t *waveData);
! bool AddStoredSample (const char *filePath);
! StoredSample* GetSampleAtIndex (int index);
!
! // Queue functions
! void ClearQueue (void);
! bool AddToQueue (QueueItem *newItem);
! bool AddToQueue (player_audio_wav_t *waveData);
! bool AddToQueue (AudioSample *sample);
! bool AddSilence (uint32_t time, AudioSample *format);
! void AdvanceQueue (void);
!
! // Playback functions
! // bool SetGeneralParams (void);
! // bool SetWaveHWParams (AudioSample *sample);
! bool SetupPlayBack (void);
! bool SetPBParams (AudioSample *sample);
! void PlaybackCallback (int numFrames);
!
! // Record functions
! bool SetupRecord (void);
! bool SetRecParams (void);
! void RecordCallback (int numFrames);
! void PublishRecordedData (void);
!
! // Playback/record control functions
! void StartPlayback (void);
! void StopPlayback (void);
! void StartRecording (void);
! void StopRecording (void);
// Mixer functions
***************
*** 146,153 ****
void MixerLevelsToPlayer (player_audio_mixer_channel_list_t
*dest);
void SetElementLevel (uint32_t index, float level);
! void SetElementMute (uint32_t index, player_bool_t mute);
void PublishMixerData (void);
float LevelToPlayer (long min, long max, long level);
long LevelFromPlayer (long min, long max, float level);
void PrintMixerElements (MixerElement *elements, uint32_t
count);
};
--- 180,197 ----
void MixerLevelsToPlayer (player_audio_mixer_channel_list_t
*dest);
void SetElementLevel (uint32_t index, float level);
! void SetElementSwitch (uint32_t index, player_bool_t active);
void PublishMixerData (void);
float LevelToPlayer (long min, long max, long level);
long LevelFromPlayer (long min, long max, float level);
void PrintMixerElements (MixerElement *elements, uint32_t
count);
+
+ // Command and request handling
+ int HandleWavePlayCmd (player_audio_wav_t *waveData);
+ int HandleSamplePlayCmd (player_audio_sample_item_t *data);
+ int HandleRecordCmd (player_bool_t *data);
+ int HandleMixerChannelCmd (player_audio_mixer_channel_list_t
*data);
+ int HandleSampleLoadReq (player_audio_sample_t *data,
MessageQueue *resp_queue);
+ int HandleSampleRetrieveReq (player_audio_sample_t *data,
MessageQueue *resp_queue);
+ int HandleMixerChannelListReq
(player_audio_mixer_channel_list_detail_t *data, MessageQueue *resp_queue);
+ int HandleMixerChannelLevelReq
(player_audio_mixer_channel_list_t *data, MessageQueue *resp_queue);
};
Index: Makefile.am
===================================================================
RCS file: /cvsroot/playerstage/code/player/server/drivers/audio/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** Makefile.am 1 Jun 2006 20:16:33 -0000 1.3
--- Makefile.am 16 Jul 2006 02:50:08 -0000 1.4
***************
*** 7,9 ****
AM_CPPFLAGS = -Wall -I$(top_srcdir)
! libalsa_la_SOURCES = alsa.cc
--- 7,9 ----
AM_CPPFLAGS = -Wall -I$(top_srcdir)
! libalsa_la_SOURCES = alsa.cc audio_sample.cc
Index: alsa.cc
===================================================================
RCS file: /cvsroot/playerstage/code/player/server/drivers/audio/alsa.cc,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** alsa.cc 18 Jun 2006 06:59:08 -0000 1.4
--- alsa.cc 16 Jul 2006 02:50:08 -0000 1.5
***************
*** 44,51 ****
PLAYER_AUDIO_SAMPLE_RETRIEVE_REQ - Send stored samples to remote clients (max
1MB)
! Planned future support includes:
! - The callback method of managing buffers (to allow for blocking/nonblocking
and
! less skippy playback).
! - Recording.
@par Samples
--- 44,50 ----
PLAYER_AUDIO_SAMPLE_RETRIEVE_REQ - Send stored samples to remote clients (max
1MB)
[...2822 lines suppressed...]
{
return HandleMixerChannelLevelReq
(reinterpret_cast<player_audio_mixer_channel_list_t*> (data), resp_queue);
--- 2217,2233 ----
}
// Requests
! else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ,
PLAYER_AUDIO_SAMPLE_LOAD_REQ, device_addr) && pbHandle)
{
return HandleSampleLoadReq
(reinterpret_cast<player_audio_sample_t*> (data), resp_queue);
}
! else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ,
PLAYER_AUDIO_SAMPLE_RETRIEVE_REQ, device_addr) && pbHandle)
{
return HandleSampleRetrieveReq
(reinterpret_cast<player_audio_sample_t*> (data), resp_queue);
}
! else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ,
PLAYER_AUDIO_MIXER_CHANNEL_LIST_REQ, device_addr) && mixerHandle)
{
return HandleMixerChannelListReq
(reinterpret_cast<player_audio_mixer_channel_list_detail_t*> (data),
resp_queue);
}
! else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ,
PLAYER_AUDIO_MIXER_CHANNEL_LEVEL_REQ, device_addr) && mixerHandle)
{
return HandleMixerChannelLevelReq
(reinterpret_cast<player_audio_mixer_channel_list_t*> (data), resp_queue);
--- NEW FILE: audio_sample.h ---
/*
* Player - One Hell of a Robot Server
* Copyright (C) 2003
* Brian Gerkey
*
*
* 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
*
*/
// Sample type
typedef uint8_t SampleType;
// No type - no wave data loaded
const SampleType SAMPLE_TYPE_NONE = 0;
// File samples must be opened, and the data comes from/goes to the file on
demand
const SampleType SAMPLE_TYPE_FILE = 1;
// Memory samples are stored as data in memory, eg a sample received via the
player server
const SampleType SAMPLE_TYPE_MEM = 2;
class AudioSample
{
public:
AudioSample (void);
~AudioSample (void);
// Data management functions
void SetDataPosition (uint32_t newPosition); // Set current
position in the data (in frames, not bytes)
uint32_t GetDataPosition (void) const; // Get current
position in the data (in frames, not bytes)
uint32_t GetDataLength (void) const; // Get length
of data (in frames, not bytes)
int GetData (int count, uint8_t *buffer); // Get a block
of data
void ClearSample (void);
// Clear the entire sample (including format), making this a SAMPLE_TYPE_NONE
bool FillSilence (uint32_t time); // Fill
the sample with silence
// Data conversion functions
bool ToPlayer (player_audio_wav_t *dest);
// Convert to player wave structure
bool FromPlayer (const player_audio_wav_t *source); //
Convert from player wave structure
// File management functions
bool LoadFile (const char *fileName); // Load wave data from
a file
void CloseFile (void); //
Close the opened file
const char* GetFilePath (void) const { return filePath; }
// Wave format functions
SampleType GetType (void) const { return type; }
void SetType (SampleType val) { type = val; }
uint16_t GetNumChannels (void) const { return numChannels; }
void SetNumChannels (uint16_t val) { numChannels =
val; }
uint32_t GetSampleRate (void) const { return
sampleRate; }
void SetSampleRate (uint32_t val) { sampleRate =
val; byteRate = blockAlign * sampleRate; }
uint32_t GetByteRate (void) const { return
byteRate; }
uint16_t GetBlockAlign (void) const { return
blockAlign; }
void SetBlockAlign (uint16_t val) { blockAlign =
val; byteRate = blockAlign * sampleRate; }
uint16_t GetBitsPerSample (void) const { return bitsPerSample;
}
void SetBitsPerSample (uint16_t val) { bitsPerSample = val; }
uint32_t GetNumFrames (void) const { return
numFrames; }
bool SameFormat (const AudioSample *rhs);
void CopyFormat (const AudioSample *rhs);
// Other useful functions
void PrintWaveInfo (void); // Print out the wave
information
private:
SampleType type; // Sample type
// Information about the wave this sample stores
uint16_t numChannels; // Number of channels in the data
uint32_t sampleRate; // Number of samples per second
uint32_t byteRate; // Number of bytes per second
uint16_t blockAlign; // Number of bytes for one sample over
all channels (i.e. frame size)
uint16_t bitsPerSample; // Number of bits per sample (eg 8, 16,
24, ...)
uint32_t numFrames; // Number of frames (divide by
sampleRate to get time)
// Current position in the wave data (in bytes)
uint32_t position;
// If this is a file sample, this is the file info
FILE *waveFile; // File pointer
char *filePath; // Path to the file on disc
uint32_t headerSize; // Size of the wave format header in
the file (i.e. start of actual data in the file)
// If this is a memory sample, the data is stored here
uint32_t dataLength; // Length of data in bytes
uint8_t *data; // Array on the heap containing
the data
};
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit