alsa.cc

00001 /*
00002  *  Player - One Hell of a Robot Server
00003  *  Copyright (C) 2003
00004  *     Brian Gerkey
00005  *
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  */
00022 
00023 /*
00024  * A driver to provide access to the ALSA sound system.
00025  */
00026 
00189 /* Debug info levels:
00190  * 0    None
00191  * 1    Samples loaded at startup, mixer filters
00192  * 2    Mixer elements enumerated + capabilities
00193  * 3    Sample info
00194  * 4    Recording start/stop, message handling
00195  * 5    Ludicrous amounts of info
00196  */
00197 
00198 #include <libplayercore/playercore.h>
00199 #include <sys/time.h>
00200 #include <string.h>
00201 #include <iostream>
00202 using namespace std;
00203 
00204 #include "alsa.h"
00205 
00206 // Initialisation function
00207 Driver* Alsa_Init (ConfigFile* cf, int section)
00208 {
00209         return reinterpret_cast<Driver*> (new Alsa (cf, section));
00210 }
00211 
00212 // Register function
00213 void Alsa_Register (DriverTable* table)
00214 {
00215         table->AddDriver("alsa", Alsa_Init);
00216 }
00217 
00219 //      Stored sample functions
00221 
00222 // Adds a new stored sample (already initialised) to the linked list
00223 bool Alsa::AddStoredSample (StoredSample *newSample)
00224 {
00225         if (samplesHead == NULL)
00226         {
00227                 samplesHead = samplesTail = newSample;
00228         }
00229         else
00230         {
00231                 samplesTail->next = newSample;
00232                 samplesTail = newSample;
00233         }
00234 
00235         return true;
00236 }
00237 
00238 bool Alsa::AddStoredSample (player_audio_wav_t *waveData)
00239 {
00240         StoredSample *newSample = NULL;
00241         if ((newSample = new StoredSample) == NULL)
00242         {
00243                 PLAYER_ERROR ("Failed to allocate memory for new stored sample");
00244                 return false;
00245         }
00246 
00247         if ((newSample->sample = new AudioSample) == NULL)
00248         {
00249                 PLAYER_ERROR ("Failed to allocate memory for new stored audio sample");
00250                 delete newSample;
00251                 return false;
00252         }
00253 
00254         if (!newSample->sample->FromPlayer (waveData))
00255         {
00256                 delete newSample->sample;
00257                 delete newSample;
00258                 return false;
00259         }
00260 
00261         newSample->index = nextSampleIdx++;
00262         newSample->next = NULL;
00263 
00264         if (debugLevel >= 1)
00265                  cout << "ALSA: Added stored sample to list at index " << newSample->index << endl;
00266         if (debugLevel >= 3)
00267                  newSample->sample->PrintWaveInfo ();
00268         return AddStoredSample (newSample);
00269 }
00270 
00271 bool Alsa::AddStoredSample (const char *filePath)
00272 {
00273         StoredSample *newSample = NULL;
00274         if ((newSample = new StoredSample) == NULL)
00275         {
00276                 PLAYER_ERROR ("Failed to allocate memory for new stored sample");
00277                 return false;
00278         }
00279 
00280         if ((newSample->sample = new AudioSample) == NULL)
00281         {
00282                 PLAYER_ERROR ("Failed to allocate memory for new stored audio sample");
00283                 delete newSample;
00284                 return false;
00285         }
00286 
00287         if (!newSample->sample->LoadFile (filePath))
00288         {
00289                 delete newSample->sample;
00290                 delete newSample;
00291                 return false;
00292         }
00293 
00294         newSample->index = nextSampleIdx++;
00295         newSample->next = NULL;
00296 
00297         if (debugLevel >= 1)
00298                 cout << "ALSA: Added stored sample " << filePath << " to list at index " << newSample->index << endl;
00299         if (debugLevel >= 3)
00300                 newSample->sample->PrintWaveInfo ();
00301         return AddStoredSample (newSample);
00302 }
00303 
00304 // Finds the sample with the specified index
00305 StoredSample* Alsa::GetSampleAtIndex (int index)
00306 {
00307         if (samplesHead)
00308         {
00309                 StoredSample *currentSample = samplesHead;
00310                 while (currentSample != NULL)
00311                 {
00312                         if (currentSample->index == index)
00313                                 return currentSample;
00314                         currentSample = currentSample->next;
00315                 }
00316         }
00317         return NULL;
00318 }
00319 
00321 //      Queue management functions
00323 
00324 // Deletes all data stored in the queue
00325 void Alsa::ClearQueue (void)
00326 {
00327         QueueItem *currentItem = queueHead;
00328         QueueItem *previousItem = NULL;
00329 
00330         while (currentItem != NULL)
00331         {
00332                 if (currentItem->temp)
00333                         delete currentItem->sample;
00334                 previousItem = currentItem;
00335                 currentItem = currentItem->next;
00336                 delete previousItem;
00337         }
00338         queueHead = NULL;
00339         queueTail = NULL;
00340 }
00341 
00342 bool Alsa::AddToQueue (QueueItem *newItem)
00343 {
00344         if (!useQueue)  // If configured to not use a queue, clear out current queue first
00345         {
00346                 StopPlayback ();        // Must stop playback before deleting the data being played
00347                 ClearQueue ();
00348         }
00349 
00350         if (queueHead == NULL)
00351         {
00352                 queueHead = queueTail = newItem;
00353         }
00354         else
00355         {
00356                 queueTail->next = newItem;
00357                 queueTail = newItem;
00358         }
00359 
00360         return true;
00361 }
00362 
00363 bool Alsa::AddToQueue (player_audio_wav_t *waveData)
00364 {
00365         QueueItem *newItem = NULL;
00366 
00367         if ((newItem = new QueueItem) == NULL)
00368         {
00369                 PLAYER_ERROR ("Failed to allocate memory for new queue item");
00370                 return false;
00371         }
00372 
00373         if ((newItem->sample = new AudioSample) == NULL)
00374         {
00375                 PLAYER_ERROR ("Failed to allocate memory for new audio sample");
00376                 delete newItem;
00377                 return false;
00378         }
00379 
00380         if (!newItem->sample->FromPlayer (waveData))
00381         {
00382                 delete newItem->sample;
00383                 delete newItem;
00384                 return false;
00385         }
00386 
00387         newItem->temp = true;
00388         newItem->next = NULL;
00389 
00390         // If silence is wanted between samples, add it now (but only if not
00391         // the first thing in the queue)
00392         if (silenceTime != 0 && queueHead != NULL)
00393         {
00394                 if (!AddSilence (silenceTime, newItem->sample))
00395                 {
00396                         delete newItem->sample;
00397                         delete newItem;
00398                         return false;
00399                 }
00400         }
00401 
00402         return AddToQueue (newItem);
00403 }
00404 
00405 bool Alsa::AddToQueue (AudioSample *sample)
00406 {
00407         QueueItem *newItem = NULL;
00408 
00409         if ((newItem = new QueueItem) == NULL)
00410         {
00411                 PLAYER_ERROR ("Failed to allocate memory for new queue item");
00412                 return false;
00413         }
00414 
00415         newItem->sample = sample;
00416         newItem->temp = false;
00417         newItem->next = NULL;
00418 
00419         // If silence is wanted between samples, add it now (but only if not
00420         // the first thing in the queue)
00421         if (silenceTime != 0 && queueHead != NULL)
00422         {
00423                 if (!AddSilence (silenceTime, sample))
00424                 {
00425                         delete newItem;
00426                         return false;
00427                 }
00428         }
00429 
00430         return AddToQueue (newItem);
00431 }
00432 
00433 // Adds a block of silence into the queue as an audio sample
00434 // time: The length of silence to add
00435 // format: A pointer to another audio sample who's format should be copied
00436 // Returns: true on success, false otherwise
00437 bool Alsa::AddSilence (uint32_t time, AudioSample *format)
00438 {
00439         QueueItem *newItem = NULL;
00440 
00441         if ((newItem = new QueueItem) == NULL)
00442         {
00443                 PLAYER_ERROR ("Failed to allocate memory for silence queue item");
00444                 return false;
00445         }
00446 
00447         if ((newItem->sample = new AudioSample) == NULL)
00448         {
00449                 PLAYER_ERROR ("Failed to allocate memory for silence audio sample");
00450                 delete newItem;
00451                 return false;
00452         }
00453 
00454         newItem->temp = true;
00455         newItem->next = NULL;
00456 
00457         // Empty the new sample
00458         newItem->sample->ClearSample ();
00459         // Copy the format of the provided sample
00460         newItem->sample->CopyFormat (format);
00461         // Fill it up with silence
00462         if (!newItem->sample->FillSilence (time))
00463         {
00464                 delete newItem->sample;
00465                 delete newItem;
00466                 return false;
00467         }
00468         // Add it to the queue
00469         return AddToQueue (newItem);
00470 }
00471 
00472 void Alsa::AdvanceQueue (void)
00473 {
00474         // Move the queue head forward one
00475         QueueItem *oldHead = queueHead;
00476         queueHead = queueHead->next;
00477 
00478         // Delete the old head, including sample if necessary
00479         if (oldHead->temp)
00480                 delete oldHead->sample;
00481         else
00482                 // If the sample wasn't temp, rewind it
00483                 oldHead->sample->SetDataPosition (0);
00484         delete oldHead;
00485 
00486 /*      if (queueHead != NULL)
00487         {
00488                 printf ("Playing sample:\n");
00489                 queueHead->sample->PrintWaveInfo ();
00490         }*/
00491 }
00492 
00494 //      Playback functions (setting params, writing data to the buffer, etc)
00496 
00497 bool Alsa::SetupPlayBack (void)
00498 {
00499         // If no device configured, return
00500         if (!pbDevice)
00501                 return false;
00502 
00503         // Open the pcm device in blocking mode
00504         if (snd_pcm_open (&pbHandle, pbDevice, SND_PCM_STREAM_PLAYBACK, 0) < 0)
00505         {
00506                 PLAYER_ERROR1 ("Error opening PCM device %s for playback", pbDevice);
00507                 return false;
00508         }
00509 
00510         // Set parameters for the pcm device
00511 //      if (!SetGeneralParams ())
00512 //              return -1;
00513 
00514         // Setup polling file descriptors
00515         numPBFDs = snd_pcm_poll_descriptors_count (pbHandle);
00516         if ((pbFDs = (struct pollfd*) new struct pollfd[numPBFDs]) == NULL)
00517         {
00518                 PLAYER_ERROR ("Error allocating memory for playback file descriptors");
00519                 return false;
00520         }
00521         snd_pcm_poll_descriptors (pbHandle, pbFDs, numPBFDs);
00522 
00523         return true;
00524 }
00525 
00526 // Sets the hardware parameters of the sound device to the provided wave data's format
00527 bool Alsa::SetPBParams (AudioSample *sample)
00528 {
00529         snd_pcm_hw_params_t *hwparams;                  // Hardware parameters
00530         snd_pcm_sw_params_t *swparams;                  // Software parameters
00531 
00532         // Allocate params structure on stack
00533         snd_pcm_hw_params_alloca(&hwparams);
00534 
00535         // Init parameters
00536         if (snd_pcm_hw_params_any (pbHandle, hwparams) < 0)
00537         {
00538                 PLAYER_ERROR ("Cannot configure this playback device");
00539                 return false;
00540         }
00541 
00542         unsigned int exactRate; // Sample rate returned by snd_pcm_hw_params_set_rate_near
00543 
00544         // Use interleaved access
00545         if (snd_pcm_hw_params_set_access (pbHandle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
00546         {
00547                 PLAYER_ERROR ("Error setting interleaved access for playback device");
00548                 return false;
00549         }
00550 
00551         // Set sound format
00552         snd_pcm_format_t format;
00553         switch (sample->GetBitsPerSample ())
00554         {
00555                 case 8:
00556                         format = SND_PCM_FORMAT_U8;
00557                         break;
00558                 case 16:
00559                         format = SND_PCM_FORMAT_S16_LE;
00560                         break;
00561                 case 24:
00562                         if ((sample->GetBlockAlign () / sample->GetNumChannels ()) == 3)
00563                                 format = SND_PCM_FORMAT_S24_3LE;
00564                         else
00565                                 format = SND_PCM_FORMAT_S24_LE;
00566                         break;
00567                 case 32:
00568                         format = SND_PCM_FORMAT_S32_LE;
00569                         break;
00570                 default:
00571                         PLAYER_ERROR ("Cannot play audio with this format");
00572                         return false;
00573         }
00574         if (snd_pcm_hw_params_set_format (pbHandle, hwparams, format) < 0)
00575         {
00576                 PLAYER_ERROR ("Error setting format for playback device");
00577                 return false;
00578         }
00579         // Set sample rate
00580         exactRate = sample->GetSampleRate ();
00581         if (snd_pcm_hw_params_set_rate_near (pbHandle, hwparams, &exactRate, 0) < 0)
00582         {
00583                 PLAYER_ERROR ("Error setting sample rate for playback device");
00584                 return false;
00585         }
00586         if (exactRate != sample->GetSampleRate ())
00587                 PLAYER_WARN2 ("Rate %dHz not supported by hardware for playback device, using %dHz instead", sample->GetSampleRate (), exactRate);
00588 
00589         // Set number of channels
00590         if (snd_pcm_hw_params_set_channels(pbHandle, hwparams, sample->GetNumChannels ()) < 0)
00591         {
00592                 PLAYER_ERROR ("Error setting channels for playback device");
00593                 return false;
00594         }
00595 
00596         // Set the length of the buffer
00597         actPBBufferTime = cfgPBBufferTime * 1000;
00598         if (snd_pcm_hw_params_set_buffer_time_near (pbHandle, hwparams, &actPBBufferTime, 0) < 0)
00599         {
00600                 PLAYER_ERROR ("Error setting periods for playback device");
00601                 return false;
00602         }
00603         if (actPBBufferTime < cfgPBBufferTime * 900)    // cfgPBBufferTime * 1000 * 9/10
00604                 PLAYER_WARN2 ("Buffer length for playback device reduced from %dus to %dus", cfgPBBufferTime * 1000, actPBBufferTime);
00605 
00606 //      snd_pcm_hw_params_get_buffer_size (hwparams, &pbPeriodSize);
00607 
00608         // Set the length of a period
00609         actPBPeriodTime = cfgPBPeriodTime * 1000;
00610         if (actPBPeriodTime > (actPBBufferTime / 2))
00611         {
00612                 actPBPeriodTime = (actPBBufferTime / 2);
00613                 PLAYER_WARN1 ("Period time for playback device too long, reduced to %dms", actPBPeriodTime / 1000);
00614         }
00615         if (snd_pcm_hw_params_set_period_time_near (pbHandle, hwparams, &actPBPeriodTime, 0) < 0)
00616         {
00617                 PLAYER_ERROR ("Error setting period time for playback device");
00618                 return false;
00619         }
00620         if (actPBPeriodTime < cfgPBPeriodTime * 900)    // cfgPBPeriodTime * 1000 * 9/10
00621                 PLAYER_WARN2 ("Period length for playback device reduced from %dms to %dms", cfgPBPeriodTime, actPBPeriodTime / 1000);
00622 
00623         snd_pcm_hw_params_get_period_size (hwparams, &pbPeriodSize, 0);
00624 
00625         // Allocate a buffer the size of one period
00626         if (periodBuffer != NULL)
00627                 delete[] periodBuffer;
00628         if ((periodBuffer = new uint8_t[pbPeriodSize * sample->GetBlockAlign ()]) == NULL)
00629         {
00630                 PLAYER_ERROR ("Failed to allocate memory for period buffer");
00631                 return false;
00632         }
00633 
00634         // Apply hwparams to the pcm device
00635         if (snd_pcm_hw_params (pbHandle, hwparams) < 0)
00636         {
00637                 PLAYER_ERROR ("Error setting HW params for playback device");
00638                 return false;
00639         }
00640 
00641         // Set software parameters for the pcm device
00642         snd_pcm_sw_params_alloca (&swparams);   // Allocate params structure on stack
00643         // Get the current software parameters
00644         if (snd_pcm_sw_params_current (pbHandle, swparams) < 0)
00645         {
00646                 PLAYER_ERROR ("Error getting current SW params for playback device");
00647                 return false;
00648         }
00649         // Set notification of pbBufSize bytes available for writing
00650         if (snd_pcm_sw_params_set_avail_min (pbHandle, swparams, pbPeriodSize) < 0)
00651         {
00652                 PLAYER_ERROR ("Error setting avil_min notification for playback device");
00653                 return false;
00654         }
00655         // Set the paramters on the device
00656         if (snd_pcm_sw_params (pbHandle, swparams) < 0)
00657         {
00658                 PLAYER_ERROR ("Error setting SW params for playback device");
00659                 return false;
00660         }
00661 
00662         return true;
00663 }
00664 
00665 // // Sets the general hardware parameters of the sound device
00666 // // (Those not affected by wave format)
00667 // bool Alsa::SetGeneralParams (void)
00668 // {
00669 //      snd_pcm_sw_params_t *swparams;                  // Software parameters
00670 //      snd_pcm_hw_params_t *hwparams;                  // Hardware parameters
00671 //      snd_pcm_hw_params_alloca (&hwparams);   // Allocate params structure on stack
00672 //
00673 //      // Init parameters
00674 //      if (snd_pcm_hw_params_any (pbHandle, hwparams) < 0)
00675 //      {
00676 //              PLAYER_ERROR ("Cannot configure this PCM device");
00677 //              return false;
00678 //      }
00679 //
00680 // //   int periods = 2;                // Number of periods
00681 // //   snd_pcm_uframes_t periodSize = 8192;    // Periodsize (bytes) of the output buffer
00682 //
00683 //      // Use interleaved access
00684 //      if (snd_pcm_hw_params_set_access (pbHandle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
00685 //      {
00686 //              PLAYER_ERROR ("Error setting interleaved access");
00687 //              return false;
00688 //      }
00689 //
00690 //      // Set number of periods
00691 //      if (snd_pcm_hw_params_set_periods(pbHandle, hwparams, pbNumPeriods, 0) < 0)
00692 //      {
00693 //              PLAYER_ERROR ("Error setting periods");
00694 //              return false;
00695 //      }
00696 //
00697 //      // Set the size of a period
00698 //      if (snd_pcm_hw_params_set_period_size (pbHandle, hwparams, pbPeriodSize, 0) < 0)
00699 //      {
00700 //              PLAYER_ERROR ("Error setting period size");
00701 //              return false;
00702 //      }
00703 //
00704 //      // Apply hwparams to the pcm device
00705 //      if (snd_pcm_hw_params (pbHandle, hwparams) < 0)
00706 //      {
00707 //              PLAYER_ERROR ("Error setting HW params");
00708 //              return false;
00709 //      }
00710 //
00711 //      // Don't need this anymore (I think) TODO: figure out why this causes glib errors
00712 // //   snd_pcm_hw_params_free (hwparams);
00713 //
00714 //      // Set software parameters for the pcm device
00715 //      snd_pcm_sw_params_alloca (&swparams);   // Allocate params structure on stack
00716 //      // Get the current software parameters
00717 //      if (snd_pcm_sw_params_current (pbHandle, swparams) < 0)
00718 //      {
00719 //              PLAYER_ERROR ("Error getting current SW params");
00720 //              return false;
00721 //      }
00722 //      // Set notification of pbBufSize bytes available for writing
00723 //      if (snd_pcm_sw_params_set_avail_min (pbHandle, swparams, pbPeriodSize) < 0)
00724 //      {
00725 //              PLAYER_ERROR ("Error setting avil_min notification");
00726 //              return false;
00727 //      }
00728 //      // Set the paramters on the device
00729 //      if (snd_pcm_sw_params (pbHandle, swparams) < 0)
00730 //      {
00731 //              PLAYER_ERROR ("Error setting SW params");
00732 //              return false;
00733 //      }
00734 //
00735 //      return true;
00736 // }
00737 //
00738 // // Sets the hardware parameters of the sound device to the provided wave data's format
00739 // bool Alsa::SetWaveHWParams (AudioSample *sample)
00740 // {
00741 //      snd_pcm_hw_params_t *hwparams;                  // Hardware parameters
00742 //      snd_pcm_hw_params_alloca(&hwparams);    // Allocate params structure on stack
00743 //
00744 //      // Init parameters
00745 //      if (snd_pcm_hw_params_any (pbHandle, hwparams) < 0)
00746 //      {
00747 //              PLAYER_ERROR ("Cannot configure this PCM device");
00748 //              return false;
00749 //      }
00750 //
00751 //      unsigned int exactRate; // Sample rate returned by snd_pcm_hw_params_set_rate_near
00752 //
00753 //      printf ("Stream state is %d\n", snd_pcm_state (pbHandle));
00754 //
00755 //      // Set sound format
00756 //      snd_pcm_format_t format;
00757 //      switch (sample->GetBitsPerSample ())
00758 //      {
00759 //              case 8:
00760 //                      format = SND_PCM_FORMAT_U8;
00761 //                      break;
00762 //              case 16:
00763 //                      format = SND_PCM_FORMAT_S16_LE;
00764 //                      break;
00765 //              case 24:
00766 //                      if ((sample->GetBlockAlign () / sample->GetNumChannels ()) == 3)
00767 //                              format = SND_PCM_FORMAT_S24_3LE;
00768 //                      else
00769 //                              format = SND_PCM_FORMAT_S24_LE;
00770 //                      break;
00771 //              case 32:
00772 //                      format = SND_PCM_FORMAT_S32_LE;
00773 //                      break;
00774 //              default:
00775 //                      PLAYER_ERROR ("Cannot play audio with this format");
00776 //                      return false;
00777 //      }
00778 //      if (snd_pcm_hw_params_set_format (pbHandle, hwparams, format) < 0)
00779 //      {
00780 //              PLAYER_ERROR ("Error setting format");
00781 //              return false;
00782 //      }
00783 //      // Set sample rate
00784 //      exactRate = sample->GetSampleRate ();
00785 //      if (snd_pcm_hw_params_set_rate_near (pbHandle, hwparams, &exactRate, 0) < 0)
00786 //      {
00787 //              PLAYER_ERROR ("Error setting sample rate");
00788 //              return false;
00789 //      }
00790 //      if (exactRate != sample->GetSampleRate ())
00791 //              PLAYER_WARN2 ("Rate %dHz not supported by hardware, using %dHz instead", sample->GetSampleRate (), exactRate);
00792 //
00793 //      // Set number of channels
00794 //      if (snd_pcm_hw_params_set_channels(pbHandle, hwparams, sample->GetNumChannels ()) < 0)
00795 //      {
00796 //              PLAYER_ERROR ("Error setting channels");
00797 //              return false;
00798 //      }
00799 //
00800 //      // Apply hwparams to the pcm device
00801 //      if (snd_pcm_hw_params (pbHandle, hwparams) < 0)
00802 //      {
00803 //              PLAYER_ERROR ("Error setting HW params");
00804 //              return false;
00805 //      }
00806 //
00807 //      return true;
00808 // }
00809 
00810 // Called to write data to the playback buffer when it is ready for writing
00811 // numFrames: The number of frames that can be written
00812 void Alsa::PlaybackCallback (int numFrames)
00813 {
00814         int framesToWrite = 0;
00815 
00816         // Get frames from audio samples until filled the buffer, or hit a sample
00817         // with a different format to the current sample
00818         while (framesToWrite < numFrames && playState == PB_STATE_PLAYING)
00819         {
00820                 int framesToCopy = numFrames - framesToWrite;
00821                 // Request frames from the sample
00822                 // Want to get the number of frames not yet filled in the buffer and
00823                 // place them however far into the buffer the last lot got up to
00824                 int framesCopied = queueHead->sample->GetData (framesToCopy, &periodBuffer[framesToWrite * queueHead->sample->GetBlockAlign ()]);
00825                 // If got no frames, something went wrong with this sample
00826                 if (framesCopied < 0)
00827                 {
00828                         // If no frames copied so far, nothing to write so drain
00829                         // The write after this won't happen because of the while loop condition
00830                         PLAYER_ERROR ("Error reading wave data");
00831                         playState = PB_STATE_DRAIN;
00832                 }
00833                 // If got less than requested, end of the current sample
00834                 else if (framesCopied < framesToCopy)
00835                 {
00836                         // If the next sample has the same format as the current one, advance
00837                         // the queue and begin copying from that instead
00838                         if (queueHead->next != NULL)
00839                         {
00840                                 if (queueHead->sample->SameFormat (queueHead->next->sample))
00841                                         AdvanceQueue ();
00842                                 // If it doesn't, move to drain state
00843                                 else
00844                                         playState = PB_STATE_DRAIN;
00845                         }
00846                         // If it doesn't, move to drain state
00847                         else
00848                         {
00849                                 playState = PB_STATE_DRAIN;
00850                         }
00851                         // Add the number of frames copied to the number to write
00852                         framesToWrite += framesCopied;
00853                 }
00854                 // Got the requested number, so not much to do
00855                 else
00856                         framesToWrite += framesCopied;
00857         }
00858 
00859         // Keep writing until all the data we got has been written to the playback buffer
00860         uint8_t *dataPos = periodBuffer;
00861         while (framesToWrite > 0)
00862         {
00863                 int framesWritten = snd_pcm_writei (pbHandle, dataPos, framesToWrite);
00864                 if (framesWritten > 0 && framesWritten <= framesToWrite)
00865                 {       // Not all was written
00866                         snd_pcm_wait (pbHandle, 100);
00867                         // Calculate how many frames remain unwritten
00868                         framesToWrite -= framesWritten;
00869                         // Move the data pointer appropriately
00870                         dataPos += framesWritten * queueHead->sample->GetBlockAlign ();
00871                 }
00872                 else if (framesWritten == -EAGAIN)
00873                 {       // Nothing was written, but not a disasterous error?
00874                         snd_pcm_wait (pbHandle, 100);
00875                 }
00876                 else if (framesWritten == -EPIPE)
00877                 {
00878                         PLAYER_WARN ("Buffer underrun occured during playback");
00879                         // Need to prepare the device again after an xrun
00880                         snd_pcm_prepare (pbHandle);
00881                 }
00882                 else
00883                 {
00884                         PLAYER_ERROR2 ("Error writing to playback buffer: (%d) %s", framesWritten, snd_strerror (framesWritten));
00885                 }
00886         };
00887 
00888 //      struct timeval timeVal;
00889 //      gettimeofday (&timeVal, NULL);
00890 //      printf ("%d.%d: Wrote %d bytes in total\n", timeVal.tv_sec, timeVal.tv_usec, totalFrames);
00891 //      fflush (NULL);
00892 
00893         // If state has moved to drain
00894         if (playState == PB_STATE_DRAIN)
00895         {
00896                 // Tell the pcm device to drain the buffer
00897                 snd_pcm_drain (pbHandle);
00898 //              struct timeval timeVal;
00899 //              gettimeofday (&timeVal, NULL);
00900 //              printf ("%d.%d: Set to drain\n", timeVal.tv_sec, timeVal.tv_usec);
00901 //              fflush (NULL);
00902         }
00903 }
00904 
00906 //      Record functions (setting params, reading data from the buffer, etc)
00908 
00909 bool Alsa::SetupRecord (void)
00910 {
00911         // If no device configured, return
00912         if (!recDevice)
00913                 return false;
00914 
00915         // Open the pcm device in blocking mode
00916         if (snd_pcm_open (&recHandle, recDevice, SND_PCM_STREAM_CAPTURE, 0) < 0)
00917         {
00918                 PLAYER_ERROR1 ("Error opening PCM device %s for recording", recDevice);
00919                 return false;
00920         }
00921 
00922         // Set hardware/software parameters
00923         if (!SetRecParams ())
00924                 return false;
00925 
00926         // Setup polling file descriptors
00927         numRecFDs = snd_pcm_poll_descriptors_count (recHandle);
00928         if ((recFDs = (struct pollfd*) new struct pollfd[numRecFDs]) == NULL)
00929         {
00930                 PLAYER_ERROR ("Error allocating memory for record file descriptors");
00931                 return false;
00932         }
00933         snd_pcm_poll_descriptors (recHandle, recFDs, numRecFDs);
00934 
00935         return true;
00936 }
00937 
00938 // Sets the hardware parameters of the sound device to the provided wave data's format
00939 bool Alsa::SetRecParams (void)
00940 {
00941         snd_pcm_hw_params_t *hwparams;                  // Hardware parameters
00942         snd_pcm_sw_params_t *swparams;                  // Software parameters
00943 
00944         // Allocate params structure on stack
00945         snd_pcm_hw_params_alloca(&hwparams);
00946 
00947         // Init parameters
00948         if (snd_pcm_hw_params_any (recHandle, hwparams) < 0)
00949         {
00950                 PLAYER_ERROR ("Cannot configure this recording device");
00951                 return false;
00952         }
00953 
00954         unsigned int exactRate; // Sample rate returned by snd_pcm_hw_params_set_rate_near
00955 
00956         // Use interleaved access
00957         if (snd_pcm_hw_params_set_access (recHandle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
00958         {
00959                 PLAYER_ERROR ("Error setting interleaved access for recording device");
00960                 return false;
00961         }
00962 
00963         // Set sound format
00964         snd_pcm_format_t format;
00965         switch (recBits)
00966         {
00967                 case 8:
00968                         format = SND_PCM_FORMAT_U8;
00969                         break;
00970                 case 16:
00971                         format = SND_PCM_FORMAT_S16_LE;
00972                         break;
00973                 case 24:
00974                         format = SND_PCM_FORMAT_S24_LE;
00975                         break;
00976                 case 32:
00977                         format = SND_PCM_FORMAT_S32_LE;
00978                         break;
00979                 default:
00980                         PLAYER_ERROR ("Cannot record audio with this format");
00981                         return false;
00982         }
00983         if (snd_pcm_hw_params_set_format (recHandle, hwparams, format) < 0)
00984         {
00985                 PLAYER_ERROR ("Error setting format for recording device");
00986                 return false;
00987         }
00988         // Set sample rate
00989         exactRate = recSampleRate;
00990         if (snd_pcm_hw_params_set_rate_near (recHandle, hwparams, &exactRate, 0) < 0)
00991         {
00992                 PLAYER_ERROR ("Error setting sample rate for recording device");
00993                 return false;
00994         }
00995         if (exactRate != recSampleRate)
00996                 PLAYER_WARN2 ("Rate %dHz not supported by hardware for recording device, using %dHz instead", recSampleRate, exactRate);
00997         recSampleRate = exactRate;
00998 
00999         // Set number of channels
01000         if (snd_pcm_hw_params_set_channels (recHandle, hwparams, recNumChannels) < 0)
01001         {
01002                 PLAYER_ERROR ("Error setting channels for recording device");
01003                 return false;
01004         }
01005 
01006         // Set the length of the buffer
01007         actRecBufferTime = cfgRecBufferTime * 1000;
01008         if (snd_pcm_hw_params_set_buffer_time_near (recHandle, hwparams, &actRecBufferTime, 0) < 0)
01009         {
01010                 PLAYER_ERROR ("Error setting periods for recording device");
01011                 return false;
01012         }
01013         if (actRecBufferTime < cfgRecBufferTime * 900)  // cfgPBBufferTime * 1000 * 9/10
01014                 PLAYER_WARN2 ("Buffer length for recording device reduced from %dus to %dus", cfgRecBufferTime * 1000, actRecBufferTime);
01015 
01016 //      snd_pcm_hw_params_get_buffer_size (hwparams, &recPeriodSize);
01017 
01018         // Set the length of a period
01019         actRecPeriodTime = cfgRecPeriodTime * 1000;
01020         if (actRecPeriodTime > (actRecBufferTime / 2))
01021         {
01022                 actRecPeriodTime = (actRecBufferTime / 2);
01023                 PLAYER_WARN1 ("Period time for recording device too long, reduced to %dms", actRecPeriodTime / 1000);
01024         }
01025         if (snd_pcm_hw_params_set_period_time_near (recHandle, hwparams, &actRecPeriodTime, 0) < 0)
01026         {
01027                 PLAYER_ERROR ("Error setting period time for recording device");
01028                 return false;
01029         }
01030         if (actRecPeriodTime < cfgRecPeriodTime * 900)  // cfgPBPeriodTime * 1000 * 9/10
01031                 PLAYER_WARN2 ("Period length for recording device reduced from %dms to %dms", cfgRecPeriodTime, actRecPeriodTime / 1000);
01032 
01033         snd_pcm_hw_params_get_period_size (hwparams, &recPeriodSize, 0);
01034 
01035         // Apply hwparams to the pcm device
01036         if (snd_pcm_hw_params (recHandle, hwparams) < 0)
01037         {
01038                 PLAYER_ERROR ("Error setting HW params for recording device");
01039                 return false;
01040         }
01041 
01042         // Set software parameters for the pcm device
01043         snd_pcm_sw_params_alloca (&swparams);   // Allocate params structure on stack
01044         // Get the current software parameters
01045         if (snd_pcm_sw_params_current (recHandle, swparams) < 0)
01046         {
01047                 PLAYER_ERROR ("Error getting current SW params for recording device");
01048                 return false;
01049         }
01050         // Set notification of pbBufSize bytes available for writing
01051         if (snd_pcm_sw_params_set_avail_min (recHandle, swparams, recPeriodSize) < 0)
01052         {
01053                 PLAYER_ERROR ("Error setting avil_min notification for recording device");
01054                 return false;
01055         }
01056         // Set the paramters on the device
01057         if (snd_pcm_sw_params (recHandle, swparams) < 0)
01058         {
01059                 PLAYER_ERROR ("Error setting SW params for recording device");
01060                 return false;
01061         }
01062 
01063         return true;
01064 }
01065 
01066 // Created a buffer to store recorded data into
01067 // length: the size of the buffer in ms
01068 bool Alsa::SetupRecordBuffer (uint32_t length)
01069 {
01070         // If recData exists, delete it
01071         if (recData)
01072         {
01073                 PLAYER_WARN ("recData not empty before starting recording");
01074                 delete[] recData;
01075         }
01076         // Allocate a data storage area big enough for the time required
01077         uint32_t bytesPerSec = recNumChannels * (recBits / 8) * recSampleRate;
01078         recDataLength = static_cast<uint32_t> (bytesPerSec * (length / 1000.0f));
01079         // Need to ensure the length is a multiple of the frame size
01080         recDataLength = recDataLength - (recDataLength % ((recBits / 8) * recNumChannels));
01081         if ((recData = new uint8_t[recDataLength]) == NULL)
01082         {
01083                 PLAYER_ERROR ("Failed to allocate memory for recorded data buffer");
01084                 return false;
01085         }
01086         recDataOffset = 0;
01087 
01088         return true;
01089 }
01090 
01091 // Called to write data to the playback buffer when it is ready for writing
01092 // numFrames: The number of frames that can be written
01093 void Alsa::RecordCallback (int numFrames)
01094 {
01095         int totalRead = 0;
01096 
01097         // If nowhere to save the data, return
01098         if (!recData)
01099         {
01100                 PLAYER_ERROR ("Tried to record to NULL data buffer");
01101                 return;
01102         }
01103 
01104         while (totalRead < numFrames)
01105         {
01106                 int framesToRead = numFrames - totalRead;
01107                 if (snd_pcm_frames_to_bytes (recHandle, framesToRead) + recDataOffset > recDataLength)
01108                         // Don't read past the end of the buffer
01109                         framesToRead = snd_pcm_bytes_to_frames (recHandle, recDataLength - recDataOffset);
01110                 int framesRead = snd_pcm_readi (recHandle, &recData[recDataOffset], framesToRead);
01111                 // If got data
01112                 if (framesRead > 0)
01113                 {
01114                         recDataOffset += snd_pcm_frames_to_bytes (recHandle, framesRead);
01115                         totalRead += framesRead;
01116                         // If this buffer is full, publish the data (resetting the buffer to zero)
01117                         if (recDataOffset >= recDataLength)
01118                                 HandleRecordedData ();
01119                 }
01120                 // Overrun
01121                 else if (framesRead == -EPIPE)
01122                 {
01123                         PLAYER_WARN ("Buffer overrun occured during recording");
01124                         // Need to prepare the device again after an xrun
01125                         snd_pcm_prepare (recHandle);
01126                 }
01127                 // Some other error
01128                 else
01129                 {
01130                         PLAYER_ERROR2 ("Error reading from record buffer: (%d) %s", framesRead, snd_strerror (framesRead));
01131                         StopRecording ();
01132                 }
01133         }
01134 }
01135 
01136 // Handles data recorded by sending it to the current recording destination
01137 void Alsa::HandleRecordedData (void)
01138 {
01139         // If the destination is a client, publish the data and keep recording
01140         if (recDest < 0)
01141         {
01142                 PublishRecordedData ();
01143                 return;
01144         }
01145 
01146         // Otherwise it must be for a sample, so store it (overwriting as necessary)
01147         // The StoredSample for the sample on the list will already be present because
01148         // if replacing, just reuse the StoredSample struct, if not replacing then
01149         // there will be a placeholder StoredSample waiting
01150 
01151         // Find the sample slot
01152         StoredSample *sampleSlot;
01153         if ((sampleSlot = GetSampleAtIndex (recDest)) == NULL)
01154         {
01155                 PLAYER_ERROR1 ("Couldn't find sample at index %d", recDest);
01156         }
01157         else
01158         {
01159                 // Create the new sample
01160                 AudioSample *newSample = NULL;
01161                 if ((newSample = new AudioSample (recData, recDataLength, recNumChannels, recSampleRate, recBits)) == NULL)
01162                 {
01163                         PLAYER_ERROR ("Failed to allocate memory for new audio sample");
01164                 }
01165                 else
01166                 {
01167                         // Delete the old sample if there is one
01168                         if (sampleSlot->sample)
01169                                 delete sampleSlot->sample;
01170                         // Update the pointer
01171                         sampleSlot->sample = newSample;
01172                 }
01173         }
01174 
01175         // All done (for better or for worse), clean up
01176         delete[] recData;       // Have to do this before called StopRecording to avoid recursion
01177         recData = NULL;
01178         StopRecording ();       // Because only recording one sample, can stop recording now
01179 }
01180 
01181 // Publishes recorded data to clients
01182 void Alsa::PublishRecordedData (void)
01183 {
01184         // Don't do anything if there is no data
01185         if (!recData || recDataOffset == 0)
01186                 return;
01187 
01188         // Create a data structure for sending data to clients
01189         player_audio_wav_t packet;
01190         memset (&packet, 0, sizeof (player_audio_wav_t));
01191 
01192         // Set the format field of the data structure
01193         packet.format = PLAYER_AUDIO_FORMAT_RAW;
01194         if (recNumChannels == 2)
01195                 packet.format |= PLAYER_AUDIO_STEREO;
01196         else if (recNumChannels != 1)
01197         {
01198                 PLAYER_ERROR ("Cannot convert wave to player struct: wrong number of channels");
01199                 delete recData;
01200                 recData = NULL;
01201                 StopRecording ();
01202                 return;
01203         }
01204         switch (recSampleRate)
01205         {
01206                 case 11025:
01207                         packet.format |= PLAYER_AUDIO_FREQ_11k;
01208                         break;
01209                 case 22050:
01210                         packet.format |= PLAYER_AUDIO_FREQ_22k;
01211                         break;
01212                 case 44100:
01213                         packet.format |= PLAYER_AUDIO_FREQ_44k;
01214                         break;
01215                 case 48000:
01216                         packet.format |= PLAYER_AUDIO_FREQ_48k;
01217                         break;
01218                 default:
01219                         PLAYER_ERROR ("Cannot convert wave to player struct: wrong sample rate");
01220                         delete recData;
01221                         recData = NULL;
01222                         StopRecording ();
01223                         return;
01224         }
01225         switch (recBits)
01226         {
01227                 case 8:
01228                         packet.format |= PLAYER_AUDIO_8BIT;
01229                         break;
01230                 case 16:
01231                         packet.format |= PLAYER_AUDIO_16BIT;
01232                         break;
01233                 case 24:
01234                         packet.format |= PLAYER_AUDIO_24BIT;
01235                         break;
01236                 default:
01237                         PLAYER_ERROR ("Cannot convert wave to player struct: wrong format (bits per sample)");
01238                         delete recData;
01239                         recData = NULL;
01240                         StopRecording ();
01241                         return;
01242         }
01243 
01244         // Publish the data, splitting as necessary
01245         uint32_t copiedOffset = 0;
01246         while (copiedOffset < recDataOffset)
01247         {
01248                 // Copy from copiedOffset to whichever is closer of recDataOffset and PLAYER_AUDIO_WAV_BUFFER_SIZE
01249                 uint32_t bytesToCopy;
01250                 if ((recDataOffset - copiedOffset) < (PLAYER_MAX_PAYLOAD_SIZE - sizeof (player_audio_wav_t)))
01251                         bytesToCopy = recDataOffset - copiedOffset; // Copy until the end of the recorded data
01252                 else
01253                         bytesToCopy = (PLAYER_MAX_PAYLOAD_SIZE - sizeof (player_audio_wav_t)); // Copy another chunk out
01254                 // Allocate this much space
01255                 if ((packet.data = new uint8_t[bytesToCopy]) == NULL)
01256                 {
01257                         PLAYER_ERROR ("Failed to allocate temp space");
01258                         delete recData;
01259                         recData = NULL;
01260                         StopRecording ();
01261                         return;
01262                 }
01263                 memcpy (packet.data, &recData[copiedOffset], bytesToCopy);
01264                 copiedOffset += bytesToCopy;
01265                 packet.data_count = bytesToCopy;
01266 
01267                 // Publish this packet
01268                 Publish (device_addr, PLAYER_MSGTYPE_DATA, PLAYER_AUDIO_DATA_WAV_REC, reinterpret_cast<void*> (&packet), sizeof (player_audio_wav_t), NULL);
01269                 delete[] packet.data;
01270         }
01271         // Set the local record buffer position back to the start
01272         recDataOffset = 0;
01273 }
01274 
01276 //      Playback/record control functions
01278 
01279 // Start outputting sound (if there is some to output)
01280 void Alsa::StartPlayback (void)
01281 {
01282         // Don't do anything if already playing or no device
01283         if (playState != PB_STATE_STOPPED || !pbHandle)
01284                 return;
01285 
01286         // If there is data in the queue
01287         if (queueHead != NULL)
01288         {
01289                 if (debugLevel >= 4)
01290                 {
01291                         cout << "ALSA: Starting playback, sample info:" << endl;
01292                         queueHead->sample->PrintWaveInfo ();
01293                 }
01294                 // Set the parameters for the head of the queue
01295                 SetPBParams (queueHead->sample);
01296                 // Set playback state to PLAYING
01297                 playState = PB_STATE_PLAYING;
01298         }
01299 
01300         // Update clients about state
01301         SendStateMessage ();
01302 }
01303 
01304 // Stop outputting sound - actually more like a pause, as doesn't reset the
01305 // queue position
01306 void Alsa::StopPlayback (void)
01307 {
01308         if (debugLevel >= 4)
01309                 cout << "ALSA: Stopping playback" << endl;
01310 
01311         // Set playback to false
01312         playState = PB_STATE_STOPPED;
01313         // Drop anything currently in the buffer and stop the card
01314     if (pbHandle)
01315         snd_pcm_drop (pbHandle);
01316 
01317         // Update clients about state
01318         SendStateMessage ();
01319 }
01320 
01321 // Start recording sound
01322 void Alsa::StartRecording (void)
01323 {
01324         // Don't do anything if already recording or no device
01325         if (recState != PB_STATE_STOPPED || !recHandle)
01326                 return;
01327         // Also an error if nowhere to record to
01328         if (!recData)
01329         {
01330                 PLAYER_ERROR ("Tried to start recording with no local data buffer");
01331                 return;
01332         }
01333 
01334         if (debugLevel >= 4)
01335                 cout << "ALSA: Starting recording, destination: " << ((recDest < 0) ? "clients" : "sample") << endl;
01336 
01337         recDataOffset = 0;
01338         // Prepare the recording device
01339         snd_pcm_prepare (recHandle);
01340         // Start the recording device
01341         int result = 0;
01342         if ((result = snd_pcm_start (recHandle)) < 0)
01343         {
01344                 PLAYER_ERROR2 ("Error starting recording: (%d) %s", result, snd_strerror (result));
01345                 delete recData;
01346                 recData = NULL;
01347                 return;
01348         }
01349         // Move to recording state
01350         recState = PB_STATE_RECORDING;
01351 
01352         // Update clients about state
01353         SendStateMessage ();
01354 }
01355 
01356 // Stop recording sound
01357 void Alsa::StopRecording (void)
01358 {
01359         if (debugLevel >= 4)
01360                 cout << "ALSA: Stopping recording" << endl;
01361 
01362         // Stop the device
01363         snd_pcm_drop (recHandle);
01364         // Move to stopped state
01365         recState = PB_STATE_STOPPED;
01366         // If there is data left over, handle it
01367         if (recData)
01368         {
01369                 HandleRecordedData ();
01370                 delete[] recData;
01371                 recData = NULL;
01372         }
01373         recDataOffset = 0;
01374 
01375         // Update clients about state
01376         SendStateMessage ();
01377 }
01378 
01380 //      Mixer functions (finding channels, setting levels, etc)
01382 
01383 // Opens the mixer interface and enumerates the mixer capabilities
01384 bool Alsa::SetupMixer (void)
01385 {
01386         // Open the mixer interface
01387         if (snd_mixer_open (&mixerHandle, 0) < 0)
01388         {
01389                 PLAYER_WARN ("Could not open mixer");
01390                 return false;
01391         }
01392 
01393         // Attach it to the device
01394         if (snd_mixer_attach (mixerHandle, mixerDevice) < 0)
01395         {
01396                 PLAYER_WARN1 ("Could not attach mixer to mixer device %s", mixerDevice);
01397                 return false;
01398         }
01399 
01400         // Register... something that the alsa docs weren't very clear on
01401         if (snd_mixer_selem_register (mixerHandle, NULL, NULL) < 0)
01402         {
01403                 PLAYER_WARN ("Could not register mixer");
01404                 return false;
01405         }
01406 
01407         // Load elements
01408         if (snd_mixer_load (mixerHandle) < 0)
01409         {
01410                 PLAYER_WARN ("Could not load mixer elements");
01411                 return false;
01412         }
01413 
01414         // Enumerate the elements
01415         if (!EnumMixerElements ())
01416                 return false;
01417 
01418         return true;
01419 }
01420 
01421 // Enumerates the mixer elements - i.e. finds out what each is
01422 // Prepares the found data to be used with player
01423 bool Alsa::EnumMixerElements (void)
01424 {
01425         MixerElement *elements = NULL;
01426         snd_mixer_elem_t *elem = NULL;
01427         uint32_t count = 0;
01428 
01429         // Count the number of elements to store
01430         for (elem = snd_mixer_first_elem (mixerHandle); elem != NULL; elem = snd_mixer_elem_next (elem))
01431         {
01432                 if (snd_mixer_elem_get_type (elem) == SND_MIXER_ELEM_SIMPLE && snd_mixer_selem_is_active (elem))
01433                         count++;
01434                 else if (debugLevel >= 5)
01435                         cout << "ALSA: Skipping non-SND_MIXER_ELEM_SIMPLE or inactive element" << endl;
01436         }
01437 
01438         if (debugLevel >= 5)
01439                 cout << "ALSA: Found " << count << " elements to enumerate" << endl;
01440 
01441         // Allocate space to store the elements
01442         if (count <= 0)
01443         {
01444                 PLAYER_WARN ("Found zero or less mixer elements");
01445                 return false;
01446         }
01447         if ((elements = new MixerElement[count]) == NULL)
01448         {
01449                 PLAYER_WARN1 ("Failed to allocate memory to store %d elements", count);
01450                 return false;
01451         }
01452         memset (elements, 0, sizeof (MixerElement) * count);
01453 
01454         // Get each element and its capabilities
01455         uint32_t ii = 0;
01456         for (elem = snd_mixer_first_elem (mixerHandle); elem != NULL; elem = snd_mixer_elem_next (elem), ii++)
01457         {
01458                 if (snd_mixer_elem_get_type (elem) == SND_MIXER_ELEM_SIMPLE && snd_mixer_selem_is_active (elem))
01459                 {
01460                         elements[ii].elem = elem;
01461                         if (!EnumElementCaps (&(elements[ii])))
01462                         {
01463                                 CleanUpMixerElements (elements, count);
01464                                 return false;
01465                         }
01466                 }
01467         }
01468 
01469         // Split channels capable of both playback and capture (makes it easier to manage via player)
01470         MixerElement *splitElems = NULL;
01471         uint32_t newCount = count;
01472         if ((splitElems = SplitElements (elements, newCount)) == NULL)
01473         {
01474                 PLAYER_WARN ("Error splitting mixer elements");
01475                 CleanUpMixerElements (elements, count);
01476                 return false;
01477         }
01478 
01479         // Done with the old elements list now
01480         CleanUpMixerElements (elements, count);
01481 
01482         // Filter elements by mixerFilters if necessary
01483         // Needs to be done after splitting them to ensure we have got the most accurate element names
01484         uint32_t newNewCount = newCount;
01485         if (mixerFilters)
01486         {
01487                 if ((mixerElements = FilterElements (splitElems, newNewCount)) == NULL)
01488                 {
01489                         PLAYER_WARN ("Error filtering mixer elements");
01490                         CleanUpMixerElements (splitElems, newCount);
01491                         return false;
01492                 }
01493                 // Note that FilterElements will take care of cleaning up any unused elements for us
01494         }
01495         else
01496                 mixerElements = splitElems;
01497 
01498         numElements = newNewCount;
01499 
01500         if (debugLevel >= 2)
01501                 PrintMixerElements (mixerElements, numElements);
01502         return true;
01503 }
01504 
01505 // Enumerates the capabilities of a single element
01506 bool Alsa::EnumElementCaps (MixerElement *element)
01507 {
01508         snd_mixer_elem_t *elem = element->elem;
01509         if (!elem)
01510         {
01511                 PLAYER_WARN ("Attempted to enumerate NULL element pointer");
01512                 return false;
01513         }
01514 
01515         // Get the element name
01516         element->name = strdup (snd_mixer_selem_get_name (elem));
01517         // Get capabilities
01518         // Volumes
01519         if (snd_mixer_selem_has_playback_volume (elem))
01520                 element->caps |= ELEMCAP_PLAYBACK_VOL;
01521         if (snd_mixer_selem_has_capture_volume (elem))
01522                 element->caps |= ELEMCAP_CAPTURE_VOL;
01523         if (snd_mixer_selem_has_common_volume (elem))
01524                 element->caps |= ELEMCAP_COMMON_VOL;
01525         // Switches
01526         if (snd_mixer_selem_has_playback_switch (elem))
01527                 element->caps |= ELEMCAP_PLAYBACK_SWITCH;
01528         if (snd_mixer_selem_has_capture_switch (elem))
01529                 element->caps |= ELEMCAP_CAPTURE_SWITCH;
01530         if (snd_mixer_selem_has_common_switch (elem))
01531                 element->caps |= ELEMCAP_COMMON_SWITCH;
01532         // Joined switches
01533 //      if (snd_mixer_selem_has_playback_switch (elem))
01534 //              mixerElements[index].caps |= ELEMCAP_PB_JOINED_SWITCH;
01535 //      if (snd_mixer_selem_has_capture_switch (elem))
01536 //              mixerElements[index].caps |= ELEMCAP_CAP_JOINED_SWITCH;
01537 
01538         element->playSwitch = 1;
01539         element->capSwitch = 1;
01540         element->comSwitch = 1;
01541 
01542         if (debugLevel >= 5)
01543                 cout << "ALSA: Found mixer element: " << element->name << endl;
01544         // Find channels for this element
01545         for (int ii = -1; ii <= (int) SND_MIXER_SCHN_LAST; ii++)
01546         {
01547                 if (snd_mixer_selem_has_playback_channel (elem, static_cast<snd_mixer_selem_channel_id_t> (ii)))
01548                 {
01549 //                      printf ("Element has playback channel %d: %s\n", ii, snd_mixer_selem_channel_name (static_cast<snd_mixer_selem_channel_id_t> (ii)));
01550                         element->caps |= ELEMCAP_CAN_PLAYBACK;
01551                         // Get the current volume of this channel and make it the element one, if don't have that yet
01552                         if (!element->curPlayVol)
01553                                 snd_mixer_selem_get_playback_volume (elem, static_cast<snd_mixer_selem_channel_id_t> (ii), &(element->curPlayVol));
01554                         // Get the switch status of this channel
01555                         if (element->caps & ELEMCAP_PLAYBACK_SWITCH)
01556                                 snd_mixer_selem_get_playback_switch (elem, static_cast<snd_mixer_selem_channel_id_t> (ii), &element->playSwitch);
01557                 }
01558                 if (snd_mixer_selem_has_capture_channel (elem, static_cast<snd_mixer_selem_channel_id_t> (ii)))
01559                 {
01560 //                      printf ("Element has capture channel %d: %s\n", ii, snd_mixer_selem_channel_name (static_cast<snd_mixer_selem_channel_id_t> (ii)));
01561                         element->caps |= ELEMCAP_CAN_CAPTURE;
01562                         // Get the current volume of this channel and make it the element one, if don't have that yet
01563                         if (!element->curCapVol)
01564                                 snd_mixer_selem_get_capture_volume (elem, static_cast<snd_mixer_selem_channel_id_t> (ii), &(element->curCapVol));
01565                         // Get the switch status of this channel
01566                         if (element->caps & ELEMCAP_CAPTURE_SWITCH)
01567                                 snd_mixer_selem_get_capture_switch (elem, static_cast<snd_mixer_selem_channel_id_t> (ii), &element->capSwitch);
01568                 }
01569         }
01570 
01571         // Get volume ranges
01572         if ((element->caps & ELEMCAP_CAN_PLAYBACK) && (element->caps & ELEMCAP_PLAYBACK_VOL))
01573         {
01574                 snd_mixer_selem_get_playback_volume_range (elem, &(element->minPlayVol), &(element->maxPlayVol));
01575         }
01576         if ((element->caps & ELEMCAP_CAN_CAPTURE) && (element->caps & ELEMCAP_CAPTURE_VOL))
01577         {
01578                 snd_mixer_selem_get_capture_volume_range (elem, &(element->minCapVol), &(element->maxCapVol));
01579         }
01580         if (element->caps & ELEMCAP_COMMON_VOL)
01581         {
01582                 // If statement on next line isn't a typo, min vol will probably be zero whether it's been filled in or not, max won't
01583                 element->minComVol = element->maxPlayVol ? element->minPlayVol : element->minCapVol;
01584                 element->maxComVol = element->maxPlayVol ? element->maxPlayVol : element->maxCapVol;
01585         }
01586 
01587         // Common switch status
01588         if (element->caps & ELEMCAP_COMMON_SWITCH)
01589                 element->comSwitch = element->playSwitch ? element->playSwitch : element->capSwitch;
01590 
01591 //      printf ("Element volume levels:\n");
01592 //      printf ("Playback:\t%ld, %ld, %ld, %s\n", element->minPlayVol, element->curPlayVol, element->maxPlayVol, element->playSwitch ? "Active" : "Inactive");
01593 //      printf ("Capture:\t%ld, %ld, %ld, %s\n", element->minCapVol, element->curCapVol, element->maxCapVol, element->capSwitch ? "Active" : "Inactive");
01594 //      printf ("Common:\t%ld, %ld, %ld, %s\n", element->minComVol, element->curComVol, element->maxComVol, element->comSwitch ? "Active" : "Inactive");
01595 
01596         return true;
01597 }
01598 
01599 // Splits elements into two separate elements for those elements that are capable
01600 // of entirely separate playback and capture
01601 MixerElement* Alsa::SplitElements (MixerElement *elements, uint32_t &count)
01602 {
01603         MixerElement *result = NULL;
01604         // Count the number of elements we will get as a result:
01605         // Each current element adds 2 if it does both with separate controls, 1 otherwise
01606         uint32_t numSplitElements = 0;
01607         for (uint32_t ii = 0; ii < count; ii++)
01608         {
01609                 if ((elements[ii].caps & ELEMCAP_CAN_PLAYBACK) && (elements[ii].caps & ELEMCAP_CAN_CAPTURE) &&
01610                                 !(elements[ii].caps & ELEMCAP_COMMON_VOL) && !(elements[ii].caps & ELEMCAP_COMMON_SWITCH))
01611                         numSplitElements += 2;
01612                 else
01613                         numSplitElements += 1;
01614         }
01615 
01616         // Allocate space for the new array of elements
01617         if (numSplitElements <= 0)
01618         {
01619                 PLAYER_WARN ("Found zero or less split mixer elements");
01620                 return NULL;
01621         }
01622         if ((result = new MixerElement[numSplitElements]) == NULL)
01623         {
01624                 PLAYER_WARN1 ("Failed to allocate memory to store %d split elements", numSplitElements);
01625                 return NULL;
01626         }
01627         memset (result, 0, sizeof (MixerElement) * numSplitElements);
01628 
01629         // Copy relevant data across
01630         uint32_t currentIndex = 0;
01631         for (uint32_t ii = 0; ii < count; ii++)
01632         {
01633                 // Element capable of separate playback and record
01634                 if ((elements[ii].caps & ELEMCAP_CAN_PLAYBACK) && (elements[ii].caps & ELEMCAP_CAN_CAPTURE) &&
01635                                 !(elements[ii].caps & ELEMCAP_COMMON_VOL) && !(elements[ii].caps & ELEMCAP_COMMON_SWITCH))
01636                 {
01637                         // In this case, split the element, so will set data for currentIndex and currentIndex+1
01638                         // Playback element
01639                         result[currentIndex].elem = elements[ii].elem;
01640                         result[currentIndex].caps = ELEMCAP_CAN_PLAYBACK;
01641                         result[currentIndex].minPlayVol = elements[ii].minPlayVol;
01642                         result[currentIndex].curPlayVol = elements[ii].curPlayVol;
01643                         result[currentIndex].maxPlayVol = elements[ii].maxPlayVol;
01644                         result[currentIndex].playSwitch = elements[ii].playSwitch;
01645                         result[currentIndex].name = reinterpret_cast<char*> (malloc (strlen (elements[ii].name) + strlen (" (Playback)") + 1));
01646                         strncpy (result[currentIndex].name, elements[ii].name, strlen (elements[ii].name) + 1);
01647                         strncpy (&(result[currentIndex].name[strlen (elements[ii].name)]), " (Playback)", strlen (" (Playback)") + 1);
01648 
01649                         // Capture element
01650                         result[currentIndex + 1].elem = elements[ii].elem;
01651                         result[currentIndex + 1].caps = ELEMCAP_CAN_CAPTURE;
01652                         result[currentIndex + 1].minCapVol = elements[ii].minCapVol;
01653                         result[currentIndex + 1].curCapVol = elements[ii].curCapVol;
01654                         result[currentIndex + 1].maxCapVol = elements[ii].maxCapVol;
01655                         result[currentIndex + 1].capSwitch = elements[ii].capSwitch;
01656                         result[currentIndex + 1].name = reinterpret_cast<char*> (malloc (strlen (elements[ii].name) + strlen (" (Capture)") + 1));
01657                         strncpy (result[currentIndex + 1].name, elements[ii].name, strlen (elements[ii].name) + 1);
01658                         strncpy (&(result[currentIndex + 1].name[strlen (elements[ii].name)]), " (Capture)", strlen (" (Capture)") + 1);
01659 
01660                         currentIndex += 2;
01661                 }
01662                 // Element that can only playback
01663                 else if ((elements[ii].caps & ELEMCAP_CAN_PLAYBACK) && !(elements[ii].caps & ELEMCAP_CAN_CAPTURE))
01664                 {
01665                         // Just copy in this case
01666                         result[currentIndex].elem = elements[ii].elem;
01667                         result[currentIndex].caps = ELEMCAP_CAN_PLAYBACK;
01668                         result[currentIndex].minPlayVol = elements[ii].minPlayVol;
01669                         result[currentIndex].curPlayVol = elements[ii].curPlayVol;
01670                         result[currentIndex].maxPlayVol = elements[ii].maxPlayVol;
01671                         result[currentIndex].playSwitch = elements[ii].playSwitch;
01672                         result[currentIndex].name = strdup (elements[ii].name);
01673 
01674                         currentIndex += 1;
01675                 }
01676                 // Element that can only capture
01677                 else if (!(elements[ii].caps & ELEMCAP_CAN_PLAYBACK) && (elements[ii].caps & ELEMCAP_CAN_CAPTURE))
01678                 {
01679                         // Just copy in this case
01680                         result[currentIndex].elem = elements[ii].elem;
01681                         result[currentIndex].caps = ELEMCAP_CAN_CAPTURE;
01682                         result[currentIndex].minCapVol = elements[ii].minCapVol;
01683                         result[currentIndex].curCapVol = elements[ii].curCapVol;
01684                         result[currentIndex].maxCapVol = elements[ii].maxCapVol;
01685                         result[currentIndex].capSwitch = elements[ii].capSwitch;
01686                         result[currentIndex].name = strdup (elements[ii].name);
01687 
01688                         currentIndex += 1;
01689                 }
01690                 // Element that can do both but cannot set independent volumes
01691                 else
01692                 {
01693                         result[currentIndex].elem = elements[ii].elem;
01694                         result[currentIndex].caps = ELEMCAP_CAN_PLAYBACK & ELEMCAP_CAN_CAPTURE & ELEMCAP_COMMON;
01695                         result[currentIndex].minComVol = elements[ii].minComVol;
01696                         result[currentIndex].curComVol = elements[ii].curComVol;
01697                         result[currentIndex].maxComVol = elements[ii].maxComVol;
01698                         result[currentIndex].comSwitch = elements[ii].comSwitch;
01699                         result[currentIndex].name = strdup (elements[ii].name);
01700 
01701                         currentIndex += 1;
01702                 }
01703         }
01704 
01705         count = numSplitElements;
01706         return result;
01707 }
01708 
01709 // Filters elements by their name according to the strings in mixerFilters
01710 // This function will clean up memory used by any unused entries in elements itself
01711 MixerElement* Alsa::FilterElements (MixerElement *elements, uint32_t &count)
01712 {
01713         MixerElement *result = NULL;
01714         bool *keep = NULL;
01715 
01716         // Allocate an array of bools to mark each element as keep or delete
01717         if ((keep = new bool[count]) == NULL)
01718         {
01719                 PLAYER_WARN ("Failed to allocate memory to check elements for filter matches");
01720                 return NULL;
01721         }
01722         memset (keep, 0, sizeof (bool) * count);
01723 
01724         if (debugLevel >= 5)
01725                 cout << "Checking " << count << " mixer elements for filter matches" << endl;
01726 
01727         // Go through the list of elements
01728         uint32_t filteredCount = 0;
01729         for (uint32_t ii = 0; ii < count; ii++)
01730         {
01731                 // For this element, check its name against every string in mixerFilters until a match is found
01732                 for (uint32_t jj = 0; mixerFilters[jj] != NULL; jj++)
01733                 {
01734                         if ((!mixerFilterExact && strcasestr (elements[ii].name, mixerFilters[jj]) != NULL) ||
01735                                 (mixerFilterExact && strcmp (elements[ii].name, mixerFilters[jj]) == 0))
01736                         {
01737                                 if (debugLevel >= 5)
01738                                         cout << "Found match between " << elements[ii].name << " (" << ii << ") and " << mixerFilters[jj] << endl;
01739                                 // Found a match, mark it as keep and break
01740                                 keep[ii] = true;
01741                                 filteredCount++;
01742                                 break;
01743                         }
01744                 }
01745         }
01746 
01747         // Allocate memory for the final list
01748         if ((result = new MixerElement[filteredCount]) == NULL)
01749         {
01750                 PLAYER_WARN ("Failed to allocate memory to store final list of filtered elements");
01751                 return NULL;
01752         }
01753         if (debugLevel >= 5)
01754                 cout << "Keeping " << filteredCount << " mixer elements" << endl;
01755         // Go through the keep array, and for each index marked as true, copy to the result
01756         // For those marked as false, delete the element's memory
01757         filteredCount = 0;
01758         for (uint32_t ii = 0; ii < count; ii++)
01759         {
01760                 if (keep[ii])
01761                 {
01762                         memcpy (&result[filteredCount], &elements[ii], sizeof (MixerElement));
01763                         if (debugLevel >= 5)
01764                                 cout << "Keeping mixer element \"" << result[filteredCount].name << "\" (" << ii << ")" << endl;
01765                         filteredCount++;
01766                 }
01767                 else
01768                 {
01769                         if (debugLevel >= 5)
01770                                 cout << "Deleting mixer element \"" << elements[ii].name << "\" (" << ii << ")" << endl;
01771                         if (elements[ii].name)
01772                                 free (elements[ii].name);
01773                 }
01774         }
01775         count = filteredCount;
01776 
01777         // Clean up the old list
01778         delete[] elements;
01779         // Also clean up the keep array
01780         delete[] keep;
01781 
01782         return result;
01783 }
01784 
01785 // Cleans up mixer element data
01786 void Alsa::CleanUpMixerElements (MixerElement *elements, uint32_t count)
01787 {
01788         for (uint32_t ii = 0; ii < count; ii++)
01789         {
01790                 if (elements[ii].name)
01791                         free (elements[ii].name);
01792         }
01793         delete[] elements;
01794 }
01795 
01796 // Converts mixer information to player details
01797 void Alsa::MixerDetailsToPlayer (player_audio_mixer_channel_list_detail_t *dest)
01798 {
01799         memset (dest, 0, sizeof (player_audio_mixer_channel_list_detail_t));
01800 
01801         dest->details_count = numElements;
01802         dest->default_output = 0;
01803         dest->default_input = 0;        // TODO: figure out what the default is... driver option maybe?
01804 
01805         for (uint32_t ii = 0; ii < numElements; ii++)
01806         {
01807                 dest->details[ii].name_count = strlen (mixerElements[ii].name);
01808                 strncpy (dest->details[ii].name, mixerElements[ii].name, strlen (mixerElements[ii].name) + 1);
01809                 if ((mixerElements[ii].caps & ELEMCAP_CAN_PLAYBACK) && !(mixerElements[ii].caps & ELEMCAP_CAN_CAPTURE))
01810                         dest->details[ii].caps = PLAYER_AUDIO_MIXER_CHANNEL_TYPE_OUTPUT;
01811                 else if (!(mixerElements[ii].caps & ELEMCAP_CAN_PLAYBACK) && (mixerElements[ii].caps & ELEMCAP_CAN_CAPTURE))
01812                         dest->details[ii].caps = PLAYER_AUDIO_MIXER_CHANNEL_TYPE_INPUT;
01813                 else
01814                         dest->details[ii].caps = PLAYER_AUDIO_MIXER_CHANNEL_TYPE_INPUT & PLAYER_AUDIO_MIXER_CHANNEL_TYPE_OUTPUT;
01815         }
01816 }
01817 
01818 // Converts mixer information to player levels
01819 void Alsa::MixerLevelsToPlayer (player_audio_mixer_channel_list_t *dest)
01820 {
01821         memset (dest, 0, sizeof (player_audio_mixer_channel_list_t));
01822 
01823         dest->channels_count = numElements;
01824 
01825         for (uint32_t ii = 0; ii < numElements; ii++)
01826         {
01827                 long min = 0, cur = 0, max = 0;
01828                 int switchStatus = 0;
01829                 if (mixerElements[ii].caps & ELEMCAP_CAN_PLAYBACK)
01830                 {
01831                         min = mixerElements[ii].minPlayVol;
01832                         cur = mixerElements[ii].curPlayVol;
01833                         max = mixerElements[ii].maxPlayVol;
01834                         switchStatus = mixerElements[ii].playSwitch;
01835                 }
01836                 else if (mixerElements[ii].caps & ELEMCAP_CAN_CAPTURE)
01837                 {
01838                         min = mixerElements[ii].minCapVol;
01839                         cur = mixerElements[ii].curCapVol;
01840                         max = mixerElements[ii].maxCapVol;
01841                         switchStatus = mixerElements[ii].capSwitch;
01842                 }
01843                 else if (mixerElements[ii].caps & ELEMCAP_COMMON)
01844                 {
01845                         min = mixerElements[ii].minComVol;
01846                         cur = mixerElements[ii].curComVol;
01847                         max = mixerElements[ii].maxComVol;
01848                         switchStatus = mixerElements[ii].comSwitch;
01849                 }
01850                 dest->channels[ii].amplitude = LevelToPlayer (min, max, cur);
01851                 dest->channels[ii].active.state = switchStatus;
01852                 dest->channels[ii].index = ii;
01853         }
01854 }
01855 
01856 // Sets the volume level of an element
01857 void Alsa::SetElementLevel (uint32_t index, float level)
01858 {
01859         long newValue = 0;
01860 
01861         if (mixerElements[index].caps & ELEMCAP_CAN_PLAYBACK)
01862         {
01863                 // Calculate the new level
01864                 newValue = LevelFromPlayer (mixerElements[index].minPlayVol, mixerElements[index].maxPlayVol, level);
01865                 // Set the volume for all channels in this element
01866                 if (snd_mixer_selem_set_playback_volume_all (mixerElements[index].elem, newValue) < 0)
01867                 {
01868                         PLAYER_WARN1 ("Error setting playback level for element %d", index);
01869                 }
01870                 else
01871                         mixerElements[index].curPlayVol = newValue;
01872         }
01873         else if (mixerElements[index].caps & ELEMCAP_CAN_CAPTURE)
01874         {
01875                 // Calculate the new level
01876                 newValue = LevelFromPlayer (mixerElements[index].minCapVol, mixerElements[index].maxCapVol, level);
01877                 // Set the volume for all channels in this element
01878                 if (snd_mixer_selem_set_capture_volume_all (mixerElements[index].elem, newValue) < 0)
01879                 {
01880                         PLAYER_WARN1 ("Error setting capture level for element %d", index);
01881                 }
01882                 else
01883                         mixerElements[index].curCapVol = newValue;
01884         }
01885         else if (mixerElements[index].caps & ELEMCAP_COMMON)
01886         {
01887                 // Calculate the new level
01888                 newValue = LevelFromPlayer (mixerElements[index].minComVol, mixerElements[index].maxComVol, level);
01889                 // Set the volume for all channels in this element
01890                 if (snd_mixer_selem_set_playback_volume_all (mixerElements[index].elem, newValue) < 0)
01891                 {
01892                         PLAYER_WARN1 ("Error setting common level for element %d", index);
01893                 }
01894                 else
01895                         mixerElements[index].curComVol = newValue;
01896         }
01897 }
01898 
01899 // Sets the switch for an element
01900 void Alsa::SetElementSwitch (uint32_t index, player_bool_t active)
01901 {
01902         if (mixerElements[index].caps & ELEMCAP_CAN_PLAYBACK)
01903         {
01904                 // Set the switch for all channels in this element
01905                 if (snd_mixer_selem_set_playback_switch_all (mixerElements[index].elem, active.state) < 0)
01906                 {
01907                         PLAYER_WARN1 ("Error setting playback switch for element %d", index);
01908                 }
01909                 else
01910                         mixerElements[index].playSwitch = active.state;
01911         }
01912         else if (mixerElements[index].caps & ELEMCAP_CAN_CAPTURE)
01913         {
01914                 // Set the switch for all channels in this element
01915                 if (snd_mixer_selem_set_capture_switch_all (mixerElements[index].elem, active.state) < 0)
01916                 {
01917                         PLAYER_WARN1 ("Error setting capture switch for element %d", index);
01918                 }
01919                 else
01920                         mixerElements[index].capSwitch = active.state;
01921         }
01922         else if (mixerElements[index].caps & ELEMCAP_COMMON)
01923         {
01924                 // Set the switch for all channels in this element
01925                 if (snd_mixer_selem_set_playback_switch_all (mixerElements[index].elem, active.state) < 0)
01926                 {
01927                         PLAYER_WARN1 ("Error setting common switch for element %d", index);
01928                 }
01929                 else
01930                         mixerElements[index].comSwitch = active.state;
01931         }
01932 }
01933 
01934 // Publishes mixer information as a data message
01935 void Alsa::PublishMixerData (void)
01936 {
01937         player_audio_mixer_channel_list_t data;
01938 
01939         MixerLevelsToPlayer (&data);
01940         Publish (device_addr, PLAYER_MSGTYPE_DATA, PLAYER_AUDIO_DATA_MIXER_CHANNEL, reinterpret_cast<void*> (&data), sizeof (player_audio_mixer_channel_list_t), NULL);
01941 }
01942 
01943 // Converts an element level from a long to a float between 0 and 1
01944 float Alsa::LevelToPlayer (long min, long max, long level)
01945 {
01946         float result = 0.0f;
01947         if ((max - min) != 0)
01948                 result = static_cast<float> (level - min) / static_cast<float> (max - min);
01949         return result;
01950 }
01951 
01952 // Converts an element level from a float between 0 and 1 to a long between min and max
01953 long Alsa::LevelFromPlayer (long min, long max, float level)
01954 {
01955         long result = static_cast<long> ((max - min) * level);
01956         return result;
01957 }
01958 
01959 // Handy debug function
01960 void Alsa::PrintMixerElements (MixerElement *elements, uint32_t count)
01961 {
01962         long min, cur, max;
01963         int switchStatus;
01964         cout << "ALSA: Mixer elements:" << endl;
01965         for (uint32_t ii = 0; ii < count; ii++)
01966         {
01967                 if (elements[ii].caps & ELEMCAP_CAN_PLAYBACK)
01968                 {
01969                         min = elements[ii].minPlayVol;
01970                         cur = elements[ii].curPlayVol;
01971                         max = elements[ii].maxPlayVol;
01972                         switchStatus = elements[ii].playSwitch;
01973                 }
01974                 else if (elements[ii].caps & ELEMCAP_CAN_CAPTURE)
01975                 {
01976                         min = elements[ii].minCapVol;
01977                         cur = elements[ii].curCapVol;
01978                         max = elements[ii].maxCapVol;
01979                         switchStatus = elements[ii].capSwitch;
01980                 }
01981                 else if (elements[ii].caps & ELEMCAP_COMMON)
01982                 {
01983                         min = elements[ii].minComVol;
01984                         cur = elements[ii].curComVol;
01985                         max = elements[ii].maxComVol;
01986                         switchStatus = elements[ii].comSwitch;
01987                 }
01988                 cout << "\tElement " << ii << ":\t" << elements[ii].name << endl;
01989                 cout << "\tCapabilities:\t";
01990                 if (elements[ii].caps & ELEMCAP_CAN_PLAYBACK)
01991                         cout << "playback\t";
01992                 if (elements[ii].caps & ELEMCAP_CAN_CAPTURE)
01993                         cout << "capture\t";
01994                 if (elements[ii].caps & ELEMCAP_COMMON)
01995                         cout << "common";
01996                 cout << endl;
01997                 cout << "\tVolume range:\t" << min << "->" << max << endl;
01998                 cout << "\tCurrent volume:\t" << cur << endl;
01999                 cout << "\tActive:\t" << (switchStatus ? "Yes" : "No") << endl;
02000         }
02001 }
02002 
02004 //      Driver management
02006 
02007 // Constructor.  Retrieve options from the configuration file and do any
02008 // pre-Setup() setup.
02009 Alsa::Alsa (ConfigFile* cf, int section)
02010         : Driver (cf, section, false, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_AUDIO_CODE)
02011 {
02012         pbDevice = mixerDevice = recDevice = NULL;
02013         pbHandle = NULL;
02014         recHandle = NULL;
02015         mixerHandle = NULL;
02016         samplesHead = samplesTail = NULL;
02017         queueHead = queueTail = NULL;
02018         mixerFilters = NULL;
02019         nextSampleIdx = 0;
02020         mixerElements = NULL;
02021         periodBuffer = NULL;
02022         pbFDs = recFDs = NULL;
02023         recData = NULL;
02024         const char *str;
02025 
02026         // Read the config file options - see header for descriptions if not here
02027         useQueue = cf->ReadBool (section, "usequeue", true);
02028         debugLevel = cf->ReadInt (section, "debug", 0);
02029         mixerFilterExact = cf->ReadBool (section, "mixerfilterexact", false);
02030         str = cf->ReadString (section, "pbdevice", NULL);
02031         if (str)
02032                 pbDevice = strdup(str);
02033 
02034         str = cf->ReadString (section, "mixerdevice", NULL);
02035         if (str)
02036             mixerDevice = strdup (str);
02037 
02038         str = cf->ReadString (section, "recdevice", NULL);
02039         if (str)
02040                 recDevice = strdup (str);
02041 
02042     cfgPBPeriodTime = cf->ReadInt (section, "pb_periodlength", 50);
02043         cfgPBBufferTime = cf->ReadInt (section, "pb_bufferlength", 500);
02044         // Don't have silence if not using the queue system
02045         silenceTime = useQueue? cf->ReadInt (section, "pb_silence", 0) : 0;
02046         cfgRecPeriodTime = cf->ReadInt (section, "rec_periodlength", 50);
02047         cfgRecBufferTime = cf->ReadInt (section, "rec_bufferlength", 500);
02048         cfgRecStoreTime = cf->ReadInt (section, "rec_storelength", cfgRecBufferTime);
02049         recNumChannels = cf->ReadInt (section, "rec_nch", 1);
02050         recSampleRate = cf->ReadInt (section, "rec_sr", 44100);
02051         recBits = cf->ReadInt (section, "rec_bits", 16);
02052         if (debugLevel > 1)
02053         {
02054                 cout << "Playback device: " << pbDevice << endl;
02055                 cout << "Mixer device: " << mixerDevice << endl;
02056                 cout << "Record device: " << recDevice << endl;
02057         }
02058 
02059         // Check recording rates are sane
02060         if (recNumChannels != 1 && recNumChannels != 2)
02061         {
02062                 PLAYER_WARN ("Recording channels must be 1 or 2; recording functionality will not be available");
02063                 if (recDevice)
02064                         free (recDevice);
02065                 recDevice = NULL;
02066         }
02067         if (recSampleRate != 11025 && recSampleRate != 22050 && recSampleRate != 44100 && recSampleRate != 48000)
02068         {
02069                 PLAYER_WARN ("Recording sample rate must be one of 11025Hz, 22050Hz, 44100Hz, 48000Hz; recording functionality will not be available");
02070                 if (recDevice)
02071                         free (recDevice);
02072                 recDevice = NULL;
02073         }
02074         if (recBits != 8 && recBits != 16)
02075         {
02076                 PLAYER_WARN ("Recording bits per sample must be 8 or 16; recording functionality will not be available");
02077                 if (recDevice)
02078                         free (recDevice);
02079                 recDevice = NULL;
02080         }
02081 
02082         // Read sample names
02083         int numSamples = cf->GetTupleCount (section, "samples");
02084         if (numSamples > 0)
02085         {
02086                 for (int ii = 0; ii < numSamples; ii++)
02087                 {
02088                         if (!AddStoredSample (cf->ReadTupleString (section, "samples", ii, "error_bad_sample_path")))
02089                         {
02090                                 PLAYER_ERROR1 ("Could not add audio sample %d", cf->ReadTupleString (section, "samples", ii, ""));
02091                                 return;
02092                         }
02093                 }
02094         }
02095 
02096         // Read mixer filter list
02097         int numMixerFilters = cf->GetTupleCount (section, "mixerfilters");
02098         if (numMixerFilters > 0)
02099         {
02100                 // Create space to store the filters plus the null terminator
02101                 if ((mixerFilters = new char*[numMixerFilters + 1]) == NULL)
02102                         PLAYER_ERROR1 ("Could not create space to store %d mixer filters", numMixerFilters);
02103                 else
02104                 {
02105                         int ii;
02106                         // Add each filter to the list
02107                         for (ii = 0; ii < numMixerFilters; ii++)
02108                         {
02109                                 str = cf->ReadTupleString (section, "mixerfilters", ii, NULL);
02110                                 if (str)
02111                                 {
02112                                         mixerFilters[ii] = strdup (str);
02113                                         if (debugLevel >= 1)
02114                                                 cout << "ALSA: Added mixer filter: " << mixerFilters[ii] << endl;
02115                                 }
02116                         }
02117                         // Null terminate the list (for ease of cleanup)
02118                         mixerFilters[ii] = NULL;
02119                 }
02120         }
02121 
02122         return;
02123 }
02124 
02125 // Destructor
02126 Alsa::~Alsa (void)
02127 {
02128         if (pbDevice)
02129                 free (pbDevice);
02130         if (mixerDevice)
02131                 free (mixerDevice);
02132         if (recDevice)
02133                 free (recDevice);
02134         if (samplesHead)
02135         {
02136                 StoredSample *currentSample = samplesHead;
02137                 StoredSample *previousSample = currentSample;
02138                 while (currentSample != NULL)
02139                 {
02140                         if (currentSample->sample)
02141                                 delete currentSample->sample;
02142                         previousSample = currentSample;
02143                         currentSample = currentSample->next;
02144                         delete previousSample;
02145                 }
02146         }
02147         if (mixerFilters)
02148         {
02149                 for (int ii = 0; mixerFilters[ii] != NULL; ii++)
02150                         free (mixerFilters[ii]);
02151                 delete[] mixerFilters;
02152         }
02153 }
02154 
02155 // Set up the device. Return 0 if things go well, and -1 otherwise.
02156 int Alsa::Setup (void)
02157 {
02158         // Clear queue and set to initial values
02159         ClearQueue ();
02160 
02161         // Only setup playback if a playback name was configured
02162         if (pbDevice)
02163         {
02164                 if (!SetupPlayBack ())
02165                 {
02166                         PLAYER_WARN ("Error opening playback device, playback functionality will not be available");
02167                         pbHandle = NULL;
02168                 }
02169         }
02170 
02171         // Only setup mixer if a mixer name was configured
02172         if (mixerDevice)
02173         {
02174                 if (!SetupMixer ())
02175                 {
02176                         PLAYER_WARN ("Error opening mixer, mixer functionality will not be available");
02177                         mixerHandle = NULL;
02178                 }
02179         }
02180 
02181         // Only setup recording if a recorder name was configured
02182         if (recDevice)
02183         {
02184                 if (!SetupRecord ())
02185                 {
02186                         PLAYER_WARN ("Error opening record device, record functionality will not be available");
02187                         recHandle = NULL;
02188                 }
02189         }
02190 
02191         playState = PB_STATE_STOPPED;
02192         recState = PB_STATE_STOPPED;
02193 
02194         StartThread ();
02195         return 0;
02196 }
02197 
02198 
02199 // Shutdown the device
02200 int Alsa::Shutdown (void)
02201 {
02202         StopThread ();
02203 
02204         // Clean up PCM file descriptors
02205         if (pbFDs)
02206                 delete[] pbFDs;
02207         pbFDs = NULL;
02208         if (recFDs)
02209                 delete[] recFDs;
02210         recFDs = NULL;
02211         // Close the playback handle
02212         if (pbHandle)
02213         {
02214                 // Stop playback
02215                 StopPlayback ();
02216                 snd_pcm_close (pbHandle);
02217         }
02218         // Clean up periodBuffer
02219         if (periodBuffer != NULL)
02220         {
02221                 delete[] periodBuffer;
02222                 periodBuffer = NULL;
02223         }
02224         // Close the record handle
02225         if (recHandle)
02226         {
02227                 StopRecording ();
02228                 snd_pcm_close (recHandle);
02229         }
02230         // Clean up the record data buffer
02231         if (recData)
02232                 delete recData;
02233         // Remove any queued sample data
02234         ClearQueue ();
02235 
02236         if (mixerHandle)
02237         {
02238                 if (numElements > 0)
02239                 {
02240                         CleanUpMixerElements (mixerElements, numElements);
02241                 }
02242                 if (snd_mixer_detach (mixerHandle, mixerDevice) < 0)
02243                         PLAYER_WARN ("Error detaching mixer interface");
02244                 else
02245                 {
02246                         if (snd_mixer_close (mixerHandle) < 0)
02247                                 PLAYER_WARN ("Error closing mixer interface");
02248                         else
02249                         {
02250                                 // TODO: Figure out why this causes a segfault
02251 //                              snd_mixer_free (mixerHandle);
02252                         }
02253                 }
02254         }
02255 
02256         return 0;
02257 }
02258 
02259 
02261 //      Thread stuff
02263 
02264 void Alsa::Main (void)
02265 {
02266         while (1)
02267         {
02268                 pthread_testcancel ();
02269 
02270                 // Check playback state
02271                 // Check if draining the current sample
02272                 if (playState == PB_STATE_DRAIN)
02273                 {
02274                         // If so, need to wait until it finishes
02275                         if (snd_pcm_state (pbHandle) == SND_PCM_STATE_DRAINING)
02276                         {
02277                                 // Do nothing if still draining
02278 //                              printf ("Still draining\n");
02279                         }
02280                         // The state after draining is complete is SETUP
02281                         else if (snd_pcm_state (pbHandle) == SND_PCM_STATE_SETUP || snd_pcm_state (pbHandle) == SND_PCM_STATE_PREPARED)
02282                         {
02283                                 // Then move on to the next
02284                                 AdvanceQueue ();
02285                                 // If there is a next, set it up for playing
02286                                 if (queueHead != NULL)
02287                                 {
02288                                         // Set parameters for the new sample
02289                                         SetPBParams (queueHead->sample);
02290                                         // Finished draining, so set to playing (the next if will catch this and start immediately)
02291                                         playState = PB_STATE_PLAYING;
02292                                 }
02293                                 // If nothing left, moved to STOPPED state
02294                                 else
02295                                 {
02296                                         playState = PB_STATE_STOPPED;
02297                                         SendStateMessage ();
02298                                 }
02299                         }
02300                         else
02301                         {
02302                                 PLAYER_WARN1 ("Unexpected PCM state for drain: %d", snd_pcm_state (pbHandle));
02303                                 playState = PB_STATE_STOPPED;
02304                                 SendStateMessage ();
02305                         }
02306                 }
02307                 // If playing, check if the buffer is ready for more data
02308                 if (playState == PB_STATE_PLAYING)
02309                 {
02310                         if (poll (pbFDs, numPBFDs, 5) > 0)
02311                         {
02312                                 // If it is, check each file descriptor
02313                                 for (int ii = 0; ii < numPBFDs; ii++)
02314                                         if (pbFDs[ii].revents > 0)
02315                                                 PlaybackCallback (pbPeriodSize);
02316                         }
02317                 }
02318 
02319                 // Check record state
02320                 if (recState == PB_STATE_RECORDING)
02321                 {
02322                         if (poll (recFDs, numRecFDs, 5) > 0)
02323                         {
02324                                 // If it is, check each file descriptor
02325                                 for (int ii = 0; ii < numRecFDs; ii++)
02326                                         if (recFDs[ii].revents > 0)
02327                                                 RecordCallback (recPeriodSize);
02328                         }
02329                 }
02330 
02331             // Handle pending messages
02332                 if (!InQueue->Empty ())
02333                 {
02334                         // Process one message at a time before checking sound buffer states
02335                         ProcessMessages (1);
02336                 }
02337         }
02338 }
02339 
02340 
02341 // Sends a PLAYER_AUDIO_DATA_STATE message describing the current state of the driver
02342 void Alsa::SendStateMessage (void)
02343 {
02344         player_audio_state_t msg;
02345 
02346         msg.state = 0;
02347         if (playState == PB_STATE_PLAYING || playState == PB_STATE_DRAIN)
02348                 msg.state |= PLAYER_AUDIO_STATE_PLAYING;
02349         if (recState == PB_STATE_RECORDING)
02350                 msg.state |= PLAYER_AUDIO_STATE_RECORDING;
02351         if (msg.state == 0)
02352                 msg.state = PLAYER_AUDIO_STATE_STOPPED;
02353 
02354         Publish (device_addr, PLAYER_MSGTYPE_DATA, PLAYER_AUDIO_DATA_STATE, reinterpret_cast<void*> (&msg), sizeof (player_audio_state_t), NULL);
02355 }
02356 
02357 
02359 //      Message handling
02361 
02362 int Alsa::HandleWavePlayCmd (player_audio_wav_t *data)
02363 {
02364         // Add the wave to the queue
02365         if (!AddToQueue (data))
02366         {
02367                 PLAYER_WARN ("Unable to add wave data to queue");
02368                 return -1;
02369         }
02370 
02371         // Start playback
02372         StartPlayback ();
02373 
02374         return 0;
02375 }
02376 
02377 int Alsa::HandleSamplePlayCmd (player_audio_sample_item_t *data)
02378 {
02379         StoredSample *sample;
02380         // Find the sample to be retrieved
02381         if ((sample = GetSampleAtIndex (data->index)) == NULL)
02382         {
02383                 PLAYER_ERROR1 ("Couldn't find sample at index %d", data->index);
02384                 return -1;
02385         }
02386 
02387         // Add the sample to the queue
02388         if (!AddToQueue (sample->sample))
02389         {
02390                 PLAYER_WARN ("Unable to add sample to queue");
02391                 return -1;
02392         }
02393 
02394         // Start playback
02395         StartPlayback ();
02396 
02397         return 0;
02398 }
02399 
02400 int Alsa::HandleRecordCmd (player_bool_t *data)
02401 {
02402         if (data->state)
02403         {
02404                 // Set recording destination to -1 for clients
02405                 recDest = -1;
02406                 // Create a local buffer of suitable length
02407                 if (!SetupRecordBuffer (cfgRecStoreTime))
02408                 {
02409                         PLAYER_ERROR ("Failed to setup local recording buffer");
02410                         return 0;
02411                 }
02412                 // Start recording
02413                 StartRecording ();
02414         }
02415         else
02416                 StopRecording ();
02417 
02418         return 0;
02419 }
02420 
02421 int Alsa::HandleMixerChannelCmd (player_audio_mixer_channel_list_t *data)
02422 {
02423         for (uint32_t ii = 0; ii < data->channels_count; ii++)
02424         {
02425                 SetElementLevel (data->channels[ii].index, data->channels[ii].amplitude);
02426                 SetElementSwitch (data->channels[ii].index, data->channels[ii].active);
02427         }
02428 
02429         PublishMixerData ();
02430 
02431         return 0;
02432 }
02433 
02434 int Alsa::HandleSampleLoadReq (player_audio_sample_t *data, QueuePointer &resp_queue)
02435 {
02436         // If the requested index to store at is at end or -1, append to the list
02437         if (data->index == nextSampleIdx || data->index == -1)
02438         {
02439                 if (!AddStoredSample (&data->sample))
02440                         return -1;      // Error occured
02441                 // If no error, all happy so fall through to the end of the function and send ack
02442         }
02443         // If the sample is negative (but not -1) or beyond the end, error
02444         else if (data->index < -1 || data->index > nextSampleIdx)
02445         {
02446                 PLAYER_ERROR1 ("Can't add sample at negative index %d", data->index);
02447                 return -1;
02448         }
02449         else
02450         {
02451                 // Find the sample to be replaced
02452                 StoredSample *oldSample;
02453                 if ((oldSample = GetSampleAtIndex (data->index)) == NULL)
02454                 {
02455                         PLAYER_ERROR1 ("Couldn't find sample at index %d", data->index);
02456                         return -1;
02457                 }
02458                 // Replace it with the new one, freeing the old one
02459                 // First create the new sample
02460                 AudioSample *newSample = NULL;
02461                 if ((newSample = new AudioSample) == NULL)
02462                 {
02463                         PLAYER_ERROR ("Failed to allocate memory for new audio sample");
02464                         return -1;
02465                 }
02466                 if (!newSample->FromPlayer (&data->sample))
02467                 {
02468                         PLAYER_ERROR ("Failed to copy new audio sample");
02469                         return -1;
02470                 }
02471                 // Delete the old sample
02472                 if (oldSample->sample)
02473                         delete oldSample->sample;
02474                 // Update the pointer
02475                 oldSample->sample = newSample;
02476         }
02477         Publish (device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_AUDIO_REQ_SAMPLE_LOAD, NULL, 0, NULL);
02478         return 0;
02479 }
02480 
02481 int Alsa::HandleSampleRetrieveReq (player_audio_sample_t *data, QueuePointer &resp_queue)
02482 {
02483         // If the requested index to retrieve is beyond the end or negative, error
02484         if (data->index >= nextSampleIdx || data->index < 0)
02485         {
02486                 PLAYER_ERROR1 ("Can't retrieve sample from invalid index %d", data->index);
02487                 return -1;
02488         }
02489         else
02490         {
02491                 // Find the sample to be retrieved
02492                 StoredSample *sample;
02493                 if ((sample = GetSampleAtIndex (data->index)) == NULL)
02494                 {
02495                         PLAYER_ERROR1 ("Couldn't find sample at index %d", data->index);
02496                         return -1;
02497                 }
02498                 // Convert the data to a player struct
02499                 player_audio_sample_t result;
02500                 memset (&result, 0, sizeof (player_audio_sample_t));
02501                 result.index = data->index;
02502                 sample->sample->ToPlayer (&result.sample);
02503                 Publish (device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_AUDIO_REQ_SAMPLE_RETRIEVE, &result, sizeof (player_audio_sample_t), NULL);
02504                 return 0;
02505         }
02506         return -1;
02507 }
02508 
02509 // Handle a request to record a sample and store it locally in the sample store
02510 int Alsa::HandleSampleRecordReq (player_audio_sample_rec_req_t *data, QueuePointer &resp_queue)
02511 {
02512         // Can't record to sample and clients at the same time (yet)
02513         if (recState == PB_STATE_RECORDING)
02514         {
02515                 PLAYER_WARN ("Tried to record a sample while already recording");
02516                 return -1;
02517         }
02518         // Set the recording destination appropriately
02519         // (Just set recDest for now, will actually store when recording is complete)
02520         if (data->index < 0 || data->index == nextSampleIdx)
02521         {       // Store at next available
02522                 // Add a placeholder sample on the list so that any other additions to the
02523                 // queue while recording don't cause problems - can just fill in the sample pointer later
02524                 StoredSample *placeHolder = NULL;
02525                 if ((placeHolder = new StoredSample) == NULL)
02526                 {
02527                         PLAYER_ERROR ("Failed to allocate sample storage");
02528                         return -1;
02529                 }
02530                 recDest = nextSampleIdx++;      // Incremement next sample index
02531                 memset (placeHolder, 0, sizeof (StoredSample));
02532                 placeHolder->index = recDest;
02533                 AddStoredSample (placeHolder);
02534         }
02535         else if (data->index > nextSampleIdx)
02536         {
02537                 // Error - can't store beyond end of list (like with load requests)
02538                 PLAYER_ERROR2 ("Can't add sample at index %d, greater than %d", data->index, nextSampleIdx);
02539                 return -1;
02540         }
02541         else
02542         {       // Replace
02543                 recDest = data->index;
02544         }
02545         if (debugLevel >= 4)
02546                 cout << "ALSA: Recording new sample to index " << recDest << endl;
02547         // Create a buffer to store data in until recording is complete
02548         if (!SetupRecordBuffer (data->length))
02549         {
02550                 PLAYER_ERROR ("Failed to setup local recording buffer");
02551                 return -1;
02552         }
02553         // Start recording
02554         StartRecording ();
02555         // Send the response
02556         player_audio_sample_rec_req_t response;
02557         response.index = recDest;
02558         response.length = data->length;
02559         Publish (device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_AUDIO_REQ_SAMPLE_REC, &response, sizeof (player_audio_sample_rec_req_t), NULL);
02560         return 0;
02561 }
02562 
02563 int Alsa::HandleMixerChannelListReq (player_audio_mixer_channel_list_detail_t *data, QueuePointer &resp_queue)
02564 {
02565         player_audio_mixer_channel_list_detail_t result;
02566         MixerDetailsToPlayer (&result);
02567         Publish (device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_AUDIO_REQ_MIXER_CHANNEL_LIST, &result, sizeof (player_audio_mixer_channel_list_detail_t), NULL);
02568 
02569         return 0;
02570 }
02571 
02572 int Alsa::HandleMixerChannelLevelReq (player_audio_mixer_channel_list_t *data, QueuePointer &resp_queue)
02573 {
02574         player_audio_mixer_channel_list_t result;
02575         MixerLevelsToPlayer (&result);
02576         Publish (device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_AUDIO_REQ_MIXER_CHANNEL_LEVEL, &result, sizeof (player_audio_mixer_channel_list_t), NULL);
02577 
02578         return 0;
02579 }
02580 
02581 // Message processing
02582 int Alsa::ProcessMessage (QueuePointer &resp_queue, player_msghdr *hdr, void *data)
02583 {
02584         // Check for capabilities requests first
02585         HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_CAPABILTIES_REQ);
02586         if (pbHandle)
02587         {
02588                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_WAV_PLAY);
02589                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_SAMPLE_PLAY);
02590                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_SAMPLE_LOAD);
02591                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_SAMPLE_RETRIEVE);
02592         }
02593         if (recHandle)
02594         {
02595                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_WAV_STREAM_REC);
02596                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_SAMPLE_REC);
02597         }
02598         if (mixerHandle)
02599         {
02600                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_MIXER_CHANNEL);
02601                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_MIXER_CHANNEL_LIST);
02602                 HANDLE_CAPABILITY_REQUEST (device_addr, resp_queue, hdr, data, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_MIXER_CHANNEL_LEVEL);
02603         }
02604 
02605         // Commands
02606         if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_WAV_PLAY, device_addr) && pbHandle)
02607         {
02608                 HandleWavePlayCmd (reinterpret_cast<player_audio_wav_t*> (data));
02609                 return 0;
02610         }
02611         else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_SAMPLE_PLAY, device_addr) && pbHandle)
02612         {
02613                 HandleSamplePlayCmd (reinterpret_cast<player_audio_sample_item_t*> (data));
02614                 return 0;
02615         }
02616         else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_WAV_STREAM_REC, device_addr) && recHandle)
02617         {
02618                 HandleRecordCmd (reinterpret_cast<player_bool_t*> (data));
02619                 return 0;
02620         }
02621         else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, PLAYER_AUDIO_CMD_MIXER_CHANNEL, device_addr) && mixerHandle)
02622         {
02623                 HandleMixerChannelCmd (reinterpret_cast<player_audio_mixer_channel_list_t*> (data));
02624                 return 0;
02625         }
02626         // Requests
02627         else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_SAMPLE_LOAD, device_addr) && pbHandle)
02628         {
02629                 return HandleSampleLoadReq (reinterpret_cast<player_audio_sample_t*> (data), resp_queue);
02630         }
02631         else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_SAMPLE_RETRIEVE, device_addr) && pbHandle)
02632         {
02633                 return HandleSampleRetrieveReq (reinterpret_cast<player_audio_sample_t*> (data), resp_queue);
02634         }
02635         else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_SAMPLE_REC, device_addr) && recHandle)
02636         {
02637                 return HandleSampleRecordReq (reinterpret_cast<player_audio_sample_rec_req_t*> (data), resp_queue);
02638         }
02639         else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_MIXER_CHANNEL_LIST, device_addr) && mixerHandle)
02640         {
02641                 return HandleMixerChannelListReq (reinterpret_cast<player_audio_mixer_channel_list_detail_t*> (data), resp_queue);
02642         }
02643         else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ, PLAYER_AUDIO_REQ_MIXER_CHANNEL_LEVEL, device_addr) && mixerHandle)
02644         {
02645                 return HandleMixerChannelLevelReq (reinterpret_cast<player_audio_mixer_channel_list_t*> (data), resp_queue);
02646         }
02647 
02648         return -1;
02649 }

Last updated 12 September 2005 21:38:45