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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions