mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-19 12:06:15 +02:00
improved alsa error handling
This commit is contained in:
parent
74cdd5ea64
commit
80eb832eac
4 changed files with 212 additions and 68 deletions
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "alsaPlayer.h"
|
||||
#include "common/log.h"
|
||||
#include "common/snapException.h"
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <iostream>
|
||||
|
||||
|
@ -25,12 +26,12 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
Player::Player(const PcmDevice& pcmDevice, Stream* stream) : buff_(NULL), active_(false), stream_(stream), pcmDevice_(pcmDevice)
|
||||
Player::Player(const PcmDevice& pcmDevice, Stream* stream) : handle_(NULL), buff_(NULL), active_(false), stream_(stream), pcmDevice_(pcmDevice)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
snd_pcm_t* Player::initAlsa()
|
||||
void Player::initAlsa()
|
||||
{
|
||||
unsigned int tmp, rate;
|
||||
int pcm, channels;
|
||||
|
@ -41,14 +42,10 @@ snd_pcm_t* Player::initAlsa()
|
|||
rate = format.rate;
|
||||
channels = format.channels;
|
||||
|
||||
snd_pcm_t* pcm_handle(NULL);
|
||||
|
||||
/* Open the PCM device in playback mode */
|
||||
if ((pcm = snd_pcm_open(&pcm_handle, pcmDevice_.name.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0)
|
||||
{
|
||||
logE << "ERROR: Can't open " << pcmDevice_.name << " PCM device. " << snd_strerror(pcm) << "\n";
|
||||
return NULL;
|
||||
}
|
||||
if ((pcm = snd_pcm_open(&handle_, pcmDevice_.name.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0)
|
||||
throw new SnapException("Can't open " + pcmDevice_.name + " PCM device. " + snd_strerror(pcm));
|
||||
|
||||
/* struct snd_pcm_playback_info_t pinfo;
|
||||
if ( (pcm = snd_pcm_playback_info( pcm_handle, &pinfo )) < 0 )
|
||||
fprintf( stderr, "Error: playback info error: %s\n", snd_strerror( err ) );
|
||||
|
@ -57,32 +54,20 @@ snd_pcm_t* Player::initAlsa()
|
|||
/* Allocate parameters object and fill it with default values*/
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
|
||||
snd_pcm_hw_params_any(pcm_handle, params);
|
||||
snd_pcm_hw_params_any(handle_, params);
|
||||
|
||||
/* Set parameters */
|
||||
if ((pcm = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
|
||||
{
|
||||
logE << "ERROR: Can't set interleaved mode. " << snd_strerror(pcm) << "\n";
|
||||
return NULL;
|
||||
}
|
||||
if ((pcm = snd_pcm_hw_params_set_access(handle_, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
|
||||
throw new SnapException("Can't set interleaved mode. " + string(snd_strerror(pcm)));
|
||||
|
||||
if ((pcm = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE)) < 0)
|
||||
{
|
||||
logE << "ERROR: Can't set format. " << snd_strerror(pcm) << "\n";
|
||||
return NULL;
|
||||
}
|
||||
if ((pcm = snd_pcm_hw_params_set_format(handle_, params, SND_PCM_FORMAT_S16_LE)) < 0)
|
||||
throw new SnapException("Can't set format. " + string(snd_strerror(pcm)));
|
||||
|
||||
if ((pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels)) < 0)
|
||||
{
|
||||
logE << "ERROR: Can't set channels number. " << snd_strerror(pcm) << "\n";
|
||||
return NULL;
|
||||
}
|
||||
if ((pcm = snd_pcm_hw_params_set_channels(handle_, params, channels)) < 0)
|
||||
throw new SnapException("Can't set channels number. " + string(snd_strerror(pcm)));
|
||||
|
||||
if ((pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0)) < 0)
|
||||
{
|
||||
logE << "ERROR: Can't set rate. " << snd_strerror(pcm) << "\n";
|
||||
return NULL;
|
||||
}
|
||||
if ((pcm = snd_pcm_hw_params_set_rate_near(handle_, params, &rate, 0)) < 0)
|
||||
throw new SnapException("Can't set rate. " + string(snd_strerror(pcm)));
|
||||
|
||||
unsigned int buffer_time;
|
||||
snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0);
|
||||
|
@ -91,23 +76,20 @@ snd_pcm_t* Player::initAlsa()
|
|||
|
||||
unsigned int period_time = buffer_time / 4;
|
||||
|
||||
snd_pcm_hw_params_set_period_time_near(pcm_handle, params, &period_time, 0);
|
||||
snd_pcm_hw_params_set_buffer_time_near(pcm_handle, params, &buffer_time, 0);
|
||||
snd_pcm_hw_params_set_period_time_near(handle_, params, &period_time, 0);
|
||||
snd_pcm_hw_params_set_buffer_time_near(handle_, params, &buffer_time, 0);
|
||||
|
||||
// long unsigned int periodsize = stream_->format.msRate() * 50;//2*rate/50;
|
||||
// if ((pcm = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, params, &periodsize)) < 0)
|
||||
// logE << "Unable to set buffer size " << (long int)periodsize << ": " << snd_strerror(pcm) << "\n";
|
||||
|
||||
/* Write parameters */
|
||||
if ((pcm = snd_pcm_hw_params(pcm_handle, params)) < 0)
|
||||
{
|
||||
logE << "ERROR: Can't set harware parameters. " << snd_strerror(pcm) << "\n";
|
||||
return NULL;
|
||||
}
|
||||
if ((pcm = snd_pcm_hw_params(handle_, params)) < 0)
|
||||
throw new SnapException("Can't set harware parameters. " + string(snd_strerror(pcm)));
|
||||
|
||||
/* Resume information */
|
||||
logD << "PCM name: " << snd_pcm_name(pcm_handle) << "\n";
|
||||
logD << "PCM state: " << snd_pcm_state_name(snd_pcm_state(pcm_handle)) << "\n";
|
||||
logD << "PCM name: " << snd_pcm_name(handle_) << "\n";
|
||||
logD << "PCM state: " << snd_pcm_state_name(snd_pcm_state(handle_)) << "\n";
|
||||
snd_pcm_hw_params_get_channels(params, &tmp);
|
||||
logD << "channels: " << tmp << "\n";
|
||||
|
||||
|
@ -126,22 +108,21 @@ snd_pcm_t* Player::initAlsa()
|
|||
|
||||
snd_pcm_sw_params_t *swparams;
|
||||
snd_pcm_sw_params_alloca(&swparams);
|
||||
snd_pcm_sw_params_current(pcm_handle, swparams);
|
||||
snd_pcm_sw_params_current(handle_, swparams);
|
||||
|
||||
snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames_);
|
||||
snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, frames_);
|
||||
snd_pcm_sw_params_set_avail_min(handle_, swparams, frames_);
|
||||
snd_pcm_sw_params_set_start_threshold(handle_, swparams, frames_);
|
||||
// snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, frames_);
|
||||
snd_pcm_sw_params(pcm_handle, swparams);
|
||||
return pcm_handle;
|
||||
snd_pcm_sw_params(handle_, swparams);
|
||||
}
|
||||
|
||||
|
||||
void Player::uninitAlsa(snd_pcm_t* handle)
|
||||
void Player::uninitAlsa()
|
||||
{
|
||||
if (handle != NULL)
|
||||
if (handle_ != NULL)
|
||||
{
|
||||
snd_pcm_drain(handle);
|
||||
snd_pcm_close(handle);
|
||||
snd_pcm_drain(handle_);
|
||||
snd_pcm_close(handle_);
|
||||
}
|
||||
|
||||
if (buff_ != NULL)
|
||||
|
@ -154,6 +135,7 @@ void Player::uninitAlsa(snd_pcm_t* handle)
|
|||
|
||||
void Player::start()
|
||||
{
|
||||
initAlsa();
|
||||
active_ = true;
|
||||
playerThread_ = thread(&Player::worker, this);
|
||||
}
|
||||
|
@ -172,42 +154,33 @@ void Player::stop()
|
|||
active_ = false;
|
||||
playerThread_.join();
|
||||
}
|
||||
uninitAlsa();
|
||||
}
|
||||
|
||||
|
||||
void Player::worker()
|
||||
{
|
||||
snd_pcm_t* handle = NULL;
|
||||
snd_pcm_sframes_t pcm;
|
||||
snd_pcm_sframes_t framesAvail;
|
||||
snd_pcm_sframes_t framesDelay;
|
||||
while (active_)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
if ((handle = initAlsa()) == NULL)
|
||||
{
|
||||
usleep(100*1000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
snd_pcm_avail_delay(handle, &framesAvail, &framesDelay);
|
||||
snd_pcm_avail_delay(handle_, &framesAvail, &framesDelay);
|
||||
chronos::usec delay((chronos::usec::rep) (1000 * (double) framesDelay / stream_->getFormat().msRate()));
|
||||
logD << "Avail: " << framesAvail << ", delay: " << framesDelay << ", delay[ms]: " << delay.count() / 1000 << "\n";
|
||||
|
||||
if (stream_->getPlayerChunk(buff_, delay, frames_))
|
||||
{
|
||||
if ((pcm = snd_pcm_writei(handle, buff_, frames_)) == -EPIPE)
|
||||
if ((pcm = snd_pcm_writei(handle_, buff_, frames_)) == -EPIPE)
|
||||
{
|
||||
logE << "XRUN\n";
|
||||
snd_pcm_prepare(handle);
|
||||
snd_pcm_prepare(handle_);
|
||||
}
|
||||
else if (pcm < 0)
|
||||
{
|
||||
logE << "ERROR. Can't write to PCM device: " << snd_strerror(pcm) << "\n";
|
||||
uninitAlsa(handle);
|
||||
handle = NULL;
|
||||
uninitAlsa();
|
||||
initAlsa();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -216,7 +189,6 @@ void Player::worker()
|
|||
usleep(100*1000);
|
||||
}
|
||||
}
|
||||
uninitAlsa(handle);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue