summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuo Jinghua <sunmoon1997@gmail.com>2009-03-04 17:26:04 +0800
committerLuo Jinghua <sunmoon1997@gmail.com>2009-03-04 17:26:04 +0800
commit7ed6c0aea4d0fe11ebb1f07567ef14fd6f57e786 (patch)
tree26d195f34a8dea6d4a5e0b4814818a001b1a4014 /src
parent67f3784304b9904e9006aaa7056ef29accd141b4 (diff)
AlsaDevice: reopen pcm device once smd_pcm_writei doesn't work any more.
Diffstat (limited to 'src')
-rw-r--r--src/device_alsa.cpp91
-rw-r--r--src/device_alsa.h7
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;
};
}