mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	alsa: rework buffer/period configuration
- As discussed on alsa-devel it's probably better to initialize the buffer size first, followed by the period size. If that fails try the other way round. If that fails try to configure only buffer size. If that fails try to configure only period size. Finally, try to configure neither. - Don't require integral periods anymore. Both of these changes should help improving compatibility with various weirder sound devices, such as TV cards.
This commit is contained in:
		
							parent
							
								
									71e066c873
								
							
						
					
					
						commit
						557c429510
					
				
					 4 changed files with 216 additions and 129 deletions
				
			
		| 
						 | 
					@ -116,7 +116,6 @@ struct userdata {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_usec_t watermark_dec_not_before;
 | 
					    pa_usec_t watermark_dec_not_before;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unsigned nfragments;
 | 
					 | 
				
			||||||
    pa_memchunk memchunk;
 | 
					    pa_memchunk memchunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *device_name;  /* name of the PCM device */
 | 
					    char *device_name;  /* name of the PCM device */
 | 
				
			||||||
| 
						 | 
					@ -943,8 +942,7 @@ static int unsuspend(struct userdata *u) {
 | 
				
			||||||
    pa_sample_spec ss;
 | 
					    pa_sample_spec ss;
 | 
				
			||||||
    int err;
 | 
					    int err;
 | 
				
			||||||
    pa_bool_t b, d;
 | 
					    pa_bool_t b, d;
 | 
				
			||||||
    unsigned nfrags;
 | 
					    snd_pcm_uframes_t period_size, buffer_size;
 | 
				
			||||||
    snd_pcm_uframes_t period_size;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_assert(u);
 | 
					    pa_assert(u);
 | 
				
			||||||
    pa_assert(!u->pcm_handle);
 | 
					    pa_assert(!u->pcm_handle);
 | 
				
			||||||
| 
						 | 
					@ -961,12 +959,12 @@ static int unsuspend(struct userdata *u) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss = u->sink->sample_spec;
 | 
					    ss = u->sink->sample_spec;
 | 
				
			||||||
    nfrags = u->nfragments;
 | 
					 | 
				
			||||||
    period_size = u->fragment_size / u->frame_size;
 | 
					    period_size = u->fragment_size / u->frame_size;
 | 
				
			||||||
 | 
					    buffer_size = u->hwbuf_size / u->frame_size;
 | 
				
			||||||
    b = u->use_mmap;
 | 
					    b = u->use_mmap;
 | 
				
			||||||
    d = u->use_tsched;
 | 
					    d = u->use_tsched;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, u->hwbuf_size / u->frame_size, &b, &d, TRUE)) < 0) {
 | 
					    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, TRUE)) < 0) {
 | 
				
			||||||
        pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));
 | 
					        pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -981,10 +979,11 @@ static int unsuspend(struct userdata *u) {
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) {
 | 
					    if (period_size*u->frame_size != u->fragment_size ||
 | 
				
			||||||
        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)",
 | 
					        buffer_size*u->frame_size != u->hwbuf_size) {
 | 
				
			||||||
                    (unsigned long) u->nfragments, (unsigned long) u->fragment_size,
 | 
					        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)",
 | 
				
			||||||
                    (unsigned long) nfrags, period_size * u->frame_size);
 | 
					                    (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size,
 | 
				
			||||||
 | 
					                    (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size));
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1638,8 +1637,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 | 
				
			||||||
    const char *dev_id = NULL;
 | 
					    const char *dev_id = NULL;
 | 
				
			||||||
    pa_sample_spec ss, requested_ss;
 | 
					    pa_sample_spec ss, requested_ss;
 | 
				
			||||||
    pa_channel_map map;
 | 
					    pa_channel_map map;
 | 
				
			||||||
    uint32_t nfrags, frag_size, tsched_size, tsched_watermark;
 | 
					    uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark;
 | 
				
			||||||
    snd_pcm_uframes_t period_frames, tsched_frames;
 | 
					    snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
 | 
				
			||||||
    size_t frame_size;
 | 
					    size_t frame_size;
 | 
				
			||||||
    pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;
 | 
					    pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;
 | 
				
			||||||
    pa_sink_new_data data;
 | 
					    pa_sink_new_data data;
 | 
				
			||||||
| 
						 | 
					@ -1673,7 +1672,10 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buffer_size = nfrags * frag_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    period_frames = frag_size/frame_size;
 | 
					    period_frames = frag_size/frame_size;
 | 
				
			||||||
 | 
					    buffer_frames = buffer_size/frame_size;
 | 
				
			||||||
    tsched_frames = tsched_size/frame_size;
 | 
					    tsched_frames = tsched_size/frame_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
 | 
					    if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
 | 
				
			||||||
| 
						 | 
					@ -1740,7 +1742,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 | 
				
			||||||
                      &u->device_name,
 | 
					                      &u->device_name,
 | 
				
			||||||
                      &ss, &map,
 | 
					                      &ss, &map,
 | 
				
			||||||
                      SND_PCM_STREAM_PLAYBACK,
 | 
					                      SND_PCM_STREAM_PLAYBACK,
 | 
				
			||||||
                      &nfrags, &period_frames, tsched_frames,
 | 
					                      &period_frames, &buffer_frames, tsched_frames,
 | 
				
			||||||
                      &b, &d, mapping)))
 | 
					                      &b, &d, mapping)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
| 
						 | 
					@ -1755,7 +1757,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 | 
				
			||||||
                      &u->device_name,
 | 
					                      &u->device_name,
 | 
				
			||||||
                      &ss, &map,
 | 
					                      &ss, &map,
 | 
				
			||||||
                      SND_PCM_STREAM_PLAYBACK,
 | 
					                      SND_PCM_STREAM_PLAYBACK,
 | 
				
			||||||
                      &nfrags, &period_frames, tsched_frames,
 | 
					                      &period_frames, &buffer_frames, tsched_frames,
 | 
				
			||||||
                      &b, &d, profile_set, &mapping)))
 | 
					                      &b, &d, profile_set, &mapping)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
| 
						 | 
					@ -1767,7 +1769,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 | 
				
			||||||
                      &u->device_name,
 | 
					                      &u->device_name,
 | 
				
			||||||
                      &ss, &map,
 | 
					                      &ss, &map,
 | 
				
			||||||
                      SND_PCM_STREAM_PLAYBACK,
 | 
					                      SND_PCM_STREAM_PLAYBACK,
 | 
				
			||||||
                      &nfrags, &period_frames, tsched_frames,
 | 
					                      &period_frames, &buffer_frames, tsched_frames,
 | 
				
			||||||
                      &b, &d, FALSE)))
 | 
					                      &b, &d, FALSE)))
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1819,7 +1821,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
 | 
					    pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
 | 
				
			||||||
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
 | 
					    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
 | 
				
			||||||
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
 | 
					    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (buffer_frames * frame_size));
 | 
				
			||||||
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
 | 
					    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
 | 
				
			||||||
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial"));
 | 
					    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1860,13 +1862,15 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 | 
				
			||||||
    pa_sink_set_rtpoll(u->sink, u->rtpoll);
 | 
					    pa_sink_set_rtpoll(u->sink, u->rtpoll);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    u->frame_size = frame_size;
 | 
					    u->frame_size = frame_size;
 | 
				
			||||||
    u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size);
 | 
					    u->fragment_size = frag_size = (size_t) (period_frames * frame_size);
 | 
				
			||||||
    u->nfragments = nfrags;
 | 
					    u->hwbuf_size = buffer_size = (size_t) (buffer_frames * frame_size);
 | 
				
			||||||
    u->hwbuf_size = u->fragment_size * nfrags;
 | 
					 | 
				
			||||||
    pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels);
 | 
					    pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",
 | 
					    pa_log_info("Using %0.1f fragments of size %lu bytes (%0.2fms), buffer size is %lu bytes (%0.2fms)",
 | 
				
			||||||
                nfrags, (long unsigned) u->fragment_size,
 | 
					                (double) u->hwbuf_size / (double) u->fragment_size,
 | 
				
			||||||
 | 
					                (long unsigned) u->fragment_size,
 | 
				
			||||||
 | 
					                (double) pa_bytes_to_usec(u->fragment_size, &ss) / PA_USEC_PER_MSEC,
 | 
				
			||||||
 | 
					                (long unsigned) u->hwbuf_size,
 | 
				
			||||||
                (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC);
 | 
					                (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_sink_set_max_request(u->sink, u->hwbuf_size);
 | 
					    pa_sink_set_max_request(u->sink, u->hwbuf_size);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,8 +111,6 @@ struct userdata {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_usec_t watermark_dec_not_before;
 | 
					    pa_usec_t watermark_dec_not_before;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unsigned nfragments;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    char *device_name;
 | 
					    char *device_name;
 | 
				
			||||||
    char *control_device;
 | 
					    char *control_device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -891,8 +889,7 @@ static int unsuspend(struct userdata *u) {
 | 
				
			||||||
    pa_sample_spec ss;
 | 
					    pa_sample_spec ss;
 | 
				
			||||||
    int err;
 | 
					    int err;
 | 
				
			||||||
    pa_bool_t b, d;
 | 
					    pa_bool_t b, d;
 | 
				
			||||||
    unsigned nfrags;
 | 
					    snd_pcm_uframes_t period_size, buffer_size;
 | 
				
			||||||
    snd_pcm_uframes_t period_size;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_assert(u);
 | 
					    pa_assert(u);
 | 
				
			||||||
    pa_assert(!u->pcm_handle);
 | 
					    pa_assert(!u->pcm_handle);
 | 
				
			||||||
| 
						 | 
					@ -909,12 +906,12 @@ static int unsuspend(struct userdata *u) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss = u->source->sample_spec;
 | 
					    ss = u->source->sample_spec;
 | 
				
			||||||
    nfrags = u->nfragments;
 | 
					 | 
				
			||||||
    period_size = u->fragment_size / u->frame_size;
 | 
					    period_size = u->fragment_size / u->frame_size;
 | 
				
			||||||
 | 
					    buffer_size = u->hwbuf_size / u->frame_size;
 | 
				
			||||||
    b = u->use_mmap;
 | 
					    b = u->use_mmap;
 | 
				
			||||||
    d = u->use_tsched;
 | 
					    d = u->use_tsched;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, u->hwbuf_size / u->frame_size, &b, &d, TRUE)) < 0) {
 | 
					    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, TRUE)) < 0) {
 | 
				
			||||||
        pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));
 | 
					        pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -929,10 +926,11 @@ static int unsuspend(struct userdata *u) {
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) {
 | 
					    if (period_size*u->frame_size != u->fragment_size ||
 | 
				
			||||||
        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)",
 | 
					        buffer_size*u->frame_size != u->hwbuf_size) {
 | 
				
			||||||
                    (unsigned long) u->nfragments, (unsigned long) u->fragment_size,
 | 
					        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)",
 | 
				
			||||||
                    (unsigned long) nfrags, period_size * u->frame_size);
 | 
					                    (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size,
 | 
				
			||||||
 | 
					                    (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size));
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1483,8 +1481,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 | 
				
			||||||
    const char *dev_id = NULL;
 | 
					    const char *dev_id = NULL;
 | 
				
			||||||
    pa_sample_spec ss, requested_ss;
 | 
					    pa_sample_spec ss, requested_ss;
 | 
				
			||||||
    pa_channel_map map;
 | 
					    pa_channel_map map;
 | 
				
			||||||
    uint32_t nfrags, frag_size, tsched_size, tsched_watermark;
 | 
					    uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark;
 | 
				
			||||||
    snd_pcm_uframes_t period_frames, tsched_frames;
 | 
					    snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
 | 
				
			||||||
    size_t frame_size;
 | 
					    size_t frame_size;
 | 
				
			||||||
    pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;
 | 
					    pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;
 | 
				
			||||||
    pa_source_new_data data;
 | 
					    pa_source_new_data data;
 | 
				
			||||||
| 
						 | 
					@ -1518,7 +1516,10 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buffer_size = nfrags * frag_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    period_frames = frag_size/frame_size;
 | 
					    period_frames = frag_size/frame_size;
 | 
				
			||||||
 | 
					    buffer_frames = buffer_size/frame_size;
 | 
				
			||||||
    tsched_frames = tsched_size/frame_size;
 | 
					    tsched_frames = tsched_size/frame_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
 | 
					    if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
 | 
				
			||||||
| 
						 | 
					@ -1584,7 +1585,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 | 
				
			||||||
                      &u->device_name,
 | 
					                      &u->device_name,
 | 
				
			||||||
                      &ss, &map,
 | 
					                      &ss, &map,
 | 
				
			||||||
                      SND_PCM_STREAM_CAPTURE,
 | 
					                      SND_PCM_STREAM_CAPTURE,
 | 
				
			||||||
                      &nfrags, &period_frames, tsched_frames,
 | 
					                      &period_frames, &buffer_frames, tsched_frames,
 | 
				
			||||||
                      &b, &d, mapping)))
 | 
					                      &b, &d, mapping)))
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1598,7 +1599,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 | 
				
			||||||
                      &u->device_name,
 | 
					                      &u->device_name,
 | 
				
			||||||
                      &ss, &map,
 | 
					                      &ss, &map,
 | 
				
			||||||
                      SND_PCM_STREAM_CAPTURE,
 | 
					                      SND_PCM_STREAM_CAPTURE,
 | 
				
			||||||
                      &nfrags, &period_frames, tsched_frames,
 | 
					                      &period_frames, &buffer_frames, tsched_frames,
 | 
				
			||||||
                      &b, &d, profile_set, &mapping)))
 | 
					                      &b, &d, profile_set, &mapping)))
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1609,7 +1610,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 | 
				
			||||||
                      &u->device_name,
 | 
					                      &u->device_name,
 | 
				
			||||||
                      &ss, &map,
 | 
					                      &ss, &map,
 | 
				
			||||||
                      SND_PCM_STREAM_CAPTURE,
 | 
					                      SND_PCM_STREAM_CAPTURE,
 | 
				
			||||||
                      &nfrags, &period_frames, tsched_frames,
 | 
					                      &period_frames, &buffer_frames, tsched_frames,
 | 
				
			||||||
                      &b, &d, FALSE)))
 | 
					                      &b, &d, FALSE)))
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1661,7 +1662,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
 | 
					    pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
 | 
				
			||||||
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
 | 
					    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
 | 
				
			||||||
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
 | 
					    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (buffer_frames * frame_size));
 | 
				
			||||||
    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
 | 
					    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
 | 
				
			||||||
    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial"));
 | 
					    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1702,13 +1703,15 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 | 
				
			||||||
    pa_source_set_rtpoll(u->source, u->rtpoll);
 | 
					    pa_source_set_rtpoll(u->source, u->rtpoll);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    u->frame_size = frame_size;
 | 
					    u->frame_size = frame_size;
 | 
				
			||||||
    u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size);
 | 
					    u->fragment_size = frag_size = (size_t) (period_frames * frame_size);
 | 
				
			||||||
    u->nfragments = nfrags;
 | 
					    u->hwbuf_size = buffer_size = (size_t) (buffer_frames * frame_size);
 | 
				
			||||||
    u->hwbuf_size = u->fragment_size * nfrags;
 | 
					 | 
				
			||||||
    pa_cvolume_mute(&u->hardware_volume, u->source->sample_spec.channels);
 | 
					    pa_cvolume_mute(&u->hardware_volume, u->source->sample_spec.channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",
 | 
					    pa_log_info("Using %0.1f fragments of size %lu bytes (%0.2fms), buffer size is %lu bytes (%0.2fms)",
 | 
				
			||||||
                nfrags, (long unsigned) u->fragment_size,
 | 
					                (double) u->hwbuf_size / (double) u->fragment_size,
 | 
				
			||||||
 | 
					                (long unsigned) u->fragment_size,
 | 
				
			||||||
 | 
					                (double) pa_bytes_to_usec(u->fragment_size, &ss) / PA_USEC_PER_MSEC,
 | 
				
			||||||
 | 
					                (long unsigned) u->hwbuf_size,
 | 
				
			||||||
                (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC);
 | 
					                (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (u->use_tsched) {
 | 
					    if (u->use_tsched) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,6 +93,7 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_assert(pcm_handle);
 | 
					    pa_assert(pcm_handle);
 | 
				
			||||||
 | 
					    pa_assert(hwparams);
 | 
				
			||||||
    pa_assert(f);
 | 
					    pa_assert(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
 | 
					    if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
 | 
				
			||||||
| 
						 | 
					@ -148,33 +149,71 @@ try_auto:
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int set_period_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
 | 
				
			||||||
 | 
					    snd_pcm_uframes_t s;
 | 
				
			||||||
 | 
					    int d, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(pcm_handle);
 | 
				
			||||||
 | 
					    pa_assert(hwparams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s = size;
 | 
				
			||||||
 | 
					    d = 0;
 | 
				
			||||||
 | 
					    if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
 | 
				
			||||||
 | 
					        s = size;
 | 
				
			||||||
 | 
					        d = -1;
 | 
				
			||||||
 | 
					        if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
 | 
				
			||||||
 | 
					            s = size;
 | 
				
			||||||
 | 
					            d = 1;
 | 
				
			||||||
 | 
					            if ((ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d)) < 0) {
 | 
				
			||||||
 | 
					                pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
 | 
					                return ret;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(pcm_handle);
 | 
				
			||||||
 | 
					    pa_assert(hwparams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size)) < 0) {
 | 
				
			||||||
 | 
					        pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Set the hardware parameters of the given ALSA device. Returns the
 | 
					/* Set the hardware parameters of the given ALSA device. Returns the
 | 
				
			||||||
 * selected fragment settings in *period and *period_size */
 | 
					 * selected fragment settings in *period and *period_size */
 | 
				
			||||||
int pa_alsa_set_hw_params(
 | 
					int pa_alsa_set_hw_params(
 | 
				
			||||||
        snd_pcm_t *pcm_handle,
 | 
					        snd_pcm_t *pcm_handle,
 | 
				
			||||||
        pa_sample_spec *ss,
 | 
					        pa_sample_spec *ss,
 | 
				
			||||||
        uint32_t *periods,
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,
 | 
					        snd_pcm_uframes_t *period_size,
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,
 | 
					        pa_bool_t *use_mmap,
 | 
				
			||||||
        pa_bool_t *use_tsched,
 | 
					        pa_bool_t *use_tsched,
 | 
				
			||||||
        pa_bool_t require_exact_channel_number) {
 | 
					        pa_bool_t require_exact_channel_number) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int ret = -1;
 | 
					    int ret = -1;
 | 
				
			||||||
 | 
					    snd_pcm_hw_params_t *hwparams, *hwparams_copy;
 | 
				
			||||||
 | 
					    int dir;
 | 
				
			||||||
    snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
 | 
					    snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
 | 
				
			||||||
    unsigned int _periods = periods ? *periods : 0;
 | 
					    snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
 | 
				
			||||||
    unsigned int r = ss->rate;
 | 
					 | 
				
			||||||
    unsigned int c = ss->channels;
 | 
					 | 
				
			||||||
    pa_sample_format_t f = ss->format;
 | 
					 | 
				
			||||||
    snd_pcm_hw_params_t *hwparams;
 | 
					 | 
				
			||||||
    pa_bool_t _use_mmap = use_mmap && *use_mmap;
 | 
					    pa_bool_t _use_mmap = use_mmap && *use_mmap;
 | 
				
			||||||
    pa_bool_t _use_tsched = use_tsched && *use_tsched;
 | 
					    pa_bool_t _use_tsched = use_tsched && *use_tsched;
 | 
				
			||||||
    int dir;
 | 
					    pa_sample_spec _ss = *ss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_assert(pcm_handle);
 | 
					    pa_assert(pcm_handle);
 | 
				
			||||||
    pa_assert(ss);
 | 
					    pa_assert(ss);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    snd_pcm_hw_params_alloca(&hwparams);
 | 
					    snd_pcm_hw_params_alloca(&hwparams);
 | 
				
			||||||
 | 
					    snd_pcm_hw_params_alloca(&hwparams_copy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
 | 
					    if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
 | 
				
			||||||
        pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
 | 
					        pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
| 
						 | 
					@ -208,114 +247,140 @@ int pa_alsa_set_hw_params(
 | 
				
			||||||
    if (!_use_mmap)
 | 
					    if (!_use_mmap)
 | 
				
			||||||
        _use_tsched = FALSE;
 | 
					        _use_tsched = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = set_format(pcm_handle, hwparams, &f)) < 0)
 | 
					    if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0)
 | 
				
			||||||
        goto finish;
 | 
					        goto finish;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) {
 | 
					    if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) {
 | 
				
			||||||
        pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
 | 
					        pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
        goto finish;
 | 
					        goto finish;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (require_exact_channel_number) {
 | 
					    if (require_exact_channel_number) {
 | 
				
			||||||
        if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0) {
 | 
					        if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) {
 | 
				
			||||||
            pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", c, pa_alsa_strerror(ret));
 | 
					            pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
 | 
				
			||||||
            goto finish;
 | 
					            goto finish;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					        unsigned int c = _ss.channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
 | 
					        if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
 | 
				
			||||||
            pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", c, pa_alsa_strerror(ret));
 | 
					            pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
 | 
				
			||||||
            goto finish;
 | 
					            goto finish;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _ss.channels = c;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0) {
 | 
					    if (_use_tsched && tsched_size > 0) {
 | 
				
			||||||
        pa_log_debug("snd_pcm_hw_params_set_periods_integer() failed: %s", pa_alsa_strerror(ret));
 | 
					        _buffer_size = pa_convert_size(tsched_size, ss, &_ss);
 | 
				
			||||||
        goto finish;
 | 
					        _period_size = _buffer_size;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        _period_size = pa_convert_size(_period_size, ss, &_ss);
 | 
				
			||||||
 | 
					        _buffer_size = pa_convert_size(_buffer_size, ss, &_ss);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (_period_size > 0 && tsched_size > 0 && _periods > 0) {
 | 
					    if (_buffer_size > 0 || _period_size > 0) {
 | 
				
			||||||
        snd_pcm_uframes_t buffer_size;
 | 
					        snd_pcm_uframes_t max_frames = 0;
 | 
				
			||||||
        unsigned int p;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
 | 
					        if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
 | 
				
			||||||
        _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate);
 | 
					            pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
        tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate);
 | 
					        else
 | 
				
			||||||
 | 
					            pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) max_frames * PA_MSEC_PER_SEC / _ss.rate);
 | 
				
			||||||
        if (_use_tsched) {
 | 
					 | 
				
			||||||
            buffer_size = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size)) < 0)
 | 
					 | 
				
			||||||
                pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _period_size = tsched_size;
 | 
					 | 
				
			||||||
            _periods = 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Some ALSA drivers really don't like if we set the buffer
 | 
					        /* Some ALSA drivers really don't like if we set the buffer
 | 
				
			||||||
         * size first and the number of periods second. (which would
 | 
					         * size first and the number of periods second. (which would
 | 
				
			||||||
         * make a lot more sense to me) So, follow this rule and
 | 
					         * make a lot more sense to me) So, try a few combinations
 | 
				
			||||||
         * adjust the periods first and the buffer size second */
 | 
					         * before we give up. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* First we pass 0 as direction to get exactly what we
 | 
					        if (_buffer_size > 0 && _period_size > 0) {
 | 
				
			||||||
         * asked for. That this is necessary is presumably a bug
 | 
					            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
 | 
				
			||||||
         * in ALSA. All in all this is mostly a hint to ALSA, so
 | 
					 | 
				
			||||||
         * we don't care if this fails. */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        p = _periods;
 | 
					            /* First try: set buffer size first, followed by period size */
 | 
				
			||||||
        dir = 0;
 | 
					            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
 | 
				
			||||||
        if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) {
 | 
					                set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
 | 
				
			||||||
            p = _periods;
 | 
					                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
 | 
				
			||||||
            dir = 1;
 | 
					                pa_log_debug("Set buffer size first, period size second.");
 | 
				
			||||||
            if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) {
 | 
					                goto success;
 | 
				
			||||||
                p = _periods;
 | 
					            }
 | 
				
			||||||
                dir = -1;
 | 
					
 | 
				
			||||||
                if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir)) < 0)
 | 
					            /* Second try: set period size first, followed by buffer size */
 | 
				
			||||||
                    pa_log_info("snd_pcm_hw_params_set_periods_near() failed: %s", pa_alsa_strerror(ret));
 | 
					            if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
 | 
				
			||||||
 | 
					                set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
 | 
				
			||||||
 | 
					                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
 | 
				
			||||||
 | 
					                pa_log_debug("Set period size first, buffer size second.");
 | 
				
			||||||
 | 
					                goto success;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Now set the buffer size */
 | 
					        if (_buffer_size > 0) {
 | 
				
			||||||
        buffer_size = _periods * _period_size;
 | 
					            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
 | 
				
			||||||
        if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)
 | 
					
 | 
				
			||||||
            pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
 | 
					            /* Third try: set only buffer size */
 | 
				
			||||||
 | 
					            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
 | 
				
			||||||
 | 
					                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
 | 
				
			||||||
 | 
					                pa_log_debug("Set only buffer size second.");
 | 
				
			||||||
 | 
					                goto success;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (_period_size > 0) {
 | 
				
			||||||
 | 
					            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Fourth try: set only period size */
 | 
				
			||||||
 | 
					            if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
 | 
				
			||||||
 | 
					                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
 | 
				
			||||||
 | 
					                pa_log_debug("Set only period size second.");
 | 
				
			||||||
 | 
					                goto success;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if  ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
 | 
					    pa_log_debug("Set neither period nor buffer size.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Last chance, set nothing */
 | 
				
			||||||
 | 
					    if  ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
 | 
				
			||||||
 | 
					        pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
        goto finish;
 | 
					        goto finish;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ss->rate != r)
 | 
					success:
 | 
				
			||||||
        pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ss->channels != c)
 | 
					    if (ss->rate != _ss.rate)
 | 
				
			||||||
        pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c);
 | 
					        pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, _ss.rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ss->format != f)
 | 
					    if (ss->channels != _ss.channels)
 | 
				
			||||||
        pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f));
 | 
					        pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, _ss.channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ss->format != _ss.format)
 | 
				
			||||||
 | 
					        pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(_ss.format));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = snd_pcm_prepare(pcm_handle)) < 0) {
 | 
					    if ((ret = snd_pcm_prepare(pcm_handle)) < 0) {
 | 
				
			||||||
        pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret));
 | 
					        pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
        goto finish;
 | 
					        goto finish;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((ret = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
 | 
				
			||||||
 | 
					        pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
 | 
					        goto finish;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
 | 
					    if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
 | 
				
			||||||
        (ret = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0) {
 | 
					        (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
 | 
				
			||||||
        pa_log_info("snd_pcm_hw_params_get_period{s|_size}() failed: %s", pa_alsa_strerror(ret));
 | 
					        pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret));
 | 
				
			||||||
        goto finish;
 | 
					        goto finish;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If the sample rate deviates too much, we need to resample */
 | 
					    /* If the sample rate deviates too much, we need to resample */
 | 
				
			||||||
    if (r < ss->rate*.95 || r > ss->rate*1.05)
 | 
					    if (_ss.rate < ss->rate*.95 || _ss.rate > ss->rate*1.05)
 | 
				
			||||||
        ss->rate = r;
 | 
					        ss->rate = _ss.rate;
 | 
				
			||||||
    ss->channels = (uint8_t) c;
 | 
					    ss->channels = _ss.channels;
 | 
				
			||||||
    ss->format = f;
 | 
					    ss->format = _ss.format;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_assert(_periods > 0);
 | 
					 | 
				
			||||||
    pa_assert(_period_size > 0);
 | 
					    pa_assert(_period_size > 0);
 | 
				
			||||||
 | 
					    pa_assert(_buffer_size > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (periods)
 | 
					    if (buffer_size)
 | 
				
			||||||
        *periods = _periods;
 | 
					        *buffer_size = _buffer_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (period_size)
 | 
					    if (period_size)
 | 
				
			||||||
        *period_size = _period_size;
 | 
					        *period_size = _period_size;
 | 
				
			||||||
| 
						 | 
					@ -393,8 +458,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
 | 
				
			||||||
        pa_sample_spec *ss,
 | 
					        pa_sample_spec *ss,
 | 
				
			||||||
        pa_channel_map* map,
 | 
					        pa_channel_map* map,
 | 
				
			||||||
        int mode,
 | 
					        int mode,
 | 
				
			||||||
        uint32_t *nfrags,
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,
 | 
					        snd_pcm_uframes_t *period_size,
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,
 | 
					        pa_bool_t *use_mmap,
 | 
				
			||||||
        pa_bool_t *use_tsched,
 | 
					        pa_bool_t *use_tsched,
 | 
				
			||||||
| 
						 | 
					@ -410,8 +475,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
 | 
				
			||||||
    pa_assert(dev);
 | 
					    pa_assert(dev);
 | 
				
			||||||
    pa_assert(ss);
 | 
					    pa_assert(ss);
 | 
				
			||||||
    pa_assert(map);
 | 
					    pa_assert(map);
 | 
				
			||||||
    pa_assert(nfrags);
 | 
					 | 
				
			||||||
    pa_assert(period_size);
 | 
					 | 
				
			||||||
    pa_assert(ps);
 | 
					    pa_assert(ps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* First we try to find a device string with a superset of the
 | 
					    /* First we try to find a device string with a superset of the
 | 
				
			||||||
| 
						 | 
					@ -433,8 +496,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
 | 
				
			||||||
                ss,
 | 
					                ss,
 | 
				
			||||||
                map,
 | 
					                map,
 | 
				
			||||||
                mode,
 | 
					                mode,
 | 
				
			||||||
                nfrags,
 | 
					 | 
				
			||||||
                period_size,
 | 
					                period_size,
 | 
				
			||||||
 | 
					                buffer_size,
 | 
				
			||||||
                tsched_size,
 | 
					                tsched_size,
 | 
				
			||||||
                use_mmap,
 | 
					                use_mmap,
 | 
				
			||||||
                use_tsched,
 | 
					                use_tsched,
 | 
				
			||||||
| 
						 | 
					@ -460,8 +523,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
 | 
				
			||||||
                ss,
 | 
					                ss,
 | 
				
			||||||
                map,
 | 
					                map,
 | 
				
			||||||
                mode,
 | 
					                mode,
 | 
				
			||||||
                nfrags,
 | 
					 | 
				
			||||||
                period_size,
 | 
					                period_size,
 | 
				
			||||||
 | 
					                buffer_size,
 | 
				
			||||||
                tsched_size,
 | 
					                tsched_size,
 | 
				
			||||||
                use_mmap,
 | 
					                use_mmap,
 | 
				
			||||||
                use_tsched,
 | 
					                use_tsched,
 | 
				
			||||||
| 
						 | 
					@ -478,7 +541,18 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
 | 
				
			||||||
    /* OK, we didn't find any good device, so let's try the raw hw: stuff */
 | 
					    /* OK, we didn't find any good device, so let's try the raw hw: stuff */
 | 
				
			||||||
    d = pa_sprintf_malloc("hw:%s", dev_id);
 | 
					    d = pa_sprintf_malloc("hw:%s", dev_id);
 | 
				
			||||||
    pa_log_debug("Trying %s as last resort...", d);
 | 
					    pa_log_debug("Trying %s as last resort...", d);
 | 
				
			||||||
    pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched, FALSE);
 | 
					    pcm_handle = pa_alsa_open_by_device_string(
 | 
				
			||||||
 | 
					            d,
 | 
				
			||||||
 | 
					            dev,
 | 
				
			||||||
 | 
					            ss,
 | 
				
			||||||
 | 
					            map,
 | 
				
			||||||
 | 
					            mode,
 | 
				
			||||||
 | 
					            period_size,
 | 
				
			||||||
 | 
					            buffer_size,
 | 
				
			||||||
 | 
					            tsched_size,
 | 
				
			||||||
 | 
					            use_mmap,
 | 
				
			||||||
 | 
					            use_tsched,
 | 
				
			||||||
 | 
					            FALSE);
 | 
				
			||||||
    pa_xfree(d);
 | 
					    pa_xfree(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pcm_handle && mapping)
 | 
					    if (pcm_handle && mapping)
 | 
				
			||||||
| 
						 | 
					@ -493,8 +567,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(
 | 
				
			||||||
        pa_sample_spec *ss,
 | 
					        pa_sample_spec *ss,
 | 
				
			||||||
        pa_channel_map* map,
 | 
					        pa_channel_map* map,
 | 
				
			||||||
        int mode,
 | 
					        int mode,
 | 
				
			||||||
        uint32_t *nfrags,
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,
 | 
					        snd_pcm_uframes_t *period_size,
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,
 | 
					        pa_bool_t *use_mmap,
 | 
				
			||||||
        pa_bool_t *use_tsched,
 | 
					        pa_bool_t *use_tsched,
 | 
				
			||||||
| 
						 | 
					@ -508,8 +582,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(
 | 
				
			||||||
    pa_assert(dev);
 | 
					    pa_assert(dev);
 | 
				
			||||||
    pa_assert(ss);
 | 
					    pa_assert(ss);
 | 
				
			||||||
    pa_assert(map);
 | 
					    pa_assert(map);
 | 
				
			||||||
    pa_assert(nfrags);
 | 
					 | 
				
			||||||
    pa_assert(period_size);
 | 
					 | 
				
			||||||
    pa_assert(m);
 | 
					    pa_assert(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try_ss.channels = m->channel_map.channels;
 | 
					    try_ss.channels = m->channel_map.channels;
 | 
				
			||||||
| 
						 | 
					@ -524,8 +596,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(
 | 
				
			||||||
            &try_ss,
 | 
					            &try_ss,
 | 
				
			||||||
            &try_map,
 | 
					            &try_map,
 | 
				
			||||||
            mode,
 | 
					            mode,
 | 
				
			||||||
            nfrags,
 | 
					 | 
				
			||||||
            period_size,
 | 
					            period_size,
 | 
				
			||||||
 | 
					            buffer_size,
 | 
				
			||||||
            tsched_size,
 | 
					            tsched_size,
 | 
				
			||||||
            use_mmap,
 | 
					            use_mmap,
 | 
				
			||||||
            use_tsched,
 | 
					            use_tsched,
 | 
				
			||||||
| 
						 | 
					@ -547,8 +619,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(
 | 
				
			||||||
        pa_sample_spec *ss,
 | 
					        pa_sample_spec *ss,
 | 
				
			||||||
        pa_channel_map* map,
 | 
					        pa_channel_map* map,
 | 
				
			||||||
        int mode,
 | 
					        int mode,
 | 
				
			||||||
        uint32_t *nfrags,
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,
 | 
					        snd_pcm_uframes_t *period_size,
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,
 | 
					        pa_bool_t *use_mmap,
 | 
				
			||||||
        pa_bool_t *use_tsched,
 | 
					        pa_bool_t *use_tsched,
 | 
				
			||||||
| 
						 | 
					@ -579,7 +651,15 @@ snd_pcm_t *pa_alsa_open_by_device_string(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pa_log_debug("Managed to open %s", d);
 | 
					        pa_log_debug("Managed to open %s", d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) {
 | 
					        if ((err = pa_alsa_set_hw_params(
 | 
				
			||||||
 | 
					                     pcm_handle,
 | 
				
			||||||
 | 
					                     ss,
 | 
				
			||||||
 | 
					                     period_size,
 | 
				
			||||||
 | 
					                     buffer_size,
 | 
				
			||||||
 | 
					                     tsched_size,
 | 
				
			||||||
 | 
					                     use_mmap,
 | 
				
			||||||
 | 
					                     use_tsched,
 | 
				
			||||||
 | 
					                     require_exact_channel_number)) < 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!reformat) {
 | 
					            if (!reformat) {
 | 
				
			||||||
                reformat = TRUE;
 | 
					                reformat = TRUE;
 | 
				
			||||||
| 
						 | 
					@ -632,8 +712,8 @@ snd_pcm_t *pa_alsa_open_by_template(
 | 
				
			||||||
        pa_sample_spec *ss,
 | 
					        pa_sample_spec *ss,
 | 
				
			||||||
        pa_channel_map* map,
 | 
					        pa_channel_map* map,
 | 
				
			||||||
        int mode,
 | 
					        int mode,
 | 
				
			||||||
        uint32_t *nfrags,
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,
 | 
					        snd_pcm_uframes_t *period_size,
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,
 | 
					        pa_bool_t *use_mmap,
 | 
				
			||||||
        pa_bool_t *use_tsched,
 | 
					        pa_bool_t *use_tsched,
 | 
				
			||||||
| 
						 | 
					@ -653,8 +733,8 @@ snd_pcm_t *pa_alsa_open_by_template(
 | 
				
			||||||
                ss,
 | 
					                ss,
 | 
				
			||||||
                map,
 | 
					                map,
 | 
				
			||||||
                mode,
 | 
					                mode,
 | 
				
			||||||
                nfrags,
 | 
					 | 
				
			||||||
                period_size,
 | 
					                period_size,
 | 
				
			||||||
 | 
					                buffer_size,
 | 
				
			||||||
                tsched_size,
 | 
					                tsched_size,
 | 
				
			||||||
                use_mmap,
 | 
					                use_mmap,
 | 
				
			||||||
                use_tsched,
 | 
					                use_tsched,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,8 +42,8 @@
 | 
				
			||||||
int pa_alsa_set_hw_params(
 | 
					int pa_alsa_set_hw_params(
 | 
				
			||||||
        snd_pcm_t *pcm_handle,
 | 
					        snd_pcm_t *pcm_handle,
 | 
				
			||||||
        pa_sample_spec *ss,                /* modified at return */
 | 
					        pa_sample_spec *ss,                /* modified at return */
 | 
				
			||||||
        uint32_t *periods,                 /* modified at return */
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,    /* modified at return */
 | 
					        snd_pcm_uframes_t *period_size,    /* modified at return */
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,    /* modified at return */
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,               /* modified at return */
 | 
					        pa_bool_t *use_mmap,               /* modified at return */
 | 
				
			||||||
        pa_bool_t *use_tsched,             /* modified at return */
 | 
					        pa_bool_t *use_tsched,             /* modified at return */
 | 
				
			||||||
| 
						 | 
					@ -60,8 +60,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
 | 
				
			||||||
        pa_sample_spec *ss,               /* modified at return */
 | 
					        pa_sample_spec *ss,               /* modified at return */
 | 
				
			||||||
        pa_channel_map* map,              /* modified at return */
 | 
					        pa_channel_map* map,              /* modified at return */
 | 
				
			||||||
        int mode,
 | 
					        int mode,
 | 
				
			||||||
        uint32_t *nfrags,                 /* modified at return */
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,   /* modified at return */
 | 
					        snd_pcm_uframes_t *period_size,   /* modified at return */
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,   /* modified at return */
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,              /* modified at return */
 | 
					        pa_bool_t *use_mmap,              /* modified at return */
 | 
				
			||||||
        pa_bool_t *use_tsched,            /* modified at return */
 | 
					        pa_bool_t *use_tsched,            /* modified at return */
 | 
				
			||||||
| 
						 | 
					@ -75,8 +75,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(
 | 
				
			||||||
        pa_sample_spec *ss,               /* modified at return */
 | 
					        pa_sample_spec *ss,               /* modified at return */
 | 
				
			||||||
        pa_channel_map* map,              /* modified at return */
 | 
					        pa_channel_map* map,              /* modified at return */
 | 
				
			||||||
        int mode,
 | 
					        int mode,
 | 
				
			||||||
        uint32_t *nfrags,                 /* modified at return */
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,   /* modified at return */
 | 
					        snd_pcm_uframes_t *period_size,   /* modified at return */
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,   /* modified at return */
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,              /* modified at return */
 | 
					        pa_bool_t *use_mmap,              /* modified at return */
 | 
				
			||||||
        pa_bool_t *use_tsched,            /* modified at return */
 | 
					        pa_bool_t *use_tsched,            /* modified at return */
 | 
				
			||||||
| 
						 | 
					@ -89,8 +89,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(
 | 
				
			||||||
        pa_sample_spec *ss,               /* modified at return */
 | 
					        pa_sample_spec *ss,               /* modified at return */
 | 
				
			||||||
        pa_channel_map* map,              /* modified at return */
 | 
					        pa_channel_map* map,              /* modified at return */
 | 
				
			||||||
        int mode,
 | 
					        int mode,
 | 
				
			||||||
        uint32_t *nfrags,                 /* modified at return */
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,   /* modified at return */
 | 
					        snd_pcm_uframes_t *period_size,   /* modified at return */
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,   /* modified at return */
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,              /* modified at return */
 | 
					        pa_bool_t *use_mmap,              /* modified at return */
 | 
				
			||||||
        pa_bool_t *use_tsched,            /* modified at return */
 | 
					        pa_bool_t *use_tsched,            /* modified at return */
 | 
				
			||||||
| 
						 | 
					@ -104,8 +104,8 @@ snd_pcm_t *pa_alsa_open_by_template(
 | 
				
			||||||
        pa_sample_spec *ss,               /* modified at return */
 | 
					        pa_sample_spec *ss,               /* modified at return */
 | 
				
			||||||
        pa_channel_map* map,              /* modified at return */
 | 
					        pa_channel_map* map,              /* modified at return */
 | 
				
			||||||
        int mode,
 | 
					        int mode,
 | 
				
			||||||
        uint32_t *nfrags,                 /* modified at return */
 | 
					 | 
				
			||||||
        snd_pcm_uframes_t *period_size,   /* modified at return */
 | 
					        snd_pcm_uframes_t *period_size,   /* modified at return */
 | 
				
			||||||
 | 
					        snd_pcm_uframes_t *buffer_size,   /* modified at return */
 | 
				
			||||||
        snd_pcm_uframes_t tsched_size,
 | 
					        snd_pcm_uframes_t tsched_size,
 | 
				
			||||||
        pa_bool_t *use_mmap,              /* modified at return */
 | 
					        pa_bool_t *use_mmap,              /* modified at return */
 | 
				
			||||||
        pa_bool_t *use_tsched,            /* modified at return */
 | 
					        pa_bool_t *use_tsched,            /* modified at return */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue