Skip to content

Underrun every second time calling PlaybackDevice.Write(buffer) #6

@ratzupaltuff

Description

@ratzupaltuff

Hi, thanks for your great library!
Unfortunately I am unable to play audio every second time I call the Write method. It plays fine the first time and fails with an underrun every second time. When adjusting the Buffer properties nothing changes.

My code:

const (
	sampleRate = 44100
	frequency  = 1760
	format   = alsa.FormatS8
	channels = 1
        
        // I tried many different combinations, I got the same behavior with every combination
	bufferFrames = periodFrames * periods
	periodFrames = sampleRate * 0.1
	periods      =  4
)

type AlsaAudioDevice struct {
	playbackDevice *alsa.PlaybackDevice
	sampleRate     int
	frequency      int
	format         alsa.Format
	channels       int
}

func NewAudioDevice(bluetoothMacAddr BTMAC) (*AlsaAudioDevice, error) {
	bufferParams := alsa.BufferParams{
		BufferFrames: bufferFrames,
		PeriodFrames: periodFrames,
		Periods:      periods,
	}
	p, err := alsa.NewPlaybackDevice("bluealsa:SRV=org.bluealsa,DEV="+string(bluetoothMacAddr)+",PROFILE=a2dp",
		channels, format, sampleRate,
		bufferParams)
	if err != nil {
		return nil, err
	}

	return &AlsaAudioDevice{playbackDevice: p}, nil
}

func (ad AlsaAudioDevice) CloseAudioDevice() {
	ad.playbackDevice.Close()
}

func (ad AlsaAudioDevice) PlayBeep(duration time.Duration) error {
	milliseconds := int(duration.Milliseconds())
	numSamples := milliseconds * sampleRate / 1000
	samples := make([]int8, numSamples*channels)

        // generate sine wave
	for i := 0; i < numSamples; i++ {
		// maxInt-1 because the max negative int is one less
		sample := int8((math.MaxInt8 - 1) * math.Sin(2*math.Pi*frequency*float64(i)/sampleRate))
		switch channels {
		case 1:
			samples[i] = sample
		case 2:
			samples[2*i] = sample   // Left channel
			samples[2*i+1] = sample // Right channel
		}
	}

	if ad.playbackDevice == nil {return errors.New("Could not access playback device")}
	samplesPlayed, err := ad.playbackDevice.Write(samples)
	if err == alsa.ErrUnderrun {
		// triggers every second time i call the Write(samples) method
		return err
	}
	if err != nil {
		return err
	}
	return nil
}

If I run PlayBeep(100*time.Millisecond) it works the first time and fails the second time. The same is true if I generate longer sine wave beeps. What can I do to fix this problem or at least debug it further? Thanks a lot!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions