diff options
Diffstat (limited to 'libao2/ao_alsa.c')
-rw-r--r-- | libao2/ao_alsa.c | 137 |
1 files changed, 79 insertions, 58 deletions
diff --git a/libao2/ao_alsa.c b/libao2/ao_alsa.c index 57f0bd07cb..6d30003187 100644 --- a/libao2/ao_alsa.c +++ b/libao2/ao_alsa.c @@ -72,9 +72,13 @@ static snd_pcm_format_t alsa_format; static snd_pcm_hw_params_t *alsa_hwparams; static snd_pcm_sw_params_t *alsa_swparams; +#define BUFFER_TIME 500000 // 0.5 s +#define FRAGCOUNT 16 + static size_t bytes_per_sample; static int alsa_can_pause; +static snd_pcm_sframes_t prepause_frames; #define ALSA_DEVICE_SIZE 256 @@ -134,8 +138,8 @@ static int control(int cmd, void *arg) mix_index = strtol(test_mix_index, &test_mix_index, 0); if (*test_mix_index){ - mp_msg(MSGT_AO,MSGL_ERR, - MSGTR_AO_ALSA_InvalidMixerIndexDefaultingToZero); + mp_tmsg(MSGT_AO,MSGL_ERR, + "[AO_ALSA] Invalid mixer index. Defaulting to 0.\n"); mix_index = 0 ; } } @@ -155,32 +159,32 @@ static int control(int cmd, void *arg) } if ((err = snd_mixer_open(&handle, 0)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerOpenError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer open error: %s\n", snd_strerror(err)); return CONTROL_ERROR; } if ((err = snd_mixer_attach(handle, card)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerAttachError, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer attach %s error: %s\n", card, snd_strerror(err)); snd_mixer_close(handle); return CONTROL_ERROR; } if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerRegisterError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer register error: %s\n", snd_strerror(err)); snd_mixer_close(handle); return CONTROL_ERROR; } err = snd_mixer_load(handle); if (err < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerLoadError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer load error: %s\n", snd_strerror(err)); snd_mixer_close(handle); return CONTROL_ERROR; } elem = snd_mixer_find_selem(handle, sid); if (!elem) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToFindSimpleControl, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to find simple control '%s',%i.\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); snd_mixer_close(handle); return CONTROL_ERROR; @@ -195,7 +199,7 @@ static int control(int cmd, void *arg) //setting channels if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingLeftChannel, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Error setting left channel, %s\n", snd_strerror(err)); snd_mixer_close(handle); return CONTROL_ERROR; @@ -205,7 +209,7 @@ static int control(int cmd, void *arg) set_vol = vol->right / f_multi + pmin + 0.5; if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingRightChannel, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Error setting right channel, %s\n", snd_strerror(err)); snd_mixer_close(handle); return CONTROL_ERROR; @@ -253,8 +257,15 @@ static void parse_device (char *dest, const char *src, int len) static void print_help (void) { - mp_msg (MSGT_AO, MSGL_FATAL, - MSGTR_AO_ALSA_CommandlineHelp); + mp_tmsg (MSGT_AO, MSGL_FATAL, + "\n[AO_ALSA] -ao alsa commandline help:\n"\ + "[AO_ALSA] Example: mplayer -ao alsa:device=hw=0.3\n"\ + "[AO_ALSA] Sets first card fourth hardware device.\n\n"\ + "[AO_ALSA] Options:\n"\ + "[AO_ALSA] noblock\n"\ + "[AO_ALSA] Opens device in non-blocking mode.\n"\ + "[AO_ALSA] device=<device-name>\n"\ + "[AO_ALSA] Sets device (change , to . and : to =)\n"); } static int str_maxlen(void *strp) { @@ -313,8 +324,6 @@ static int try_open_device(const char *device, int open_mode, int try_ac3) */ static int init(int rate_hz, int channels, int format, int flags) { - unsigned int alsa_buffer_time = 500000; /* 0.5 s */ - unsigned int alsa_fragcount = 16; int err; int block; strarg_t device; @@ -340,6 +349,8 @@ static int init(int rate_hz, int channels, int format, int flags) mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR); #endif + prepause_frames = 0; + snd_lib_error_set_handler(alsa_error_handler); ao_data.samplerate = rate_hz; @@ -457,7 +468,7 @@ static int init(int rate_hz, int channels, int format, int flags) break; default: device.str = "default"; - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ChannelsNotSupported,channels); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] %d channels are not supported.\n",channels); } device.len = strlen(device.str); if (subopt_parse(ao_subdevice, subopts) != 0) { @@ -475,19 +486,19 @@ static int init(int rate_hz, int channels, int format, int flags) if ((err = try_open_device(alsa_device, open_mode, isac3)) < 0) { if (err != -EBUSY && !block) { - mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed); + mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Open in nonblock-mode failed, trying to open in block-mode.\n"); if ((err = try_open_device(alsa_device, 0, isac3)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Playback open error: %s\n", snd_strerror(err)); return 0; } } else { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Playback open error: %s\n", snd_strerror(err)); return 0; } } if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSetBlockMode, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AL_ALSA] Error setting block-mode %s.\n", snd_strerror(err)); } else { mp_msg(MSGT_AO,MSGL_V,"alsa-init: pcm opened in blocking mode\n"); } @@ -498,7 +509,7 @@ static int init(int rate_hz, int channels, int format, int flags) // setting hw-parameters if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetInitialParameters, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get initial parameters: %s\n", snd_strerror(err)); return 0; } @@ -506,7 +517,7 @@ static int init(int rate_hz, int channels, int format, int flags) err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetAccessType, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set access type: %s\n", snd_strerror(err)); return 0; } @@ -516,8 +527,8 @@ static int init(int rate_hz, int channels, int format, int flags) if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams, alsa_format)) < 0) { - mp_msg(MSGT_AO,MSGL_INFO, - MSGTR_AO_ALSA_FormatNotSupportedByHardware, af_fmt2str_short(format)); + mp_tmsg(MSGT_AO,MSGL_INFO, + "[AO_ALSA] Format %s is not supported by hardware, trying default.\n", af_fmt2str_short(format)); alsa_format = SND_PCM_FORMAT_S16_LE; if (AF_FORMAT_IS_AC3(ao_data.format)) ao_data.format = AF_FORMAT_AC3_LE; @@ -528,7 +539,7 @@ static int init(int rate_hz, int channels, int format, int flags) if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams, alsa_format)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetFormat, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set format: %s\n", snd_strerror(err)); return 0; } @@ -536,7 +547,7 @@ static int init(int rate_hz, int channels, int format, int flags) if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams, &ao_data.channels)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetChannels, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set channels: %s\n", snd_strerror(err)); return 0; } @@ -548,7 +559,7 @@ static int init(int rate_hz, int channels, int format, int flags) if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams, 0)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToDisableResampling, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to disable resampling: %s\n", snd_strerror(err)); return 0; } @@ -557,7 +568,7 @@ static int init(int rate_hz, int channels, int format, int flags) if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, &ao_data.samplerate, NULL)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSamplerate2, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set samplerate-2: %s\n", snd_strerror(err)); return 0; } @@ -567,16 +578,16 @@ static int init(int rate_hz, int channels, int format, int flags) ao_data.bps = ao_data.samplerate * bytes_per_sample; if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, - &alsa_buffer_time, NULL)) < 0) + &(unsigned int){BUFFER_TIME}, NULL)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetBufferTimeNear, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set buffer time near: %s\n", snd_strerror(err)); return 0; } if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams, - &alsa_fragcount, NULL)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriods, + &(unsigned int){FRAGCOUNT}, NULL)) < 0) { + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set periods: %s\n", snd_strerror(err)); return 0; } @@ -584,7 +595,7 @@ static int init(int rate_hz, int channels, int format, int flags) /* finally install hardware parameters */ if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetHwParameters, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set hw-parameters: %s\n", snd_strerror(err)); return 0; } @@ -594,7 +605,7 @@ static int init(int rate_hz, int channels, int format, int flags) // gets buffersize for control if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBufferSize, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get buffersize: %s\n", snd_strerror(err)); return 0; } else { @@ -603,7 +614,7 @@ static int init(int rate_hz, int channels, int format, int flags) } if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetPeriodSize, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO ALSA] Unable to get period size: %s\n", snd_strerror(err)); return 0; } else { mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size); @@ -612,13 +623,13 @@ static int init(int rate_hz, int channels, int format, int flags) /* setting software parameters */ if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get sw-parameters: %s\n", snd_strerror(err)); return 0; } #if SND_LIB_VERSION >= 0x000901 if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBoundary, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get boundary: %s\n", snd_strerror(err)); return 0; } @@ -627,26 +638,26 @@ static int init(int rate_hz, int channels, int format, int flags) #endif /* start playing when one period has been written */ if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStartThreshold, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set start threshold: %s\n", snd_strerror(err)); return 0; } /* disable underrun reporting */ if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStopThreshold, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set stop threshold: %s\n", snd_strerror(err)); return 0; } #if SND_LIB_VERSION >= 0x000901 /* play silence when there is an underrun */ if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSilenceSize, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set silence size: %s\n", snd_strerror(err)); return 0; } #endif if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters, + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get sw-parameters: %s\n", snd_strerror(err)); return 0; } @@ -674,7 +685,7 @@ static void uninit(int immed) if ((err = snd_pcm_close(alsa_handler)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmCloseError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm close error: %s\n", snd_strerror(err)); return; } else { @@ -683,7 +694,7 @@ static void uninit(int immed) } } else { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_NoHandlerDefined); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] No handler defined!\n"); } } @@ -694,14 +705,18 @@ static void audio_pause(void) if (alsa_can_pause) { if ((err = snd_pcm_pause(alsa_handler, 1)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPauseError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm pause error: %s\n", snd_strerror(err)); return; } mp_msg(MSGT_AO,MSGL_V,"alsa-pause: pause supported by hardware\n"); } else { + if (snd_pcm_delay(alsa_handler, &prepause_frames) < 0 + || prepause_frames < 0) + prepause_frames = 0; + if ((err = snd_pcm_drop(alsa_handler)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmDropError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm drop error: %s\n", snd_strerror(err)); return; } } @@ -712,22 +727,27 @@ static void audio_resume(void) int err; if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) { - mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_PcmInSuspendModeTryingResume); + mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Pcm in suspend mode, trying to resume.\n"); while ((err = snd_pcm_resume(alsa_handler)) == -EAGAIN) sleep(1); } if (alsa_can_pause) { if ((err = snd_pcm_pause(alsa_handler, 0)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmResumeError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm resume error: %s\n", snd_strerror(err)); return; } mp_msg(MSGT_AO,MSGL_V,"alsa-resume: resume supported by hardware\n"); } else { if ((err = snd_pcm_prepare(alsa_handler)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err)); return; } + if (prepause_frames) { + void *silence = calloc(prepause_frames, bytes_per_sample); + play(silence, prepause_frames * bytes_per_sample, 0); + free(silence); + } } } @@ -736,14 +756,15 @@ static void reset(void) { int err; + prepause_frames = 0; if ((err = snd_pcm_drop(alsa_handler)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err)); return; } if ((err = snd_pcm_prepare(alsa_handler)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err)); return; } return; @@ -767,7 +788,7 @@ static int play(void* data, int len, int flags) //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len); if (!alsa_handler) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_DeviceConfigurationError); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Device configuration error."); return 0; } @@ -782,15 +803,15 @@ static int play(void* data, int len, int flags) res = 0; } else if (res == -ESTRPIPE) { /* suspend */ - mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_PcmInSuspendModeTryingResume); + mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Pcm in suspend mode, trying to resume.\n"); while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN) sleep(1); } if (res < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_WriteError, snd_strerror(res)); - mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_TryingToResetSoundcard); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Write error: %s\n", snd_strerror(res)); + mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Trying to reset soundcard.\n"); if ((res = snd_pcm_prepare(alsa_handler)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(res)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(res)); return 0; break; } @@ -810,14 +831,14 @@ static int get_space(void) if ((ret = snd_pcm_status(alsa_handler, status)) < 0) { - mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_CannotGetPcmStatus, snd_strerror(ret)); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Cannot get pcm status: %s\n", snd_strerror(ret)); return 0; } - ret = snd_pcm_status_get_avail(status) * bytes_per_sample; - if (ret > ao_data.buffersize) // Buffer underrun? - ret = ao_data.buffersize; - return ret; + unsigned space = snd_pcm_status_get_avail(status) * bytes_per_sample; + if (space > ao_data.buffersize) // Buffer underrun? + space = ao_data.buffersize; + return space; } /* delay in seconds between first and last sample in buffer */ |