diff options
author | Luo Jinghua <sunmoon1997@gmail.com> | 2009-03-04 17:26:04 +0800 |
---|---|---|
committer | Luo Jinghua <sunmoon1997@gmail.com> | 2009-03-04 17:26:04 +0800 |
commit | 7ed6c0aea4d0fe11ebb1f07567ef14fd6f57e786 (patch) | |
tree | 26d195f34a8dea6d4a5e0b4814818a001b1a4014 /src | |
parent | 67f3784304b9904e9006aaa7056ef29accd141b4 (diff) |
AlsaDevice: reopen pcm device once smd_pcm_writei doesn't work any more.
Diffstat (limited to 'src')
-rw-r--r-- | src/device_alsa.cpp | 91 | ||||
-rw-r--r-- | src/device_alsa.h | 7 |
2 files changed, 59 insertions, 39 deletions
diff --git a/src/device_alsa.cpp b/src/device_alsa.cpp index 805a8fd..cbc83ba 100644 --- a/src/device_alsa.cpp +++ b/src/device_alsa.cpp @@ -10,54 +10,66 @@ namespace audiere { - ALSAAudioDevice* - ALSAAudioDevice::create(const ParameterList& parameters) { - std::string devices[] = { - "default", "plughw:0,0", "hw:0,0", "" - }; - std::string default_device = parameters.getValue("device", devices[0].c_str()); - if (default_device != devices[0]) - devices[0] = default_device; - + static snd_pcm_t* openDevice(const std::string &name, + int rate) { int status = 0; snd_pcm_t* pcm_handle = 0; - for (int i = 0; devices[i].length() > 0; i++) { - status = snd_pcm_open(&pcm_handle, devices[i].c_str (), - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); - if (status >= 0) - break; - } + + status = snd_pcm_open(&pcm_handle, name.c_str (), + SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (status < 0) { ADR_LOG("Coudn't open haredware."); return 0; } - int rate = 48000; status = snd_pcm_set_params(pcm_handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 2, rate, 1, 0); if (status < 0) { - rate = 441000; - status = snd_pcm_set_params(pcm_handle, - SND_PCM_FORMAT_S16_LE, - SND_PCM_ACCESS_RW_INTERLEAVED, - 2, rate, 1, 0); - if (status < 0) { - ADR_LOG("Couldn't set audio device parameters."); - snd_pcm_close(pcm_handle); - return 0; + ADR_LOG("Couldn't set audio device parameters."); + snd_pcm_close(pcm_handle); + return 0; + } + + return pcm_handle; + } + + ALSAAudioDevice* + ALSAAudioDevice::create(const ParameterList& parameters) { + std::string devices[] = { + "default", "plughw:0,0", "hw:0,0", "" + }; + std::string default_device = parameters.getValue("device", devices[0].c_str()); + if (default_device != devices[0]) + devices[0] = default_device; + + int i, rate; + snd_pcm_t* pcm_handle = 0; + for (i = 0; devices[i].length() > 0; i++) { + rate = 48000; + pcm_handle = openDevice(devices[i], rate); + if (!pcm_handle) { + rate = 44100; + pcm_handle = openDevice(devices[i], rate); } + if (pcm_handle) + break; + } + if (!pcm_handle) { + ADR_LOG("Coudn't open haredware."); + return 0; } - return new ALSAAudioDevice(pcm_handle, rate, 4096); + return new ALSAAudioDevice(pcm_handle, devices[i], rate, 4096); } ALSAAudioDevice::ALSAAudioDevice(snd_pcm_t* pcm_handle, + const std::string &name, int rate, int buffer_size) - : MixerDevice(rate) + : MixerDevice(rate), m_pcm_name(name), m_rate(rate) { m_pcm_handle = pcm_handle; m_buffer_size = buffer_size; @@ -67,8 +79,10 @@ namespace audiere { ALSAAudioDevice::~ALSAAudioDevice() { ADR_GUARD("ALSAAudioDevice::~ALSAAudioDevice"); - snd_pcm_drain(m_pcm_handle); - snd_pcm_close(m_pcm_handle); + if (m_pcm_handle) { + snd_pcm_drain(m_pcm_handle); + snd_pcm_close(m_pcm_handle); + } delete [] m_buffer; } @@ -79,15 +93,23 @@ namespace audiere { int sample_len; int sample_left; char* sample_buf; + int retry = 0; sample_buf = m_buffer; sample_len = m_buffer_size / 4; sample_left = read(sample_len, sample_buf); - while (sample_len > 0) { - ret = snd_pcm_writei(m_pcm_handle, sample_buf, sample_len); + while (sample_left > 0 && m_pcm_handle) { + ret = snd_pcm_writei(m_pcm_handle, sample_buf, sample_left); if (ret == -EAGAIN || (ret > 0 && ret < sample_len)) { snd_pcm_wait(m_pcm_handle, 10); + if (++retry > 20) { + fprintf(stderr, "audiere: snd_pcm_writei doesn't work anymore, try to reopen a new pcm.\n"); + snd_pcm_close(m_pcm_handle); + m_pcm_handle = openDevice(m_pcm_name, m_rate); + if (!m_pcm_handle) + break; + } } else if (ret == -ESTRPIPE) { do { snd_pcm_wait(m_pcm_handle, 10); @@ -96,15 +118,10 @@ namespace audiere { snd_pcm_prepare(m_pcm_handle); } else if (ret == -EPIPE) { snd_pcm_prepare(m_pcm_handle); - } else if (ret == -EINTR) { - // nothing to do. - } else if (ret < 0) { - fprintf(stderr, "alsa error: %s\n", snd_strerror(ret)); - return; } if (ret > 0) { sample_buf += ret * 4; - sample_len -= ret; + sample_left -= ret; } } } diff --git a/src/device_alsa.h b/src/device_alsa.h index 8f7e125..b93383e 100644 --- a/src/device_alsa.h +++ b/src/device_alsa.h @@ -15,8 +15,9 @@ namespace audiere { private: ALSAAudioDevice(snd_pcm_t* pcm_handle, - int rate, - int buffer_size); + const std::string &name, + int rate, + int buffer_size); ~ALSAAudioDevice(); public: @@ -27,6 +28,8 @@ namespace audiere { snd_pcm_t* m_pcm_handle; int m_buffer_size; char* m_buffer; + std::string m_pcm_name; + int m_rate; }; } |