Coder Social home page Coder Social logo

pulse's Introduction

pulse

GoDoc

PulseAudio client implementation in pure Go.

Based on github.com/yobert/pulse, which provided a very useful starting point.

Uses the pulseaudio native protocol to play audio without any CGO. The proto package exposes a very low-level API while the pulse package is more convenient to use.

status

  • proto supports almost all of the protocol, shm support is still missing.

  • pulse implements sufficient functionality for most audio playing/recording applications.

examples

see demo/play and demo/record

pulse's People

Contributors

albanseurat avatar at-wat avatar ftl avatar jfreymuth avatar pdf avatar wgh- avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

pulse's Issues

Feature: TCP socket support

I found this library to be pretty useful.

Would you be open to the idea of also supporting the TCP socket client as an option during client instantiation?

get live stream from microphone

Hi guys.

I would like to ask your help to get the live stream from the microphone, to later encode to ogg, but I have no idea how to start.

Tag a release?

There are a number of changes not available on the v0.1.0 tag, such as subscription/volume consts. To get access to them with go modules users have to go get specific commits, which is not ideal.

Getting sink info with invalid index renders client useless

Querying the sink info of my main sink (index 0) works just fine. When I try to get the info from a nonexistent sink (index 123), pulse returns no such entity (as expected). However, when I want to get the main sink info again, pulse still returns no such entity despite being passed a valid sink index. I can't query sinks again until I open up a new connection.
I'm not sure if that's a limitation of PulseAudio or this library or some kind of bug on my side.
Minimal code example:

reply := proto.GetSinkInfoReply{}

client.Request(&proto.GetSinkInfo{SinkIndex: 0}, &reply) // Works fine
client.Request(&proto.GetSinkInfo{SinkIndex: 123}, &reply) // No such entity
client.Request(&proto.GetSinkInfo{SinkIndex: 0}, &reply) // No such entity

Thank you for your work on this library!

Consider making some fields exported to allow mixing high and low level interactions

There are some ops that are unimplemented on the high-level stream objects (for instance getting latency, or setting dynamic sample rate). They're usable through proto, but then everything has to be done through proto. If for instance the index field on streams was public, then I could use RawRequest to do not-yet-implemented operations on those streams.

Optionally use $PULSE_SERVER to find pulse socket

