[Mplayerxp-cvslog] SF.net SVN: mplayerxp:[560] mplayerxp
Brought to you by:
olov
From: <nic...@us...> - 2012-12-14 14:52:43
|
Revision: 560 http://mplayerxp.svn.sourceforge.net/mplayerxp/?rev=560&view=rev Author: nickols_k Date: 2012-12-14 14:52:33 +0000 (Fri, 14 Dec 2012) Log Message: ----------- convert struct ao_functions_t into class AO_Interface Modified Paths: -------------- mplayerxp/libao2/ao_alsa9.cpp mplayerxp/libao2/ao_arts.cpp mplayerxp/libao2/ao_esd.cpp mplayerxp/libao2/ao_jack.cpp mplayerxp/libao2/ao_nas.cpp mplayerxp/libao2/ao_null.cpp mplayerxp/libao2/ao_openal.cpp mplayerxp/libao2/ao_oss.cpp mplayerxp/libao2/ao_sdl.cpp mplayerxp/libao2/ao_wav.cpp mplayerxp/libao2/audio_out.cpp mplayerxp/libao2/audio_out.h mplayerxp/libao2/audio_out_internal.h mplayerxp/mplayerxp.cpp mplayerxp/postproc/af.cpp mplayerxp/postproc/af_ao2.cpp mplayerxp/xmpcore/xmp_context.cpp Modified: mplayerxp/libao2/ao_alsa9.cpp =================================================================== --- mplayerxp/libao2/ao_alsa9.cpp 2012-12-13 14:55:16 UTC (rev 559) +++ mplayerxp/libao2/ao_alsa9.cpp 2012-12-14 14:52:33 UTC (rev 560) @@ -31,25 +31,7 @@ #include "ao_msg.h" #include "libmpstream2/mrl.h" -static ao_info_t info = -{ - "ALSA-1.x audio output", - "alsa", - "Alex Beregszaszi <al...@na...>, Joy Winter <jo...@pi...>", - "under developement" -}; - -LIBAO_EXTERN(alsa) - -typedef struct priv_s { - snd_pcm_t* handler; - snd_pcm_format_t format; - snd_pcm_hw_params_t*hwparams; - snd_pcm_sw_params_t*swparams; - size_t bytes_per_sample; - int first; -}priv_t; - +namespace mpxp { typedef struct priv_conf_s { int mmap; int noblock; @@ -60,15 +42,78 @@ { "noblock", &priv_conf.noblock, MRL_TYPE_BOOL, 0, 1 }, { NULL, NULL, 0, 0, 0 } }; +class Alsa_AO_Interface : public AO_Interface { + public: + Alsa_AO_Interface(const std::string& subdevice); + virtual ~Alsa_AO_Interface(); + virtual MPXP_Rc open(unsigned flags); + virtual MPXP_Rc configure(unsigned rate,unsigned channels,unsigned format); + virtual unsigned samplerate() const; + virtual unsigned channels() const; + virtual unsigned format() const; + virtual unsigned buffersize() const; + virtual unsigned outburst() const; + virtual MPXP_Rc test_rate(unsigned r) const; + virtual MPXP_Rc test_channels(unsigned c) const; + virtual MPXP_Rc test_format(unsigned f) const; + virtual void reset(); + virtual unsigned get_space(); + virtual float get_delay(); + virtual unsigned play(const any_t* data,unsigned len,unsigned flags); + virtual void pause(); + virtual void resume(); + virtual MPXP_Rc ctrl(int cmd,long arg) const; + private: + unsigned _channels,_samplerate,_format; + unsigned _buffersize,_outburst; + unsigned bps() const { return _channels*_samplerate*afmt2bps(_format); } + void show_caps(unsigned device) const; + int xrun(const char *str_mode) const; + unsigned play_normal(const any_t* data, unsigned len); + unsigned play_mmap(const any_t* data, unsigned len); + snd_pcm_format_t fmt2alsa(unsigned format) const; + + snd_pcm_t* handler; + snd_pcm_format_t snd_format; + snd_pcm_hw_params_t* hwparams; + snd_pcm_sw_params_t* swparams; + size_t bytes_per_sample; + int first; +}; + +Alsa_AO_Interface::Alsa_AO_Interface(const std::string& _subdevice) + :AO_Interface(_subdevice) {} +Alsa_AO_Interface::~Alsa_AO_Interface() { + int err; + if(!handler) { + MSG_ERR("alsa-uninit: no handler defined!\n"); + return; + } + if (!priv_conf.noblock) { + if ((err = snd_pcm_drain(handler)) < 0) { + MSG_ERR("alsa-uninit: pcm drain error: %s\n", snd_strerror(err)); + return; + } + } + if ((err = snd_pcm_close(handler)) < 0) { + MSG_ERR("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); + return; + } else { + handler = NULL; + MSG_V("alsa-uninit: pcm closed\n"); + } + snd_pcm_hw_params_free(hwparams); + snd_pcm_sw_params_free(swparams); +} + #define ALSA_DEVICE_SIZE 48 #define BUFFERTIME // else SET_CHUNK_SIZE #undef USE_POLL -static snd_pcm_format_t __FASTCALL__ fmt2alsa(unsigned format) -{ - switch (format) +snd_pcm_format_t Alsa_AO_Interface::fmt2alsa(unsigned f) const { + switch (f) { case AFMT_S8: return SND_PCM_FORMAT_S8; @@ -132,23 +177,8 @@ } /* to set/get/query special features/parameters */ -static MPXP_Rc __FASTCALL__ control_ao(const ao_data_t* ao,int cmd, long arg) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); - int rval; +MPXP_Rc Alsa_AO_Interface::ctrl(int cmd, long arg) const { switch(cmd) { - case AOCONTROL_QUERY_FORMAT: - rval=fmt2alsa(arg); - return snd_pcm_hw_params_test_format(priv->handler, priv->hwparams,snd_pcm_format_t(rval))==0? - MPXP_True:MPXP_False; - case AOCONTROL_QUERY_CHANNELS: - rval=arg; - return snd_pcm_hw_params_test_channels(priv->handler, priv->hwparams,rval)==0? - MPXP_True:MPXP_False; - case AOCONTROL_QUERY_RATE: - rval=arg; - return snd_pcm_hw_params_test_rate(priv->handler, priv->hwparams,rval,0)==0? - MPXP_True:MPXP_False; case AOCONTROL_GET_VOLUME: case AOCONTROL_SET_VOLUME: #ifndef WORDS_BIGENDIAN @@ -167,7 +197,7 @@ long get_vol, set_vol; float calc_vol, diff, f_multi; - if(ao->format == AFMT_AC3) return MPXP_True; + if(_format == AFMT_AC3) return MPXP_True; //allocate simple id snd_mixer_selem_id_alloca(&sid); @@ -244,8 +274,7 @@ return MPXP_Unknown; } -static void __FASTCALL__ show_caps(unsigned device) -{ +void Alsa_AO_Interface::show_caps(unsigned device) const { snd_pcm_info_t *alsa_info; snd_pcm_t *pcm; snd_pcm_hw_params_t *hw_params; @@ -264,20 +293,17 @@ sdmin=snd_pcm_info_get_subdevice(alsa_info); sdmax=sdmin+snd_pcm_info_get_subdevices_count(alsa_info); MSG_INFO("AO-INFO: show caps for device %i:%i-%i\n",device,sdmin,sdmax); - for(j=sdmin;j<=sdmax;j++) - { + for(j=sdmin;j<=sdmax;j++) { int i; snd_pcm_info_set_subdevice(alsa_info,j); sprintf(adevice,"hw:%u,%u",snd_pcm_info_get_device(alsa_info),snd_pcm_info_get_subdevice(alsa_info)); MSG_INFO("AO-INFO: %s %s.%s.%s\n\n",adevice,snd_pcm_info_get_id(alsa_info),snd_pcm_info_get_name(alsa_info),snd_pcm_info_get_subdevice_name(alsa_info)); - if(snd_pcm_open(&pcm,adevice,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK)<0) - { + if(snd_pcm_open(&pcm,adevice,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK)<0) { MSG_ERR("alsa-init: playback open error: %s\n", snd_strerror(err)); return; } snd_pcm_hw_params_malloc(&hw_params); - if(snd_pcm_hw_params_any(pcm, hw_params)<0) - { + if(snd_pcm_hw_params_any(pcm, hw_params)<0) { MSG_ERR("alsa-init: can't get initial parameters: %s\n", snd_strerror(err)); return; } @@ -311,8 +337,7 @@ open & setup audio device return: 1=success 0=fail */ -static MPXP_Rc __FASTCALL__ init(ao_data_t* ao,unsigned flags) -{ +MPXP_Rc Alsa_AO_Interface::open(unsigned flags) { int err; int cards = -1; snd_pcm_info_t *alsa_info; @@ -321,21 +346,18 @@ char *alsa_port=NULL; char alsa_device[ALSA_DEVICE_SIZE]; UNUSED(flags); - priv_t*priv; - priv=new(zeromem) priv_t; - ao->priv=priv; - priv->first=1; + first=1; - priv->handler = NULL; + handler = NULL; alsa_device[0]='\0'; MSG_V("alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR); - if (ao->subdevice) { + if (!subdevice.empty()) { const char *param; char *p; // example: -ao alsa:hw:0#mmap=1 - param=mrl_parse_line(ao->subdevice,NULL,NULL,&alsa_dev,&alsa_port); + param=mrl_parse_line(subdevice,NULL,NULL,&alsa_dev,&alsa_port); mrl_parse_params(param,alsaconf); if(alsa_port) { p=strchr(alsa_port,','); @@ -395,12 +417,12 @@ str_block_mode = "block-mode"; } - if (!priv->handler) { + if (!handler) { //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC - if ((err = snd_pcm_open(&priv->handler, alsa_device, SND_PCM_STREAM_PLAYBACK, open_mode)) < 0) { + if ((err = snd_pcm_open(&handler, alsa_device, SND_PCM_STREAM_PLAYBACK, open_mode)) < 0) { if (priv_conf.noblock) { MSG_ERR("alsa-init: open in nonblock-mode failed, trying to open in block-mode\n"); - if ((err = snd_pcm_open(&priv->handler, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + if ((err = snd_pcm_open(&handler, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { MSG_ERR("alsa-init: playback open error: %s\n", snd_strerror(err)); alsa_device[0]='\0'; return MPXP_False; @@ -414,128 +436,118 @@ return MPXP_False; } } - alsa_device[0]='\0'; - if ((err = snd_pcm_nonblock(priv->handler, block_mode)) < 0) { - MSG_ERR("alsa-init: error set block-mode %s\n", snd_strerror(err)); - } - else MSG_V("alsa-init: pcm opend in %s\n", str_block_mode); + alsa_device[0]='\0'; + if ((err = snd_pcm_nonblock(handler, block_mode)) < 0) { + MSG_ERR("alsa-init: error set block-mode %s\n", snd_strerror(err)); + } else MSG_V("alsa-init: pcm opend in %s\n", str_block_mode); - snd_pcm_hw_params_malloc(&priv->hwparams); - snd_pcm_sw_params_malloc(&priv->swparams); + snd_pcm_hw_params_malloc(&hwparams); + snd_pcm_sw_params_malloc(&swparams); - // setting hw-parameters - if ((err = snd_pcm_hw_params_any(priv->handler, priv->hwparams)) < 0) - { - MSG_ERR("alsa-init: unable to get initial parameters: %s\n", + // setting hw-parameters + if ((err = snd_pcm_hw_params_any(handler, hwparams)) < 0) { + MSG_ERR("alsa-init: unable to get initial parameters: %s\n", snd_strerror(err)); - return MPXP_False; + return MPXP_False; } - MSG_DBG2("snd_pcm_hw_params_any()\n"); - if (priv_conf.mmap) { - snd_pcm_access_mask_t *mask = (snd_pcm_access_mask_t*)alloca(snd_pcm_access_mask_sizeof()); - snd_pcm_access_mask_none(mask); - snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); - snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); - snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX); - err = snd_pcm_hw_params_set_access_mask(priv->handler, priv->hwparams, mask); - MSG_ERR("alsa-init: mmap set\n"); - } else { - err = snd_pcm_hw_params_set_access(priv->handler, priv->hwparams,SND_PCM_ACCESS_RW_INTERLEAVED); - MSG_DBG2("snd_pcm_hw_params_set_access(SND_PCM_ACCESS_RW_INTERLEAVED)\n"); - } - if (err < 0) { - MSG_ERR("alsa-init: unable to set access type: %s\n", snd_strerror(err)); - return MPXP_False; - } + MSG_DBG2("snd_pcm_hw_params_any()\n"); + if (priv_conf.mmap) { + snd_pcm_access_mask_t *mask = (snd_pcm_access_mask_t*)alloca(snd_pcm_access_mask_sizeof()); + snd_pcm_access_mask_none(mask); + snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX); + err = snd_pcm_hw_params_set_access_mask(handler, hwparams, mask); + MSG_ERR("alsa-init: mmap set\n"); + } else { + err = snd_pcm_hw_params_set_access(handler, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED); + MSG_DBG2("snd_pcm_hw_params_set_access(SND_PCM_ACCESS_RW_INTERLEAVED)\n"); + } + if (err < 0) { + MSG_ERR("alsa-init: unable to set access type: %s\n", snd_strerror(err)); + return MPXP_False; + } } // end switch priv->handler (spdif) return MPXP_Ok; } // end init -static MPXP_Rc __FASTCALL__ config_ao(ao_data_t* ao,unsigned rate_hz,unsigned channels,unsigned format) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +MPXP_Rc Alsa_AO_Interface::configure(unsigned r,unsigned c,unsigned f) { int err,i; size_t chunk_size=0,chunk_bytes,bits_per_sample,bits_per_frame; snd_pcm_uframes_t dummy; - MSG_V("alsa-conf: requested format: %d Hz, %d channels, %s\n", rate_hz, - channels, ao_format_name(format)); + MSG_V("alsa-conf: requested format: %d Hz, %d channels, %s\n", r, + c, ao_format_name(f)); - ao->samplerate = rate_hz; - ao->bps = channels * rate_hz; - ao->format = format; - ao->channels = channels; - ao->outburst = OUTBURST; + _samplerate = r; + _format = f; + _channels = c; + _outburst = OUTBURST; //ao->buffersize = MAX_OUTBURST; // was 16384 - priv->format=fmt2alsa(format); + snd_format=fmt2alsa(_format); - switch(priv->format) { + switch(snd_format) { case SND_PCM_FORMAT_S16_LE: case SND_PCM_FORMAT_U16_LE: case SND_PCM_FORMAT_S16_BE: case SND_PCM_FORMAT_U16_BE: - ao->bps *= 2; - break; case SND_PCM_FORMAT_S32_LE: case SND_PCM_FORMAT_S32_BE: case SND_PCM_FORMAT_U32_LE: case SND_PCM_FORMAT_U32_BE: case SND_PCM_FORMAT_FLOAT_BE: case SND_PCM_FORMAT_FLOAT_LE: - ao->bps *= 4; - break; case SND_PCM_FORMAT_S24_LE: case SND_PCM_FORMAT_S24_BE: case SND_PCM_FORMAT_U24_LE: case SND_PCM_FORMAT_U24_BE: - ao->bps *= 3; break; case -1: MSG_ERR("alsa-conf: invalid format (%s) requested - output disabled\n", - ao_format_name(format)); + ao_format_name(_format)); return MPXP_False; default: break; } - priv->bytes_per_sample = ao->bps / ao->samplerate; + bytes_per_sample = bps() / _samplerate; - if ((err = snd_pcm_hw_params_set_format(priv->handler, priv->hwparams, - priv->format)) < 0) { + if ((err = snd_pcm_hw_params_set_format(handler, hwparams, + snd_format)) < 0) { MSG_ERR("alsa-conf: unable to set format(%s): %s\n", - snd_pcm_format_name(priv->format), + snd_pcm_format_name(snd_format), snd_strerror(err)); MSG_HINT("Please try one of: "); for(i=0;i<SND_PCM_FORMAT_LAST;i++) - if (!(snd_pcm_hw_params_test_format(priv->handler, priv->hwparams, snd_pcm_format_t(i)))) + if (!(snd_pcm_hw_params_test_format(handler, hwparams, snd_pcm_format_t(i)))) MSG_HINT("%s ",snd_pcm_format_name(snd_pcm_format_t(i))); MSG_HINT("\n"); return MPXP_False; } - MSG_DBG2("snd_pcm_hw_params_set_format(%i)\n",priv->format); + MSG_DBG2("snd_pcm_hw_params_set_format(%i)\n",snd_format); - if ((err = snd_pcm_hw_params_set_rate_near(priv->handler, priv->hwparams, &ao->samplerate, 0)) < 0) { + if ((err = snd_pcm_hw_params_set_rate_near(handler, hwparams, &_samplerate, 0)) < 0) { MSG_ERR("alsa-conf: unable to set samplerate %u: %s\n", - ao->samplerate, + _samplerate, snd_strerror(err)); return MPXP_False; } - MSG_DBG2("snd_pcm_hw_params_set_rate_near(%i)\n",ao->samplerate); + MSG_DBG2("snd_pcm_hw_params_set_rate_near(%i)\n",_samplerate); - if ((err = snd_pcm_hw_params_set_channels(priv->handler, priv->hwparams, - ao->channels)) < 0) { + if ((err = snd_pcm_hw_params_set_channels(handler, hwparams, + _channels)) < 0) { MSG_ERR("alsa-conf: unable to set %u channels: %s\n", - ao->channels, + _channels, snd_strerror(err)); return MPXP_False; } - MSG_DBG2("snd_pcm_hw_params_set_channels(%i)\n",ao->channels); + MSG_DBG2("snd_pcm_hw_params_set_channels(%i)\n",_channels); #ifdef BUFFERTIME { int dir; unsigned period_time,alsa_buffer_time = 500000; /* buffer time in us */ - if ((err = snd_pcm_hw_params_set_buffer_time_near(priv->handler, priv->hwparams, &alsa_buffer_time, &dir)) < 0) { + if ((err = snd_pcm_hw_params_set_buffer_time_near(handler, hwparams, &alsa_buffer_time, &dir)) < 0) { MSG_ERR("alsa-init: unable to set buffer time near: %s\n", snd_strerror(err)); return MPXP_False; @@ -543,7 +555,7 @@ MSG_DBG2("snd_pcm_hw_set_buffer_time_near(%i)\n",alsa_buffer_time); period_time = alsa_buffer_time/4; - if ((err = snd_pcm_hw_params_set_period_time_near(priv->handler, priv->hwparams, &period_time, &dir)) < 0) { + if ((err = snd_pcm_hw_params_set_period_time_near(handler, hwparams, &period_time, &dir)) < 0) { /* original: alsa_buffer_time/ao->bps */ MSG_ERR("alsa-init: unable to set period time: %s\n", snd_strerror(err)); @@ -557,14 +569,14 @@ int dir=0; unsigned period_time=100000; /* period time in us */ snd_pcm_uframes_t size; - if ((err = snd_pcm_hw_params_set_period_time_near(priv->handler, priv->hwparams, &period_time, &dir)) < 0) { + if ((err = snd_pcm_hw_params_set_period_time_near(handler, hwparams, &period_time, &dir)) < 0) { MSG_ERR("alsa-init: unable to set period_time: %s\n", snd_strerror(err)); return MPXP_False; } MSG_DBG2("snd_pcm_hw_set_period_time(%i)\n",period_time); //get chunksize - if ((err = snd_pcm_hw_params_get_period_size(priv->hwparams, &size, &dir)) < 0) { + if ((err = snd_pcm_hw_params_get_period_size(hwparams, &size, &dir)) < 0) { MSG_ERR("alsa-init: unable to get period_size: %s\n", snd_strerror(err)); return MPXP_False; } @@ -573,23 +585,23 @@ } #endif // gets buffersize for control_ao - if ((err = snd_pcm_hw_params_get_buffer_size(priv->hwparams,&dummy)) < 0) { + if ((err = snd_pcm_hw_params_get_buffer_size(hwparams,&dummy)) < 0) { MSG_ERR("alsa-conf: unable to get buffersize: %s\n", snd_strerror(err)); return MPXP_False; } else { - ao->buffersize = dummy * priv->bytes_per_sample; - MSG_V("alsa-conf: got buffersize=%i\n", ao->buffersize); + _buffersize = dummy * bytes_per_sample; + MSG_V("alsa-conf: got buffersize=%i\n", _buffersize); } MSG_DBG2("snd_pcm_hw_params_get_buffer_size(%i)\n",dummy); - bits_per_sample = snd_pcm_format_physical_width(priv->format); + bits_per_sample = snd_pcm_format_physical_width(snd_format); MSG_DBG2("%i=snd_pcm_hw_format_pohysical_width()\n",bits_per_sample); - bits_per_frame = bits_per_sample * channels; + bits_per_frame = bits_per_sample * _channels; chunk_bytes = chunk_size * bits_per_frame / 8; MSG_V("alsa-conf: bits per sample (bps)=%i, bits per frame (bpf)=%i, chunk_bytes=%i\n",bits_per_sample,bits_per_frame,chunk_bytes); /* finally install hardware parameters */ - if ((err = snd_pcm_hw_params(priv->handler, priv->hwparams)) < 0) { + if ((err = snd_pcm_hw_params(handler, hwparams)) < 0) { MSG_ERR("alsa-conf: unable to set hw-parameters: %s\n", snd_strerror(err)); return MPXP_False; @@ -597,76 +609,42 @@ MSG_DBG2("snd_pcm_hw_params()\n"); // setting sw-params (only avail-min) if noblocking mode was choosed if (priv_conf.noblock) { - if ((err = snd_pcm_sw_params_current(priv->handler, priv->swparams)) < 0) { + if ((err = snd_pcm_sw_params_current(handler, swparams)) < 0) { MSG_ERR("alsa-conf: unable to get parameters: %s\n",snd_strerror(err)); return MPXP_False; } //set min available frames to consider pcm ready (4) //increased for nonblock-mode should be set dynamically later - if ((err = snd_pcm_sw_params_set_avail_min(priv->handler, priv->swparams, 4)) < 0) { + if ((err = snd_pcm_sw_params_set_avail_min(handler, swparams, 4)) < 0) { MSG_ERR("alsa-conf: unable to set avail_min %s\n",snd_strerror(err)); return MPXP_False; } - if ((err = snd_pcm_sw_params(priv->handler, priv->swparams)) < 0) { + if ((err = snd_pcm_sw_params(handler, swparams)) < 0) { MSG_ERR("alsa-conf: unable to install sw-params\n"); return MPXP_False; } }//end swparams - if ((err = snd_pcm_prepare(priv->handler)) < 0) { + if ((err = snd_pcm_prepare(handler)) < 0) { MSG_ERR("alsa-conf: pcm prepare error: %s\n", snd_strerror(err)); return MPXP_False; } // end setting hw-params MSG_V("alsa-conf: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", - ao->samplerate, ao->channels, priv->bytes_per_sample, ao->buffersize, - snd_pcm_format_description(priv->format)); + _samplerate, _channels, bytes_per_sample, _buffersize, + snd_pcm_format_description(snd_format)); return MPXP_Ok; } // end config_ao -/* close audio device */ -static void uninit(ao_data_t* ao) -{ +void Alsa_AO_Interface::pause() { int err; - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); - if(!priv->handler) { - MSG_ERR("alsa-uninit: no handler defined!\n"); - delete priv; - return; - } if (!priv_conf.noblock) { - if ((err = snd_pcm_drain(priv->handler)) < 0) { - MSG_ERR("alsa-uninit: pcm drain error: %s\n", snd_strerror(err)); - delete priv; - return; - } - } - - if ((err = snd_pcm_close(priv->handler)) < 0) { - MSG_ERR("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); - delete priv; - return; - } else { - priv->handler = NULL; - MSG_V("alsa-uninit: pcm closed\n"); - } - snd_pcm_hw_params_free(priv->hwparams); - snd_pcm_sw_params_free(priv->swparams); - delete priv; -} - -static void audio_pause(ao_data_t* ao) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); - int err; - - if (!priv_conf.noblock) { //drain causes error in nonblock-mode! - if ((err = snd_pcm_drain(priv->handler)) < 0) { + if ((err = snd_pcm_drain(handler)) < 0) { MSG_ERR("alsa-pause: pcm drain error: %s\n", snd_strerror(err)); return; } @@ -676,28 +654,24 @@ } } -static void audio_resume(ao_data_t* ao) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +void Alsa_AO_Interface::resume() { int err; - if ((err = snd_pcm_prepare(priv->handler)) < 0) { + if ((err = snd_pcm_prepare(handler)) < 0) { MSG_ERR("alsa-resume: pcm prepare error: %s\n", snd_strerror(err)); return; } } /* stop playing and empty buffers (for seeking/pause) */ -static void reset(ao_data_t* ao) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +void Alsa_AO_Interface::reset() { int err; - if ((err = snd_pcm_drop(priv->handler)) < 0) { + if ((err = snd_pcm_drop(handler)) < 0) { MSG_ERR("alsa-reset: pcm drop error: %s\n", snd_strerror(err)); return; } - if ((err = snd_pcm_prepare(priv->handler)) < 0) { + if ((err = snd_pcm_prepare(handler)) < 0) { MSG_ERR("alsa-reset: pcm prepare error: %s\n", snd_strerror(err)); return; } @@ -718,28 +692,23 @@ } #endif -#ifndef timersub -#define timersub(a, b, result) \ -do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ -} while (0) -#endif +static void _timersub(const struct timeval*a,const struct timeval* b,struct timeval* result) { + result->tv_sec = a->tv_sec - b->tv_sec; + result->tv_usec = a->tv_usec - b->tv_usec; + if (result->tv_usec < 0) { + --result->tv_sec; + result->tv_usec += 1000000; + } +} /* I/O error handler */ -static int __FASTCALL__ xrun(const ao_data_t* ao,const char *str_mode) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +int Alsa_AO_Interface::xrun(const char *str_mode) const { int err; snd_pcm_status_t *status; snd_pcm_status_alloca(&status); - if ((err = snd_pcm_status(priv->handler, status))<0) { + if ((err = snd_pcm_status(handler, status))<0) { MSG_ERR("status error: %s", snd_strerror(err)); return 0; } @@ -748,13 +717,13 @@ struct timeval now, diff, tstamp; gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); - timersub(&now, &tstamp, &diff); + _timersub(&now, &tstamp, &diff); MSG_V("alsa-%s: xrun of at least %.3f msecs. resetting stream\n", str_mode, diff.tv_sec * 1000 + diff.tv_usec / 1000.0); } - if ((err = snd_pcm_prepare(priv->handler))<0) { + if ((err = snd_pcm_prepare(handler))<0) { MSG_ERR("xrun: prepare error: %s", snd_strerror(err)); return 0; } @@ -762,16 +731,12 @@ return 1; /* ok, data should be accepted again */ } -static unsigned __FASTCALL__ play_normal(ao_data_t* ao,const any_t* data, unsigned len); -static unsigned __FASTCALL__ play_mmap(ao_data_t* ao,const any_t* data, unsigned len); - -static unsigned __FASTCALL__ play(ao_data_t* ao,const any_t* data, unsigned len, unsigned flags) -{ +unsigned Alsa_AO_Interface::play(const any_t* data, unsigned len, unsigned flags) { unsigned result; UNUSED(flags); MSG_DBG2("[ao_alsa] %s playing %i bytes\n",priv_conf.mmap?"mmap":"normal",len); - if (priv_conf.mmap) result = play_mmap(ao,data, len); - else result = play_normal(ao,data, len); + if (priv_conf.mmap) result = play_mmap(data, len); + else result = play_normal(data, len); return result; } @@ -782,36 +747,33 @@ thanxs for marius <ma...@ro...> for giving us the light ;) */ -static unsigned __FASTCALL__ play_normal(ao_data_t* ao,const any_t* data, unsigned len) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); - //priv->bytes_per_sample is always 4 for 2 chn S16_LE - unsigned num_frames = len / priv->bytes_per_sample; - char *output_samples = (char *)data; +unsigned Alsa_AO_Interface::play_normal(const any_t* data, unsigned len) { + unsigned num_frames = len / bytes_per_sample; + const char *output_samples = (const char *)data; snd_pcm_sframes_t res = 0; //fprintf(stderr,"alsa-play: frames=%i, len=%i\n",num_frames,len); - if (!priv->handler) { + if (!handler) { MSG_ERR("alsa-play: device configuration error"); return 0; } while (num_frames > 0) { - res = snd_pcm_writei(priv->handler, (any_t*)output_samples, num_frames); + res = snd_pcm_writei(handler, (any_t*)output_samples, num_frames); if (res == -EAGAIN) { - snd_pcm_wait(priv->handler, 1000); + snd_pcm_wait(handler, 1000); } else if (res == -EPIPE) { /* underrun */ - if (xrun(ao,"play") <= 0) { + if (xrun("play") <= 0) { MSG_ERR("alsa-play: xrun reset error"); return 0; } } else if (res == -ESTRPIPE) { /* suspend */ MSG_WARN("alsa-play: pcm in suspend mode. trying to resume\n"); - while ((res = snd_pcm_resume(priv->handler)) == -EAGAIN) sleep(1); + while ((res = snd_pcm_resume(handler)) == -EAGAIN) ::sleep(1); } else if (res < 0) { MSG_ERR("alsa-play: unknown status, trying to reset soundcard\n"); - if ((res = snd_pcm_prepare(priv->handler)) < 0) { + if ((res = snd_pcm_prepare(handler)) < 0) { MSG_ERR("alsa-play: snd prepare error"); return 0; break; @@ -820,7 +782,7 @@ if (res > 0) { /* output_samples += ao->channels * res; */ - output_samples += res * priv->bytes_per_sample; + output_samples += res * bytes_per_sample; num_frames -= res; } } //end while @@ -836,51 +798,49 @@ * 'An overview of the ALSA API' http://people.debian.org/~joshua/x66.html * and some help by Paul Davis <pb...@op...> */ -static unsigned __FASTCALL__ play_mmap(ao_data_t* ao,const any_t* data, unsigned len) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +unsigned Alsa_AO_Interface::play_mmap(const any_t* data, unsigned len) { snd_pcm_sframes_t commitres, frames_available; snd_pcm_uframes_t frames_transmit, size, offset; const snd_pcm_channel_area_t *area; - any_t*outbuffer; + any_t* outbuffer; unsigned result; #ifdef USE_POLL //seems not really be needed struct pollfd *ufds; int count; - count = snd_pcm_poll_descriptors_count (priv->handler); + count = snd_pcm_poll_descriptors_count (handler); ufds = mp_malloc(sizeof(struct pollfd) * count); - snd_pcm_poll_descriptors(priv->handler, ufds, count); + snd_pcm_poll_descriptors(handler, ufds, count); //first wait_for_poll - if (err = (wait_for_poll(priv->handler, ufds, count) < 0)) { - if (snd_pcm_state(priv->handler) == SND_PCM_STATE_XRUN || - snd_pcm_state(priv->handler) == SND_PCM_STATE_SUSPENDED) { + if (err = (wait_for_poll(handler, ufds, count) < 0)) { + if (snd_pcm_state(handler) == SND_PCM_STATE_XRUN || + snd_pcm_state(handler) == SND_PCM_STATE_SUSPENDED) { xrun("play"); } } #endif - outbuffer = alloca(ao->buffersize); + outbuffer = alloca(_buffersize); //don't trust get_space() ;) - frames_available = snd_pcm_avail_update(priv->handler) * priv->bytes_per_sample; - if (frames_available < 0) xrun(ao,"play"); + frames_available = snd_pcm_avail_update(handler) * bytes_per_sample; + if (frames_available < 0) xrun("play"); if (frames_available < 4) { - if (priv->first) { - priv->first = 0; - snd_pcm_start(priv->handler); + if (first) { + first = 0; + snd_pcm_start(handler); } else { //FIXME should break and return 0? - snd_pcm_wait(priv->handler, -1); - priv->first = 1; + snd_pcm_wait(handler, -1); + first = 1; } } /* len is simply the available bufferspace got by get_space() * but real avail_buffer in frames is ab/priv->bytes_per_sample */ - size = len / priv->bytes_per_sample; + size = len / bytes_per_sample; //if (verbose) //printf("len: %i size %i, f_avail %i, bps %i ...\n", len, size, frames_available, priv->bytes_per_sample); @@ -890,43 +850,26 @@ /* prepare areas and set sw-pointers * frames_transmit returns the real available buffer-size * sometimes != frames_available cause of ringbuffer 'emulation' */ - snd_pcm_mmap_begin(priv->handler, &area, &offset, &frames_transmit); + snd_pcm_mmap_begin(handler, &area, &offset, &frames_transmit); /* this is specific to interleaved streams (or non-interleaved * streams with only one channel) */ outbuffer = ((char *) area->addr + (area->first + area->step * offset) / 8); //8 //write data - memcpy(outbuffer, data, (frames_transmit * priv->bytes_per_sample)); - commitres = snd_pcm_mmap_commit(priv->handler, offset, frames_transmit); + memcpy(outbuffer, data, (frames_transmit * bytes_per_sample)); + commitres = snd_pcm_mmap_commit(handler, offset, frames_transmit); if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames_transmit) { - if (snd_pcm_state(priv->handler) == SND_PCM_STATE_XRUN || - snd_pcm_state(priv->handler) == SND_PCM_STATE_SUSPENDED) { - xrun(ao,"play"); + if (snd_pcm_state(handler) == SND_PCM_STATE_XRUN || + snd_pcm_state(handler) == SND_PCM_STATE_SUSPENDED) { + xrun("play"); } } - //if (verbose) - //printf("mmap ft: %i, cres: %i\n", frames_transmit, commitres); - - /* err = snd_pcm_area_copy(&area, offset, &data, offset, len, priv->format); */ - /* if (err < 0) { */ - /* printf("area-copy-error\n"); */ - /* return 0; */ - /* } */ - //calculate written frames! - result = commitres * priv->bytes_per_sample; + result = commitres * bytes_per_sample; - - /* if (verbose) { */ - /* if (len == result) */ - /* printf("result: %i, frames written: %i ...\n", result, frames_transmit); */ - /* else */ - /* printf("result: %i, frames written: %i, result != len ...\n", result, frames_transmit); */ - /* } */ - //mplayer doesn't like -result if ((int)result < 0) result = 0; @@ -946,9 +889,7 @@ GET_SPACE_UNDEFINED }space_status; /* how many byes are mp_free in the buffer */ -static unsigned get_space(const ao_data_t* ao) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +unsigned Alsa_AO_Interface::get_space() { snd_pcm_status_t *status; int ret,st; space_status e_status=GET_SPACE_UNDEFINED; @@ -960,7 +901,7 @@ return 0; } - if ((ret = snd_pcm_status(priv->handler, status)) < 0) { + if ((ret = snd_pcm_status(handler, status)) < 0) { MSG_ERR("alsa-space: cannot get pcm status: %s\n", snd_strerror(ret)); return 0; } @@ -971,14 +912,14 @@ case SND_PCM_STATE_PREPARED: if (e_status!=GET_SPACE_OPEN) { e_status = GET_SPACE_PREPARED; - priv->first = 1; - ret = snd_pcm_status_get_avail(status) * priv->bytes_per_sample; + first = 1; + ret = snd_pcm_status_get_avail(status) * bytes_per_sample; if (ret == 0) //ugly workaround for hang in mmap-mode ret = 10; break; } case SND_PCM_STATE_RUNNING: - ret = snd_pcm_status_get_avail(status) * priv->bytes_per_sample; + ret = snd_pcm_status_get_avail(status) * bytes_per_sample; //avail_frames = snd_pcm_avail_update(priv->handler) * priv->bytes_per_sample; if (e_status!=GET_SPACE_OPEN && e_status!=GET_SPACE_PREPARED) e_status = GET_SPACE_RUNNING; @@ -989,16 +930,16 @@ ret = 0; break; case SND_PCM_STATE_XRUN: - xrun(ao,"space"); + xrun("space"); e_status = GET_SPACE_XRUN; - priv->first = 1; + first = 1; ret = 0; break; default: e_status = GET_SPACE_UNDEFINED; - ret = snd_pcm_status_get_avail(status) * priv->bytes_per_sample; + ret = snd_pcm_status_get_avail(status) * bytes_per_sample; if (ret <= 0) { - xrun(ao,"space"); + xrun("space"); } } @@ -1015,10 +956,9 @@ } /* delay in seconds between first and last sample in buffer */ -static float get_delay(const ao_data_t* ao) +float Alsa_AO_Interface::get_delay() { - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); - if (priv->handler) { + if (handler) { snd_pcm_status_t *status; int r; float ret; @@ -1028,7 +968,7 @@ return 0; } - if ((ret = snd_pcm_status(priv->handler, status)) < 0) { + if ((ret = snd_pcm_status(handler, status)) < 0) { MSG_ERR("alsa-delay: cannot get pcm status: %s\n", snd_strerror(ret)); return 0; } @@ -1038,7 +978,7 @@ case SND_PCM_STATE_PREPARED: case SND_PCM_STATE_RUNNING: r=snd_pcm_status_get_delay(status); - ret = (float)r/(float)ao->samplerate; + ret = (float)r/(float)_samplerate; break; default: ret = 0; @@ -1049,3 +989,36 @@ return ret; } else return 0; } + +unsigned Alsa_AO_Interface::samplerate() const { return _samplerate; } +unsigned Alsa_AO_Interface::channels() const { return _channels; } +unsigned Alsa_AO_Interface::format() const { return _format; } +unsigned Alsa_AO_Interface::buffersize() const { return _buffersize; } +unsigned Alsa_AO_Interface::outburst() const { return _outburst; } +MPXP_Rc Alsa_AO_Interface::test_channels(unsigned c) const { + return snd_pcm_hw_params_test_channels(handler, hwparams,c)==0? + MPXP_True:MPXP_False; +} +MPXP_Rc Alsa_AO_Interface::test_rate(unsigned r) const { + return snd_pcm_hw_params_test_rate(handler, hwparams,r,0)==0? + MPXP_True:MPXP_False; +} +MPXP_Rc Alsa_AO_Interface::test_format(unsigned f) const { + snd_pcm_format_t rval; + rval=fmt2alsa(f); + return snd_pcm_hw_params_test_format(handler, hwparams,snd_pcm_format_t(rval))==0? + MPXP_True:MPXP_False; +} + +static AO_Interface* query_interface(const std::string& sd) { return new Alsa_AO_Interface(sd); } + +extern const ao_info_t audio_out_alsa = +{ + "ALSA-1.x audio output", + "alsa", + "Alex Beregszaszi <al...@na...>, Joy Winter <jo...@pi...>", + "under developement", + query_interface +}; +} //namespace mpxp + Modified: mplayerxp/libao2/ao_arts.cpp =================================================================== --- mplayerxp/libao2/ao_arts.cpp 2012-12-13 14:55:16 UTC (rev 559) +++ mplayerxp/libao2/ao_arts.cpp 2012-12-14 14:52:33 UTC (rev 560) @@ -32,33 +32,57 @@ #include "afmt.h" #include "ao_msg.h" +namespace mpxp { /* Feel mp_free to experiment with the following values: */ #define ARTS_PACKETS 10 /* Number of audio packets */ #define ARTS_PACKET_SIZE_LOG2 11 /* Log2 of audio packet size */ +class Arts_AO_Interface : public AO_Interface { + public: + Arts_AO_Interface(const std::string& subdevice); + virtual ~Arts_AO_Interface(); -static const ao_info_t info = -{ - "aRts audio output", - "arts", - "Michele Balistreri <br...@gm...>", - "" + virtual MPXP_Rc open(unsigned flags); + virtual MPXP_Rc configure(unsigned rate,unsigned channels,unsigned format); + virtual unsigned samplerate() const; + virtual unsigned channels() const; + virtual unsigned format() const; + virtual unsigned buffersize() const; + virtual unsigned outburst() const; + virtual MPXP_Rc test_rate(unsigned r) const; + virtual MPXP_Rc test_channels(unsigned c) const; + virtual MPXP_Rc test_format(unsigned f) const; + virtual void reset(); + virtual unsigned get_space(); + virtual float get_delay(); + virtual unsigned play(const any_t* data,unsigned len,unsigned flags); + virtual void pause(); + virtual void resume(); + virtual MPXP_Rc ctrl(int cmd,long arg) const; + private: + unsigned _channels,_samplerate,_format; + unsigned _buffersize,_outburst; + unsigned bps() const { return _channels*_samplerate*afmt2bps(_format); } + + arts_stream_t stream; }; -LIBAO_EXTERN(arts) +Arts_AO_Interface::Arts_AO_Interface(const std::string& _subdevice) + :AO_Interface(_subdevice) {} +Arts_AO_Interface::~Arts_AO_Interface() { + arts_close_stream(stream); + arts_free(); +} -static MPXP_Rc control_ao(const ao_data_t* ao,int cmd, long arg) -{ - UNUSED(ao); +MPXP_Rc Arts_AO_Interface::ctrl(int cmd, long arg) const { UNUSED(cmd); UNUSED(arg); return MPXP_Unknown; } -static MPXP_Rc init(ao_data_t* ao,unsigned flags) +MPXP_Rc Arts_AO_Interface::open(unsigned flags) { int err; - UNUSED(ao); UNUSED(flags); if( (err=arts_init()) ) { @@ -70,9 +94,7 @@ return MPXP_Ok; } -static MPXP_Rc __FASTCALL__ config_ao(ao_data_t* ao,unsigned rate,unsigned channels,unsigned format) -{ - arts_stream_t stream; +MPXP_Rc Arts_AO_Interface::configure(unsigned r,unsigned c,unsigned f) { unsigned frag_spec,samplesize; /* * arts supports 8bit unsigned and 16bit signed sample formats @@ -82,10 +104,13 @@ * Unsupported formats are translated to one of these two formats * using mplayer's audio filters. */ - switch (format) { + _samplerate=r; + _channels=c; + _format=f; + switch (f) { case AFMT_U8: case AFMT_S8: - format = AFMT_U8; + _format = AFMT_U8; samplesize=1; break; #if 0 @@ -93,31 +118,25 @@ case AFMT_S24_BE: case AFMT_U24_LE: case AFMT_U24_BE: - format = AFMT_S24_LE; + _format = AFMT_S24_LE; samplesize=3; break; case AFMT_S32_LE: case AFMT_S32_BE: case AFMT_U32_LE: case AFMT_U32_BE: - format = AFMT_S32_LE; + _format = AFMT_S32_LE; samplesize=4; break; #endif default: samplesize=2; - format = AFMT_S16_LE; /* artsd always expects little endian?*/ + _format = AFMT_S16_LE; /* artsd always expects little endian?*/ break; } - ao->format = format; - ao->channels = channels; - ao->samplerate = rate; - ao->bps = rate*channels*samplesize; + stream=arts_play_stream(_samplerate, samplesize*8, _channels, "MPlayerXP"); - stream=arts_play_stream(rate, samplesize*8, channels, "MPlayerXP"); - ao->priv=stream; - if(stream == NULL) { MSG_ERR("[aRts] Can't open stream\n"); arts_free(); @@ -129,47 +148,61 @@ arts_stream_set(stream, ARTS_P_BLOCKING, 1); frag_spec = ARTS_PACKET_SIZE_LOG2 | ARTS_PACKETS << 16; arts_stream_set(stream, ARTS_P_PACKET_SETTINGS, frag_spec); - ao->buffersize = arts_stream_get(stream, ARTS_P_BUFFER_SIZE); + _buffersize = arts_stream_get(stream, ARTS_P_BUFFER_SIZE); MSG_INFO("[aRts] Stream opened\n"); - MSG_V("[aRts] buffersize=%u\n",ao->buffersize); + MSG_V("[aRts] buffersize=%u\n",_buffersize); MSG_V("[aRts] buffersize=%u\n", arts_stream_get(stream, ARTS_P_PACKET_SIZE)); return MPXP_Ok; } -static void uninit(ao_data_t* ao) +unsigned Arts_AO_Interface::play(const any_t* data,unsigned len,unsigned flags) { - arts_stream_t stream=ao->priv; - arts_close_stream(stream); - arts_free(); -} - -static unsigned play(ao_data_t* ao,const any_t* data,unsigned len,unsigned flags) -{ - arts_stream_t stream=ao->priv; UNUSED(flags); return arts_write(stream, data, len); } -static void audio_pause(ao_data_t* ao) -{ - UNUSED(ao); +void Arts_AO_Interface::pause() {} +void Arts_AO_Interface::resume() {} +void Arts_AO_Interface::reset() {} +unsigned Arts_AO_Interface::get_space() { + return arts_stream_get(stream, ARTS_P_BUFFER_SPACE); } -static void audio_resume(ao_data_t* ao) { UNUSED(ao); } -static void reset(ao_data_t* ao) { UNUSED(ao); } +float Arts_AO_Interface::get_delay() { + return ((float) (_buffersize - arts_stream_get(stream, + ARTS_P_BUFFER_SPACE))) / ((float) bps()); +} -static unsigned get_space(const ao_data_t* ao) -{ - arts_stream_t stream=ao->priv; - return arts_stream_get(stream, ARTS_P_BUFFER_SPACE); +unsigned Arts_AO_Interface::samplerate() const { return _samplerate; } +unsigned Arts_AO_Interface::channels() const { return _channels; } +unsigned Arts_AO_Interface::format() const { return _format; } +unsigned Arts_AO_Interface::buffersize() const { return _buffersize; } +unsigned Arts_AO_Interface::outburst() const { return _outburst; } +MPXP_Rc Arts_AO_Interface::test_channels(unsigned c) const { UNUSED(c); return MPXP_Ok; } +MPXP_Rc Arts_AO_Interface::test_rate(unsigned r) const { UNUSED(r); return MPXP_Ok; } +MPXP_Rc Arts_AO_Interface::test_format(unsigned f) const { + switch (f) { + case AFMT_U8: + case AFMT_S8: + case AFMT_U16_LE: + case AFMT_S16_LE: + case AFMT_U16_BE: + case AFMT_S16_BE: return MPXP_Ok; + default: break; + } + return MPXP_False; } -static float get_delay(const ao_data_t* ao) +static AO_Interface* query_interface(const std::string& sd) { return new Arts_AO_Interface(sd); } + +extern const ao_info_t audio_out_arts = { - arts_stream_t stream=ao->priv; - return ((float) (ao->buffersize - arts_stream_get(stream, - ARTS_P_BUFFER_SPACE))) / ((float) ao->bps); -} - + "aRts audio output", + "arts", + "Michele Balistreri <br...@gm...>", + "", + query_interface +}; +} // namespace mpxp Modified: mplayerxp/libao2/ao_esd.cpp =================================================================== --- mplayerxp/libao2/ao_esd.cpp 2012-12-13 14:55:16 UTC (rev 559) +++ mplayerxp/libao2/ao_esd.cpp 2012-12-14 14:52:33 UTC (rev 560) @@ -56,6 +56,8 @@ #include "afmt.h" #include "ao_msg.h" + +namespace mpxp { #define ESD_RESAMPLES 0 #define ESD_DEBUG 0 @@ -65,37 +67,68 @@ #define dprintf(...) /**/ #endif - #define ESD_CLIENT_NAME "MPlayerXP" #define ESD_MAX_DELAY (1.0f) /* max amount of data buffered in esd (#sec) */ -static const ao_info_t info = -{ - "EsounD audio output", - "esd", - "Juergen Keil <jk...@to...>", - "" +class Esd_AO_Interface : public AO_Interface { + public: + Esd_AO_Interface(const std::string& subdevice); + virtual ~Esd_AO_Interface(); + + virtual MPXP_Rc open(unsigned flags); + virtual MPXP_Rc configure(unsigned rate,unsigned channels,unsigned format); + virtual unsigned samplerate() const; + virtual unsigned channels() const; + virtual unsigned format() const; + virtual unsigned buffersize() const; + virtual unsigned outburst() const; + virtual MPXP_Rc test_rate(unsigned r) const; + virtual MPXP_Rc test_channels(unsigned c) const; + virtual MPXP_Rc test_format(unsigned f) const; + virtual void reset(); + virtual unsigned get_space(); + virtual float get_delay(); + virtual unsigned play(const any_t* data,unsigned len,unsigned flags); + virtual void pause(); + virtual void resume(); + virtual MPXP_Rc ctrl(int cmd,long arg) const; + private: + unsigned _channels,_samplerate,_format; + unsigned _buffersize,_outburst; + unsigned bps() const { return _channels*_samplerate*afmt2bps(_format); } + + int fd; + int play_fd; + esd_server_info_t*svinfo; + int latency; + int bytes_per_sample; + unsigned long samples_written; + struct timeval play_start; + float audio_delay; }; -LIBAO_EXTERN(esd) +Esd_AO_Interface::Esd_AO_Interface(const std::string& _subdevice) + :AO_Interface(_subdevice) {} +Esd_AO_Interface::~Esd_AO_Interface() { + if (play_fd >= 0) { + esd_close(play_fd); + play_fd = -1; + } -typedef struct priv_s { - int fd; - int play_fd; - esd_server_info_t* svinfo; - int latency; - int bytes_per_sample; - unsigned long samples_written; - struct timeval play_start; - float audio_delay; -}priv_t; + if (svinfo) { + esd_free_server_info(svinfo); + svinfo = NULL; + } + if (fd >= 0) { + esd_close(fd); + fd = -1; + } +} /* * to set/get/query special features/parameters */ -static MPXP_Rc control_ao(const ao_data_t* ao,int cmd, long arg) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +MPXP_Rc Esd_AO_Interface::ctrl(int cmd, long arg) const { esd_player_info_t *esd_pi; esd_info_t *esd_i; time_t now; @@ -111,7 +144,7 @@ } dprintf("esd: get vol\n"); - if ((esd_i = esd_get_all_info(priv->fd)) == NULL) + if ((esd_i = esd_get_all_info(fd)) == NULL) return MPXP_Error; for (esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next) @@ -132,7 +165,7 @@ case AOCONTROL_SET_VOLUME: dprintf("esd: set vol\n"); - if ((esd_i = esd_get_all_info(priv->fd)) == NULL) + if ((esd_i = esd_get_all_info(fd)) == NULL) return MPXP_Error; for (esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next) @@ -141,7 +174,7 @@ if (esd_pi != NULL) { ao_control_vol_t *vol = (ao_control_vol_t *)arg; - esd_set_stream_pan(priv->fd, esd_pi->source_id, + esd_set_stream_pan(fd, esd_pi->source_id, vol->left * ESD_VOLUME_BASE / 100, vol->right * ESD_VOLUME_BASE / 100); @@ -161,17 +194,12 @@ * open & setup audio device * return: 1=success 0=fail */ -static MPXP_Rc init(ao_data_t* ao,unsigned flags) -{ - priv_t*priv; - ao->priv=new(zeromem) priv_t; - ao->priv=priv; - priv->fd=priv->play_fd=-1; - char *server = ao->subdevice; /* NULL for localhost */ +MPXP_Rc Esd_AO_Interface::open(unsigned flags) { + fd=play_fd=-1; UNUSED(flags); - if (priv->fd < 0) { - priv->fd = esd_open_sound(server); - if (priv->fd < 0) { + if (fd < 0) { + fd = esd_open_sound(subdevice.c_str()); + if (fd < 0) { MSG_ERR("ESD: Can't open sound: %s\n", strerror(errno)); return MPXP_False; } @@ -179,67 +207,60 @@ return MPXP_Ok; } -static MPXP_Rc config_ao(ao_data_t* ao,unsigned rate_hz,unsigned channels,unsigned format) +MPXP_Rc Esd_AO_Interface::configure(unsigned r,unsigned c,unsigned f) { - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); - char *server = ao->subdevice; /* NULL for localhost */ + std::string server = subdevice; /* NULL for localhost */ esd_format_t esd_fmt; - int bytes_per_sample; + int _bytes_per_sample; int fl; float lag_seconds, lag_net, lag_serv; struct timeval proto_start, proto_end; - /* get server info, and measure network latency */ - gettimeofday(&proto_start, NULL); - priv->svinfo = esd_get_server_info(priv->fd); - if(server) { - gettimeofday(&proto_end, NULL); - lag_net = (proto_end.tv_sec - proto_start.tv_sec) + - (proto_end.tv_usec - proto_start.tv_usec) / 1000000.0; - lag_net /= 2.0; /* round trip -> one way */ - } else - lag_net = 0.0; /* no network lag */ - /* - if (priv->svinfo) { - mp_msg(MSGT_AO, MSGL_INFO, "AO: [esd] server info:\n"); - esd_print_server_info(priv->svinfo); - } - */ + /* get server info, and measure network latency */ + gettimeofday(&proto_start, NULL); + svinfo = esd_get_server_info(fd); + if(!server.empty()) { + gettimeofday(&proto_end, NULL); + lag_net = (proto_end.tv_sec - proto_start.tv_sec) + + (proto_end.tv_usec - proto_start.tv_usec) / 1000000.0; + lag_net /= 2.0; /* round trip -> one way */ + } else + lag_net = 0.0; /* no network lag */ esd_fmt = ESD_STREAM | ESD_PLAY; #if ESD_RESAMPLES /* let the esd daemon convert sample rate */ #else /* let mplayer's audio filter convert the sample rate */ - if (priv->svinfo != NULL) - rate_hz = priv->svinfo->rate; + if (svinfo != NULL) + r = svinfo->rate; #endif - ao->samplerate = rate_hz; + _samplerate = r; - /* EsounD can play mono or stereo */ - switch (channels) { - case 1: - esd_fmt |= ESD_MONO; - ao->channels = bytes_per_sample = 1; + /* EsounDscan play mono or stereo */ + switch (c) { + case 1: + esd_fmt |= ESD_MONO; + _channels = _bytes_per_sample = 1; + break; + default: + esd_fmt |= ESD_STEREO; + _channels = _bytes_per_sample = 2; break; - default: - esd_fmt |= ESD_STEREO; - ao->channels = bytes_per_sample = 2; - break; } /* EsounD can play 8bit unsigned and 16bit signed native */ - switch (format) { - case AFMT_S8: - case AFMT_U8: - esd_fmt |= ESD_BITS8; - ao->format = AFMT_U8; - break; - default: - esd_fmt |= ESD_BITS16; - ao->format = AFMT_S16_NE; - bytes_per_sample *= 2; - break; + switch (f) { + case AFMT_S8: + case AFMT_U8: + esd_fmt |= ESD_BITS8; + _format = AFMT_U8; + break; + default: + esd_fmt |= ESD_BITS16; + _format = AFMT_S16_NE; + _bytes_per_sample *= 2; + break; } /* modify priv->audio_delay depending on priv->latency @@ -247,86 +268,57 @@ * adjust according to rate_hz & bytes_per_sample */ #ifdef CONFIG_ESD_LATENCY - priv->latency = esd_get_latency(priv->fd); + latency = esd_get_latency(fd); #else - priv->latency = ((channels == 1 ? 2 : 1) * ESD_DEFAULT_RATE * - (ESD_BUF_SIZE + 64 * (4.0f / bytes_per_sample)) - ) / rate_hz; - priv->latency += ESD_BUF_SIZE * 2; + latency = ((_channels == 1 ? 2 : 1) * ESD_DEFAULT_RATE * + (ESD_BUF_SIZE + 64 * (4.0f / _bytes_per_sample)) + ) / _samplerate; + latency += ESD_BUF_SIZE * 2; #endif - if(priv->latency > 0) { - lag_serv = (priv->latency * 4.0f) / (bytes_per_sample * rate_hz); + if(latency > 0) { + lag_serv = (latency * 4.0f) / (_bytes_per_sample * _samplerate); lag_seconds = lag_net + lag_serv; - priv->audio_delay += lag_seconds; + audio_delay += lag_seconds; MSG_INFO("ESD: LatencyInfo: %f %f %f\n",lag_serv, lag_net, lag_seconds); } - priv->play_fd = esd_play_stream_fallback(esd_fmt, rate_hz, - server, ESD_CLIENT_NAME); - if (priv->play_fd < 0) { + play_fd = esd_play_stream_fallback(esd_fmt, _samplerate, + server.c_str(), ESD_CLIENT_NAME); + if (play_fd < 0) { MSG_ERR("ESD: Can't open play stream: %s\n", strerror(errno)); return MPXP_False; } /* enable non-blocking i/o on the socket connection to the esd server */ - if ((fl = fcntl(priv->play_fd, F_GETFL)) >= 0) - fcntl(priv->play_fd, F_SETFL, O_NDELAY|fl); + if ((fl = ::fcntl(play_fd, F_GETFL)) >= 0) ::fcntl(play_fd, F_SETFL, O_NDELAY|fl); #if ESD_DEBUG { int sbuf, rbuf, len; len = sizeof(sbuf); - getsockopt(priv->play_fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &len); + getsockopt(play_fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &len); len = sizeof(rbuf); - getsockopt(priv->play_fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &len); + getsockopt(play_fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &len); dprintf("esd: send/receive socket buffer space %d/%d bytes\n", sbuf, rbuf); } #endif - ao->bps = bytes_per_sample * rate_hz; - ao->outburst = ao->bps > 100000 ? 4*ESD_BUF_SIZE : 2*ESD_BUF_SIZE; + _outburst = bps() > 100000 ? 4*ESD_BUF_SIZE : 2*ESD_BUF_SIZE; - priv->play_start.tv_sec = 0; - priv->samples_written = 0; - priv->bytes_per_sample = bytes_per_sample; + play_start.tv_sec = 0; + samples_written = 0; + bytes_per_sample = _bytes_per_sample; return MPXP_Ok; } - /* - * close audio device - */ -static void uninit(ao_data_t* ao) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); - if (priv->play_fd >= 0) { - esd_close(priv->play_fd); - priv->play_fd = -1; - } - - if (priv->svinfo) { - esd_free_server_info(priv->svinfo); - priv->svinfo = NULL; - } - - if (priv->fd >= 0) { - esd_close(priv->fd); - priv->fd = -1; - } - delete priv; -} - - -/* * plays 'len' bytes of 'data' * it should round it down to outburst*n * return: number of bytes played */ -static unsigned play(ao_data_t* ao,const any_t* data, unsigned len, unsigned flags) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +unsigned Esd_AO_Interface::play(const any_t* data, unsigned len, unsigned flags) { unsigned offs; unsigned nwritten; int nsamples; @@ -337,14 +329,14 @@ #define SINGLE_WRITE 0 #if SINGLE_WRITE - nwritten = write(priv->play_fd, data, len); + nwritten = ::write(play_fd, data, len); #else for (offs = 0, nwritten=0; offs + ESD_BUF_SIZE <= len; offs += ESD_BUF_SIZE) { /* * note: we're writing to a non-blocking socket here. * A partial write means, that the socket buffer is full. */ - n = write(priv->play_fd, (char*)data + offs, ESD_BUF_SIZE); + n = ::write(play_fd, (char*)data + offs, ESD_BUF_SIZE); if ( n < 0 ) { if ( errno != EAGAIN ) { dprintf("esd play: write failed: %s\n", strerror(errno)); @@ -359,39 +351,26 @@ #endif if (nwritten > 0) { - if (!priv->play_start.tv_sec) - gettimeofday(&priv->play_start, NULL); - nsamples = nwritten / priv->bytes_per_sample; - priv->samples_written += nsamples; + if (!play_start.tv_sec) + ::gettimeofday(&play_start, NULL); + nsamples = nwritten / bytes_per_sample; + samples_written += nsamples; - dprintf("esd play: %d %lu\n", nsamples, priv->samples_written); + dprintf("esd play: %d %lu\n", nsamples, samples_written); } else { - dprintf("esd play: blocked / %lu\n", priv->samples_written); + dprintf("esd play: blocked / %lu\n", samples_written); } - return nwritten; } - /* * stop playing, keep buffers (for pause) */ -static void audio_pause(ao_data_t* ao) -{ - /* - * not possible with priv-> the esd daemom will continue playing - * buffered data (not more than ESD_MAX_DELAY seconds of samples) - */ - UNUSED(ao); -} - - +void Esd_AO_Interface::pause() {} /* * resume playing, after audio_pause() */ -static void audio_resume(ao_data_t* ao) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +void Esd_AO_Interface::resume() { /* * not possible with priv-> * @@ -399,33 +378,25 @@ * buffered data; we restart our time based delay computation * for an audio resume. */ - priv->play_start.tv_sec = 0; - priv->samples_written = 0; + play_start.tv_sec = 0; + samples_written = 0; } - /* * stop playing and empty buffers (for seeking/pause) */ -static void reset(ao_data_t* ao) -{ +void Esd_AO_Interface::reset() { #ifdef __svr4__ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); /* throw away data buffered in the esd connection */ - if (ioctl(priv->play_fd, I_FLUSH, FLUSHW)) - perror("I_FLUSH"); -#else - UNUSED(ao); + if (::ioctl(play_fd, I_FLUSH, FLUSHW)) perror("I_FLUSH"); #endif } - /* * return: how many bytes can be played without blocking */ -static unsigned get_space(const ao_data_t* ao) +unsigned Esd_AO_Interface::get_space() { - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); struct timeval tmout; fd_set wfds; float current_delay; @@ -438,24 +409,24 @@ * device, and the consequence is a huge slow down for things like * esd_get_all_info(). */ - if ((current_delay = get_delay(ao)) >= ESD_MAX_DELAY) { + if ((current_delay = get_delay()) >= ESD_MAX_DELAY) { dprintf("esd get_space: too much data buffered\n"); return 0; } FD_ZERO(&wfds); - FD_SET(priv->play_fd, &wfds); + FD_SET(play_fd, &wfds); tmout.tv_sec = 0; tmout.tv_usec = 0; - if (select(priv->play_fd + 1, NULL, &wfds, NULL, &tmout) != 1) + if (::select(play_fd + 1, NULL, &wfds, NULL, &tmout) != 1) return 0; - if (!FD_ISSET(priv->play_fd, &wfds)) + if (!FD_ISSET(play_fd, &wfds)) return 0; /* try to fill 50% of the remaining "mp_free" buffer space */ - space = (ESD_MAX_DELAY - current_delay) * ao->bps * 0.5f; + space = (ESD_MAX_DELAY - current_delay) * bps() * 0.5f; /* round up to next multiple of ESD_BUF_SIZE */ space = (space + ESD_BUF_SIZE-1) / ESD_BUF_SIZE * ESD_BUF_SIZE; @@ -464,34 +435,50 @@ return space; } - /* * return: delay in seconds between first and last sample in buffer */ -static float get_delay(const ao_data_t* ao) -{ - priv_t*priv=reinterpret_cast<priv_t*>(ao->priv); +float Esd_AO_Interface::get_delay() { struct timeval now; double buffered_samples_time; double play_time; - if (!priv->play_start.tv_sec) - return 0; + if (!play_start.tv_sec) return 0; - buffered_samples_time = (float)priv->samples_written / ao->samplerate; - gettimeofday(&now, NULL); - play_time = now.tv_sec - priv->play_start.tv_sec; - play_time += (now.tv_usec - priv->play_start.tv_usec) / 1000000.; + buffered_samples_time = (float)samples_written / _samplerate; + ::gettimeofday(&now, NULL); + play_time = now.tv_sec - play_start.tv_sec; + play_time += (now.tv_usec - play_start.tv_usec) / 1000000.; /* dprintf("esd delay: %f %f\n", play_time, buffered_samples_time); */ if (play_time > buffered_samples_time) { dprintf("esd: underflow\n"); - priv->play_start.tv_sec = 0; - priv->samples_written = 0; + play_start.tv_sec = 0; + samples_written = 0; return 0; } dprintf("esd: get_delay %f\n", buffered_samples_time - play_time); return buffered_samples_time - play_time; } + +unsigned Esd_AO_Interface::samplerate() const { return _samplerate; } +unsigned Esd_AO_Interface::channels() const { return _channels; } +unsigned Esd_AO_Interface::format() const { return _format; } +unsigned Esd_AO_Interface::buffersize() const { return _buffersize; } +unsigned Esd_AO_Interface::outburst() const { return _outburst; } +MPXP_Rc Esd_AO_Interface::test_channels(unsigned c) const { UNUSED(c); return MPXP_Ok; } +MPXP_Rc Esd_AO_Interface::test_rate(unsigned r) const { UNUSED(r); return MPXP_Ok; } +MPXP_Rc Esd_AO_Interface::test_format(unsigned f) const { UNUSED(f); return MPXP_Ok; } + +static AO_Interface* query_interface(const std::string& sd) { return new Esd_AO_Interface(sd); } + +extern const ao_info_t audio_out_esd = { + "EsounD audio output", + "esd", + "Juergen Keil <jk...@to...>", + "", + query_interface +}; +} // namespace mpxp Modified: mplayerxp/libao2/ao_jack.cpp =================================================================== --- mplayerxp/libao2/ao_jack.cpp 2012-12-13 14:55:16 UTC (rev 559) +++ mplayerxp/libao2/ao_jack.cpp 2012-12-14 14:52:33 UTC (rev 560) @@ -39,42 +39,71 @@ #include "mp_conf_lavc.h" #include <jack/jack.h> -static const ao_info_t info = -{ - "JACK audio output", - "jack", - "Reimar Döffinger <Rei...@st...>", - "based on ao_sdl.c" -}; +namespace mpxp { -LIBAO_EXTERN(jack) - //! maximum number of channels supported, avoids lots of mallocs #define MAX_CHANS 6 -typedef struct priv_s { - jack_port_t * ports[MAX_CHANS]; - unsigned num_ports; ///< Number of used ports == number of channels - jack_client_t * client; - float latency; - int estimate; - volatile int paused; ///< set if paused - volatile int underrun; ///< signals if an priv->underrun occured +class Jack_AO_Interface : public AO_Interface { + public: + Jack_AO_Interface(const std::string& subdevice); + virtual ~Jack_AO_Interface(); - volatile float callback_interval; - volatile float callback_time; + virtual MPXP_Rc open(unsigned flags); + virtual MPXP_Rc configure(unsigned rate,unsigned channels,unsigned format); + virtual unsigned samplerate() const; + virtual unsigned channels() const; + virtual unsigned format() const; + virtual unsigned buffersize() const; + virtual unsigned outburst() const; + virtual MPXP_Rc test_rate(unsigned r) const; + virtual MPXP_Rc test_channels(unsigned c) const; + virtual MPXP_Rc test_format(unsigned f) const; + virtual void reset(); + virtual unsigned get_space(); + virtual float get_delay(); + virtual unsigned play(const any_t* data,unsigned len,unsigned flags); + virtual void pause(); + virtual void resume(); + virtual MPXP_Rc ctrl(int cmd,long arg) const; + static void deinterleave_data(any_t*_info, any_t*src, int len); + static int outputaudio(jack_nframes_t nframes, any_t* _ao); + private: + unsigned _channels,_samplerate,_format; + unsigned _buffersize,_outburst; + unsigned bps() const { return _channels*_samplerate*afmt2bps(_format); } + unsigned read_buffer(float **bufs, unsigned cnt, unsigned num_bufs); + int write_buffer(const unsigned char* data, int len); + static void silence(float **bufs, int cnt, int num_bufs); - AVFifoBuffer * buffer; //! buffer for audio data -}priv_t; + jack_port_t * ports[MAX_CHANS]; + unsigned num_ports; ///< Number of used ports == number of channels + jack_client_t * client; + float latency; + int estimate; + volatile int paused; ///< set if paused + volatile int underrun; ///< signals if an priv->underrun occur... [truncated message content] |