[pulseaudio-discuss] flat volumes for privileged apps

2015-10-19 Thread Wim Taymans
Hi all,

Now that we are talking about flat volumes again (but I don't want to
hijack the other thread), I would like to present another alternative to fix
the problems with flat-volumes.

The idea is that all apps, by default, operate in non-flat volume mode.
This means all volume control done from the app is relative to the master
volume.

Privileged apps can see flat-volumes and thus (indirectly) change the
master volume. One such privileged app is the volume control applet but
it could be possible to manually enable trusted apps (maybe with a switch
in the volume control next to the app stream).

I made a little hack to let you try this, gnome-control-center is a
hardcoded
privileged app but you can see how we can store that in the database later
or how we can hook this into the security framework.

http://cgit.freedesktop.org/~wtay/pulseaudio/commit/?h=flat-volume-privilege-hack&id=1b203fe6bcc8bba1db1911fd4dbf225f36a6dbb9

I like this idea because:

1) it does not need any new api or changes to apps
2) sets a default that will not cause 100% master volume with misbehaving
apps
3) has the master/app volume separation that people understand and that is
also exposed in apps (volume in totem, master in gnome-shell header).
4) still exposes the flat-volume model if needed, which is IMHO the only way
to sanely increase the volume of just 1 single app (when it needs
adjusting
the master volume).
5) minimal code changes.

What do you think?

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


Re: [pulseaudio-discuss] flat volumes for privileged apps

2015-10-20 Thread Wim Taymans
Removing the flat volume from pulseaudio and moving it into the mixer would
make it hard to impossible to implement the following items:

1) give some apps flat volumes and others not.
2) raise the volume of just one stream in the mixer without affecting
others. Since the mixer is not running inside pulseaudio, it can't
atomically update both the master volume and the volumes of all other
streams

Wim




On 19 October 2015 at 17:32, Alexander E. Patrakov 
wrote:

> 19.10.2015 19:38, Wim Taymans wrote:
>
>> Hi all,
>>
>> Now that we are talking about flat volumes again (but I don't want to
>> hijack the other thread), I would like to present another alternative to
>> fix
>> the problems with flat-volumes.
>>
>> The idea is that all apps, by default, operate in non-flat volume mode.
>> This means all volume control done from the app is relative to the master
>> volume.
>>
>> Privileged apps can see flat-volumes and thus (indirectly) change the
>> master volume. One such privileged app is the volume control applet but
>> it could be possible to manually enable trusted apps (maybe with a switch
>> in the volume control next to the app stream).
>>
>> I made a little hack to let you try this, gnome-control-center is a
>> hardcoded
>> privileged app but you can see how we can store that in the database later
>> or how we can hook this into the security framework.
>>
>>
>> http://cgit.freedesktop.org/~wtay/pulseaudio/commit/?h=flat-volume-privilege-hack&id=1b203fe6bcc8bba1db1911fd4dbf225f36a6dbb9
>>
>> I like this idea because:
>>
>> 1) it does not need any new api or changes to apps
>> 2) sets a default that will not cause 100% master volume with misbehaving
>>  apps
>> 3) has the master/app volume separation that people understand and that is
>>  also exposed in apps (volume in totem, master in gnome-shell header).
>> 4) still exposes the flat-volume model if needed, which is IMHO the only
>> way
>>  to sanely increase the volume of just 1 single app (when it needs
>> adjusting
>>  the master volume).
>> 5) minimal code changes.
>>
>> What do you think?
>>
>
> I have looked into this patch idea, and I think that even more minimal
> changes on pulseaudio side (but not minimal overall) are possible. However,
> your approach has an advantage of actually having a patch :)
>
> Please note that, under your proposal, and also without any patch, any
> application can introspect and set any sink volume directly, but no
> application except dedicated mixer applications currently does this.
>
> So here is a strawman counterproposal that should have a similar effect.
> Feel free to test whether the idea is implementable, and compare.
>
> 1. All apps operate with non-flat volumes. Thus, we don't have to
> implement any policy in pulseaudio, and can even remove all the flat-volume
> code.
>
> 2. Alter the logic for presenting sink input volumes to the user in
> gnome-control-center and all other mixer applications. That is, it should
> introspect both sink and sink input volumes, and move the slider to the
> correct position according to the product of them. If a user moves the
> slider, adjust the sink input volume if possible (i.e. if it is left of the
> sink volume). If not, adjust both the sink volume and volumes of all sink
> inputs connected there.
>
> I.e., move all flat volume logic from pulseaudio into mixer applications,
> like it is done in Windows 7. Then we would have a very simple rule to
> enforce if we want to implement privileged/unprivileged app separation:
> "privileged app" = "has access to sink volumes".
>
>
> Yes, I understand that this proposal looks at odds with my previous "ack"
> to Arun's idea. That "ack" is still in force.
>
> --
> Alexander E. Patrakov
> ___
> pulseaudio-discuss mailing list
> pulseaudio-discuss@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] flat volumes for privileged apps

2015-10-20 Thread Wim Taymans
On 20 October 2015 at 06:53, Arun Raghavan  wrote:

> On Mon, 2015-10-19 at 16:38 +0200, Wim Taymans wrote:
>
> I think this option is more or less the same as disabling flat volumes.
> The user is back to having at least two actions to control volume
> (either app slider and panel slider, or open panel and adjust app
> slider).
>

It is, it would disable flat volumes by default. But it would allow you to
enable them again for the streams you want.


>
> The point of flat volumes was that if you're using the application
> volume slider, you don't need to hunt for two volume sliders to adjust
> to get the full range of volume that your hardware allows. To my mind,
> your proposal makes sense as an alternative to what I suggested only if
> we move to a model where we suggests applications do _not_ have volume
> sliders at all, and then design the desktop UX differently to provide a
> single-action way to adjust volumes.
>


> As an example, the shell could track what the current playing stream is
> based on the foreground application and volume controls (hardware and
> panel mixer) could track that volume and apply changes as flat volumes.
> So the user is always only dealing with one control, by default. (I
> just thought of this, so probably needs to be fleshed out to make
> sense, or maybe it doesn't at all.)
>

This is an interesting idea. Because the slider is part of the shell, we
can trust it to be user-controlled and thus give is access to the
flat-volumes of
the stream. It's like the slider from the current app in the mixer appears
in the shell task bar.

In any case, this would work nicely with this proposal and since you would
remove the volume from the apps, making all app-controlled volumes relative
would be a good default.

Wim


>
> -- Arun
> ___
> pulseaudio-discuss mailing list
> pulseaudio-discuss@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] Access control

2016-07-15 Thread Wim Taymans
Hi guys,

I'm having another look at the access control patches. I revived my old
patches and found some trouble with the async stuff that I fixed here:

  https://cgit.freedesktop.org/~wtay/pulseaudio/log/?h=access-hooks

There is also an example on how to start and complete an async access
check for starting a recording. I believe Ahmed Darwish is building on
top of that so it might be useful to get it working.

Now I'm taking a look at the info in pa_client that is available to decide
what access checks we need to do for each client.

Ideally we would need the pid of the process with we can currently find
in the pa_proplist of the client. Unfortunately this pid is whatever the
client
sends us in a proplist in the set_client_name command so we need something
more secure.

We do send the pid and gid with the SCM_CREDENTIALS ancillary data in
the AUTH command. Since the kernel checks things, we can be guaranteed
that when we get the credentials, they are correct.

What I would like to do is make these credentials available somewhere. I
would like to make a new key in the client proplist with the verified pid
from
the credentials but the problem is that we then need to make sure that a
set_client_name command can't overwrite the value, which involves some
filtering or keys.

Alternatively we could make a new pa_client field to store the verified pid
and gid.. Does this sound better or worse?

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


Re: [pulseaudio-discuss] Access control

2016-07-15 Thread Wim Taymans
On 15 July 2016 at 11:14, David Henningsson  wrote:

>
>
> On 2016-07-15 11:05, Wim Taymans wrote:
>
>> Hi guys,
>>
>> I'm having another look at the access control patches. I revived my old
>> patches and found some trouble with the async stuff that I fixed here:
>>
>> https://cgit.freedesktop.org/~wtay/pulseaudio/log/?h=access-hooks <
>> https://cgit.freedesktop.org/%7Ewtay/pulseaudio/log/?h=access-hooks>
>>
>
> FWIW, I also remember fixing a bug or two before I added your patches to
> Ubuntu. The way it looks in Ubuntu now is here:
>
>
> http://anonscm.debian.org/cgit/pkg-pulseaudio/pulseaudio.git/tree/debian/patches?h=ubuntu
>
> (see patches 0406, 0407 and 0408)
>

It looks ok, you fixed the length in _copy and the reading of the command
and tag when resuming the async operation.

Interestingly you added the pa_creds to the pa_client. Any reason not to
upstream this?

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


[pulseaudio-discuss] Access control

2017-01-27 Thread Wim Taymans
Hi All,

I took another look at the access control patches.

There was a desire from Arun and Tanu to have the access control
checks more integrated
into the core objects instead of just some checks in the native protocol.

I was a bit reluctant to start this because it would involve passing
around a lot of pa_client
objects to many functions in order to do access control. This week, I
put my brain to 0 and
started this anyway, You can find the result in this branch:

(1)  https://cgit.freedesktop.org/~wtay/pulseaudio/log/?h=access-hooks-arg

I then spent some time thinking about using TLS to pass the client
around, more like a context
to evaluate the functions in than an argument of the function. Tanu
then suggested to put the
current_client in the pa_core object where it can be picked up from
anywhere. The trick is then
to set and clear the current_client in the various protocols. The
result can be seen here:

(2) https://cgit.freedesktop.org/~wtay/pulseaudio/log/?h=access-hooks-core

You can still find the old way here:

(3) https://cgit.freedesktop.org/~wtay/pulseaudio/log/?h=access-hooks

I think (1) is quite ugly and requires you to modify many functions
with a new parameter that
is not at all related to what the function does. It does however give
you good control over what
you can check. One example is pa_sink_update_rate() which might
suspend and unsuspend
the source to implement the rate change. It a new client does not have
permission to suspend a
sink, it will not be able to change the rate.

(2) looks quite ok. Setting and clearing the current_client is
straightforward and easily verifiable.
You can also be certain that when you add new checks, you can just get
the client from there
instead of having to change a method. The downside is that if ever a
non-main thread tries to
do some access control, you get random behaviour. using TLS will, of
course fix this.

(3) is probably still the most simple solution but only deals with the
native-protocol. (1) and (2)
now also automatically work for the cli, DBus, esound, http, simple
and native protocol.

What do you think? Which option do you like best?
Wim
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] Access control

2017-02-14 Thread Wim Taymans
On 13 February 2017 at 13:58, Tanu Kaskinen  wrote:
> On Fri, 2017-01-27 at 17:15 +0100, Wim Taymans wrote:
>> Hi All,
>>
>> I think (1) is quite ugly and requires you to modify many functions
>> with a new parameter that
>> is not at all related to what the function does.
>
> I disagree with the characterization that the client parameter is not
> related to what the function does. If the function does access control,
> then the client parameter is very much related to that.

Together with things such as logging,configuration and allocation, security
is typically a Cross-cutting concern
(https://en.wikipedia.org/wiki/Cross-cutting_concern).
The methods that operate on objects should not include the parameters for
the cross-cutting concern, you would typically keep those stored in a global
environment or singleton (like how we have the logging in a singleton, the
mempool and configuration in pa_core, ..).
We should to the same with the current client, IMHO.

>
>> It does however give
>> you good control over what
>> you can check. One example is pa_sink_update_rate() which might
>> suspend and unsuspend
>> the source to implement the rate change. It a new client does not have
>> permission to suspend a
>> sink, it will not be able to change the rate.
>
> If I understood correctly, you're comparing options (1) and (2) here,
> and you're saying that option (2) will prevent sink rate changes
> for streams that are played by clients that don't have the permission
> to suspend sinks. I don't think that's true. pa_sink_update_rate() can
> set current_client to NULL before it calls pa_sink_suspend().

That is true but it is not so nice because it assumes that pa_sink_update_rate()
knows pa_sink_suspend() is going to perform some sort of access
control that would somehow fail and so it needs to work around it. Ideally
pa_sink_suspend() knows in what context it's called and can decide this
for itself.

Fortunately pa_sink_suspend() has a 'cause' argument that we can actually
use for this: PA_SUSPEND_USER. We are lucky here, theoretically, in some
cases there might not be enough context to do the right access checks.

>
>> (2) looks quite ok. Setting and clearing the current_client is
>> straightforward and easily verifiable.
>> You can also be certain that when you add new checks, you can just get
>> the client from there
>> instead of having to change a method. The downside is that if ever a
>> non-main thread tries to
>> do some access control, you get random behaviour. using TLS will, of
>> course fix this.
>
> I don't know why you're worried about other threads. I don't see the
> need to do access control from other threads than the main thread.

I've put some asserts to make sure the set and get are always done from
the control thread.

>
>> (3) is probably still the most simple solution but only deals with the
>> native-protocol. (1) and (2)
>> now also automatically work for the cli, DBus, esound, http, simple
>> and native protocol.
>>
>> What do you think? Which option do you like best?
>
> I feel I need to have a close look at all the implementations to give a
> definite opinion. So far I've only looked at the implementation of (3).
> At the moment I'm not strongly opposed to any of the alternatives, but
> if I had to choose right now, I'd prefer (1), then (2) and last (3).
> Option (3) is last, because it's easier to forget access checks when
> the core doesn't enforce it. (1) and (2) are functionally equivalent.
> Both are about enforcing access control in the core, and in both cases
> the core functions need the client object as a parameter. Option (1)
> does the parameter passing in the usual way, and option (2) does the
> parameter passing in an unusual way. Option (1) makes it obvious which
> functions involve access control, and forces the programmer to think
> about how access control should be done in each case, which I believe
> reduces the possibility for errors.
>

I've update the flatpak branch here:
https://cgit.freedesktop.org/~wtay/pulseaudio/log/?h=flatpack

Since option 3 is now at the bottom of the list and I also think it's
inferior to the
other options, I'm no longer going to update or propose it.

I tried to incorporate the suggestions you listed below.

> creds: add pid to pa_creds and use store it in pa_client
> 
>
> This patch seems to have three separate changes that should probably be
> in separate patches: adding pid to pa_creds, adding creds to pa_client
> and adding the CLIENT_AUTH hook.

Split into 3 patches.

>
> +typedef struct pa_protocol_nat

[pulseaudio-discuss] [PATCH] combine-sinks: add suport for DYNAMIC_LATENCY

2014-04-15 Thread Wim Taymans
Mark the sink as DYNAMIC_LATENCY and implement update_sink_latency_range
on its sink-input to collect the combined latency range of all sinks.

Implement update_requested_latency on the sink to configure the final
latency by combining the sink-input requested latencies. This makes us
honour the client latency request.

We don't need to call update_max_request() and update_fixed_latency()
when adding and removing outputs, this is already done when we attach
the sink-inputs.

Also add more debug log.

Fixes https://bugs.freedesktop.org/show_bug.cgi?id=47899
---
 src/modules/module-combine-sink.c | 135 +++---
 1 file changed, 98 insertions(+), 37 deletions(-)

diff --git a/src/modules/module-combine-sink.c 
b/src/modules/module-combine-sink.c
index deabceb..d705542 100644
--- a/src/modules/module-combine-sink.c
+++ b/src/modules/module-combine-sink.c
@@ -104,7 +104,8 @@ struct output {
 
 /* For communication of the stream parameters to the sink thread */
 pa_atomic_t max_request;
-pa_atomic_t requested_latency;
+pa_atomic_t max_latency;
+pa_atomic_t min_latency;
 
 PA_LLIST_FIELDS(struct output);
 };
@@ -150,11 +151,12 @@ enum {
 SINK_MESSAGE_NEED,
 SINK_MESSAGE_UPDATE_LATENCY,
 SINK_MESSAGE_UPDATE_MAX_REQUEST,
-SINK_MESSAGE_UPDATE_REQUESTED_LATENCY
+SINK_MESSAGE_UPDATE_LATENCY_RANGE
 };
 
 enum {
 SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
+SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY
 };
 
 static void output_disable(struct output *o);
@@ -469,35 +471,44 @@ static void 
sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
 return;
 
 pa_atomic_store(&o->max_request, (int) nbytes);
+pa_log_debug("Sink input update max request %lu", (unsigned long) nbytes);
 pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL);
 }
 
 /* Called from thread context */
-static void sink_input_update_sink_requested_latency_cb(pa_sink_input *i) {
+static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
 struct output *o;
-pa_usec_t c;
+pa_usec_t min, max, fix;
 
 pa_assert(i);
 
 pa_sink_input_assert_ref(i);
 pa_assert_se(o = i->userdata);
 
-c = pa_sink_get_requested_latency_within_thread(i->sink);
-
-if (c == (pa_usec_t) -1)
-c = i->sink->thread_info.max_latency;
+fix = i->sink->thread_info.fixed_latency;
+if (fix > 0) {
+  min = fix;
+  max = fix;
+} else {
+  min = i->sink->thread_info.min_latency;
+  max = i->sink->thread_info.max_latency;
+}
 
-if (pa_atomic_load(&o->requested_latency) == (int) c)
+if ((pa_atomic_load(&o->min_latency) == (int) min) &&
+(pa_atomic_load(&o->max_latency) == (int) max))
 return;
 
-pa_atomic_store(&o->requested_latency, (int) c);
-pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_REQUESTED_LATENCY, NULL, 0, NULL, NULL);
+pa_atomic_store(&o->min_latency, (int) min);
+pa_atomic_store(&o->max_latency, (int) max);
+pa_log_debug("Sink input update latency range %lu %lu", (unsigned long) 
min, (unsigned long) max);
+pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_LATENCY_RANGE, NULL, 0, NULL, NULL);
 }
 
 /* Called from I/O thread context */
 static void sink_input_attach_cb(pa_sink_input *i) {
 struct output *o;
-pa_usec_t c;
+pa_usec_t fix, min, max;
+size_t nbytes;
 
 pa_sink_input_assert_ref(i);
 pa_assert_se(o = i->userdata);
@@ -517,13 +528,23 @@ static void sink_input_attach_cb(pa_sink_input *i) {
 
 pa_sink_input_request_rewind(i, 0, false, true, true);
 
-pa_atomic_store(&o->max_request, (int) pa_sink_input_get_max_request(i));
+nbytes = pa_sink_input_get_max_request(i);
+pa_atomic_store(&o->max_request, (int) nbytes);
+pa_log_debug("attach max request %lu", (unsigned long) nbytes);
 
-c = pa_sink_get_requested_latency_within_thread(i->sink);
-pa_atomic_store(&o->requested_latency, (int) (c == (pa_usec_t) -1 ? 0 : 
c));
+fix = i->sink->thread_info.fixed_latency;
+if (fix > 0) {
+  min = max = fix;
+} else {
+  min = i->sink->thread_info.min_latency;
+  max = i->sink->thread_info.max_latency;
+}
+pa_atomic_store(&o->min_latency, (int) min);
+pa_atomic_store(&o->max_latency, (int) max);
+pa_log_debug("attach latency range %lu %lu", (unsigned long) min, 
(unsigned long) max);
 
 pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL);
-pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_REQUESTED_LATENCY, NULL, 0, NULL, NULL);
+pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_LATENCY_RANGE, NULL, 0, NULL, NULL);
 }
 
 /* Called from I/O thread context */