The normal libpulse uses this environment variable to determine which socket to connect to. It might make sense to do the same. (see: https://github.com/pulseaudio/pulseaudio/blob/master/src/pulse/client-conf.c#L51)

Alternatively the socket path could be made configurable so that users who really need it can do a more complicated dance to figure out what environment variables to use in order to find the native socket.

Either way is fine for me, and I could just open an PR depending on preference.

Cannot use RawRequest with GetPlaybackLatency

Doing this:

latRequest := proto.GetPlaybackLatency{
        StreamIndex: stream.StreamIndex(),
        Time:        proto.Time{0, 0},
}
var latReply proto.GetPlaybackLatencyReply
pc.RawRequest(&latRequest, &latReply)

Fails like this:

panic: reflect: reflect.flag.mustBeAssignable using value obtained using unexported field

goroutine 7 [running]:
reflect.flag.mustBeAssignableSlow(0x1ab)
        /usr/lib/go-1.13/src/reflect/value.go:244 +0x1b9
reflect.flag.mustBeAssignable(...)
        /usr/lib/go-1.13/src/reflect/value.go:234
reflect.Value.SetUint(0x53d580, 0xc00022e008, 0x1ab, 0x0)
        /usr/lib/go-1.13/src/reflect/value.go:1685 +0x3b
github.com/jfreymuth/pulse/proto.(*ProtocolReader).value(0xc0000a60c0, 0x549d40, 0xc00022e000, 0xc000000020)
        /home/andrew/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/reader.go:249 +0xd2e
github.com/jfreymuth/pulse/proto.(*Client).readLoop(0xc0000a60c0)
        /home/andrew/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/client.go:138 +0x448
created by github.com/jfreymuth/pulse/proto.(*Client).Open
        /home/andrew/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/client.go:49 +0x163

I think that this is because of the _ field in GetPlaybackLatencyReply. Perhaps (*ProtocolReader).value should have

if !f.CanSet() {
    continue
}

Structs Source && Sync have unexported field

Hi. Why this struct fields leave unexported?

pulse/source.go

Lines 5 to 8 in 75628da

// A Source is an input device.
type Source struct {
info proto.GetSourceInfoReply
}

pulse/sink.go

Lines 5 to 8 in 75628da

// A Sink is an output device.
type Sink struct {
info proto.GetSinkInfoReply
}

For i.e. i want get sink properties like this:

func main() {

  client, err := pulse.NewClient()
  defer client.Close()
  sources, err := client.ListSources()
....
  for _, source := range sources {
		if isBluetoothDevice(client, source) {
			fmt.Printf("device name: %s", source.Name)
			fmt.Println("----------")
		}
    }
} 
func isBluetoothDevice(device interface{}) bool {
	switch device := device.(type) {
	case *pulse.Source:
		_, ok := device.Properties["device.api"]
		if device.(pulse.Source).info.Properties["device.api"] == "bluez"
			return true
		.....
	default:
		return false
	}
}

But field info unexported ๐Ÿ˜ž

Send on closed channel panic on RecordStream.Close() after error

Calling RecordStream.Close() after error causes panic: send on closed channel.
I think proto.Client.Send() and proto.Client.Request() are better to return error if the client is already closed or errored.

panic: send on closed channel

goroutine 1531535 [running]:
github.com/jfreymuth/pulse/proto.(*Client).Request(0xc000aea180, 0xf46100, 0xc0006b09b0, 0x0, 0x0, 0xc000359c01, 0xc000530001)
	/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/client.go:83 +0x385
github.com/jfreymuth/pulse.(*RecordStream).Close(0xc0003d2140)
	/go/pkg/mod/github.com/jfreymuth/[email protected]/record.go:97 +0x88
github.com/pion/mediadevices/pkg/driver/microphone.(*microphone).AudioRecord.func2(0x411a86, 0xc0007eab10, 0x30, 0x30)
	/go/pkg/mod/github.com/pion/[email protected]/pkg/driver/microphone/microphone_linux.go:103 +0x1b0
github.com/pion/mediadevices/pkg/io/audio.ReaderFunc.Read(0xc000aec280, 0x0, 0x203000, 0xc0007ff000, 0x0)
	/go/pkg/mod/github.com/pion/[email protected]/pkg/io/audio/audio.go:14 +0x27
github.com/seqsense/sq-video-gw/video-sender/audiowatchdog.New.func1.2(0x203000, 0x203000, 0x203000, 0xbd23a0)
	/go/src/seqsense/sq-video-gw/video-sender/audiowatchdog/audiowatchdog.go:34 +0x4e
github.com/pion/mediadevices/pkg/io/audio.ReaderFunc.Read(0xc000573740, 0xf1, 0x2, 0x0, 0xc0007e4a40)
	/go/pkg/mod/github.com/pion/[email protected]/pkg/io/audio/audio.go:14 +0x27
github.com/pion/mediadevices/pkg/io/audio.NewBuffer.func1.1(0x400, 0xc0007e4a20, 0xc0007e4a40, 0x1)
	/go/pkg/mod/github.com/pion/[email protected]/pkg/io/audio/buffer.go:22 +0x9d
github.com/pion/mediadevices/pkg/io/audio.ReaderFunc.Read(0xc000573800, 0xc000359e88, 0x40a935, 0xc000390180, 0xc000359f08)
	/go/pkg/mod/github.com/pion/[email protected]/pkg/io/audio/audio.go:14 +0x27
github.com/pion/mediadevices/pkg/io/audio.NewChannelMixer.func1.1(0x38cbf4d9d587d, 0xc00041a160, 0xc000a026c0, 0xc0006b0988)
	/go/pkg/mod/github.com/pion/[email protected]/pkg/io/audio/mixer.go:12 +0x5c
github.com/pion/mediadevices/pkg/io/audio.ReaderFunc.Read(0xc000573830, 0xc000359f68, 0xb04364, 0xc0008149b0, 0xc000af3400)
	/go/pkg/mod/github.com/pion/[email protected]/pkg/io/audio/audio.go:14 +0x27
github.com/pion/mediadevices/pkg/codec/opus.(*encoder).Read(0xc0005737d0, 0xc000af3400, 0x400, 0x400, 0x0, 0x0, 0x0)
	/go/pkg/mod/github.com/pion/[email protected]/pkg/codec/opus/opus.go:76 +0x38
github.com/pion/mediadevices.(*track).start(0xc0003fa230)
	/go/pkg/mod/github.com/pion/[email protected]/track.go:156 +0x7d
created by github.com/pion/mediadevices.newTrack
	/go/pkg/mod/github.com/pion/[email protected]/track.go:112 +0x4cc

Short writes to a playback stream can cause high CPU consumption

Thanks to the recent changes, I've got my app 99% working. However, the change to the playback interface doesn't quite work right.

Suppose my callback gets a request for 3000 samples, and it delivers 2048, because that's what it has available right now. p.requested will become 952, and run will immediately loop around and call my callback again with a request for 952 (or more). This will probably fail, and I will return 0, and the loop in run will spin at 100% CPU on calls to my callback and nonblocking channel reads, until my buffer fills again.

The only time it ever settles down is if the callback delivers exactly as many bytes as requested, and the nonblock read fails, in which case run will exit that loop and block on the channel read in the outer loop.

Locally modifying playback.go to add

if n == 0 {
    break
}

immediately before the select at line 103 doesn't cause any problems on my system, and brings CPU usage down to where it should be. Pulse always seems willing to deliver another request before it gets to an underrun.

Slice bounds out of range while parsing a prop list

It seems like there's an edge case where parsing an element of a prop list returns a length of zero causing an out-of-bounds:

out[key] = string(value[:len(value)-1])

I can't reproduce this reliably, so I hope this stack trace helps:

panic: runtime error: slice bounds out of range [:-1]

goroutine 7 [running]:
github.com/jfreymuth/pulse/proto.(*ProtocolReader).propList(0xc000182000, 0xc0001b4690)
	/home/krem/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/reader.go:174 +0x2a3
github.com/jfreymuth/pulse/proto.(*ProtocolReader).value(0xc000182000, 0x7ffbe0, 0xc000258480, 0x20)
	/home/krem/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/reader.go:262 +0x71c
github.com/jfreymuth/pulse/proto.(*Client).parseInfoList(0xc000182000, 0x7ffb80, 0xc00022a340, 0x958)
	/home/krem/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/client.go:236 +0x858
github.com/jfreymuth/pulse/proto.(*Client).readLoop(0xc000182000)
	/home/krem/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/client.go:136 +0x36a
created by github.com/jfreymuth/pulse/proto.(*Client).Open
	/home/krem/go/pkg/mod/github.com/jfreymuth/[email protected]/proto/client.go:48 +0x12c

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.