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

Reply via email to