MercurySoundDriverALSA.cpp

Go to the documentation of this file.
00001 #include <math.h>
00002 #include "MercurySoundDriverALSA.h"
00003 #include "MercuryLog.h"
00004 
00005 MercurySoundDriverALSA::MercurySoundDriverALSA()
00006     :MercurySoundDriver(), m_pcmHandle(NULL)
00007 {
00008 }
00009 
00010 MercurySoundDriverALSA::~MercurySoundDriverALSA()
00011 {
00012 }
00013 
00014 void MercurySoundDriverALSA::ALSACallback(snd_async_handler_t *pcm_callback)
00015 {
00016     MercurySoundDriverALSA* sd = (MercurySoundDriverALSA*)snd_async_handler_get_callback_private(pcm_callback);
00017     sd->WriteSoundFrames();
00018 #if defined( NO_THREADS )
00019     sd->ProcessPlayingSounds();
00020 #endif
00021 }
00022 
00023 void MercurySoundDriverALSA::Init()
00024 {
00025     MercurySoundDriver::Init();
00026     m_name = "default";
00027 
00028     int err = snd_pcm_open(&m_pcmHandle, m_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
00029     if (err < 0)
00030         printf("can not open audio device %s (%s)\n", m_name.c_str(), snd_strerror(err) );
00031 
00032     SetupHWParams();
00033     SetupSWParams();
00034     
00035     m_buffer = new int16_t[m_bufferSize*m_channels];
00036     memset(m_buffer, 0, m_bufferSize*m_channels*sizeof(int16_t));
00037     m_buffer2 = new int16_t[m_bufferSize*m_channels];
00038     memset(m_buffer2, 0, m_bufferSize*m_channels*sizeof(int16_t));
00039     
00040     snd_pcm_prepare (m_pcmHandle);
00041     Start();    
00042     
00043     ProcessPlayingSounds();
00044 
00045     snd_async_handler_t *pcm_callback;
00046     snd_async_add_pcm_handler(&pcm_callback, m_pcmHandle, MercurySoundDriverALSA::ALSACallback, this);
00047     void *private_data = snd_async_handler_get_callback_private(pcm_callback);
00048 }
00049 
00050 void MercurySoundDriverALSA::WriteSoundFrames()
00051 {
00052     m_mutex.Wait();
00053     
00054     snd_pcm_sframes_t avail( snd_pcm_avail_update(m_pcmHandle) );   
00055     while ( (avail >= m_writeSize) && (m_sentFrames < m_bufferSize) )
00056     {
00057         unsigned long numFrames = avail<(m_bufferSize-m_sentFrames)?avail:(m_bufferSize-m_sentFrames);
00058         unsigned long byteOffset = m_sentFrames*m_channels;
00059         int wrote = snd_pcm_writei(m_pcmHandle, (*m_front)+byteOffset, numFrames);
00060 //      printf("numframes:%d -> %d\n", numFrames, wrote);
00061         
00062         if (wrote < 0)
00063         {
00064             Recover(wrote);
00065 //          WriteSoundFrames();
00066             Start();
00067             m_mutex.UnLock();
00068             return;
00069         }
00070         
00071         m_sentFrames += wrote;
00072         avail = snd_pcm_avail_update(m_pcmHandle);
00073     }
00074     
00075     if (m_sentFrames >= m_bufferSize)
00076     {
00077         m_sentFrames = 0;
00078         m_needData = true;
00079     }
00080         
00081     m_mutex.UnLock();
00082 }
00083 
00084 void MercurySoundDriverALSA::Recover(int error)
00085 {
00086     if( error == -EPIPE )
00087     {
00088         LOG.Warn("ALSA buffer underrun");
00089         snd_pcm_prepare(m_pcmHandle);
00090     }
00091     if( error == -ESTRPIPE )
00092     {
00093         LOG.Warn("ALSA suspend");
00094         while (snd_pcm_resume(m_pcmHandle) == -EAGAIN)
00095             usleep(10000); // 10ms
00096     }
00097 }
00098 
00099 void MercurySoundDriverALSA::SetupHWParams()
00100 {
00101     snd_pcm_hw_params_t *hw_params;
00102     snd_pcm_hw_params_malloc(&hw_params);
00103     
00104     snd_pcm_hw_params_any(m_pcmHandle, hw_params);
00105 
00106     snd_pcm_hw_params_set_access(m_pcmHandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
00107     snd_pcm_hw_params_set_format(m_pcmHandle, hw_params, SND_PCM_FORMAT_S16_LE);
00108     snd_pcm_hw_params_set_rate_near(m_pcmHandle, hw_params, &m_rate, NULL);
00109     snd_pcm_hw_params_set_channels(m_pcmHandle, hw_params, m_channels);
00110     snd_pcm_hw_params_set_buffer_size_near(m_pcmHandle, hw_params, &m_bufferSize);
00111     snd_pcm_hw_params_set_period_size_near(m_pcmHandle, hw_params, &m_writeSize, NULL);
00112 
00113     snd_pcm_hw_params(m_pcmHandle, hw_params);
00114     snd_pcm_hw_params_free(hw_params);
00115 }
00116 
00117 void MercurySoundDriverALSA::SetupSWParams()
00118 {
00119     snd_pcm_sw_params_t *sw_params;
00120 
00121     snd_pcm_sw_params_malloc(&sw_params);
00122     snd_pcm_sw_params_current(m_pcmHandle, sw_params);
00123     snd_pcm_sw_params_set_start_threshold(m_pcmHandle, sw_params, m_bufferSize - m_writeSize);
00124     snd_pcm_sw_params_set_avail_min(m_pcmHandle, sw_params, m_writeSize);
00125     snd_pcm_sw_params(m_pcmHandle, sw_params);
00126     snd_pcm_sw_params_free (sw_params);
00127 }
00128 
00129 void MercurySoundDriverALSA::Cleanup()
00130 {
00131     snd_pcm_close(m_pcmHandle);
00132 }
00133 
00134 void MercurySoundDriverALSA::Start()
00135 {
00136     int wrote = snd_pcm_writei (m_pcmHandle, *m_front, m_bufferSize);
00137     snd_pcm_start(m_pcmHandle);
00138 }
00139 
00140 /* 
00141  * Copyright (c) 2007 Joshua Allen
00142  * All rights reserved.
00143  *
00144  * Redistribution and use in source and binary forms, with or
00145  * without modification, are permitted provided that the following
00146  * conditions are met:
00147  *  -   Redistributions of source code must retain the above
00148  *      copyright notice, this list of conditions and the following disclaimer.
00149  *  -   Redistributions in binary form must reproduce the above copyright
00150  *      notice, this list of conditions and the following disclaimer in
00151  *      the documentation and/or other materials provided with the distribution.
00152  *  -   Neither the name of the Mercury Engine nor the names of its
00153  *      contributors may be used to endorse or promote products derived from
00154  *      this software without specific prior written permission.
00155  *
00156  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00157  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00158  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00159  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00160  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00161  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00162  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00163  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00164  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00165  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00166  */

Hosted by SourceForge.net Logo