@@ -580,6 +601,14 @@ static int sink_inpu

[pulseaudio-discuss] [PATCH 2/2] combine-sink: add suport for DYNAMIC_LATENCY

2014-05-27 Thread Wim Taymans
Mark the sink as DYNAMIC_LATENCY and implement update_sink_latency_range
on its sink-input to collect the combined latency range of all sinks.

Implement update_requested_latency on the sink to configure the final
latency by combining the sink-input requested latencies. This makes us
honour the client latency request.

Also add more debug log.

Fixes https://bugs.freedesktop.org/show_bug.cgi?id=47899
---
 src/modules/module-combine-sink.c | 134 --
 1 file changed, 98 insertions(+), 36 deletions(-)

diff --git a/src/modules/module-combine-sink.c 
b/src/modules/module-combine-sink.c
index a454a21..ada5611 100644
--- a/src/modules/module-combine-sink.c
+++ b/src/modules/module-combine-sink.c
@@ -104,7 +104,8 @@ struct output {
 
 /* For communication of the stream parameters to the sink thread */
 pa_atomic_t max_request;
-pa_atomic_t requested_latency;
+pa_atomic_t max_latency;
+pa_atomic_t min_latency;
 
 PA_LLIST_FIELDS(struct output);
 };
@@ -150,11 +151,12 @@ enum {
 SINK_MESSAGE_NEED,
 SINK_MESSAGE_UPDATE_LATENCY,
 SINK_MESSAGE_UPDATE_MAX_REQUEST,
-SINK_MESSAGE_UPDATE_REQUESTED_LATENCY
+SINK_MESSAGE_UPDATE_LATENCY_RANGE
 };
 
 enum {
 SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
+SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY
 };
 
 static void output_disable(struct output *o);
@@ -469,35 +471,44 @@ static void 
sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
 return;
 
 pa_atomic_store(&o->max_request, (int) nbytes);
+pa_log_debug("Sink input update max request %lu", (unsigned long) nbytes);
 pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL);
 }
 
 /* Called from thread context */
-static void sink_input_update_sink_requested_latency_cb(pa_sink_input *i) {
+static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
 struct output *o;
-pa_usec_t c;
+pa_usec_t min, max, fix;
 
 pa_assert(i);
 
 pa_sink_input_assert_ref(i);
 pa_assert_se(o = i->userdata);
 
-c = pa_sink_get_requested_latency_within_thread(i->sink);
-
-if (c == (pa_usec_t) -1)
-c = i->sink->thread_info.max_latency;
+fix = i->sink->thread_info.fixed_latency;
+if (fix > 0) {
+min = fix;
+max = fix;
+} else {
+min = i->sink->thread_info.min_latency;
+max = i->sink->thread_info.max_latency;
+}
 
-if (pa_atomic_load(&o->requested_latency) == (int) c)
+if ((pa_atomic_load(&o->min_latency) == (int) min) &&
+(pa_atomic_load(&o->max_latency) == (int) max))
 return;
 
-pa_atomic_store(&o->requested_latency, (int) c);
-pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_REQUESTED_LATENCY, NULL, 0, NULL, NULL);
+pa_atomic_store(&o->min_latency, (int) min);
+pa_atomic_store(&o->max_latency, (int) max);
+pa_log_debug("Sink input update latency range %lu %lu", (unsigned long) 
min, (unsigned long) max);
+pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_LATENCY_RANGE, NULL, 0, NULL, NULL);
 }
 
 /* Called from I/O thread context */
 static void sink_input_attach_cb(pa_sink_input *i) {
 struct output *o;
-pa_usec_t c;
+pa_usec_t fix, min, max;
+size_t nbytes;
 
 pa_sink_input_assert_ref(i);
 pa_assert_se(o = i->userdata);
@@ -517,10 +528,20 @@ static void sink_input_attach_cb(pa_sink_input *i) {
 
 pa_sink_input_request_rewind(i, 0, false, true, true);
 
-pa_atomic_store(&o->max_request, (int) pa_sink_input_get_max_request(i));
+nbytes = pa_sink_input_get_max_request(i);
+pa_atomic_store(&o->max_request, (int) nbytes);
+pa_log_debug("attach max request %lu", (unsigned long) nbytes);
 
-c = pa_sink_get_requested_latency_within_thread(i->sink);
-pa_atomic_store(&o->requested_latency, (int) (c == (pa_usec_t) -1 ? 0 : 
c));
+fix = i->sink->thread_info.fixed_latency;
+if (fix > 0) {
+min = max = fix;
+} else {
+min = i->sink->thread_info.min_latency;
+max = i->sink->thread_info.max_latency;
+}
+pa_atomic_store(&o->min_latency, (int) min);
+pa_atomic_store(&o->max_latency, (int) max);
+pa_log_debug("attach latency range %lu %lu", (unsigned long) min, 
(unsigned long) max);
 
 /* We register the output. That means that the sink will start to pass 
data to
  * this output. */
@@ -547,6 +568,7 @@ static void sink_input_detach_cb(pa_sink_input *i) {
 pa_rtpoll_item_free(o->outq_rtpoll_item_write);
 o->outq_rtpoll_item_write = NULL;
 }
+
 }
 
 /* Called from main context */
@@ -585,6 +607,14 @@ static int sink_input_process_msg(pa_msgobject *obj, int 
code, void *data, int64
 pa_memblockq_flush_write(o->memblockq, true);
 
 return 0;
+
+case SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY: {
+pa_usec

[pulseaudio-discuss] [PATCH 0/2] combine-sink: add support for DYNAMIC_LATENCY

2014-05-27 Thread Wim Taymans
Here are the updated patches that add support for DYNAMIC_LATENCY in
the combine-sink module.

I've also include a small patch to rework the way outputs are added and
removed, I think this is nicer and more symetric.

Wim Taymans (2):
  combine-sink: rework output add/remove
  combine-sink: add support for DYNAMIC_LATENCY

 src/modules/module-combine-sink.c | 159 ++
 1 file changed, 108 insertions(+), 51 deletions(-)

-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 1/2] combine-sink: rework output add/remove

2014-05-27 Thread Wim Taymans
Add the output from its sink-input attached callback and remove it
again from the detach callback. This simplifies some output_enable
and we can also avoid posting 2 messages for the sink.
---
 src/modules/module-combine-sink.c | 27 +++
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/src/modules/module-combine-sink.c 
b/src/modules/module-combine-sink.c
index ccb2a49..a454a21 100644
--- a/src/modules/module-combine-sink.c
+++ b/src/modules/module-combine-sink.c
@@ -522,8 +522,9 @@ static void sink_input_attach_cb(pa_sink_input *i) {
 c = pa_sink_get_requested_latency_within_thread(i->sink);
 pa_atomic_store(&o->requested_latency, (int) (c == (pa_usec_t) -1 ? 0 : 
c));
 
-pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL);
-pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_REQUESTED_LATENCY, NULL, 0, NULL, NULL);
+/* We register the output. That means that the sink will start to pass 
data to
+ * this output. */
+pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, 
PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL);
 }
 
 /* Called from I/O thread context */
@@ -533,6 +534,10 @@ static void sink_input_detach_cb(pa_sink_input *i) {
 pa_sink_input_assert_ref(i);
 pa_assert_se(o = i->userdata);
 
+/* We unregister the output. That means that the sink doesn't
+ * pass any further data to this output */
+pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, 
PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
+
 if (o->inq_rtpoll_item_read) {
 pa_rtpoll_item_free(o->inq_rtpoll_item_read);
 o->inq_rtpoll_item_read = NULL;
@@ -719,6 +724,7 @@ static void output_add_within_thread(struct output *o) {
 
 /* Called from thread context of the io thread */
 static void output_remove_within_thread(struct output *o) {
+
 pa_assert(o);
 pa_sink_assert_io_context(o->sink);
 
@@ -965,18 +971,11 @@ static void output_enable(struct output *o) {
 if (output_create_sink_input(o) >= 0) {
 
 if (pa_sink_get_state(o->sink) != PA_SINK_INIT) {
-
-/* First we register the output. That means that the sink
- * will start to pass data to this output. */
-pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, 
PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL);
-
-/* Then we enable the sink input. That means that the sink
+/* Enable the sink input. That means that the sink
  * is now asked for new data. */
 pa_sink_input_put(o->sink_input);
 
-} else
-/* Hmm the sink is not yet started, do things right here */
-output_add_within_thread(o);
+}
 }
 
 o->ignore_state_change = false;
@@ -989,14 +988,10 @@ static void output_disable(struct output *o) {
 if (!o->sink_input)
 return;
 
-/* First we disable the sink input. That means that the sink is
+/* We disable the sink input. That means that the sink is
  * not asked for new data anymore  */
 pa_sink_input_unlink(o->sink_input);
 
-/* Then we unregister the output. That means that the sink doesn't
- * pass any further data to this output */
-pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, 
PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
-
 /* Now deallocate the stream */
 pa_sink_input_unref(o->sink_input);
 o->sink_input = NULL;
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH] combine-sink: add suport for DYNAMIC_LATENCY

2014-06-10 Thread Wim Taymans
Mark the sink as DYNAMIC_LATENCY and implement update_sink_latency_range
on its sink-input to collect the combined latency range of all sinks.

Implement update_requested_latency on the sink to configure the final
latency by combining the sink-input requested latencies. This makes us
honour the client latency request.

Also add more debug log.

Fixes https://bugs.freedesktop.org/show_bug.cgi?id=47899
---
 src/modules/module-combine-sink.c | 142 --
 1 file changed, 107 insertions(+), 35 deletions(-)

diff --git a/src/modules/module-combine-sink.c 
b/src/modules/module-combine-sink.c
index a454a21..fa9c90b 100644
--- a/src/modules/module-combine-sink.c
+++ b/src/modules/module-combine-sink.c
@@ -104,7 +104,8 @@ struct output {
 
 /* For communication of the stream parameters to the sink thread */
 pa_atomic_t max_request;
-pa_atomic_t requested_latency;
+pa_atomic_t max_latency;
+pa_atomic_t min_latency;
 
 PA_LLIST_FIELDS(struct output);
 };
@@ -131,6 +132,8 @@ struct userdata {
 pa_resample_method_t resample_method;
 
 pa_usec_t block_usec;
+pa_usec_t default_min_latency;
+pa_usec_t default_max_latency;
 
 pa_idxset* outputs; /* managed in main context */
 
@@ -150,11 +153,12 @@ enum {
 SINK_MESSAGE_NEED,
 SINK_MESSAGE_UPDATE_LATENCY,
 SINK_MESSAGE_UPDATE_MAX_REQUEST,
-SINK_MESSAGE_UPDATE_REQUESTED_LATENCY
+SINK_MESSAGE_UPDATE_LATENCY_RANGE
 };
 
 enum {
 SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
+SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY
 };
 
 static void output_disable(struct output *o);
@@ -469,35 +473,44 @@ static void 
sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
 return;
 
 pa_atomic_store(&o->max_request, (int) nbytes);
+pa_log_debug("Sink input update max request %lu", (unsigned long) nbytes);
 pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL);
 }
 
 /* Called from thread context */
-static void sink_input_update_sink_requested_latency_cb(pa_sink_input *i) {
+static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
 struct output *o;
-pa_usec_t c;
+pa_usec_t min, max, fix;
 
 pa_assert(i);
 
 pa_sink_input_assert_ref(i);
 pa_assert_se(o = i->userdata);
 
-c = pa_sink_get_requested_latency_within_thread(i->sink);
-
-if (c == (pa_usec_t) -1)
-c = i->sink->thread_info.max_latency;
+fix = i->sink->thread_info.fixed_latency;
+if (fix > 0) {
+min = fix;
+max = fix;
+} else {
+min = i->sink->thread_info.min_latency;
+max = i->sink->thread_info.max_latency;
+}
 
-if (pa_atomic_load(&o->requested_latency) == (int) c)
+if ((pa_atomic_load(&o->min_latency) == (int) min) &&
+(pa_atomic_load(&o->max_latency) == (int) max))
 return;
 
-pa_atomic_store(&o->requested_latency, (int) c);
-pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_REQUESTED_LATENCY, NULL, 0, NULL, NULL);
+pa_atomic_store(&o->min_latency, (int) min);
+pa_atomic_store(&o->max_latency, (int) max);
+pa_log_debug("Sink input update latency range %lu %lu", (unsigned long) 
min, (unsigned long) max);
+pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), 
SINK_MESSAGE_UPDATE_LATENCY_RANGE, NULL, 0, NULL, NULL);
 }
 
 /* Called from I/O thread context */
 static void sink_input_attach_cb(pa_sink_input *i) {
 struct output *o;
-pa_usec_t c;
+pa_usec_t fix, min, max;
+size_t nbytes;
 
 pa_sink_input_assert_ref(i);
 pa_assert_se(o = i->userdata);
@@ -517,10 +530,20 @@ static void sink_input_attach_cb(pa_sink_input *i) {
 
 pa_sink_input_request_rewind(i, 0, false, true, true);
 
-pa_atomic_store(&o->max_request, (int) pa_sink_input_get_max_request(i));
+nbytes = pa_sink_input_get_max_request(i);
+pa_atomic_store(&o->max_request, (int) nbytes);
+pa_log_debug("attach max request %lu", (unsigned long) nbytes);
 
-c = pa_sink_get_requested_latency_within_thread(i->sink);
-pa_atomic_store(&o->requested_latency, (int) (c == (pa_usec_t) -1 ? 0 : 
c));
+fix = i->sink->thread_info.fixed_latency;
+if (fix > 0) {
+min = max = fix;
+} else {
+min = i->sink->thread_info.min_latency;
+max = i->sink->thread_info.max_latency;
+}
+pa_atomic_store(&o->min_latency, (int) min);
+pa_atomic_store(&o->max_latency, (int) max);
+pa_log_debug("attach latency range %lu %lu", (unsigned long) min, 
(unsigned long) max);
 
 /* We register the output. That means that the sink will start to pass 
data to
  * this output. */
@@ -547,6 +570,7 @@ static void sink_input_detach_cb(pa_sink_input *i) {
 pa_rtpoll_item_free(o->outq_rtpoll_item_write);
 o->outq_rtpoll_item_write = NULL;
 }
+
 }
 
 /* Called from main context */
@@ -585,6 +609,14 @@ static i

[pulseaudio-discuss] [PATCH] combine-sink: add support for DYNAMIC_LATENCY

2014-06-10 Thread Wim Taymans
Here is an updated patch that implements DYNAMIC_LATENCY in the combine module.

As suggested, the min latency is now set to 0 (or 500, it's clamped internally)
when no output is connected. Max latency is always capped to 200ms (or
min_latency, if it is larger).

When no latency is requested from the sink-inputs, we configure ourselves for
our calculated max_latency. 

Inspired by the null-sink, we use the configured latency to make sure that the
null-renderer is woken up often enough.


Wim Taymans (1):
  combine-sink: add suport for DYNAMIC_LATENCY

 src/modules/module-combine-sink.c | 142 --
 1 file changed, 107 insertions(+), 35 deletions(-)

-- 
1.9.3

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


Re: [pulseaudio-discuss] ofono/HFP patches

2014-08-11 Thread Wim Taymans
You can get that eror when there is a problem with fd-passing over DBus.
Anything special with your setup? SELinux, for example, did the same thing
to me.  See if sudo setenforce 0 makes it work...

Wim


On 11 August 2014 15:07, Tanu Kaskinen 
wrote:

> On Fri, 2014-08-08 at 13:09 +0300, Tanu Kaskinen wrote:
> > On Fri, 2014-08-08 at 12:47 +0300, Von Dentz, Luiz wrote:
> > > Ive just return from vacation so it will take a few days to catch up,
> > > if you fill that you can do it quickly please go ahead.
> >
> > "Quickly" is a relative term... I should have time to do it during next
> > week.
>
> BlueZ doesn't seem to work on my machine (see [1]), so I can't do any
> testing, and I don't want to write untested patches.
>
> [1] http://marc.info/?l=linux-bluetooth&m=140776166414824&w=2
>
> --
> Tanu
>
> ___
> pulseaudio-discuss mailing list
> pulseaudio-discuss@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH 3/4] bluez5-util: always DISCONNECT on free

2014-09-01 Thread Wim Taymans
We always disconnect before free, move the state changed function in the
free method.
---
 src/modules/bluetooth/bluez5-util.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/modules/bluetooth/bluez5-util.c 
b/src/modules/bluetooth/bluez5-util.c
index b5c0726..777aca9 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -197,6 +197,8 @@ void pa_bluetooth_transport_put(pa_bluetooth_transport *t) {
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t) {
 pa_assert(t);
 
+transport_state_changed(t, PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED);
+
 if (t->dispose)
 t->dispose (t);
 pa_hashmap_remove(t->device->discovery->transports, t->path);
@@ -414,7 +416,6 @@ static void device_free(pa_bluetooth_device *d) {
 if (!(t = d->transports[i]))
 continue;
 
-transport_state_changed(t, PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED);
 pa_bluetooth_transport_free(t);
 }
 
@@ -1435,7 +1436,6 @@ static DBusMessage 
*endpoint_clear_configuration(DBusConnection *conn, DBusMessa
 
 if ((t = pa_hashmap_get(y->transports, path))) {
 pa_log_debug("Clearing transport %s profile %s", t->path, 
pa_bluetooth_profile_to_string(t->profile));
-transport_state_changed(t, PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED);
 pa_bluetooth_transport_free(t);
 }
 
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 2/4] bluez5-util: add dispose function

2014-09-01 Thread Wim Taymans
Add a dispose function to the transport that is called before freeing
the transport. Useful for cleaning up extra userdata.
---
 src/modules/bluetooth/bluez5-util.c | 2 ++
 src/modules/bluetooth/bluez5-util.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/src/modules/bluetooth/bluez5-util.c 
b/src/modules/bluetooth/bluez5-util.c
index 93677b4..b5c0726 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -197,6 +197,8 @@ void pa_bluetooth_transport_put(pa_bluetooth_transport *t) {
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t) {
 pa_assert(t);
 
+if (t->dispose)
+t->dispose (t);
 pa_hashmap_remove(t->device->discovery->transports, t->path);
 pa_xfree(t->owner);
 pa_xfree(t->path);
diff --git a/src/modules/bluetooth/bluez5-util.h 
b/src/modules/bluetooth/bluez5-util.h
index 67377e9..1c64d72 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -60,6 +60,7 @@ typedef enum pa_bluetooth_transport_state {
 
 typedef int (*pa_bluetooth_transport_acquire_cb)(pa_bluetooth_transport *t, 
bool optional, size_t *imtu, size_t *omtu);
 typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t);
+typedef void (*pa_bluetooth_transport_dispose_cb)(pa_bluetooth_transport *t);
 
 struct pa_bluetooth_transport {
 pa_bluetooth_device *device;
@@ -76,6 +77,7 @@ struct pa_bluetooth_transport {
 
 pa_bluetooth_transport_acquire_cb acquire;
 pa_bluetooth_transport_release_cb release;
+pa_bluetooth_transport_dispose_cb dispose;
 void *userdata;
 };
 
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 4/4] backend-null: add HSP profile support

2014-09-01 Thread Wim Taymans
Add simple support for the HSP profile. This allows pulseaudio to output
audio to a Headset using the HSP profile.

Make the null backend the default, now that it does something.
---
 configure.ac |   4 +-
 src/modules/bluetooth/backend-null.c | 457 ++-
 2 files changed, 455 insertions(+), 6 deletions(-)

diff --git a/configure.ac b/configure.ac
index 7b56210..6eb956e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1030,9 +1030,9 @@ AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1])
 ## Bluetooth Headset profiles backend ##
 
 AC_ARG_WITH(bluetooth_headset_backend,
-AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend 
for Bluetooth headset profiles (ofono)]))
+AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend 
for Bluetooth headset profiles (null)]))
 if test -z "$with_bluetooth_headset_backend" ; then
-BLUETOOTH_HEADSET_BACKEND=ofono
+BLUETOOTH_HEADSET_BACKEND=null
 else
 BLUETOOTH_HEADSET_BACKEND=$with_bluetooth_headset_backend
 fi
diff --git a/src/modules/bluetooth/backend-null.c 
b/src/modules/bluetooth/backend-null.c
index f8a145b..e3fe215 100644
--- a/src/modules/bluetooth/backend-null.c
+++ b/src/modules/bluetooth/backend-null.c
@@ -23,15 +23,464 @@
 #include 
 #endif
 
+#include 
+#include 
+#include 
+#include 
 #include 
 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
 #include "bluez5-util.h"
 
+struct pa_bluetooth_backend {
+  pa_core *core;
+  pa_dbus_connection *connection;
+  pa_bluetooth_discovery *discovery;
+
+  PA_LLIST_HEAD(pa_dbus_pending, pending);
+};
+
+struct transport_rfcomm {
+int rfcomm_fd;
+pa_io_event *rfcomm_io;
+pa_bluetooth_backend *backend;
+};
+
+#define BLUEZ_SERVICE "org.bluez"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1"
+
+#define BLUEZ_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported"
+
+#define BLUEZ_PROFILE_MANAGER_INTERFACE BLUEZ_SERVICE ".ProfileManager1"
+#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1"
+
+#define HSP_AG_PROFILE "/Profile/HSPAGProfile"
+
+#define PROFILE_INTROSPECT_XML  \
+DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE   \
+""\
+" " \
+"  "   \
+"  "   \
+"  "\
+"  "   \
+"  "  \
+"   " \
+"  "   \
+"  " \
+"   " \
+"   " \
+"   "   \
+"  "   \
+" " \
+" " \
+"  "\
+"   "  \
+"  "   \
+" " \
+""
+
+static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, 
DBusMessage *m,
+DBusPendingCallNotifyFunction 
func, void *call_data) {
+pa_dbus_pending *p;
+DBusPendingCall *call;
+
+pa_assert(backend);
+pa_assert(m);
+
+
pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(backend->connection),
 m, &call, -1));
+
+p = pa_dbus_pending_new(pa_dbus_connection_get(backend->connection), m, 
call, backend, call_data);
+PA_LLIST_PREPEND(pa_dbus_pending, backend->pending, p);
+dbus_pending_call_set_notify(call, func, p, NULL);
+
+return p;
+}
+
+static int bluez5_sco_acquire_cb(pa_bluetooth_transport *t, bool optional, 
size_t *imtu, size_t *omtu) {
+pa_bluetooth_device *d = t->device;
+struct sockaddr_sco addr;
+int err, i;
+int sock;
+bdaddr_t src;
+bdaddr_t dst;
+int voice = 0x60;
+const char *src_addr, *dst_addr;
+
+src_addr = d->adapter->address;
+dst_addr = d->address;
+
+for (i = 5; i >= 0; i--, src_addr += 3)
+src.b[i] = strtol(src_addr, NULL, 16);
+for (i = 5; i >= 0; i--, dst_addr += 3)
+dst.b[i] = strtol(dst_addr, NULL, 16);
+
+sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+if (sock < 0) {
+pa_log_error("socket(SEQPACKET, SCO) %s", pa_cstrerror(errno));
+return -1;
+}
+
+memset(&addr, 0, sizeof(addr));
+addr.sco_family = AF_BLUETOOTH;
+bacpy(&addr.sco_bdaddr, &src);
+
+if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+pa_log_error("bind(): %s", pa_cstrerror(errno));
+goto fail_close;
+}
+
+if (voice) {
+struct bt_voice opts;
+
+/* SCO voice setting */
+memset(&opts, 0, sizeof(opts));
+

[pulseaudio-discuss] [PATCH 0/4] Add simple HSP support in null backend

2014-09-01 Thread Wim Taymans
This set of patches adds a simple handler for the HSP profile to bluez
and makes a new card for each connected device. This makes it possible to
send audio to a Headset.

The first 3 patches are mostly some very small cleanups and little bits to
implement the last patch.

The patch also switches the default backend from ofono to null.

Wim Taymans (4):
  bluez5-device: use get_profile_direction
  bluez5-util: add dispose function
  bluez5-util: always DISCONNECT on free
  backend-null: add HSP profile support

 configure.ac |   4 +-
 src/modules/bluetooth/backend-null.c | 457 ++-
 src/modules/bluetooth/bluez5-util.c  |   6 +-
 src/modules/bluetooth/bluez5-util.h  |   2 +
 src/modules/bluetooth/module-bluez5-device.c |  32 +-
 5 files changed, 476 insertions(+), 25 deletions(-)

-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 1/4] bluez5-device: use get_profile_direction

2014-09-01 Thread Wim Taymans
Use the get_profile_direction() helper function to decide when to add a
source and a sink instead of enumerating profiles.
---
 src/modules/bluetooth/module-bluez5-device.c | 32 +---
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/src/modules/bluetooth/module-bluez5-device.c 
b/src/modules/bluetooth/module-bluez5-device.c
index fdf4078..49f4676 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -1210,6 +1210,19 @@ static int setup_transport(struct userdata *u) {
 }
 
 /* Run from main thread */
+static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
+static const pa_direction_t profile_direction[] = {
+[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
+[PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_OFF] = 0
+};
+
+return profile_direction[p];
+}
+
+/* Run from main thread */
 static int init_profile(struct userdata *u) {
 int r = 0;
 pa_assert(u);
@@ -1220,13 +1233,11 @@ static int init_profile(struct userdata *u) {
 
 pa_assert(u->transport);
 
-if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || u->profile == 
PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
+if (get_profile_direction (u->profile) & PA_DIRECTION_OUTPUT)
 if (add_sink(u) < 0)
 r = -1;
 
-if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == 
PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
+if (get_profile_direction (u->profile) & PA_DIRECTION_INPUT)
 if (add_source(u) < 0)
 r = -1;
 
@@ -1546,19 +1557,6 @@ static char *cleanup_name(const char *name) {
 }
 
 /* Run from main thread */
-static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
-static const pa_direction_t profile_direction[] = {
-[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
-[PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_OFF] = 0
-};
-
-return profile_direction[p];
-}
-
-/* Run from main thread */
 static pa_available_t get_port_availability(struct userdata *u, pa_direction_t 
direction) {
 pa_available_t result = PA_AVAILABLE_NO;
 unsigned i;
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 1/5] bluez5-device: use get_profile_direction

2014-09-08 Thread Wim Taymans
Use the get_profile_direction() helper function to decide when to add a
source and a sink instead of enumerating profiles.
---
 src/modules/bluetooth/module-bluez5-device.c | 32 +---
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/src/modules/bluetooth/module-bluez5-device.c 
b/src/modules/bluetooth/module-bluez5-device.c
index fdf4078..49f4676 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -1210,6 +1210,19 @@ static int setup_transport(struct userdata *u) {
 }
 
 /* Run from main thread */
+static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
+static const pa_direction_t profile_direction[] = {
+[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
+[PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_OFF] = 0
+};
+
+return profile_direction[p];
+}
+
+/* Run from main thread */
 static int init_profile(struct userdata *u) {
 int r = 0;
 pa_assert(u);
@@ -1220,13 +1233,11 @@ static int init_profile(struct userdata *u) {
 
 pa_assert(u->transport);
 
-if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || u->profile == 
PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
+if (get_profile_direction (u->profile) & PA_DIRECTION_OUTPUT)
 if (add_sink(u) < 0)
 r = -1;
 
-if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == 
PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
+if (get_profile_direction (u->profile) & PA_DIRECTION_INPUT)
 if (add_source(u) < 0)
 r = -1;
 
@@ -1546,19 +1557,6 @@ static char *cleanup_name(const char *name) {
 }
 
 /* Run from main thread */
-static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
-static const pa_direction_t profile_direction[] = {
-[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
-[PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_OFF] = 0
-};
-
-return profile_direction[p];
-}
-
-/* Run from main thread */
 static pa_available_t get_port_availability(struct userdata *u, pa_direction_t 
direction) {
 pa_available_t result = PA_AVAILABLE_NO;
 unsigned i;
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 4/5] configure: fix headset check

2014-09-08 Thread Wim Taymans
---
 configure.ac | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 7b56210..e1e2572 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1037,7 +1037,7 @@ else
 BLUETOOTH_HEADSET_BACKEND=$with_bluetooth_headset_backend
 fi
 
-AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono && "test 
"x$BLUETOOTH_HEADSET_BACKEND" != "xnull"],
+AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test 
"x$BLUETOOTH_HEADSET_BACKEND" != "xnull"],
 [AC_MSG_ERROR([*** Invalid Bluetooth Headset backend])])
 
 AC_SUBST(BLUETOOTH_HEADSET_BACKEND)
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 0/5] Add simple HSP support in new native backend

2014-09-08 Thread Wim Taymans
This set of patches adds a simple handler for the HSP profile to bluez
and makes a new card for each connected device. This makes it possible to
send audio to a Headset. The profile is implemented in a new native
headset backend.

The first 4 patches are mostly some very small cleanups and little bits to
implement the last patch.

The patch also switches the default backend from ofono to native.

Wim Taymans (5):
  bluez5-device: use get_profile_direction
  bluez5-util: add dispose function
  bluez5-util: always DISCONNECT on free
  configure: fix headset check
  backend-native: add a new native headset backend

 configure.ac |   6 +-
 src/modules/bluetooth/backend-native.c   | 474 +++
 src/modules/bluetooth/bluez5-util.c  |   6 +-
 src/modules/bluetooth/bluez5-util.h  |   2 +
 src/modules/bluetooth/module-bluez5-device.c |  32 +-
 5 files changed, 498 insertions(+), 22 deletions(-)
 create mode 100644 src/modules/bluetooth/backend-native.c

-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 2/5] bluez5-util: add dispose function

2014-09-08 Thread Wim Taymans
Add a dispose function to the transport that is called before freeing
the transport. Useful for cleaning up extra userdata.
---
 src/modules/bluetooth/bluez5-util.c | 2 ++
 src/modules/bluetooth/bluez5-util.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/src/modules/bluetooth/bluez5-util.c 
b/src/modules/bluetooth/bluez5-util.c
index 93677b4..b5c0726 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -197,6 +197,8 @@ void pa_bluetooth_transport_put(pa_bluetooth_transport *t) {
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t) {
 pa_assert(t);
 
+if (t->dispose)
+t->dispose (t);
 pa_hashmap_remove(t->device->discovery->transports, t->path);
 pa_xfree(t->owner);
 pa_xfree(t->path);
diff --git a/src/modules/bluetooth/bluez5-util.h 
b/src/modules/bluetooth/bluez5-util.h
index 67377e9..1c64d72 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -60,6 +60,7 @@ typedef enum pa_bluetooth_transport_state {
 
 typedef int (*pa_bluetooth_transport_acquire_cb)(pa_bluetooth_transport *t, 
bool optional, size_t *imtu, size_t *omtu);
 typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t);
+typedef void (*pa_bluetooth_transport_dispose_cb)(pa_bluetooth_transport *t);
 
 struct pa_bluetooth_transport {
 pa_bluetooth_device *device;
@@ -76,6 +77,7 @@ struct pa_bluetooth_transport {
 
 pa_bluetooth_transport_acquire_cb acquire;
 pa_bluetooth_transport_release_cb release;
+pa_bluetooth_transport_dispose_cb dispose;
 void *userdata;
 };
 
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 5/5] backend-native: add a new native headset backend

2014-09-08 Thread Wim Taymans
Add a simple native headset backend that implements support for the
blutooth HSP profile.
This allows pulseaudio to output audio to a Headset using the HSP profile.

Make the native backend the default.
---
 configure.ac   |   6 +-
 src/modules/bluetooth/backend-native.c | 474 +
 2 files changed, 477 insertions(+), 3 deletions(-)
 create mode 100644 src/modules/bluetooth/backend-native.c

diff --git a/configure.ac b/configure.ac
index e1e2572..a91639f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1030,14 +1030,14 @@ AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1])
 ## Bluetooth Headset profiles backend ##
 
 AC_ARG_WITH(bluetooth_headset_backend,
-AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend 
for Bluetooth headset profiles (ofono)]))
+
AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend 
for Bluetooth headset profiles (native)]))
 if test -z "$with_bluetooth_headset_backend" ; then
-BLUETOOTH_HEADSET_BACKEND=ofono
+BLUETOOTH_HEADSET_BACKEND=native
 else
 BLUETOOTH_HEADSET_BACKEND=$with_bluetooth_headset_backend
 fi
 
-AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test 
"x$BLUETOOTH_HEADSET_BACKEND" != "xnull"],
+AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test 
"x$BLUETOOTH_HEADSET_BACKEND" != "xnull" && test "x$BLUETOOTH_HEADSET_BACKEND" 
!= "xnative"],
 [AC_MSG_ERROR([*** Invalid Bluetooth Headset backend])])
 
 AC_SUBST(BLUETOOTH_HEADSET_BACKEND)
diff --git a/src/modules/bluetooth/backend-native.c 
b/src/modules/bluetooth/backend-native.c
new file mode 100644
index 000..8af610c
--- /dev/null
+++ b/src/modules/bluetooth/backend-native.c
@@ -0,0 +1,474 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2014 Wim Taymans 
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include 
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "bluez5-util.h"
+
+struct pa_bluetooth_backend {
+  pa_core *core;
+  pa_dbus_connection *connection;
+  pa_bluetooth_discovery *discovery;
+
+  PA_LLIST_HEAD(pa_dbus_pending, pending);
+};
+
+struct transport_rfcomm {
+int rfcomm_fd;
+pa_io_event *rfcomm_io;
+pa_bluetooth_backend *backend;
+};
+
+#define BLUEZ_SERVICE "org.bluez"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1"
+
+#define BLUEZ_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported"
+
+#define BLUEZ_PROFILE_MANAGER_INTERFACE BLUEZ_SERVICE ".ProfileManager1"
+#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1"
+
+#define HSP_AG_PROFILE "/Profile/HSPAGProfile"
+
+#define PROFILE_INTROSPECT_XML  \
+DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE   \
+""\
+" " \
+"  "   \
+"  "   \
+"  "\
+"  "   \
+"  "  \
+"   " \
+"  "   \
+"  " \
+"   " \
+"   " \
+"   "   \
+"  "   \
+" " \
+" " \
+"  "\
+"   "  \
+"  "   \
+" " \
+""
+
+static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, 
DBusMessage *m,

[pulseaudio-discuss] [PATCH 3/5] bluez5-util: always DISCONNECT on free

2014-09-08 Thread Wim Taymans
We always disconnect before free, move the state changed function in the
free method.
---
 src/modules/bluetooth/bluez5-util.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/modules/bluetooth/bluez5-util.c 
b/src/modules/bluetooth/bluez5-util.c
index b5c0726..777aca9 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -197,6 +197,8 @@ void pa_bluetooth_transport_put(pa_bluetooth_transport *t) {
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t) {
 pa_assert(t);
 
+transport_state_changed(t, PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED);
+
 if (t->dispose)
 t->dispose (t);
 pa_hashmap_remove(t->device->discovery->transports, t->path);
@@ -414,7 +416,6 @@ static void device_free(pa_bluetooth_device *d) {
 if (!(t = d->transports[i]))
 continue;
 
-transport_state_changed(t, PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED);
 pa_bluetooth_transport_free(t);
 }
 
@@ -1435,7 +1436,6 @@ static DBusMessage 
*endpoint_clear_configuration(DBusConnection *conn, DBusMessa
 
 if ((t = pa_hashmap_get(y->transports, path))) {
 pa_log_debug("Clearing transport %s profile %s", t->path, 
pa_bluetooth_profile_to_string(t->profile));
-transport_state_changed(t, PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED);
 pa_bluetooth_transport_free(t);
 }
 
-- 
1.9.3

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


Re: [pulseaudio-discuss] [PATCH 0/5] Add simple HSP support in new native backend

2014-09-15 Thread Wim Taymans
>
> This set of patches adds a simple handler for the HSP profile to bluez
>> and makes a new card for each connected device. This makes it possible to
>> send audio to a Headset. The profile is implemented in a new native
>> headset backend.
>>
>> The first 4 patches are mostly some very small cleanups and little bits to
>> implement the last patch.
>>
>> The patch also switches the default backend from ofono to native.
>>
>
> Thanks for this patch set!
>
> Could you give a little explanation how this patch set relates to other
> patch sets (like the currently pending ofono patch set and your previous
> "null backend" patch set)?
>

These patches replace any of my previous patches, we now leave the null
backend as it is and add a new -native backend.

The idea for the native HSP backend is to have a simple implementation
without any extra dependencies. It's hard to make ofono work on desktop
machines and you don't need a full-blown phone stack to play sound through
the headset in many cases.



>
> I e, to test this, I obviously need bluez 5, but does it also require any
> pending patch set that it builds upon? And what can be expected,


It does not need anything else than bluez5. It basically restores the
functionality that got removed from bluez5 regarding the HSP profile.


> working HSP playback but not recording? Any other missing functionality
> and that you plan to add in later patches?


You can expect a new device to show up when you pair you headset. You can
then select the Headset Head Unit profile to make it connect using the HSP
Profile. Both Playback and recording work.

There is the future possibility to handle a button press and volume/gain of
the device. I'm not sure we want to handle any of them. You could map the
button press to cork/uncork the stream. You could possibly use the volume
controls in addition to the software volume but there are only 15 volume
levels. HSP only operates on 8Khz mono 16bits samples so  perhaps it is not
worth it.

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


Re: [pulseaudio-discuss] [PATCH 5/5] backend-native: add a new native headset backend

2014-09-15 Thread Wim Taymans
> > +if (imtu)
> > +*imtu = 48;
> > +
> > +if (omtu)
> > +*omtu = 48;
>
> Out of curiosity, are these values fixed in the spec?
>

They are not but the kernel does not want to give us the real MTU values so
this is hardcoded for now.

> +if (events & PA_IO_EVENT_INPUT) {
> > +char buf[512];
> > +ssize_t len;
> > +
> > +len = read (fd, buf, 511);
> > +buf[len] = 0;
> > +pa_log("RFCOMM << %s", buf);
> > +
> > +pa_log("RFCOMM >> OK");
> > +len = write (fd, "\r\nOK\r\n", 5);
> > +if (len < 0)
> > +pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno));
>
> Should we go to fail if this happens?
>

I'm ignoring this error for now, it's not critical and I expect real
failures such as disconnection etc to be handled with the HANGUP and ERROR
events.


>  d = pa_bluetooth_discovery_get_device_by_path(b->discovery, path);
> > +if (d == NULL) {
> > +pa_log_error("Device doesnt exist for %s", path);
> > +goto fail;
> > +}
> > +
> > +if (pa_streq(handler, HSP_AG_PROFILE)) {
> > +p = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
> > +} else
> > +goto refused;
>
> Is the else possible at all?
>
>
It should not be, I'll make it assert.



> > +dbus_message_iter_recurse(&element_i, &dict_i);
> > +
> > +if (key == NULL)
> > +break;
> > +if (dbus_message_iter_get_arg_type(&dict_i) != DBUS_TYPE_STRING)
> > +break;
> > +
> > +dbus_message_iter_get_basic(&dict_i, &key);
> > +
> > +if (!dbus_message_iter_next(&dict_i))
> > +break;
> > +
> > +if (dbus_message_iter_get_arg_type(&dict_i) !=
> DBUS_TYPE_VARIANT)
> > +break;
> > +
> > +pa_log_debug("key=%s", key);
> > +
> > +dbus_message_iter_next(&element_i);
> > +}
>
> If we're not doing anything with the keys, maybe we don't need to
> parse any of this?
>

I'll remove it. It should only contain a version number but I don't plan to
do anything with that for now.


>
> > +trfc =  pa_xnew0(struct transport_rfcomm, 1);
> > +trfc->rfcomm_fd = fd;
> > +trfc->rfcomm_io = b->core->mainloop->io_new(b->core->mainloop, fd,
> PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP,
> > +rfcomm_io_callback, t);
>
> Can reading/writing on the RFCOMM fd block the mainloop for long periods?
>

The socket flags are set G_IO_FLAG_NONBLOCK in bluez, AFAICS.


>
> > +trfc->backend = b;
>
> Can the backend be destroyed before the transport? Maybe we should
> only reference the mainloop instead of the backend here.
>

I'll have a look if all cleanup scenarios work fine. We should probably
just ref the mainloop, indeed.



> > +static DBusMessage *profile_request_disconnection(DBusConnection *conn,
> DBusMessage *m, void *userdata) {
> > +DBusMessage *r;
> > +
> > +pa_assert_se(r = dbus_message_new_method_return(m));
>
> How is the transport torn down in this case?
>

Bluez closes the RFCOMM socket, that makes us stop. Another case is when
the SCO socket is closed. We free the transport, which makes us remove the
device. I'll see if I can close it myself instead.


>
> > +
> > +} else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE,
> "Release")) {
> > +} else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE,
> "Cancel")) {
>
> There doesn't actually seem to be a 'Cancel' method.
>

I will remove it. It looks like it is supposed to be part of the API here:

http://git.kernel.org/cgit/bluetooth/bluez.git/tree/profiles/iap/main.c#n228

and in some exampled, but it does not look like it is used here:

is http://git.kernel.org/cgit/bluetooth/bluez.git/tree/src/profile.c

> +switch(profile) {
> > +case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
> > +object_name = HSP_AG_PROFILE;
> > +uuid = PA_BLUETOOTH_UUID_HSP_AG;
> > +break;
> > +default:
> > +pa_assert_not_reached();
> > +break;
> > +}
> > +
> pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(b->connection),
> > +  object_name, &vtable_profile, b));
> > +register_profile (b, object_name, uuid);
>
> There doesn't seem to be a way to handle failure when registering the
> profile. Should we perhaps be unregistering the object path?
>
> yes, will do.


> > +
> > +profile_done(backend, PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT);
>
> backend->connection needs to be unref'ed here.
>
> Will do,

Thanks for reviewing, will post new patches with all suggestions and fixes
soon,

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


Re: [pulseaudio-discuss] [PATCH 0/5] Add simple HSP support in new native backend

2014-09-15 Thread Wim Taymans
>
>
> With BlueZ 4 we support hardware volume, i.e. the 15 volume levels. This
> is actually quite important, because if you rely on software volume,
> there will be two independent volume controls for the headset: the
> software volume in PulseAudio, and the headset's internal volume. Not
> user-friendly at all.
>

I had a look at the bluez4 code for that, it should not be hard to add
volume handling as well.

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


[pulseaudio-discuss] [PATCH 3/3] backend-native: add a new native headset backend

2014-09-16 Thread Wim Taymans
Add a simple native headset backend that implements support for the
blutooth HSP profile.
This allows pulseaudio to output audio to a Headset using the HSP profile.

Make the native backend the default.
---
 configure.ac   |   6 +-
 src/modules/bluetooth/backend-native.c | 443 +
 2 files changed, 446 insertions(+), 3 deletions(-)
 create mode 100644 src/modules/bluetooth/backend-native.c

diff --git a/configure.ac b/configure.ac
index f13ddb0..5b3f3cc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1030,14 +1030,14 @@ AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1])
 ## Bluetooth Headset profiles backend ##
 
 AC_ARG_WITH(bluetooth_headset_backend,
-AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend 
for Bluetooth headset profiles (ofono)]))
+
AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend 
for Bluetooth headset profiles (native)]))
 if test -z "$with_bluetooth_headset_backend" ; then
-BLUETOOTH_HEADSET_BACKEND=ofono
+BLUETOOTH_HEADSET_BACKEND=native
 else
 BLUETOOTH_HEADSET_BACKEND=$with_bluetooth_headset_backend
 fi
 
-AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test 
"x$BLUETOOTH_HEADSET_BACKEND" != "xnull"],
+AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test 
"x$BLUETOOTH_HEADSET_BACKEND" != "xnull" && test "x$BLUETOOTH_HEADSET_BACKEND" 
!= "xnative"],
 [AC_MSG_ERROR([*** Invalid Bluetooth Headset backend])])
 
 AC_SUBST(BLUETOOTH_HEADSET_BACKEND)
diff --git a/src/modules/bluetooth/backend-native.c 
b/src/modules/bluetooth/backend-native.c
new file mode 100644
index 000..b3c4220
--- /dev/null
+++ b/src/modules/bluetooth/backend-native.c
@@ -0,0 +1,443 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2014 Wim Taymans 
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include 
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "bluez5-util.h"
+
+struct pa_bluetooth_backend {
+  pa_core *core;
+  pa_dbus_connection *connection;
+  pa_bluetooth_discovery *discovery;
+
+  PA_LLIST_HEAD(pa_dbus_pending, pending);
+};
+
+struct transport_rfcomm {
+int rfcomm_fd;
+pa_io_event *rfcomm_io;
+pa_mainloop_api *mainloop;
+};
+
+#define BLUEZ_SERVICE "org.bluez"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1"
+
+#define BLUEZ_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported"
+
+#define BLUEZ_PROFILE_MANAGER_INTERFACE BLUEZ_SERVICE ".ProfileManager1"
+#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1"
+
+#define HSP_AG_PROFILE "/Profile/HSPAGProfile"
+
+#define PROFILE_INTROSPECT_XML  \
+DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE   \
+""\
+" " \
+"  "   \
+"  "   \
+"  "  \
+"   " \
+"  "   \
+"  " \
+"   " \
+"   " \
+"   "   \
+"  "   \
+" " \
+" " \
+"  "\
+"   "  \
+"  "   \
+" " \
+""
+
+static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, 
DBusMessage *m,
+DBusPendingCallNotifyFunction 
func, void *call_data) {
+pa_dbus_pending *p;
+DBusPendingCall *ca

[pulseaudio-discuss] [PATCH 0/3] Add simple HSP support in new native backend

2014-09-16 Thread Wim Taymans
This set of patches adds a simple handler for the HSP profile to bluez
and makes a new card for each connected device. This makes it possible to
send audio to a Headset. The profile is implemented in a new native
headset backend.

The first 2 patches are mostly some very small cleanups and little bits to
implement the last patch.

The patch also switches the default backend from ofono to native.

This patch replaces the previously posted native backend patches and
incorporates the suggestions I received.


Wim Taymans (3):
  bluez5-device: use get_profile_direction
  bluez5-util: add dispose function
  backend-native: add a new native headset backend

 configure.ac |   6 +-
 src/modules/bluetooth/backend-native.c   | 443 +++
 src/modules/bluetooth/bluez5-util.c  |   2 +
 src/modules/bluetooth/bluez5-util.h  |   2 +
 src/modules/bluetooth/module-bluez5-device.c |  32 +-
 5 files changed, 465 insertions(+), 20 deletions(-)
 create mode 100644 src/modules/bluetooth/backend-native.c

-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 1/3] bluez5-device: use get_profile_direction

2014-09-16 Thread Wim Taymans
Use the get_profile_direction() helper function to decide when to add a
source and a sink instead of enumerating profiles.
---
 src/modules/bluetooth/module-bluez5-device.c | 32 +---
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/src/modules/bluetooth/module-bluez5-device.c 
b/src/modules/bluetooth/module-bluez5-device.c
index fdf4078..49f4676 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -1210,6 +1210,19 @@ static int setup_transport(struct userdata *u) {
 }
 
 /* Run from main thread */
+static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
+static const pa_direction_t profile_direction[] = {
+[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
+[PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_OFF] = 0
+};
+
+return profile_direction[p];
+}
+
+/* Run from main thread */
 static int init_profile(struct userdata *u) {
 int r = 0;
 pa_assert(u);
@@ -1220,13 +1233,11 @@ static int init_profile(struct userdata *u) {
 
 pa_assert(u->transport);
 
-if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || u->profile == 
PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
+if (get_profile_direction (u->profile) & PA_DIRECTION_OUTPUT)
 if (add_sink(u) < 0)
 r = -1;
 
-if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == 
PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
+if (get_profile_direction (u->profile) & PA_DIRECTION_INPUT)
 if (add_source(u) < 0)
 r = -1;
 
@@ -1546,19 +1557,6 @@ static char *cleanup_name(const char *name) {
 }
 
 /* Run from main thread */
-static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
-static const pa_direction_t profile_direction[] = {
-[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
-[PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_OFF] = 0
-};
-
-return profile_direction[p];
-}
-
-/* Run from main thread */
 static pa_available_t get_port_availability(struct userdata *u, pa_direction_t 
direction) {
 pa_available_t result = PA_AVAILABLE_NO;
 unsigned i;
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 2/3] bluez5-util: add dispose function

2014-09-16 Thread Wim Taymans
Add a dispose function to the transport that is called before freeing
the transport. Useful for cleaning up extra userdata.
---
 src/modules/bluetooth/bluez5-util.c | 2 ++
 src/modules/bluetooth/bluez5-util.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/src/modules/bluetooth/bluez5-util.c 
b/src/modules/bluetooth/bluez5-util.c
index 8bb57f4..d847255 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -203,6 +203,8 @@ void pa_bluetooth_transport_unlink(pa_bluetooth_transport 
*t) {
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t) {
 pa_assert(t);
 
+if (t->dispose)
+t->dispose (t);
 pa_hashmap_remove(t->device->discovery->transports, t->path);
 pa_xfree(t->owner);
 pa_xfree(t->path);
diff --git a/src/modules/bluetooth/bluez5-util.h 
b/src/modules/bluetooth/bluez5-util.h
index 8db4a17..fde2e78 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -60,6 +60,7 @@ typedef enum pa_bluetooth_transport_state {
 
 typedef int (*pa_bluetooth_transport_acquire_cb)(pa_bluetooth_transport *t, 
bool optional, size_t *imtu, size_t *omtu);
 typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t);
+typedef void (*pa_bluetooth_transport_dispose_cb)(pa_bluetooth_transport *t);
 
 struct pa_bluetooth_transport {
 pa_bluetooth_device *device;
@@ -76,6 +77,7 @@ struct pa_bluetooth_transport {
 
 pa_bluetooth_transport_acquire_cb acquire;
 pa_bluetooth_transport_release_cb release;
+pa_bluetooth_transport_dispose_cb dispose;
 void *userdata;
 };
 
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 1/4] bluez5-device: use get_profile_direction

2014-10-24 Thread Wim Taymans
Use the get_profile_direction() helper function to decide when to add a
source and a sink instead of enumerating profiles.
---
 src/modules/bluetooth/module-bluez5-device.c | 32 +---
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/src/modules/bluetooth/module-bluez5-device.c 
b/src/modules/bluetooth/module-bluez5-device.c
index 48e498b..15731d1 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -1210,6 +1210,19 @@ static int setup_transport(struct userdata *u) {
 }
 
 /* Run from main thread */
+static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
+static const pa_direction_t profile_direction[] = {
+[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
+[PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
+[PA_BLUETOOTH_PROFILE_OFF] = 0
+};
+
+return profile_direction[p];
+}
+
+/* Run from main thread */
 static int init_profile(struct userdata *u) {
 int r = 0;
 pa_assert(u);
@@ -1220,13 +1233,11 @@ static int init_profile(struct userdata *u) {
 
 pa_assert(u->transport);
 
-if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || u->profile == 
PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
+if (get_profile_direction (u->profile) & PA_DIRECTION_OUTPUT)
 if (add_sink(u) < 0)
 r = -1;
 
-if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == 
PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
+if (get_profile_direction (u->profile) & PA_DIRECTION_INPUT)
 if (add_source(u) < 0)
 r = -1;
 
@@ -1546,19 +1557,6 @@ static char *cleanup_name(const char *name) {
 }
 
 /* Run from main thread */
-static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
-static const pa_direction_t profile_direction[] = {
-[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
-[PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | 
PA_DIRECTION_OUTPUT,
-[PA_BLUETOOTH_PROFILE_OFF] = 0
-};
-
-return profile_direction[p];
-}
-
-/* Run from main thread */
 static pa_available_t get_port_availability(struct userdata *u, pa_direction_t 
direction) {
 pa_available_t result = PA_AVAILABLE_NO;
 unsigned i;
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 3/4] backend-native: add a new native headset backend

2014-10-24 Thread Wim Taymans
Add a simple native headset backend that implements support for the
blutooth HSP profile.
This allows pulseaudio to output audio to a Headset using the HSP profile.

Make the native backend the default.
---
 configure.ac   |   6 +-
 src/modules/bluetooth/backend-native.c | 443 +
 2 files changed, 446 insertions(+), 3 deletions(-)
 create mode 100644 src/modules/bluetooth/backend-native.c

diff --git a/configure.ac b/configure.ac
index 74bea71..9a595cb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1032,14 +1032,14 @@ AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1])
 ## Bluetooth Headset profiles backend ##
 
 AC_ARG_WITH(bluetooth_headset_backend,
-AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend 
for Bluetooth headset profiles (ofono)]))
+
AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend 
for Bluetooth headset profiles (native)]))
 if test -z "$with_bluetooth_headset_backend" ; then
-BLUETOOTH_HEADSET_BACKEND=ofono
+BLUETOOTH_HEADSET_BACKEND=native
 else
 BLUETOOTH_HEADSET_BACKEND=$with_bluetooth_headset_backend
 fi
 
-AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test 
"x$BLUETOOTH_HEADSET_BACKEND" != "xnull"],
+AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test 
"x$BLUETOOTH_HEADSET_BACKEND" != "xnull" && test "x$BLUETOOTH_HEADSET_BACKEND" 
!= "xnative"],
 [AC_MSG_ERROR([*** Invalid Bluetooth Headset backend])])
 
 AC_SUBST(BLUETOOTH_HEADSET_BACKEND)
diff --git a/src/modules/bluetooth/backend-native.c 
b/src/modules/bluetooth/backend-native.c
new file mode 100644
index 000..b3c4220
--- /dev/null
+++ b/src/modules/bluetooth/backend-native.c
@@ -0,0 +1,443 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2014 Wim Taymans 
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include 
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "bluez5-util.h"
+
+struct pa_bluetooth_backend {
+  pa_core *core;
+  pa_dbus_connection *connection;
+  pa_bluetooth_discovery *discovery;
+
+  PA_LLIST_HEAD(pa_dbus_pending, pending);
+};
+
+struct transport_rfcomm {
+int rfcomm_fd;
+pa_io_event *rfcomm_io;
+pa_mainloop_api *mainloop;
+};
+
+#define BLUEZ_SERVICE "org.bluez"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1"
+
+#define BLUEZ_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported"
+
+#define BLUEZ_PROFILE_MANAGER_INTERFACE BLUEZ_SERVICE ".ProfileManager1"
+#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1"
+
+#define HSP_AG_PROFILE "/Profile/HSPAGProfile"
+
+#define PROFILE_INTROSPECT_XML  \
+DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE   \
+""\
+" " \
+"  "   \
+"  "   \
+"  "  \
+"   " \
+"  "   \
+"  " \
+"   " \
+"   " \
+"   "   \
+"  "   \
+" " \
+" " \
+"  "\
+"   "  \
+"  "   \
+" " \
+""
+
+static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, 
DBusMessage *m,
+DBusPendingCallNotifyFunction 
func, void *call_data) {
+pa_dbus_pending *p;
+DBusPendingCall *ca

[pulseaudio-discuss] [PATCH 2/4] bluez5-util: add dispose function

2014-10-24 Thread Wim Taymans
Add a dispose function to the transport that is called before freeing
the transport. Useful for cleaning up extra userdata.
---
 src/modules/bluetooth/bluez5-util.c | 2 ++
 src/modules/bluetooth/bluez5-util.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/src/modules/bluetooth/bluez5-util.c 
b/src/modules/bluetooth/bluez5-util.c
index 1ee2f33..50f977e 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -205,6 +205,8 @@ void pa_bluetooth_transport_unlink(pa_bluetooth_transport 
*t) {
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t) {
 pa_assert(t);
 
+if (t->dispose)
+t->dispose (t);
 pa_bluetooth_transport_unlink(t);
 
 pa_xfree(t->owner);
diff --git a/src/modules/bluetooth/bluez5-util.h 
b/src/modules/bluetooth/bluez5-util.h
index 8db4a17..fde2e78 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -60,6 +60,7 @@ typedef enum pa_bluetooth_transport_state {
 
 typedef int (*pa_bluetooth_transport_acquire_cb)(pa_bluetooth_transport *t, 
bool optional, size_t *imtu, size_t *omtu);
 typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t);
+typedef void (*pa_bluetooth_transport_dispose_cb)(pa_bluetooth_transport *t);
 
 struct pa_bluetooth_transport {
 pa_bluetooth_device *device;
@@ -76,6 +77,7 @@ struct pa_bluetooth_transport {
 
 pa_bluetooth_transport_acquire_cb acquire;
 pa_bluetooth_transport_release_cb release;
+pa_bluetooth_transport_dispose_cb dispose;
 void *userdata;
 };
 
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH 4/4] backend-native: implement volume control

2014-10-24 Thread Wim Taymans
Parse the gain changed AT commands from the headset and fire 2 new
hooks as a result. The device will connect to those hooks and change the
source/sink volumes.

When the source/sink volume changes, set the gain on the microphone or
speaker respectively. Make sure we do nothing if the transport can not
handle the gain changes.
---
 src/modules/bluetooth/backend-native.c   |  47 +
 src/modules/bluetooth/bluez5-util.h  |   9 ++
 src/modules/bluetooth/module-bluez5-device.c | 140 +++
 3 files changed, 196 insertions(+)

diff --git a/src/modules/bluetooth/backend-native.c 
b/src/modules/bluetooth/backend-native.c
index b3c4220..2302754 100644
--- a/src/modules/bluetooth/backend-native.c
+++ b/src/modules/bluetooth/backend-native.c
@@ -113,6 +113,7 @@ static int bluez5_sco_acquire_cb(pa_bluetooth_transport *t, 
bool optional, size_
 src_addr = d->adapter->address;
 dst_addr = d->address;
 
+/* don't use ba2str to avoid -lbluetooth */
 for (i = 5; i >= 0; i--, src_addr += 3)
 src.b[i] = strtol(src_addr, NULL, 16);
 for (i = 5; i >= 0; i--, dst_addr += 3)
@@ -226,11 +227,21 @@ static void rfcomm_io_callback(pa_mainloop_api *io, 
pa_io_event *e, int fd, pa_i
 if (events & PA_IO_EVENT_INPUT) {
 char buf[512];
 ssize_t len;
+int gain;
 
 len = read (fd, buf, 511);
 buf[len] = 0;
 pa_log("RFCOMM << %s", buf);
 
+if (sscanf (buf, "AT+VGS=%d", &gain) == 1) {
+  t->speaker_gain = gain;
+  pa_hook_fire(pa_bluetooth_discovery_hook (t->device->discovery, 
PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), t);
+
+} else if (sscanf (buf, "AT+VGM=%d", &gain) == 1) {
+  t->microphone_gain = gain;
+  pa_hook_fire(pa_bluetooth_discovery_hook (t->device->discovery, 
PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), t);
+}
+
 pa_log("RFCOMM >> OK");
 len = write (fd, "\r\nOK\r\n", 5);
 /* we ignore any errors, it's not critical and real errors should
@@ -256,6 +267,40 @@ static void transport_dispose(pa_bluetooth_transport *t) {
 pa_xfree(trfc);
 }
 
+static void set_speaker_gain(pa_bluetooth_transport *t, uint16_t gain) {
+struct transport_rfcomm *trfc = t->userdata;
+char buf[512];
+ssize_t len, written;
+
+if (t->speaker_gain == gain)
+  return;
+
+t->speaker_gain = gain;
+
+len = sprintf (buf, "+VGS=%d\r\n", gain);
+pa_log("RFCOMM >> +VGS=%d", gain);
+written = write (trfc->rfcomm_fd, buf, len);
+if (written != len)
+pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno));
+}
+
+static void set_microphone_gain(pa_bluetooth_transport *t, uint16_t gain) {
+struct transport_rfcomm *trfc = t->userdata;
+char buf[512];
+ssize_t len, written;
+
+if (t->microphone_gain == gain)
+  return;
+
+t->microphone_gain = gain;
+
+len = sprintf (buf, "+VGM=%d\r\n", gain);
+pa_log("RFCOMM >> +VGM=%d", gain);
+written = write (trfc->rfcomm_fd, buf, len);
+if (written != len)
+pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno));
+
+}
 
 static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage 
*m, void *userdata) {
 pa_bluetooth_backend *b = userdata;
@@ -303,6 +348,8 @@ static DBusMessage *profile_new_connection(DBusConnection 
*conn, DBusMessage *m,
 t->acquire = bluez5_sco_acquire_cb;
 t->release = bluez5_sco_release_cb;
 t->dispose = transport_dispose;
+t->set_speaker_gain = set_speaker_gain;
+t->set_microphone_gain = set_microphone_gain;
 
 trfc =  pa_xnew0(struct transport_rfcomm, 1);
 trfc->rfcomm_fd = fd;
diff --git a/src/modules/bluetooth/bluez5-util.h 
b/src/modules/bluetooth/bluez5-util.h
index fde2e78..1258f07 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -40,6 +40,8 @@ typedef struct pa_bluetooth_backend pa_bluetooth_backend;
 typedef enum pa_bluetooth_hook {
 PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED,  /* Call data: 
pa_bluetooth_device */
 PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED,/* Call data: 
pa_bluetooth_transport */
+PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED,  /* Call data: 
pa_bluetooth_transport */
+PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED, /* Call data: 
pa_bluetooth_transport */
 PA_BLUETOOTH_HOOK_MAX
 } pa_bluetooth_hook_t;
 
@@ -61,6 +63,8 @@ typedef enum pa_bluetooth_transport_state {
 typedef int (*pa_bluetooth_transport_acquire_cb)(pa_bluetooth_transport *t, 
bool optional, size_t *imtu, size_t *omtu);
 typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t);
 typedef void (*pa_bluetooth_transport_dispose_cb)(pa_bluetooth_transport *t);
+typedef void 
(*pa_bluetooth_transport_set_speaker_gain_cb)(pa_bluetooth_transport *t, 
uint16_t gain);
+typedef void 
(*pa_bluetooth_transport_set_microphone_gain_cb)(pa_bluetooth_transpo

[pulseaudio-discuss] [PATCH 0/4] Add simple HSP support in new native backend v3

2014-10-24 Thread Wim Taymans
This set of patches adds a simple handler for the HSP profile to bluez
and makes a new card for each connected device. This makes it possible to
send audio to a Headset. The profile is implemented in a new native
headset backend.

The first 2 patches are mostly some very small cleanups and little bits to
implement the following patches.

The patches also switches the default backend from ofono to native.

This patchset replaces the previously posted native backend patches and
incorporates the suggestions I received to date.

Wim Taymans (4):
  bluez5-device: use get_profile_direction
  bluez5-util: add dispose function
  backend-native: add a new native headset backend
  backend-native: implement volume control

 configure.ac |   6 +-
 src/modules/bluetooth/backend-native.c   | 490 +++
 src/modules/bluetooth/bluez5-util.c  |   2 +
 src/modules/bluetooth/bluez5-util.h  |  11 +
 src/modules/bluetooth/module-bluez5-device.c | 172 +-
 5 files changed, 661 insertions(+), 20 deletions(-)
 create mode 100644 src/modules/bluetooth/backend-native.c

-- 
1.9.3

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


Re: [pulseaudio-discuss] Master is frozen

2014-11-14 Thread Wim Taymans
Can you check in the log if the volume AT commands are sent to the headset?
What I can think of is maybe that the command is not formatted properly
(like missing a \n\r somewhere, I've seen some headset be picky about that).

Wim

On 14 November 2014 10:39, Arun Raghavan  wrote:

>
> On 14 Nov 2014 15:00, "David Henningsson" 
> wrote:
> >
> >
> >
> > On 2014-11-14 07:07, Arun Raghavan wrote:
> >>
> >> Hello,
> >> As promised, master is now frozen. Please do not push anything other
> >> than essential fixes.I'd like to have some stability testing of HSP
> >> before rolling 6.0 RC1.
> >
> >
> > I'd like to have my HSP compilation patches in before 6.0 RC1. Can I
> push them?
>
> I thought this was done. Please go ahead.
>
> >> Any help here is appreciated.
> >
> >
> > Ok, with some trouble [1] I installed bluez5 in Ubuntu 15.04 and ran
> PulseAudio git master on top of that, with the native headset backend.
> >
> > Result: Headset card shows up. Switching between A2DP and HSP seems to
> be working. The hsp profile is called "headset_head_unit", which is a
> change from bluez4, but it's nothing that seems to cause problems for me.
> >
> > HSP playback and recording seems to work. Volume control (playback) and
> gain control (recording) does not work, i e, changing volume and/or gain
> has no effect on actual volume/gain.
>
> Thanks for trying this. At least the volume bit is the same for us both.
> Will need to investigate that. Wim/Luiz, any ideas?
>
> If it was otherwise stable for you, that if good news indeed.
>
> Cheers,
> Arun
>
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] Master is frozen

2014-11-14 Thread Wim Taymans
Can you compare with a hcidump of working volume?

On 14 November 2014 10:46, Arun Raghavan  wrote:

>
> On 14 Nov 2014 15:13, "Wim Taymans"  wrote:
> >
> > Can you check in the log if the volume AT commands are sent to the
> headset? What I can think of is maybe that the command is not formatted
> properly (like missing a \n\r somewhere, I've seen some headset be picky
> about that).
>
> I'd checked that the AT commands are going out fine in hcidump. Tested
> with 2 headsets here, both did not work.
>
> I did add a couple of fixes on top of your volume patches, btw.
>
> --Arun
>
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] Master is frozen

2014-11-14 Thread Wim Taymans
After reading the HSP spec some more, the volume controls are optional. It
should be mentioned in the SDP if the remote volume is supported (with the
BT assigned number 0x302 apparently). Not sure how to get to that info..

Wim

On 14 November 2014 11:04, Arun Raghavan  wrote:

>
> On 14 Nov 2014 15:31, "Wim Taymans"  wrote:
> >
> > Can you compare with a hcidump of working volume?
>
> It never actually worked for me. If you have one that works, I can compare
> with what I get here ( well probably take a day or two).
>
> -- Arun
>
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] bluetooth: set gain correctly

2014-11-14 Thread Wim Taymans
Send the right command to set the speaker and microphone gain.
---
 src/modules/bluetooth/backend-native.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/modules/bluetooth/backend-native.c 
b/src/modules/bluetooth/backend-native.c
index 86af422..cea2db2 100644
--- a/src/modules/bluetooth/backend-native.c
+++ b/src/modules/bluetooth/backend-native.c
@@ -285,8 +285,8 @@ static void set_speaker_gain(pa_bluetooth_transport *t, 
uint16_t gain) {
 
 t->speaker_gain = gain;
 
-len = sprintf(buf, "AT+VGS=%d\r", gain);
-pa_log_debug("RFCOMM >> AT+VGS=%d", gain);
+len = sprintf(buf, "+VGS=%d\r", gain);
+pa_log_debug("RFCOMM >> +VGS=%d", gain);
 
 written = write(trfc->rfcomm_fd, buf, len);
 
@@ -304,8 +304,8 @@ static void set_microphone_gain(pa_bluetooth_transport *t, 
uint16_t gain) {
 
 t->microphone_gain = gain;
 
-len = sprintf(buf, "AT+VGM=%d\r", gain);
-pa_log_debug("RFCOMM >> AT+VGM=%d", gain);
+len = sprintf(buf, "+VGM=%d\r", gain);
+pa_log_debug("RFCOMM >> +VGM=%d", gain);
 
 written = write (trfc->rfcomm_fd, buf, len);
 
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH] bluetooth: set gain correctly

2014-11-14 Thread Wim Taymans
Send the right command to set the speaker and microphone gain.

Note that setting the volume on the Headset should use the unsolicited
result code. Receiving the volume from the Headset uses the AT
command.
---
 src/modules/bluetooth/backend-native.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/modules/bluetooth/backend-native.c 
b/src/modules/bluetooth/backend-native.c
index 86af422..8407672 100644
--- a/src/modules/bluetooth/backend-native.c
+++ b/src/modules/bluetooth/backend-native.c
@@ -285,8 +285,8 @@ static void set_speaker_gain(pa_bluetooth_transport *t, 
uint16_t gain) {
 
 t->speaker_gain = gain;
 
-len = sprintf(buf, "AT+VGS=%d\r", gain);
-pa_log_debug("RFCOMM >> AT+VGS=%d", gain);
+len = sprintf(buf, "\r\n+VGS=%d\r\n", gain);
+pa_log_debug("RFCOMM >> +VGS=%d", gain);
 
 written = write(trfc->rfcomm_fd, buf, len);
 
@@ -304,8 +304,8 @@ static void set_microphone_gain(pa_bluetooth_transport *t, 
uint16_t gain) {
 
 t->microphone_gain = gain;
 
-len = sprintf(buf, "AT+VGM=%d\r", gain);
-pa_log_debug("RFCOMM >> AT+VGM=%d", gain);
+len = sprintf(buf, "\r\n+VGM=%d\r\n", gain);
+pa_log_debug("RFCOMM >> +VGM=%d", gain);
 
 written = write (trfc->rfcomm_fd, buf, len);
 
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH] Fix the gain settings on Headset

2014-11-14 Thread Wim Taymans
This patch fixes the gain settings for Headsets by sending the right
commands. It replaces the previous patch.

Wim Taymans (1):
  bluetooth: set gain correctly

 src/modules/bluetooth/backend-native.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

-- 
1.9.3

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


[pulseaudio-discuss] [PATCH] svolume.orc: avoid parameter loading undefined behaviour

2015-01-07 Thread Wim Taymans
In some cases, depending on the instruction that performs the load, orc
ignores the size of the parameter when loading it for the first time.
Explicitly load the parameter into a temp to make sure it is loaded
correctly, like we do for the 2ch case.

See https://bugzilla.gnome.org/show_bug.cgi?id=742271
---
 src/pulsecore/svolume.orc | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/pulsecore/svolume.orc b/src/pulsecore/svolume.orc
index 0edbefb..f869893 100644
--- a/src/pulsecore/svolume.orc
+++ b/src/pulsecore/svolume.orc
@@ -45,13 +45,15 @@
 
 .function pa_volume_s16ne_orc_1ch
 .dest 2 samples int16_t
-.param 4 v int32_t
+.param 4 vols int32_t
+.temp 4 v
 .temp 2 vh
 .temp 4 s
 .temp 4 mh
 .temp 4 ml
 .temp 4 signc
 
+loadpl v, vols
 convuwl s, samples
 x2 cmpgtsw signc, 0, s
 x2 andw signc, signc, v
-- 
1.9.3

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


[pulseaudio-discuss] [PATCH] backend-native: add support for the HSP HeadeSet profile

2015-02-17 Thread Wim Taymans
In addition to the HSP Audio Gateway, also add support for the HeadSet
profile in the native bluetooth backend. With this profile you can use
pulseaudio as a headset.

In the headset role, we create source and sink to receive and send the samples
from the gateway, respectively. The loopback device will automatically link
these to a sink and source for playback. Because this makes the source the
speaker and the sink the microphone, we need to reverse the roles of source
and sink compared to the gateway role.

In the gateway role, adjusting the sink volume generates a +VGS command to set
the volume on the headset. Likewise, receiving AT+VGS updates the sink volume.

In the headset role, receiving a +VGS should set the source volume and any
source volume changes should be reported back to the gateway with AT+VGS.
---
 src/modules/bluetooth/backend-native.c   | 98 +---
 src/modules/bluetooth/module-bluez5-device.c | 32 +++--
 2 files changed, 101 insertions(+), 29 deletions(-)

diff --git a/src/modules/bluetooth/backend-native.c 
b/src/modules/bluetooth/backend-native.c
index 8d9d95c..952cd68 100644
--- a/src/modules/bluetooth/backend-native.c
+++ b/src/modules/bluetooth/backend-native.c
@@ -59,6 +59,9 @@ struct transport_rfcomm {
 #define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1"
 
 #define HSP_AG_PROFILE "/Profile/HSPAGProfile"
+#define HSP_HS_PROFILE "/Profile/HSPHSProfile"
+
+#define HSP_HS_DEFAULT_CHANNEL  3
 
 #define PROFILE_INTROSPECT_XML  \
 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE   \
@@ -140,7 +143,10 @@ static int bluez5_sco_acquire_cb(pa_bluetooth_transport 
*t, bool optional, size_
 pa_log_info ("doing connect\n");
 err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
 if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
-pa_log_error("connect(): %s", pa_cstrerror(errno));
+if (optional)
+pa_log_info("optional connect(): %s", pa_cstrerror(errno));
+else
+pa_log_error("connect(): %s", pa_cstrerror(errno));
 goto fail_close;
 }
 
@@ -200,8 +206,10 @@ finish:
 static void register_profile(pa_bluetooth_backend *b, const char *profile, 
const char *uuid) {
 DBusMessage *m;
 DBusMessageIter i, d;
+dbus_bool_t autoconnect;
+dbus_uint16_t version, chan;
 
-pa_log_debug("Registering Profile %s", profile);
+pa_log_debug("Registering Profile %s %s", profile, uuid);
 
 pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", 
BLUEZ_PROFILE_MANAGER_INTERFACE, "RegisterProfile"));
 
@@ -210,6 +218,14 @@ static void register_profile(pa_bluetooth_backend *b, 
const char *profile, const
 dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &uuid);
 dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY, 
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING
 DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, 
&d);
+if (pa_streq (uuid, PA_BLUETOOTH_UUID_HSP_HS)) {
+autoconnect = 0;
+pa_dbus_append_basic_variant_dict_entry(&d, "AutoConnect", 
DBUS_TYPE_BOOLEAN, &autoconnect);
+chan = HSP_HS_DEFAULT_CHANNEL;
+pa_dbus_append_basic_variant_dict_entry(&d, "Channel", 
DBUS_TYPE_UINT16, &chan);
+version = 0x0102;
+pa_dbus_append_basic_variant_dict_entry(&d, "Version", 
DBUS_TYPE_UINT16, &version);
+}
 dbus_message_iter_close_container(&i, &d);
 
 send_and_add_to_pending(b, m, register_profile_reply, pa_xstrdup(profile));
@@ -229,29 +245,35 @@ static void rfcomm_io_callback(pa_mainloop_api *io, 
pa_io_event *e, int fd, pa_i
 if (events & PA_IO_EVENT_INPUT) {
 char buf[512];
 ssize_t len;
-int gain;
+int gain, do_reply = FALSE;
 
 len = read(fd, buf, 511);
 buf[len] = 0;
 pa_log_debug("RFCOMM << %s", buf);
 
-if (sscanf(buf, "AT+VGS=%d", &gain) == 1) {
-  t->speaker_gain = gain;
-  pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, 
PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), t);
-
-} else if (sscanf(buf, "AT+VGM=%d", &gain) == 1) {
-  t->microphone_gain = gain;
-  pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, 
PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), t);
+if (sscanf(buf, "AT+VGS=%d", &gain) == 1 || sscanf(buf, 
"\r\n+VGM=%d\r\n", &gain) == 1) {
+t->speaker_gain = gain;
+pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, 
PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), t);
+do_reply = TRUE;
+
+} else if (sscanf(buf, "AT+VGM=%d", &gain) == 1 || sscanf(buf, 
"\r\n+VGS=%d\r\n", &gain) == 1) {
+t->microphone_gain = gain;
+pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, 
PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), t);

Re: [pulseaudio-discuss] [PATCH] backend-native: add support for the HSP HeadeSet profile

2015-02-19 Thread Wim Taymans
It should work if you use pavucontrol to toggle the profile on the card
(which makes the headset start an SCO connection). Not sure what's up with
that, maybe you're right and it needs to listen for SCO connections started
from the gateway, I'll have to try.

Wim

On 19 February 2015 at 18:12, Georg Chini  wrote:

> On 17.02.2015 15:34, Wim Taymans wrote:
>
>> In addition to the HSP Audio Gateway, also add support for the HeadSet
>> profile in the native bluetooth backend. With this profile you can use
>> pulseaudio as a headset.
>>
>>
>>  Just tested it with my old Nokia 6230. Connects / disconnects OK, but no
> sound.
> I do not see any code that listens for incoming SCO connections. Is the
> support
> still incomplete?
> ___
> pulseaudio-discuss mailing list
> pulseaudio-discuss@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] backend-native: add support for the HSP HeadeSet profile

2015-02-23 Thread Wim Taymans
In addition to the HSP Audio Gateway, also add support for the HeadSet
profile in the native bluetooth backend. With this profile you can use
pulseaudio as a headset.

In the headset role, we create source and sink to receive and send the samples
from the gateway, respectively. The loopback device will automatically link
these to a sink and source for playback. Because this makes the source the
speaker and the sink the microphone, we need to reverse the roles of source
and sink compared to the gateway role.

In the gateway role, adjusting the sink volume generates a +VGS command to set
the volume on the headset. Likewise, receiving AT+VGS updates the sink volume.

In the headset role, receiving a +VGS should set the source volume and any
source volume changes should be reported back to the gateway with AT+VGS.
---
 src/modules/bluetooth/backend-native.c   | 238 ++-
 src/modules/bluetooth/module-bluez5-device.c |  32 +++-
 2 files changed, 222 insertions(+), 48 deletions(-)

diff --git a/src/modules/bluetooth/backend-native.c 
b/src/modules/bluetooth/backend-native.c
index 8d9d95c..a33edc3 100644
--- a/src/modules/bluetooth/backend-native.c
+++ b/src/modules/bluetooth/backend-native.c
@@ -44,9 +44,11 @@ struct pa_bluetooth_backend {
   PA_LLIST_HEAD(pa_dbus_pending, pending);
 };
 
-struct transport_rfcomm {
+struct transport_data {
 int rfcomm_fd;
 pa_io_event *rfcomm_io;
+int sco_fd;
+pa_io_event *sco_io;
 pa_mainloop_api *mainloop;
 };
 
@@ -59,6 +61,9 @@ struct transport_rfcomm {
 #define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1"
 
 #define HSP_AG_PROFILE "/Profile/HSPAGProfile"
+#define HSP_HS_PROFILE "/Profile/HSPHSProfile"
+
+#define HSP_HS_DEFAULT_CHANNEL  3
 
 #define PROFILE_INTROSPECT_XML  \
 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE   \
@@ -100,7 +105,7 @@ static pa_dbus_pending* 
send_and_add_to_pending(pa_bluetooth_backend *backend, D
 return p;
 }
 
-static int bluez5_sco_acquire_cb(pa_bluetooth_transport *t, bool optional, 
size_t *imtu, size_t *omtu) {
+static int sco_do_connect(pa_bluetooth_transport *t) {
 pa_bluetooth_device *d = t->device;
 struct sockaddr_sco addr;
 int err, i;
@@ -137,12 +142,51 @@ static int bluez5_sco_acquire_cb(pa_bluetooth_transport 
*t, bool optional, size_
 addr.sco_family = AF_BLUETOOTH;
 bacpy(&addr.sco_bdaddr, &dst);
 
-pa_log_info ("doing connect\n");
+pa_log_info ("doing connect");
 err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
 if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
 pa_log_error("connect(): %s", pa_cstrerror(errno));
 goto fail_close;
 }
+return sock;
+
+fail_close:
+close(sock);
+return -1;
+}
+
+static int sco_do_accept(pa_bluetooth_transport *t) {
+struct transport_data *trd = t->userdata;
+struct sockaddr_sco addr;
+socklen_t optlen;
+int sock;
+
+memset(&addr, 0, sizeof(addr));
+optlen = sizeof(addr);
+
+pa_log_info ("doing accept");
+sock = accept(trd->sco_fd, (struct sockaddr *) &addr, &optlen);
+if (sock < 0) {
+if (errno != EAGAIN)
+pa_log_error("accept(): %s", pa_cstrerror(errno));
+goto fail;
+}
+return sock;
+
+fail:
+return -1;
+}
+
+static int bluez5_sco_acquire_cb(pa_bluetooth_transport *t, bool optional, 
size_t *imtu, size_t *omtu) {
+int sock;
+
+if (optional)
+sock = sco_do_accept(t);
+else
+sock = sco_do_connect(t);
+
+if (sock < 0)
+goto fail;
 
 /* The "48" below is hardcoded until we get meaningful MTU values exposed
  * by the kernel */
@@ -155,8 +199,7 @@ static int bluez5_sco_acquire_cb(pa_bluetooth_transport *t, 
bool optional, size_
 
 return sock;
 
-fail_close:
-close(sock);
+fail:
 return -1;
 }
 
@@ -165,6 +208,62 @@ static void bluez5_sco_release_cb(pa_bluetooth_transport 
*t) {
 /* device will close the SCO socket for us */
 }
 
+static void sco_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, 
pa_io_event_flags_t events, void *userdata) {
+pa_bluetooth_transport *t = userdata;
+
+pa_assert(io);
+pa_assert(t);
+
+if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) {
+pa_log_error("error listening SCO connection: %s", 
pa_cstrerror(errno));
+goto fail;
+}
+
+pa_log_info("SCO incomming connection: changing state to PLAYING");
+pa_bluetooth_transport_set_state (t, PA_BLUETOOTH_TRANSPORT_STATE_PLAYING);
+
+fail:
+return;
+}
+
+static int bluez5_sco_listen(pa_bluetooth_transport *t) {
+struct transport_data *trd = t->userdata;
+struct sockaddr_sco addr;
+int sock;
+
+sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 
BTPROTO_SCO);
+if (sock < 0) {
+pa_log_error("socket(SEQPACKET, SCO) %s", pa_cstrerror(errno));
+return -1;
+}
+
+/* Bind

[pulseaudio-discuss] [PATCH] add support for HSP Headset profile

2015-02-23 Thread Wim Taymans
This adds support for the HSP HS role and turns pulseaudio into a
Headset.

This is an updated patch that adds support for incomming SCO connections from
the Audio Gateway.


Wim Taymans (1):
  backend-native: add support for the HSP HeadeSet profile

 src/modules/bluetooth/backend-native.c   | 238 ++-
 src/modules/bluetooth/module-bluez5-device.c |  32 +++-
 2 files changed, 222 insertions(+), 48 deletions(-)

-- 
2.1.0

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


[pulseaudio-discuss] [PATCH 0/2] access-control prototype

2015-02-23 Thread Wim Taymans
Hi all,

I've been experimenting with adding access control to pulseaudio and I would 
like to start the discussion and propose some ideas with the attached patch
set.

With the current pulseaudio policy, once the app has made a connection with the
daemon, it can perform any action it wants. This includes inspecting the state
of the various objects but more problematically, the client is allowed to
change the volume of any stream or sink/source or even kill any stream in the
daemon. Any client is also allowed to start capturing from any of the sources
or even the monitor sources of other streams. This is not something we want to
allow in all cases without explicitly asking the user first.

The primary use case for access control is sandboxed apps where we want to
restrict the actions that the sandboxed app can perform on pulseaudio. We
currently bind mount the pulseaudio socket in the sandbox and let the clients
use that to communicate over the native protocol with the pulseaudio daemon 
[1]. This is the only way to communicate with pulseaudio, so the cli protocol
and other protocols are disabled and excluded from this discussion.

Pulseaudio was not designed and built with access control in mind from the
start. Adding full control at the lowest level is probably not feasable at this
stage, and I believe it is not really needed. Instead, I've experimented with
blocking access at the protocol-native level [2]. 

With the native protocol, there are about 39 interesting actions that a client
can perform. These roughly map to the pa_context, introspection, sample cache
and pa_stream API. The idea is to fire a hook for each of these commands to
check if the object being operated on can be seen/modified by the requesting
client. The implementation of these checks happens in modules that can
implement whatever policy is needed by connecting to the various hooks. This
makes for some simple extra additions in protocol-native.c

For the subscribed events, we need to be carefull that we don't send events to
clients about objects that the client is not allowed to see, like an
input_stream of some other client, if the policy does not allow that. It's a
little tricky because with the REMOVE event, we can't get to the original
object anymore (to check who the owner was, for example). This can be solved by
keeping a list of all the events sent to a client about what objects, as is
implemented in [2].

There are more actions in the pa_stream object but I believe it is not very
useful to control access to those. Those actions are about configuring the
stream attributes and get status information about the streams. I believe it is
sufficient to allow or deny the creation of the pa_stream and after that, you
are free to use all pa_stream actions on that stream. again, moving the stream
to another sink is something that can be blocked, if needed because it is not
an action on the pa_stream.

What we eventually might want to do is ask the user for permission before a
potentially dangerous action is done (record from a source, switch
sinks/source,...). The idea is to let the access module call into a dbus api
that will handle the user interaction and tells us what to do next. We would
then also need to store those results in a database so that we don't have to
ask for permission every time. I'm not sure we can block those protocol-native
calls while waiting for the user or if we have to make them async on the server.

[2] contains a simple example access module that has some hardcoded checks on
input/output sink/source to see if the streams belong to the client that
created them. This essentially makes each client only see its own streams and
disallows any action on a stream that's not from the client. The idea is to do
different checks based on the user/cgroup/... a process is executed under,
possibly configured with a config file somehow.

What do you think? I would love to hear your ideas.

[1] https://wiki.gnome.org/action/info/Projects/SandboxedApps/Sandbox
[2] http://cgit.freedesktop.org/~wtay/pulseaudio/log/?h=access-hooks

Wim Taymans (2):
  access: add access control hooks
  module-access: make policy object containing rules

 src/Makefile.am |   8 +
 src/modules/module-access.c | 354 
 src/pulsecore/access.h  |  98 +++
 src/pulsecore/core-subscribe.c  |   2 +-
 src/pulsecore/core.c|   5 +
 src/pulsecore/core.h|   3 +
 src/pulsecore/protocol-native.c | 152 +
 7 files changed, 621 insertions(+), 1 deletion(-)
 create mode 100644 src/modules/module-access.c
 create mode 100644 src/pulsecore/access.h

-- 
2.1.0

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


[pulseaudio-discuss] [PATCH 1/2] access: add access control hooks

2015-02-23 Thread Wim Taymans
Add hooks to check if a certain operation is allowed.
Make a simple module that implements a simple policy that only allows
actions on the client's own sink_input, source_output and client.
---
 src/Makefile.am |   8 ++
 src/modules/module-access.c | 308 
 src/pulsecore/access.h  |  98 +
 src/pulsecore/core-subscribe.c  |   2 +-
 src/pulsecore/core.c|   5 +
 src/pulsecore/core.h|   3 +
 src/pulsecore/protocol-native.c | 152 
 7 files changed, 575 insertions(+), 1 deletion(-)
 create mode 100644 src/modules/module-access.c
 create mode 100644 src/pulsecore/access.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 67f8627..bd32a20 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -911,6 +911,7 @@ lib_LTLIBRARIES += libpulsecore-@PA_MAJORMINOR@.la
 
 # Pure core stuff
 libpulsecore_@PA_MAJORMINOR@_la_SOURCES = \
+   pulsecore/access.h \
pulsecore/asyncmsgq.c pulsecore/asyncmsgq.h \
pulsecore/asyncq.c pulsecore/asyncq.h \
pulsecore/auth-cookie.c pulsecore/auth-cookie.h \
@@ -1139,6 +1140,7 @@ modlibexec_LTLIBRARIES += \
 endif
 
 modlibexec_LTLIBRARIES += \
+   module-access.la \
module-cli.la \
module-cli-protocol-tcp.la \
module-simple-protocol-tcp.la \
@@ -1435,6 +1437,7 @@ endif
 
 # These are generated by an M4 script
 SYMDEF_FILES = \
+   module-access-symdef.h \
module-cli-symdef.h \
module-cli-protocol-tcp-symdef.h \
module-cli-protocol-unix-symdef.h \
@@ -1557,6 +1560,11 @@ module_simple_protocol_unix_la_CFLAGS = 
-DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE
 module_simple_protocol_unix_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_simple_protocol_unix_la_LIBADD = $(MODULE_LIBADD) libprotocol-simple.la
 
+# Access control
+module_access_la_SOURCES = modules/module-access.c
+module_access_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_access_la_LIBADD = $(MODULE_LIBADD)
+
 # CLI protocol
 
 module_cli_la_SOURCES = modules/module-cli.c
diff --git a/src/modules/module-access.c b/src/modules/module-access.c
new file mode 100644
index 000..dc04b96
--- /dev/null
+++ b/src/modules/module-access.c
@@ -0,0 +1,308 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+2015 Wim Taymans 
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include 
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "module-access-symdef.h"
+
+PA_MODULE_AUTHOR("Wim Taymans");
+PA_MODULE_DESCRIPTION("Controls access to server resources");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(true);
+PA_MODULE_USAGE("");
+
+static const char* const valid_modargs[] = {
+NULL,
+};
+
+typedef struct event_item event_item;
+
+struct event_item {
+PA_LLIST_FIELDS(event_item);
+
+uint32_t client_index;
+int facility;
+uint32_t object_index;
+};
+
+struct userdata {
+pa_core *core;
+pa_hook_slot *hook[PA_ACCESS_HOOK_MAX];
+
+PA_LLIST_HEAD(event_item, events);
+};
+
+static pa_hook_result_t access_check_owner (pa_core *c, pa_access_data *d, 
struct userdata *u) {
+pa_hook_result_t result = PA_HOOK_STOP;
+uint32_t idx = PA_INVALID_INDEX;
+
+switch (d->hook) {
+case PA_ACCESS_HOOK_GET_CLIENT_INFO:
+case PA_ACCESS_HOOK_KILL_CLIENT: {
+idx = d->object_index;
+break;
+}
+
+case PA_ACCESS_HOOK_GET_SINK_INPUT_INFO:
+case PA_ACCESS_HOOK_MOVE_SINK_INPUT:
+case PA_ACCESS_HOOK_SET_SINK_INPUT_VOLUME:
+case PA_ACCESS_HOOK_SET_SINK_INPUT_MUTE:
+case PA_ACCESS_HOOK_KILL_SINK_INPUT: {
+const pa_sink_input *si = pa_idxset_get_by_index(c->sink_inputs, 
d->object_index);
+idx = (si && si->client) ? si->client->index : PA_INVALID_INDEX;
+break;
+}
+
+case PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO:
+case PA_ACCESS_HOOK_MOVE_SOURCE_OUTPUT:
+case PA_ACCESS_HOOK_SET_SOURCE_O

[pulseaudio-discuss] [PATCH 2/2] module-access: make policy object containing rules

2015-02-23 Thread Wim Taymans
Make a policy object that contains the rules for checking access to
resources. The idea is that we can have different policies later and
then, depending on the client, use one of the policies.
---
 src/modules/module-access.c | 184 +++-
 1 file changed, 115 insertions(+), 69 deletions(-)

diff --git a/src/modules/module-access.c b/src/modules/module-access.c
index dc04b96..dd6af7f 100644
--- a/src/modules/module-access.c
+++ b/src/modules/module-access.c
@@ -52,6 +52,8 @@ static const char* const valid_modargs[] = {
 };
 
 typedef struct event_item event_item;
+typedef struct access_policy access_policy;
+typedef struct userdata userdata;
 
 struct event_item {
 PA_LLIST_FIELDS(event_item);
@@ -63,13 +65,28 @@ struct event_item {
 
 struct userdata {
 pa_core *core;
+
 pa_hook_slot *hook[PA_ACCESS_HOOK_MAX];
 
 PA_LLIST_HEAD(event_item, events);
+
+pa_idxset *policies;
+uint32_t default_policy;
+};
+
+typedef bool (*access_rule_t)(pa_core *c, pa_access_data *d, struct userdata 
*u);
+
+struct access_policy {
+uint32_t index;
+struct userdata *userdata;
+
+access_rule_t rule[PA_ACCESS_HOOK_MAX];
 };
 
-static pa_hook_result_t access_check_owner (pa_core *c, pa_access_data *d, 
struct userdata *u) {
-pa_hook_result_t result = PA_HOOK_STOP;
+
+/* rule checks if the operation on the object is performed by the owner of the 
object */
+static bool rule_check_owner (pa_core *c, pa_access_data *d, struct userdata 
*u) {
+bool result = false;
 uint32_t idx = PA_INVALID_INDEX;
 
 switch (d->hook) {
@@ -102,13 +119,57 @@ static pa_hook_result_t access_check_owner (pa_core *c, 
pa_access_data *d, struc
 break;
 }
 if (idx == d->client_index)
-result = PA_HOOK_OK;
+result = true;
 else
 pa_log("blocked operation %d/%d of client %d to client %d", d->hook, 
d->object_index, idx, d->client_index);
 
 return result;
 }
 
+/* rule allows the operation */
+static bool rule_allow (pa_core *c, pa_access_data *d, struct userdata *u) {
+pa_log("allow operation %d/%d for client %d", d->hook, d->object_index, 
d->client_index);
+return true;
+}
+
+/* rule blocks the operation */
+static bool rule_block (pa_core *c, pa_access_data *d, struct userdata *u) {
+pa_log("blocked operation %d/%d for client %d", d->hook, d->object_index, 
d->client_index);
+return false;
+}
+
+static access_policy *access_policy_new(struct userdata *u, bool allow_all) {
+access_policy *ap;
+int i;
+
+ap = pa_xnew0(access_policy, 1);
+ap->userdata = u;
+for (i = 0; i < PA_ACCESS_HOOK_MAX; i++)
+  ap->rule[i] = allow_all ? rule_allow : rule_block;
+
+pa_idxset_put(u->policies, ap, &ap->index);
+
+return ap;
+}
+
+static void access_policy_free(access_policy *ap) {
+pa_idxset_remove_by_index(ap->userdata->policies, ap->index);
+pa_xfree(ap);
+}
+
+static pa_hook_result_t check_access (pa_core *c, pa_access_data *d, struct 
userdata *u) {
+access_policy *ap;
+access_rule_t rule;
+
+ap = pa_idxset_get_by_index(u->policies, u->default_policy);
+
+rule = ap->rule[d->hook];
+if (rule && rule(c, d, u))
+  return PA_HOOK_OK;
+
+return PA_HOOK_STOP;
+}
+
 static const pa_access_hook_t 
event_hook[PA_SUBSCRIPTION_EVENT_FACILITY_MASK+1] = {
 [PA_SUBSCRIPTION_EVENT_SINK] = PA_ACCESS_HOOK_GET_SINK_INFO,
 [PA_SUBSCRIPTION_EVENT_SOURCE] = PA_ACCESS_HOOK_GET_SOURCE_INFO,
@@ -153,6 +214,7 @@ static bool remove_event(struct userdata *u, uint32_t cidx, 
int facility, uint32
 return false;
 }
 
+
 static pa_hook_result_t filter_event (pa_core *c, pa_access_data *d, struct 
userdata *u) {
 int facility;
 
@@ -195,47 +257,11 @@ static pa_hook_result_t filter_event (pa_core *c, 
pa_access_data *d, struct user
 return PA_HOOK_STOP;
 }
 
-static pa_hook_result_t access_block (pa_core *c, pa_access_data *d, struct 
userdata *u) {
-pa_log("blocked operation %d/%d for client %d", d->hook, d->object_index, 
d->client_index);
-return PA_HOOK_STOP;
-}
-
-static void install_cb(struct userdata *u, pa_access_hook_t id, pa_hook_cb_t 
cb) {
-if (u->hook[id])
-pa_hook_slot_free(u->hook[id]);
-if (cb)
-u->hook[id] = pa_hook_connect(&u->core->access[id], PA_HOOK_EARLY - 1, 
cb, u);
-else
-u->hook[id] = NULL;
-}
-
-static void allow(struct userdata *u, pa_access_hook_t id) {
-install_cb(u, id, NULL);
-}
-
-static void block(struct userdata *u, pa_access_hook_t id) {
-install_cb(u, id, (pa_hook_cb_t) access_block);
-}
-
-static void check_owner(struct userdata *u, pa_access_hook_t id) {
-install_cb(u, id, (pa_hook_cb_t) access_check_owner);
-}
-
-static void allow_all(struct userdata *u) {
-int i;
-for (i = 0; i < PA_ACCESS_HOOK_MAX; i++)
-allow(u, i);
-}
-
-static void block_all(struct userdata *u) {
-int i;
-for (i = 0; i < PA_ACCESS_HOOK_MAX; i++)
-block(u, i);
-}

[pulseaudio-discuss] Fwd: [PATCH 0/2] access-control prototype

2015-03-18 Thread Wim Taymans
And to the list..


-- Forwarded message --
From: Wim Taymans 
Date: 18 March 2015 at 09:34
Subject: Re: [pulseaudio-discuss] [PATCH 0/2] access-control prototype
To: Tanu Kaskinen 




On 17 March 2015 at 20:37, Tanu Kaskinen 
wrote:

>
> No, I don't think it's possible to keep the main thread blocked while
> waiting for input from the user.
>
> We discussed this topic a bit in IRC today, and I got the impression
> that you and Arun have already experimented a bit with asking the user
> whether certain operations should be authorized. Arun told that instead
> of having just one asynchronous call to the policy module, it would be
> easier to implement one synchronous call for "basic checks" and if the
> basic checks fail, then an asynchronous call would be made for "full
> checks" (interactive). These patches don't contain either approach (only
> synchronous hooks are used), and I have trouble understanding what the
> problem is and how does introducing one extra call help in any way.
> Could you or Arun clarify?
>

The problem is that we might have to ask the user for permission and that we
then would block the protocol-native command and thus also the main-loop.
We need a way to get back to the main-loop while waiting for the user input
and we explored 3 ideas:

 - manually run the main-loop when waiting for user-input. We were not sure
   if this is something the pulse mainloop would support so we didn't
   investigate this further.

 - make all commands support async replies. For this we would have to
   change all command handlers to store their variables in a little struct,
then
   call the access hook with that struct. When the reply is ready to be
sent we
   would call the function to generate the reply. This is not very
complicated but
   it would result in more code to review.

- do synchronous calls to the access module and add a new command that
   would allow async replies on the server and could thus be used to ask for
   user input.

So option 3 is what we're currently looking at in more detail. The idea is
that those hooks proposed in the patches, don't block but simply perform a
lookup into the
database to decide if things are allowed or refused. When a command is
not allowed, a client simply gets an PA_ERR_ACCESS reply from the server.

This would then trigger our new AUTHORIZATION request for the failed action.
This new request would be implemented in such a way that the access module
can reply in an asynchronous matter (something like a context + finish
method
is given to the hook, when the hook has the reply, it calls the finish
method to
send the reply to the client). This new request would be called
automatically by the
client library to give all clients the ability to ask for authorization.
The advantage
of this new command is that we only have to add support for async replies
to this new command. The disadvantage is that we need another round trip and
some overhead in checking permissions twice.

The only reason for this new command would be because we can then avoid
making all command async on the server.

Maybe it is worth making a prototype of option 2 (maybe only for some
commands)
to get an idea of the changes that are needed.

Wim



>
> --
> Tanu
>
>
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] Add korean translation

2015-04-07 Thread Wim Taymans
This is a patch to add korean translation that I keep around in RHEL7 but there
is no reason to not add this upstream. Translation are for 3.0 of pulseaudio.

Wim Taymans (1):
  Add korean translation

 po/LINGUAS |1 +
 po/ko.po   | 3012 
 2 files changed, 3013 insertions(+)
 create mode 100644 po/ko.po

-- 
2.1.0

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


[pulseaudio-discuss] [PATCH] Add korean translation

2015-04-07 Thread Wim Taymans
---
 po/LINGUAS |1 +
 po/ko.po   | 3012 
 2 files changed, 3013 insertions(+)
 create mode 100644 po/ko.po

diff --git a/po/LINGUAS b/po/LINGUAS
index 71c73a5..58e2bf8 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -16,6 +16,7 @@ id
 it
 ja
 kn
+ko
 ml
 mr
 nl
diff --git a/po/ko.po b/po/ko.po
new file mode 100644
index 000..9fd5940
--- /dev/null
+++ b/po/ko.po
@@ -0,0 +1,3012 @@
+# eukim , 2013. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-08-06 14:45+0530\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2013-10-20 10:38-0400\n"
+"Last-Translator: eukim \n"
+"Language-Team: Korean\n"
+"Language: ko\n"
+"X-Generator: Zanata 3.1.2\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+
+#: ../src/modules/alsa/alsa-util.c:1128 ../src/modules/alsa/alsa-util.c:1203
+#, c-format
+msgid ""
+"snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu "
+"ms).\n"
+"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
+"to the ALSA developers."
+msgstr ""
+"snd_pcm_avail()이 %lu 바이트 (%lu ms)의 매우 큰 값을 반환했습니다.\n"
+"ALSA 드라이버 '%s'의 오류일 수 있습니다. ALSA 개발자에게 이 문제를 보고해주시기 바랍니다."
+
+#: ../src/modules/alsa/alsa-util.c:1178
+#, c-format
+msgid ""
+"snd_pcm_delay() returned a value that is exceptionally large: %li bytes "
+"(%s%lu ms).\n"
+"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
+"to the ALSA developers."
+msgstr ""
+"snd_pcm_delay()가 %li 바이트 (%s%lu ms)의 매우 큰 값을 반환했습니다.\n"
+"ALSA 드라이버 '%s'의 오류일 수 있습니다. ALSA 개발자에게 이 문제를 보고해주시기 바랍니다."
+
+#: ../src/modules/alsa/alsa-util.c:1219
+#, c-format
+msgid ""
+"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail "
+"%lu.\n"
+"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
+"to the ALSA developers."
+msgstr ""
+"snd_pcm_avail_delay()가 이상한 값을 반환했습니다: 지연 시간 %lu은 사용 가능한 시간 %lu 보다 작습니다.\n"
+"ALSA 드라이버 '%s'의 오류일 수 있습니다. ALSA 개발자에게 이 문제를 보고해 주시기 바랍니다."
+
+#: ../src/modules/alsa/alsa-util.c:1262
+#, c-format
+msgid ""
+"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes "
+"(%lu ms).\n"
+"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
+"to the ALSA developers."
+msgstr ""
+"snd_pcm_mmap_begin()이 %lu 바이트 (%lu ms)의 매우 큰 값을 반환했습니다.\n"
+"ALSA 드라이버 '%s'의 오류일 수 있습니다. ALSA 개발자에게 이 문제를 보고해 주시기 바랍니다."
+
+#: ../src/modules/module-always-sink.c:38
+msgid "Always keeps at least one sink loaded even if it's a null one"
+msgstr "빈 싱크를 포함하여 최소한 하나 이상의 싱크가 존재해야 합니다."
+
+#: ../src/modules/module-always-sink.c:82
+msgid "Dummy Output"
+msgstr "가짜 출력"
+
+#: ../src/modules/module-ladspa-sink.c:53
+msgid "Virtual LADSPA sink"
+msgstr "가상 LADSPA 싱크"
+
+#: ../src/modules/module-ladspa-sink.c:57
+msgid ""
+"sink_name= sink_properties= "
+"master= format= rate= "
+"channels= channel_map= plugin= label= control= input_ladspaport_map= output_ladspaport_map= "
+msgstr ""
+"sink_name= sink_properties= "
+"master= format= rate= "
+"channels= channel_map= plugin= label= control= input_ladspaport_map= output_ladspaport_map= "
+
+#: ../src/modules/module-null-sink.c:49
+msgid "Clocked NULL sink"
+msgstr "클럭 사용 빈 싱크"
+
+#: ../src/modules/module-null-sink.c:280
+msgid "Null Output"
+msgstr "빈 출력"
+
+#: ../src/pulsecore/sink.c:3416
+msgid "Built-in Audio"
+msgstr "내장 오디오 "
+
+#: ../src/pulsecore/sink.c:3421
+msgid "Modem"
+msgstr "모뎀 "
+
+#: ../src/daemon/ltdl-bind-now.c:127
+msgid "Failed to find original lt_dlopen loader."
+msgstr "기존 lt_dlopen 로더를 찾는데 실패했습니다."
+
+#: ../src/daemon/ltdl-bind-now.c:132
+msgid "Failed to allocate new dl loader."
+msgstr "새 dl 로더를 할당하는데 실패했습니다."
+
+#: ../src/daemon/ltdl-bind-now.c:145
+msgid "Failed to add bind-now-loader."
+msgstr "bind-now-loader를 추가하는데 실패했습니다."
+
+#: ../src/daemon/main.c:139
+#, c-format
+msgid "Got signal %s."
+msgstr "시그널 %s를 받았습니다."
+
+#: ../src/daemon/main.c:166
+msgid "Exiting."
+msgstr "종료합니다."
+
+#: ../src/daemon/main.c:184
+#, c-format
+msgid "Failed to find user '%s'."
+msgstr "사용자 '%s'를 찾을 수 없습니다."
+
+#: ../src/daemon/main.c:189
+#, c-format
+msgid "Failed to find group '%s'."
+msgstr "그룹 '%s'를 찾을 수 없습니다."
+
+#: ../src/daemon/main.c:193
+#, c-format
+msgid "Found user '%s' (UID %lu) and group '%s' (GID %lu)."
+msgstr "사용자 \"%s' (UID %lu)와 그룹 '%s' (GID %lu)를 찾았습니다."
+
+#: ../src/daemon/main.c:198
+#, c-format
+msgid "GID of user '%s' and of group '%s' don't match."
+msgstr "사용자 '%s'의 GID와 그룹 '%s'가 일치하지 않습니다."
+
+#: ../src/daemon/main.c:203
+#, c-format
+msgid "Home directory of user '%s' is not '%s', ignoring."
+msgstr "사용자 '%s'의 홈 디렉토리가 '%s'가 아닙니다, 무시됨."
+
+#: ../src/daemon/main.c:206 ../src/daemon/main.c:211
+#, c-format
+msgid "Failed to create '%s': %s"
+msgstr "'%s' 생성 실패: %s"
+
+#: ../src/daemon/main.c:218
+#, c-format
+msgid "Failed to change group list: %s"
+msgstr "그

[pulseaudio-discuss] [PATCH 4/5] protocol-native: add access checks

2015-04-07 Thread Wim Taymans
Call the hooks in various places to check if an action is allowed or
not.

The hook can return PA_HOOK_OK to allow an action, PA_HOOK_STOP to
deny an action.

Returning PA_HOOK_CANCEL will handle the result asynchronously.
This is implemented by saving the state of the current command and
exiting the command (going back to the mainloop) without reply.
When the access check completes, it will call async_finish_cb, which
will use the saved state to call the original command again. The access
check will eventually return OK or STOP and the command can complete
and send a reply.
---
 src/pulsecore/protocol-native.c | 219 +++-
 1 file changed, 217 insertions(+), 2 deletions(-)

diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index b06f553..f23de31 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -294,6 +294,7 @@ static void command_set_card_profile(pa_pdispatch *pd, 
uint32_t command, uint32_
 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t 
command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t 
command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, 
uint32_t tag, pa_tagstruct *t, void *userdata);
+static pa_hook_result_t check_access(pa_pdispatch *pd, uint32_t command, 
uint32_t tag, pa_tagstruct *t, void *userdata, uint32_t idx, 
pa_subscription_event_type_t event, const char *name);
 
 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
 [PA_COMMAND_ERROR] = NULL,
@@ -1972,6 +1973,23 @@ if (!(expression)) { \
 } \
 } while(0);
 
+#define CHECK_ACCESS_STMT(c, command, tag, idx, name, async, denied) { \
+  pa_hook_result_t res = check_access(pd, command, tag, t, userdata, idx, 0, 
name); \
+  if (res == PA_HOOK_STOP) { \
+  denied; \
+  } else if (res == PA_HOOK_CANCEL) { \
+  async; \
+  } \
+};
+
+#define CHECK_ACCESS_GOTO(c, command, tag, idx, name, label) \
+CHECK_ACCESS_STMT(c, command, tag, idx, name, \
+goto label, pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); 
goto label)
+
+#define CHECK_ACCESS(c, command, tag, idx, name) \
+CHECK_ACCESS_STMT(c, command, tag, idx, name, \
+return, pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return)
+
 static pa_tagstruct *reply_new(uint32_t tag) {
 pa_tagstruct *reply;
 
@@ -2049,6 +2067,8 @@ static void command_create_playback_stream(pa_pdispatch 
*pd, uint32_t command, u
 CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == 
PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
 CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, 
PA_ERR_INVALID, finish);
 
+CHECK_ACCESS_GOTO(c, command, tag, PA_INVALID_INDEX, NULL, finish);
+
 p = pa_proplist_new();
 
 if (name)
@@ -2370,6 +2390,8 @@ static void command_create_record_stream(pa_pdispatch 
*pd, uint32_t command, uin
 CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || 
!source_name, tag, PA_ERR_INVALID, finish);
 CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == 
PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
 
+CHECK_ACCESS_GOTO(c, command, tag, PA_INVALID_INDEX, NULL, finish);
+
 p = pa_proplist_new();
 
 if (name)
@@ -2575,6 +2597,7 @@ static void command_exit(pa_pdispatch *pd, uint32_t 
command, uint32_t tag, pa_ta
 }
 
 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL);
 ret = pa_core_exit(c->protocol->core, false, 0);
 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
 
@@ -2893,6 +2916,7 @@ static void command_stat(pa_pdispatch *pd, uint32_t 
command, uint32_t tag, pa_ta
 }
 
 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL);
 
 stat = pa_mempool_get_stat(c->protocol->core->mempool);
 
@@ -3019,6 +3043,8 @@ static void command_create_upload_stream(pa_pdispatch 
*pd, uint32_t command, uin
 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 
0, tag, PA_ERR_INVALID);
 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, 
PA_ERR_TOOLARGE);
 
+CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL);
+
 p = pa_proplist_new();
 
 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
@@ -3117,6 +3143,8 @@ static void command_play_sample(pa_pdispatch *pd, 
uint32_t command, uint32_t tag
 
 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
 
+CHECK_ACCESS(c, command, tag, sink->index, name);
+
 p = pa_proplist_new();
 
 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
@@ -3160,6 +3188,8 @@ static void command_remove_sample(pa_pdispatch *pd, 
uint32_t command, uint32_t t
 CHECK_VALIDITY(c->pstream, c->authori

[pulseaudio-discuss] [PATCH 2/5] subscribe: fix typo

2015-04-07 Thread Wim Taymans
---
 src/pulsecore/core-subscribe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c
index 61c779b..5a88b7e 100644
--- a/src/pulsecore/core-subscribe.c
+++ b/src/pulsecore/core-subscribe.c
@@ -206,7 +206,7 @@ void pa_subscription_post(pa_core *c, 
pa_subscription_event_type_t t, uint32_t i
 pa_subscription_event *e;
 pa_assert(c);
 
-/* No need for queuing subscriptions of no one is listening */
+/* No need for queuing subscriptions if no one is listening */
 if (!c->subscriptions)
 return;
 
-- 
2.1.0

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


[pulseaudio-discuss] [PATCH 5/5] module-access: add example access module

2015-04-07 Thread Wim Taymans
Add an example access module that only allows access to the objects
created by the owner client.

The code is structured in such a way that multiple profiles can be
made and that a profile can be activated based on the properties of
a client.

Events need special handling, we don't want to send events to clients
about objects they are not allowed to see. We need to be careful because
we can't inspect the owner of an object anymore in a _REMOVE event for
that object. We fix this by keeping a list of all the objects for which
we were allowed to notify a CHANGE or NEW event. We then only send
REMOVE events to objects from this list.
---
 src/Makefile.am |   7 +
 src/modules/module-access.c | 479 
 2 files changed, 486 insertions(+)
 create mode 100644 src/modules/module-access.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 0813285..8b4ed31 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1149,6 +1149,7 @@ modlibexec_LTLIBRARIES += \
 endif
 
 modlibexec_LTLIBRARIES += \
+   module-access.la \
module-cli.la \
module-cli-protocol-tcp.la \
module-simple-protocol-tcp.la \
@@ -1445,6 +1446,7 @@ endif
 
 # These are generated by an M4 script
 SYMDEF_FILES = \
+   module-access-symdef.h \
module-cli-symdef.h \
module-cli-protocol-tcp-symdef.h \
module-cli-protocol-unix-symdef.h \
@@ -1567,6 +1569,11 @@ module_simple_protocol_unix_la_CFLAGS = 
-DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE
 module_simple_protocol_unix_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_simple_protocol_unix_la_LIBADD = $(MODULE_LIBADD) libprotocol-simple.la
 
+# Access control
+module_access_la_SOURCES = modules/module-access.c
+module_access_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_access_la_LIBADD = $(MODULE_LIBADD)
+
 # CLI protocol
 
 module_cli_la_SOURCES = modules/module-cli.c
diff --git a/src/modules/module-access.c b/src/modules/module-access.c
new file mode 100644
index 000..2d1ec9f
--- /dev/null
+++ b/src/modules/module-access.c
@@ -0,0 +1,479 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+        2015 Wim Taymans 
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include 
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "module-access-symdef.h"
+
+PA_MODULE_AUTHOR("Wim Taymans");
+PA_MODULE_DESCRIPTION("Controls access to server resources");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(true);
+PA_MODULE_USAGE("");
+
+static const char* const valid_modargs[] = {
+NULL,
+};
+
+typedef struct access_policy access_policy;
+typedef struct event_item event_item;
+typedef struct client_data client_data;
+typedef struct userdata userdata;
+
+typedef pa_hook_result_t (*access_rule_t)(pa_core *c, pa_access_data *d, 
struct userdata *u);
+
+struct access_policy {
+uint32_t index;
+struct userdata *userdata;
+
+access_rule_t rule[PA_ACCESS_HOOK_MAX];
+};
+
+struct event_item {
+PA_LLIST_FIELDS(event_item);
+
+int facility;
+uint32_t object_index;
+};
+struct client_data {
+uint32_t index;
+uint32_t policy;
+
+PA_LLIST_HEAD(event_item, events);
+};
+
+struct userdata {
+pa_core *core;
+
+pa_hook_slot *hook[PA_ACCESS_HOOK_MAX];
+
+pa_idxset *policies;
+uint32_t default_policy;
+
+pa_hashmap *clients;
+pa_hook_slot *client_put_slot;
+pa_hook_slot *client_proplist_changed_slot;
+pa_hook_slot *client_unlink_slot;
+};
+
+static void add_event(struct client_data *cd, int facility, uint32_t oidx) {
+event_item *i;
+
+i = pa_xnew0(event_item, 1);
+PA_LLIST_INIT(event_item, i);
+i->facility = facility;
+i->object_index = oidx;
+
+PA_LLIST_PREPEND(event_item, cd->events, i);
+}
+
+static event_item *find_event(struct client_data *cd, int facility, uint32_t 
oidx) {
+event_item *i;
+
+PA_LLIST_FOREACH(i, cd->events) {
+if (i->facility == facility && i->object_index == oidx)
+return i;
+}
+return NULL;
+}
+
+static bool remove_event(struct client_data *cd,

[pulseaudio-discuss] [PATCH 0/5] Add access control to protocol-native

2015-04-07 Thread Wim Taymans
This is a new patch series that preplaces the previous patches regarding
access control.

After some experimentation, this patch series adds support for async access
control checks, like when we need to ask for user input. The async support
is implemented by exiting the command without reply and then when the reply
becomes available, re-execute the command.

There is an example access control module that shows how one could implement
client specific access control checks.

The patch also contains a small typo fix that can probably be applied
independently.


Wim Taymans (5):
  tagstruct: add copy method
  subscribe: fix typo
  access: Add access control hooks
  protocol-native: add access checks
  module-access: add example access module

 src/Makefile.am |   8 +
 src/modules/module-access.c | 479 
 src/pulsecore/access.h  | 102 +
 src/pulsecore/core-subscribe.c  |   2 +-
 src/pulsecore/core.c|   5 +
 src/pulsecore/core.h|   3 +
 src/pulsecore/protocol-native.c | 219 +-
 src/pulsecore/tagstruct.c   |  13 ++
 src/pulsecore/tagstruct.h   |   2 +
 9 files changed, 830 insertions(+), 3 deletions(-)
 create mode 100644 src/modules/module-access.c
 create mode 100644 src/pulsecore/access.h

-- 
2.1.0

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


[pulseaudio-discuss] [PATCH 3/5] access: Add access control hooks

2015-04-07 Thread Wim Taymans
Add hooks to core to check if certain operations are allowed.
---
 src/Makefile.am|   1 +
 src/pulsecore/access.h | 102 +
 src/pulsecore/core.c   |   5 +++
 src/pulsecore/core.h   |   3 ++
 4 files changed, 111 insertions(+)
 create mode 100644 src/pulsecore/access.h

diff --git a/src/Makefile.am b/src/Makefile.am
index d582e57..0813285 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -920,6 +920,7 @@ libpulsecore_@PA_MAJORMINOR@_la_SOURCES = \
pulsecore/filter/lfe-filter.c pulsecore/filter/lfe-filter.h \
pulsecore/filter/biquad.c pulsecore/filter/biquad.h \
pulsecore/filter/crossover.c pulsecore/filter/crossover.h \
+   pulsecore/access.h \
pulsecore/asyncmsgq.c pulsecore/asyncmsgq.h \
pulsecore/asyncq.c pulsecore/asyncq.h \
pulsecore/auth-cookie.c pulsecore/auth-cookie.h \
diff --git a/src/pulsecore/access.h b/src/pulsecore/access.h
new file mode 100644
index 000..7cd2751
--- /dev/null
+++ b/src/pulsecore/access.h
@@ -0,0 +1,102 @@
+#ifndef fooaccesshfoo
+#define fooaccesshfoo
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+2015 Wim Taymans 
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include 
+
+#include 
+
+typedef enum pa_access_hook {
+/* context */
+PA_ACCESS_HOOK_EXIT_DAEMON,
+PA_ACCESS_HOOK_SET_DEFAULT_SINK,
+PA_ACCESS_HOOK_SET_DEFAULT_SOURCE,
+
+/* introspection */
+PA_ACCESS_HOOK_GET_SINK_INFO,
+PA_ACCESS_HOOK_SET_SINK_VOLUME,
+PA_ACCESS_HOOK_SET_SINK_MUTE,
+PA_ACCESS_HOOK_SUSPEND_SINK,
+PA_ACCESS_HOOK_SET_SINK_PORT,
+
+PA_ACCESS_HOOK_GET_SOURCE_INFO,
+PA_ACCESS_HOOK_SET_SOURCE_VOLUME,
+PA_ACCESS_HOOK_SET_SOURCE_MUTE,
+PA_ACCESS_HOOK_SUSPEND_SOURCE,
+PA_ACCESS_HOOK_SET_SOURCE_PORT,
+
+PA_ACCESS_HOOK_GET_SERVER_INFO,
+
+PA_ACCESS_HOOK_GET_MODULE_INFO,
+PA_ACCESS_HOOK_LOAD_MODULE,
+PA_ACCESS_HOOK_UNLOAD_MODULE,
+
+PA_ACCESS_HOOK_GET_CLIENT_INFO,
+PA_ACCESS_HOOK_KILL_CLIENT,
+
+PA_ACCESS_HOOK_GET_CARD_INFO,
+PA_ACCESS_HOOK_SET_CARD_PROFILE,
+PA_ACCESS_HOOK_SET_PORT_LATENCY_OFFSET,
+
+PA_ACCESS_HOOK_GET_SINK_INPUT_INFO,
+PA_ACCESS_HOOK_MOVE_SINK_INPUT,
+PA_ACCESS_HOOK_SET_SINK_INPUT_VOLUME,
+PA_ACCESS_HOOK_SET_SINK_INPUT_MUTE,
+PA_ACCESS_HOOK_KILL_SINK_INPUT,
+
+PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO,
+PA_ACCESS_HOOK_MOVE_SOURCE_OUTPUT,
+PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_VOLUME,
+PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_MUTE,
+PA_ACCESS_HOOK_KILL_SOURCE_OUTPUT,
+
+PA_ACCESS_HOOK_STAT,
+
+PA_ACCESS_HOOK_GET_SAMPLE_INFO,
+/* sample cache */
+PA_ACCESS_HOOK_CONNECT_UPLOAD,
+PA_ACCESS_HOOK_REMOVE_SAMPLE,
+PA_ACCESS_HOOK_PLAY_SAMPLE,
+/* stream */
+PA_ACCESS_HOOK_CONNECT_PLAYBACK,
+PA_ACCESS_HOOK_CONNECT_RECORD,
+/* extension */
+PA_ACCESS_HOOK_EXTENSION,
+
+PA_ACCESS_HOOK_FILTER_SUBSCRIBE_EVENT,
+
+PA_ACCESS_HOOK_MAX
+} pa_access_hook_t;
+
+typedef struct pa_access_data pa_access_data;
+
+struct pa_access_data {
+pa_access_hook_t hook;
+uint32_t client_index;
+uint32_t object_index;
+pa_subscription_event_type_t event;
+const char *name;
+
+void (*async_finish_cb) (pa_access_data *data, bool res);
+};
+
+#endif
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 0e63bac..9135311 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -151,6 +151,9 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, 
size_t shm_size) {
 for (j = 0; j < PA_CORE_HOOK_MAX; j++)
 pa_hook_init(&c->hooks[j], c);
 
+for (j = 0; j < PA_ACCESS_HOOK_MAX; j++)
+pa_hook_init(&c->access[j], c);
+
 pa_random(&c->cookie, sizeof(c->cookie));
 
 #ifdef SIGPIPE
@@ -222,6 +225,8 @@ static void core_free(pa_object *o) {
 
 for (j = 0; j < PA_CORE_HOOK_MAX; j++)
 pa_hook_done(&c->hooks[j]);
+for (j = 0; j < PA_ACCESS_HOOK_MAX; j++)
+pa_hook_done(&c->access[j]);
 
 pa_xfree(c);
 }
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 9fefd1b..470b821 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -50,6 +50,7 @@ typedef enum pa_suspend_cause {
 #i

[pulseaudio-discuss] [PATCH 1/5] tagstruct: add copy method

2015-04-07 Thread Wim Taymans
Add a method to copy a tagstruct. This will also reset the read pointer
back to the beginning.
---
 src/pulsecore/tagstruct.c | 13 +
 src/pulsecore/tagstruct.h |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c
index 8a29957..c29e49b 100644
--- a/src/pulsecore/tagstruct.c
+++ b/src/pulsecore/tagstruct.c
@@ -97,6 +97,19 @@ void pa_tagstruct_free(pa_tagstruct*t) {
 pa_xfree(t);
 }
 
+pa_tagstruct *pa_tagstruct_copy(pa_tagstruct*t) {
+pa_tagstruct*tc;
+
+if (!(tc = pa_flist_pop(PA_STATIC_FLIST_GET(tagstructs
+tc = pa_xnew(pa_tagstruct, 1);
+tc->data = pa_xmemdup(t->data, t->length);
+tc->allocated = t->length;
+tc->rindex = 0;
+tc->type = PA_TAGSTRUCT_DYNAMIC;
+
+return tc;
+}
+
 static inline void extend(pa_tagstruct*t, size_t l) {
 pa_assert(t);
 pa_assert(t->type != PA_TAGSTRUCT_FIXED);
diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h
index 348c65d..e648d75 100644
--- a/src/pulsecore/tagstruct.h
+++ b/src/pulsecore/tagstruct.h
@@ -64,6 +64,8 @@ pa_tagstruct *pa_tagstruct_new(void);
 pa_tagstruct *pa_tagstruct_new_fixed(const uint8_t* data, size_t length);
 void pa_tagstruct_free(pa_tagstruct*t);
 
+pa_tagstruct *pa_tagstruct_copy(pa_tagstruct*t);
+
 int pa_tagstruct_eof(pa_tagstruct*t);
 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l);
 
-- 
2.1.0

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