[pulseaudio-discuss] [PATCH] cli-command: Report error in pa_play_file.

2018-05-29 Thread Tomaz Solc
Current code does not check whether pa_play_file call failed. Hence no error is
reported in the cli interface if playback failed because e.g. file isn't
readable by the daemon.
---
 src/pulsecore/cli-command.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 44795b0d..db09e5dc 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -1282,7 +1282,12 @@ static int pa_cli_command_play_file(pa_core *c, 
pa_tokenizer *t, pa_strbuf *buf,
 return -1;
 }
 
-return pa_play_file(sink, fname, NULL);
+if (pa_play_file(sink, fname, NULL)) {
+pa_strbuf_puts(buf, "Failed to play sound file.\n");
+return -1;
+}
+
+return 0;
 }
 
 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, 
pa_strbuf *buf, bool *fail) {
-- 
2.11.0

___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [patches] constification 2/2

2018-05-29 Thread jnqnfe
Constification patch set ** 2 of 2 **

Collection of 15 patches constifying pointers in various parts of the
API.

This collection of patches have no interdependencies, they can be
applied in any order. They do *not* depend upon the 'constification
1/2' set, they can be applied independently.

fyi, I have not had an opportunity to compile them, but I don't see any
obvious issue.From 1c86d891062e22494f998bfd39987ef505dfb5e4 Mon Sep 17 00:00:00 2001
From: Lyndon Brown 
Date: Sun, 27 May 2018 07:56:11 +0100
Subject: volume: pa_cvolume_get_position: constify


diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index ead54152..fc6ac8d2 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -911,7 +911,7 @@ pa_cvolume* pa_cvolume_set_position(
 }
 
 pa_volume_t pa_cvolume_get_position(
-pa_cvolume *cv,
+const pa_cvolume *cv,
 const pa_channel_map *map,
 pa_channel_position_t t) {
 
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index 2503c3f6..fe44b0bb 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -416,7 +416,7 @@ pa_cvolume* pa_cvolume_set_position(pa_cvolume *cv, const pa_channel_map *map, p
  * position. Will return 0 if there is no channel at the position
  * specified. You can check if a channel map includes a specific
  * position by calling pa_channel_map_has_position(). \since 0.9.16 */
-pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) PA_GCC_PURE;
+pa_volume_t pa_cvolume_get_position(const pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) PA_GCC_PURE;
 
 /** This goes through all channels in a and b and sets the
  * corresponding channel in dest to the greater volume of both. a, b
From 651e090f8461eec114158aba805be791b57a1561 Mon Sep 17 00:00:00 2001
From: Lyndon Brown 
Date: Sat, 26 May 2018 23:50:55 +0100
Subject: context: pa_context_new_with_proplist: constify proplist param


diff --git a/src/pulse/context.c b/src/pulse/context.c
index e7695009..8722f350 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -125,7 +125,7 @@ static void reset_callbacks(pa_context *c) {
 c->ext_stream_restore.userdata = NULL;
 }
 
-pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
+pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, const pa_proplist *p) {
 pa_context *c;
 pa_mem_type_t type;
 
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 2cb0776e..9d4c926e 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -174,7 +174,7 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name);
 /** Instantiate a new connection context with an abstract mainloop API
  * and an application name, and specify the initial client property
  * list. \since 0.9.11 */
-pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist);
+pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, const pa_proplist *proplist);
 
 /** Decrease the reference counter of the context by one */
 void pa_context_unref(pa_context *c);
From 40cab01edae1ebed3490a39cd3141070d016b8b8 Mon Sep 17 00:00:00 2001
From: Lyndon Brown 
Date: Mon, 28 May 2018 01:12:39 +0100
Subject: context: pa_context_get_protocol_version: constify


diff --git a/src/pulse/context.c b/src/pulse/context.c
index b7556343..adbeb153 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1331,7 +1331,7 @@ const char* pa_context_get_server(pa_context *c) {
 return c->server;
 }
 
-uint32_t pa_context_get_protocol_version(pa_context *c) {
+uint32_t pa_context_get_protocol_version(const pa_context *c) {
 return PA_PROTOCOL_VERSION;
 }
 
diff --git a/src/pulse/context.h b/src/pulse/context.h
index dad7aa50..7a38ff23 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -236,7 +236,7 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su
 const char* pa_context_get_server(pa_context *c);
 
 /** Return the protocol version of the library. */
-uint32_t pa_context_get_protocol_version(pa_context *c);
+uint32_t pa_context_get_protocol_version(const pa_context *c);
 
 /** Return the protocol version of the connected server.
  * Returns PA_INVALID_INDEX on error. */
From 558bafe46d1079be68449a4116c25749031892f5 Mon Sep 17 00:00:00 2001
From: Lyndon Brown 
Date: Sun, 27 May 2018 06:24:17 +0100
Subject: context: pa_context_get_state: constify


diff --git a/src/pulse/context.c b/src/pulse/context.c
index 8722f350..b7556343 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1058,7 +1058,7 @@ void pa_context_disconnect(pa_context *c) {
 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
 }
 
-pa_context_state_t pa_context_get_state(pa_context *c) {
+pa_context_state_t pa_context_get_state(const pa_context *c) {
 pa_assert(c);
 pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
diff --git 

[pulseaudio-discuss] [patches] constification 1/2

2018-05-29 Thread jnqnfe
Constification patch set ** 1 of 2 **

Collection of 16 patches constifying pointers in various parts of the
API.

This collection of patches has interdependencies, they must be applied
in (roughly) the given order.

These start off with constifying some core hashmap functions, which
then allows various proplist related functions to be changed. A couple
of tagstruct functions are in there, and finally a couple of
context+proplist related functions.

I have not been in a position to try and compile these changes. I have
identified one possible problem - the hashmap.c BY_HASH macro - I'm not
certain offhand if a const version will be required or if the compiler
will be happy casting as is. Otherwise I'm fairly certain there are no
(obvious) issues.From ae549e3b6a02673cb128fb8a07c6d8f74c2b79ee Mon Sep 17 00:00:00 2001
From: Lyndon Brown 
Date: Sun, 27 May 2018 02:27:43 +0100
Subject: core/hashmap: constify hashmap ptr for various functions


diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c
index 2385c55c..6477783e 100644
--- a/src/pulsecore/hashmap.c
+++ b/src/pulsecore/hashmap.c
@@ -231,7 +231,7 @@ void pa_hashmap_remove_all(pa_hashmap *h) {
 }
 }
 
-void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) {
+void *pa_hashmap_iterate(const pa_hashmap *h, void **state, const void **key) {
 struct hashmap_entry *e;
 
 pa_assert(h);
@@ -264,7 +264,7 @@ at_end:
 return NULL;
 }
 
-void *pa_hashmap_iterate_backwards(pa_hashmap *h, void **state, const void **key) {
+void *pa_hashmap_iterate_backwards(const pa_hashmap *h, void **state, const void **key) {
 struct hashmap_entry *e;
 
 pa_assert(h);
@@ -297,7 +297,7 @@ at_beginning:
 return NULL;
 }
 
-void* pa_hashmap_first(pa_hashmap *h) {
+void* pa_hashmap_first(const pa_hashmap *h) {
 pa_assert(h);
 
 if (!h->iterate_list_head)
@@ -306,7 +306,7 @@ void* pa_hashmap_first(pa_hashmap *h) {
 return h->iterate_list_head->value;
 }
 
-void* pa_hashmap_last(pa_hashmap *h) {
+void* pa_hashmap_last(const pa_hashmap *h) {
 pa_assert(h);
 
 if (!h->iterate_list_tail)
@@ -329,13 +329,13 @@ void* pa_hashmap_steal_first(pa_hashmap *h) {
 return data;
 }
 
-unsigned pa_hashmap_size(pa_hashmap *h) {
+unsigned pa_hashmap_size(const pa_hashmap *h) {
 pa_assert(h);
 
 return h->n_entries;
 }
 
-bool pa_hashmap_isempty(pa_hashmap *h) {
+bool pa_hashmap_isempty(const pa_hashmap *h) {
 pa_assert(h);
 
 return h->n_entries == 0;
diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h
index b1027e75..ea883765 100644
--- a/src/pulsecore/hashmap.h
+++ b/src/pulsecore/hashmap.h
@@ -61,10 +61,10 @@ int pa_hashmap_remove_and_free(pa_hashmap *h, const void *key);
 void pa_hashmap_remove_all(pa_hashmap *h);
 
 /* Return the current number of entries of the hashmap */
-unsigned pa_hashmap_size(pa_hashmap *h);
+unsigned pa_hashmap_size(const pa_hashmap *h);
 
 /* Return true if the hashmap is empty */
-bool pa_hashmap_isempty(pa_hashmap *h);
+bool pa_hashmap_isempty(const pa_hashmap *h);
 
 /* May be used to iterate through the hashmap. Initially the opaque
pointer *state has to be set to NULL. The hashmap may not be
@@ -72,19 +72,19 @@ bool pa_hashmap_isempty(pa_hashmap *h);
via pa_hashmap_remove(). The key of the entry is returned in *key,
if key is non-NULL. After the last entry in the hashmap NULL is
returned. */
-void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key);
+void *pa_hashmap_iterate(const pa_hashmap *h, void **state, const void**key);
 
 /* Same as pa_hashmap_iterate() but goes backwards */
-void *pa_hashmap_iterate_backwards(pa_hashmap *h, void **state, const void**key);
+void *pa_hashmap_iterate_backwards(const pa_hashmap *h, void **state, const void**key);
 
 /* Remove the oldest entry in the hashmap and return it */
 void *pa_hashmap_steal_first(pa_hashmap *h);
 
 /* Return the oldest entry in the hashmap */
-void* pa_hashmap_first(pa_hashmap *h);
+void* pa_hashmap_first(const pa_hashmap *h);
 
 /* Return the newest entry in the hashmap */
-void* pa_hashmap_last(pa_hashmap *h);
+void* pa_hashmap_last(const pa_hashmap *h);
 
 /* A macro to ease iteration through all entries */
 #define PA_HASHMAP_FOREACH(e, h, state) \
From b87af9de83f95eb2271112b36ebc32da44c64d12 Mon Sep 17 00:00:00 2001
From: Lyndon Brown 
Date: Sun, 27 May 2018 02:56:11 +0100
Subject: core/hashmap: constify pointer of private hash_scan function

paves the way for doing the same for pa_hashmap_get and users of it

diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c
index 6477783e..c03af3bc 100644
--- a/src/pulsecore/hashmap.c
+++ b/src/pulsecore/hashmap.c
@@ -119,7 +119,7 @@ void pa_hashmap_free(pa_hashmap *h) {
 pa_xfree(h);
 }
 
-static struct hashmap_entry *hash_scan(pa_hashmap *h, unsigned hash, const void *key) {
+static struct hashmap_entry *hash_scan(const pa_hashmap *h, unsigned hash, const void *key) {
 struct hashmap_entry *e;
 pa_assert(h);

[pulseaudio-discuss] timer events

2018-05-29 Thread jnqnfe
tldr: timer events - am I doing something wrong, or is this feature
broken?

When putting together the Rust bindings a few months ago (see separate
announcement email), I created a few small test programs to test a
handful of features. One of the last features I tried to play with was
timer events. These events though seem to always fire immediately,
which puzzles me.

Yesterday I recreated the primary test program in C, to rule out any
Rust binding related issues, and it exhibits the same problem.

So question, am I doing something wrong (quite likely), or is this
feature broken?

I have attached a copy of both the Rust crate test program, and the C
version.

The test program is very simple, but deserves a word on usage. It
requires one cmd-line arg, a file to "play". Whatever file you point it
at it pretends contains raw audio, which it serves to PA one second's
worth at a time. What I did was to use VLC to capture the raw audio of
a video to a file, which I point it at.#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void context_state_change_cb(pa_context *context, void *data);
void stream_state_change_cb(pa_stream *stream, void *data);
void drain_cb(pa_stream *stream, int i, void *data);

void timer_event_cb(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata);
void timer_event_cb_2(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata);
void timer_event_cb_3(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata);

void main(int argc, char *argv[]) {
if (argc < 2) {
printf("Error: too few arguments!\n");
printf("Usage: %s FILENAME\n", argv[0]);
return;
}

char *filename = argv[1];

printf("opening: %s\n", filename);
int fd = open(filename, O_RDONLY);
if (!fd) {
printf("Error: failed to open file!\n");
return;
}

pa_sample_spec spec = { PA_SAMPLE_S16NE, 44100, 2 };
assert(pa_sample_spec_valid());

printf("bytes per second: %i\n", pa_bytes_per_second());
printf("frame size: %i\n", pa_frame_size());
printf("sample size: %i\n", pa_sample_size());

#define BYTES_PER_SEC 176400
#define BUFFER_SIZE BYTES_PER_SEC
char *buffer = malloc(BUFFER_SIZE);
if (!buffer) {
printf("Error: failed to alloc buffer!\n");
return;
}
assert(BUFFER_SIZE % pa_frame_size() == 0);

pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new();
if (!mainloop) {
printf("Error: failed to create mainloop!\n");
return;
}

static char * APP_NAME = "FooAppContext";
pa_context *context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), APP_NAME);

pa_context_set_state_callback(context, context_state_change_cb, (void*) mainloop);

if (pa_context_connect(context, NULL, 0, NULL) < 0) {
printf("Error: context connection failed!\n");
pa_context_set_state_callback(context, NULL, NULL);
pa_context_unref(context);
pa_threaded_mainloop_free(mainloop);
return;
}

pa_threaded_mainloop_lock(mainloop);
if (pa_threaded_mainloop_start(mainloop) < 0) {
printf("Error: failed to start mainloop!\n");
pa_threaded_mainloop_unlock(mainloop);
pa_context_disconnect(context);
pa_context_set_state_callback(context, NULL, NULL);
pa_context_unref(context);
pa_threaded_mainloop_free(mainloop);
return;
}

// Wait for context to be ready
printf("waiting for context state change...\n");
for(;;) {
bool ready = false;
switch (pa_context_get_state(context)) {
case PA_CONTEXT_READY:
ready = true;
break;
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
printf("context state failed/terminated, quitting...\n");
pa_threaded_mainloop_unlock(mainloop);
pa_threaded_mainloop_stop(mainloop);
return;
default:
pa_threaded_mainloop_wait(mainloop);
}
if (ready)
break;
}

pa_buffer_attr ba = {
(unsigned int) -1,
(unsigned int) -1,
(unsigned int) -1,
(unsigned int) -1,
(unsigned int) -1,
};

printf("creating stream...\n");
pa_stream *stream = pa_stream_new(context, "Music", , NULL);
if (!stream) {
printf("Error: failed to create stream!\n");
pa_threaded_mainloop_unlock(mainloop);
pa_threaded_mainloop_stop(mainloop);
pa_context_disconnect(context);
pa_context_set_state_callback(context, NULL, NULL);
pa_context_unref(context);
pa_threaded_mainloop_free(mainloop);
return;
}

pa_stream_set_state_callback(stream, stream_state_change_cb, 

[pulseaudio-discuss] [announce] Rust bindings!

2018-05-29 Thread jnqnfe
Hi everyone!

Back in February I released 'binding' and 'sys' crates for using
pulseaudio from Rust code. I had intended to make an announcement here
at the time, but I failed to do so, so I'm doing it now.

fyi, the 'sys' crates provide a simple description of the C interface;
The 'binding' crates take this further, providing a cleaner/safer Rust
interface.

I have provided separate crates for each PA system library (per Rust
guidelines for 'sys' crates), thus totalling six in all:

[binding crates]
 - libpulse-binding: https://crates.io/crates/libpulse-binding
 - libpulse-simple-binding: https://crates.io/crates/libpulse-simple-bi
nding
 - libpulse-mainloop-glib-binding: https://crates.io/crates/libpulse-gl
ib-binding
[sys crates]
 - libpulse-sys: https://crates.io/crates/libpulse-sys
 - libpulse-simple-sys: https://crates.io/crates/libpulse-simple-sys
 - libpulse-mainloop-glib-sys: https://crates.io/crates/libpulse-mainlo
op-glib-sys

The 'binding' crates include plenty of documentation (taken from the C
API). This can be built locally of course (cargo doc), but is also
available online at docs.rs, example: https://docs.rs/libpulse-binding/

Long term I hope that the owners of the PA project itself would like to
take over ownership and maintenance. Even longer term hopefully we will
see PA itself converting to Rust - fyi the PA projects has my full
consent to use this work of mine in converting PA itself.

fyi, I am not subscribed to this list; I am contactable at this email
address though, and bug-reports/questions/etc specific to the bindings
can be made on github (https://github.com/jnqnfe/pulse-binding-rust),
but understand that I am no PA guru :)
I do not currently have a home internet connection with my current
living situation, and manage to get online typically only once a week
at the moment, so bare in mind that it could take a while to get a
response. Appoligies in advance if I keep you waiting, I know it's not
ideal.

News related, I have two new version, v1.0.5 and v1.1.0 ready to
publish (when I next get an internet connection, at which point this
email will also get sent out of my outbox :p). The next thing planned
is to consider whether use of "Futures" would be a good idea for use in
the bindings to tidy up use of callbacks - there are some details, most
specifically callbacks, where underlying C details are exposed.

Regards,
Lyndon Brown (aka jnqnfe)
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss