Skip to content

High CPU usage after speaker.Init() called #159

Open

Description

@psaffrey

First of all, thanks for Beep and the excellent documentation.

I've written a doorbell in Go that listens to an MQTT channel and then plays a ding-dong noise when a button is pressed. I can deploy the code to multiple hosts on different platforms, which is the appeal of using Go for this.

My code runs as a systemd unit, starts up and initialises the sound streams using Beep's speaker package. However, I've noticed that the baseline CPU usages is pretty high - I have two wav files open and this is using ~15% CPU - even on a puny Celeron box this seems excessive. I've written some minimal code to reproduce this:

package main

import (
    "os"
    "github.com/faiface/beep"
    "github.com/faiface/beep/wav"
    "github.com/faiface/beep/speaker"    
    "time"
)

func main() {
    path := os.Args[1]

    f, _ := os.Open(path)

    streamer, format, _ := wav.Decode(f)    

    speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/100))
    time.Sleep(30 * time.Second)
    done := make(chan bool)
    speaker.Play(beep.Seq(streamer, beep.Callback(func() {
        done <- true
    })))
    <-done

}

Save the snippet above as play.go and then run with go run play.go <wavfile>. During the time.Sleep (after init, but before the sound is actually played) you can see the usage in top.

I can reduce the CPU usage by reducing the sample rate in the Init call - with time.Second it was down to about 1% - but that still seems high since it should be completely idle. I also tried using buffering as per the wiki, but that didn't make any difference. Did I miss something here? I'm using go1.18.1.

Activity

  1. MawKKe commented on Apr 1, 2023

    @MawKKe

    It seems that speaker.Init() launches a goroutine that polls update() continuously: https://github.com/faiface/beep/blob/master/speaker/speaker.go#L52, even when nothing is playing. It can be stopped with Close(), but then the speaker needs to be re-Init() before next Play()

  2. MarkKremer commented on Oct 7, 2023

    @MarkKremer
    Contributor

    What I think is happening is that either os.Open() or wav.Decode() returns an error. This results in the format.SampleRate being 0 and the internal buffer of the speaker having a size of 0. I suspect this messes with one of the loops in some way. Can you confirm this by adding error checks and retrying your code?

    It may be a nice addition to add a valid sample rate check in speaker.Init. Although that could invite that we then have to do that everywhere else too.

  3. psaffrey commented on Jan 23, 2024

    @psaffrey
    Author

    Sorry to comment on a closed issue and to take such a long time to get back to this: I tried this:

    package main
    
    import (
        "fmt"
        "os"
        "github.com/faiface/beep"
        "github.com/faiface/beep/wav"
        "github.com/faiface/beep/speaker"    
        "time"
    )
    
    func main() {
        path := os.Args[1]
    
        f, err := os.Open(path)
        if (err != nil) {
            fmt.Println(err)
        }
    
        streamer, format, err := wav.Decode(f)    
        if (err != nil) {
            fmt.Println(err)
        }
    
        fmt.Println(format.SampleRate)
    
        speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/100))
        time.Sleep(300 * time.Second)
        done := make(chan bool)
        speaker.Play(beep.Seq(streamer, beep.Callback(func() {
            done <- true
        })))
        <-done
    
     }
    

    Neither the os.Open() nor the wav.Decode() return an error. The SampleRate is reported as 44100, which seems about right. Is there anything else I can try?

  4. MarkKremer commented on Jan 23, 2024

    @MarkKremer
    Contributor

    Hey psaffrey, faiface/beep isn't being maintained anymore but we maintain a fork over at gopxl/beep. I've copied your comment to our repo: gopxl/beep#14 (comment). Let's continue the conversation there! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions