Re: [pulseaudio-discuss] [PATCH 4/4] alsa-mixer: Add force-hw-volume flag to alsa profile sets

2011-04-11 Thread Jyri Sarha
On Sat, 09 Apr 2011 20:20:40 +0200, David Henningsson
 wrote:
> On 2011-04-08 17:18, Colin Guthrie wrote:
>> 'Twas brillig, and o...@iki.fi at 08/04/11 15:18 did gyre and gimble:
>>> From: Jyri Sarha
>>>
>>> Before this patch, if any of the paths in a path set do not
>>> support HW volume then the HW volume is disabled for the whole
>>> set. In some cases this is a bit drastic measure. For instance,
>>> if all but one of the paths support HW volume and dB there no
>>> problem to pretend that we have HW volume for the whole set. The
>>> path without any mixers to control will just always return 0 dB
>>> and the rest is handled by SW volume. This patch adds a flag to
>>> the mapping section of profile set file to enables this behavior.
>>
>> David, this sounds similar to your USB Headset issue from a couple days
>> ago... or am I just reading too much into the description?
> 
> Sort of - it just feels like neither of us has tried to do the right 
> thing so far - I added a workaround/quirk for a few devices, and this 
> patch adds a setting to turn something on and off.
> 
> I'd like it to "just work".
> 
> Or put in another way - what's the recommended default setting of this 
> new parameter, and why?
> 

Target for my patch was to be non intrusive, but if you agree I can easily

change my patch to always behave like force-hw-volume flag was set to true
and remove the flag. It is even easier just to change the default for the 
flag. 

Cheers,
Jyri
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH 3/4] core: no rewinding on volume change if the sink does not support it.

2011-04-11 Thread Jyri Sarha



On Fri, 8 Apr 2011, Colin Guthrie wrote:

'Twas brillig, and o...@iki.fi at 08/04/11 15:18 did gyre and gimble:

From: Jyri Sarha 

...


Would it not be possible to move this check into the function itself and
just make it a noop?



The reason for this patch in the first place was the load spikes when a
user took his time to adjust volume while listening music. This fixed
the problem and did not give it any further consideration, but I can
now see that it is not the most complete fix.

It appears to me that if "flush" parameter of pa_sink_input_request_rewind() 
call is not true (IOW, reuse the rewound samples) then we could ignore

the the whole request if sink does not support rewinding. However, the
logic of different boolean parameters for pa_sink_input_request_rewind() 
is not completely clear to me.


What do you think?


I appreciate there would be FCO but it would reduce the likelihood of
this check being missed on some other calls... unless that is desirable
sometimes?



As far as I can see the only cases we want to rewind, if sink does not
support it, is when we want to throw away the already queued samples
and not just process them again with new SW volume etc.

Cheers,
Jyri
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH] call-state-tracker: New component.

2011-04-08 Thread Jyri Sarha

On Tue, 5 Apr 2011, Maarten Bosmans wrote:


What are the users of this state tracker? Is it only some out-of-tree
Meego modules? Are you planning to submit those too? At least a
snippet of how it should be used would be nice.



Hi Maarten,

To answer your question about upstreaming the "meego modules" or
part of them, I can only say that we had a plan to upstream the
applicable parts. However, now with this new Nokia strategy it
is very hard to predict what is the future of those modules.

The biggest reason why we can not just do it now is how product
specific the code currently is. The driving force have been developing
for a specific product and not so much trying to make a generic
implementations. On the other hand with Intel/Meego cooperation we were
starting to take the steps to the right direction.

Anyway, in this new situation we just plan to upstream everything
that is generic enough. For product specific modules we plan to
open source as much as possible in the out of source tree
compiled modules [1].

Best regards,
Jyri Sarha

[1] The source code for the pulseaudio modules mentioned can be found here:
http://meego.gitorious.org/maemo-multimedia/pulseaudio-modules-meego
The heavily patched pulseaudio tree we are using can be found here:
http://meego.gitorious.org/maemo-multimedia/pulseaudio

Almost all the patches are now part of the pulseaudio upstream.

ps. The above repositories are currently not up to date, but we'll
update them soon gain.
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH] alsa-sink: take base volume into account when applying hw volume

2010-12-01 Thread Jyri Sarha



On Wed, 1 Dec 2010, David Henningsson wrote:


On 2010-12-01 11:31, Jyri Sarha wrote:

Am currently working on a problem caused by safety-margin not
taken into account when rewinding. When I get this fixed I'll add a fix
for double use bug too.


Hmm, for tsched or non-tsched? I think we merged a patch related to this from 
pl bossart a while ago.




Sorry, should have been more specific. I was talking about
sync-volume-safety-margin, not rewind_safeguard related to tsched mode
rewinding. However, the two things are closely related in this problem
case. When DMA buffer is rewound the sync-volume events should rewound at
the same time. This works already now.  However the volume event rewinding
is not modifying the new expiry time with sync-volume-safety-margin
depending on whether we are changing the volume up or down.

Cheers,
Jyri
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH] alsa-sink: take base volume into account when applying hw volume

2010-12-01 Thread Jyri Sarha


On Tue, 30 Nov 2010, Colin Guthrie wrote:


Any comments on this one Jyri?

It seems add code to sink_write_volume_cb() to mirror the normal method
sink_set_volume_cb() so looks OK to me but not followed the path through
to see if this is supposed to be factored in already in some other way...

Your thoughts would be appreciated.




Yes,
The base volume stuff appeared some time between the first version of sync
volume and my upstream rebase. AFAIK, the fix is correct. However, there
is still the double use of string bug (originally coming from me, but it
looks quite different now). The bug is not serious, the print just is not 
very informative.


Am currently working on a problem caused by safety-margin not
taken into account when rewinding. When I get this fixed I'll add a fix 
for double use bug too.


Cheers,
Jyri



Col


'Twas brillig, and Juho Hämäläinen at 25/11/10 13:15 did gyre and gimble:

Currently if sink base volume differs from 0dB and sync-volume is used,
wrong volume values are written to hw. This patch fixes that.


Signed-off-by: Juho Hämäläinen 
---
  src/modules/alsa/alsa-sink.c |   10 --
  1 files changed, 8 insertions(+), 2 deletions(-)



___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss



--

Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/

Day Job:
 Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
 Mageia Contributor [http://www.mageia.org/]
 PulseAudio Hacker [http://www.pulseaudio.org/]
 Trac Hacker [http://trac.edgewall.org/]
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH] core: New LIFO style flist implementation

2010-11-20 Thread Jyri Sarha



On Fri, 20 Aug 2010, Colin Guthrie wrote:


'Twas brillig, and o...@iki.fi at 20/08/10 14:24 did gyre and gimble:

From: Jyri Sarha 

It seems the mail archive at 0pointer does not show attachments of type
"Text/X-PATCH", so here this goes again.


It's OK, it came through on gmane and no doubt to list subscribers.

Lennart is probably the best person to review this as I don't feel
confident accepting it without fully grokking the reasons for the
original implem vs. this one.

As he's currently distracted by systemd it may take him a while to
reply, but he will defo get to it in due course :)



I browsed the pulseaudio-discuss mail archives and noticed that this issue 
was left hanging in the air also on my side. At least I could not find the

the latest version of this patch anywhere. So here it comes just in case
Lennart would have time to take a look at it.

To give some extra motivation, with this patch you can solve issues like 
this :) : https://bugs.maemo.org/show_bug.cgi?id=7190


Cheers,
Jyri

--

From 12563ed356f3bb81f99aa32ba45337cfdf427b50 Mon Sep 17 00:00:00 2001

From: Jyri Sarha 
Date: Mon, 30 Nov 2009 16:55:27 +0200
Subject: [PATCH] core: New LIFO style flist implementation v2.2

The old free list implementation used objects in FIFO style. This is
bad because it tries keep all the objects ever used alive and in
memory. This minimizes the changes that an allocated object is already
in cache. When there is shortage of physical memory this may also
increase change that newly allocated object is swapped out. LIFO
(e.g. stack) style free list should help these issues. Like the old
one the new implementation is also lock free. This version (v2.1) of
the patch has a potential weakness fixed. The previous version (2.0)
did segfault when popping from empty flist, this does not.
---
 src/pulsecore/flist.c |  218 ++--
 1 files changed, 64 insertions(+), 154 deletions(-)

diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c
index 7e5ee24..e728d30 100644
--- a/src/pulsecore/flist.c
+++ b/src/pulsecore/flist.c
@@ -1,7 +1,9 @@
 /***
   This file is part of PulseAudio.

-  Copyright 2006-2008 Lennart Poettering
+  Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+  Contact: Jyri Sarha 

   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as
@@ -34,198 +36,106 @@

 #include "flist.h"

-/* Algorithm is not perfect, in a few corner cases it will fail to pop
- * from the flist although it isn't empty, and fail to push into the
- * flist, although it isn't full.
- *
- * We keep a fixed size array of entries, each item is an atomic
- * pointer.
- *
- * To accelerate finding of used/unused cells we maintain a read and a
- * write index which is used like a ring buffer. After each push we
- * increase the write index and after each pop we increase the read
- * index.
- *
- * The indexes are incremented atomically and are never truncated to
- * the buffer size. Instead we assume that the buffer size is a power
- * of two and that the truncation can thus be done by applying a
- * simple AND on read.
- *
- * To make sure that we do not look for empty cells indefinitely we
- * maintain a length value which stores the number of used cells. From
- * this value the number of unused cells is easily calculated. Please
- * note that the length value is not updated atomically with the read
- * and write index and might thus be a few cells off the real
- * value. To deal with this we always look for N_EXTRA_SCAN extra
- * cells when pushing/popping entries.
- *
- * It might make sense to replace this implementation with a link list
- * stack or queue, which however requires DCAS to be simple. Patches
- * welcome.
- *
- * Please note that this algorithm is home grown.*/
-
 #define FLIST_SIZE 128
-#define N_EXTRA_SCAN 3

-/* For debugging purposes we can define _Y to put and extra thread
- * yield between each operation. */
+/* Lock free single linked list element. */
+struct pa_flist_elem {
+pa_atomic_ptr_t next;
+pa_atomic_ptr_t ptr;
+};

-#ifdef PROFILE
-#define _Y pa_thread_yield()
-#else
-#define _Y do { } while(0)
-#endif
+typedef struct pa_flist_elem pa_flist_elem;

 struct pa_flist {
 unsigned size;
-pa_atomic_t length;
-pa_atomic_t read_idx;
-pa_atomic_t write_idx;
+/* Stack that contains pointers stored into free list */
+pa_atomic_ptr_t stored;
+/* Stack that contains empty list elements */
+pa_atomic_ptr_t empty;
+pa_flist_elem table[0];
 };

-#define PA_FLIST_CELLS(x) ((pa_atomic_ptr_t*) ((uint8_t*) (x) + 
PA_ALIGN(sizeof(struct pa_flist
+/* Lock free pop from linked list stack */
+static pa_flist_elem *stack_pop(pa_atomic_ptr_t *list) {
+pa_flist_elem *poped;
+pa_assert(

Re: [pulseaudio-discuss] Compiler optimisation dependency?

2010-10-25 Thread Jyri Sarha



On Sun, 24 Oct 2010, tarantism wrote:


I'm building pulse under Scratchbox for Maemo 5 then copying the
module-sine.so file to Nokia N900 to test.

If I use compiler options -O0 or -O1, it works fine.
If I use -O2 or -O3 I just get a sqwarking noise.

Any ideas?



How does the precompiled module-sine.so from Maemo 5 work for you (it is 
in pulseaudio-module-extra package)?


Cheers,
Jyri
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH 1/5] core: Add infrastructure for synchronizing HW and SW volume changes

2010-10-15 Thread Jyri Sarha
> Hi,
>
> Review below:
>
> 'Twas brillig, and o...@iki.fi at 13/10/10 17:40 did gyre and gimble:
>
>> +PA_SINK_SYNC_VOLUME = 0x0200U,
>> +/**< The HW volume changes are syncronized with SW volume.
>> + * \since X.X.XX */
>> +
>>  } pa_sink_flags_t;
>
> Can you put 0.9.22 here? If needed I'll do a global find and replace on
> any \since 0.9.22's if/when we release that version from stable queue
> instead, but I'll almost certainly forget to fix up x.x.xx replacements.
>

Sure.

>
>> diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
>> index ff4cc17..0f2af4f 100644
>> --- a/src/pulsecore/sink.c
>> +++ b/src/pulsecore/sink.c
>
>
>> +struct sink_message_set_port {
>> +pa_device_port *port;
>> +int ret;
>> +};
>> +
>
> I'll refer to this below[1]
>
>> @@ -1459,7 +1493,8 @@ void pa_sink_set_volume(
>>   * apply one to s->soft_volume */
>>
>>  pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
>> -s->set_volume(s);
>> +if (!(s->flags & PA_SINK_SYNC_VOLUME))
>> +s->set_volume(s);
>>
>>  } else
>>  /* If we have no function set_volume(), then the soft volume
>
> Hmm, should this "if" have an "else" that sets send_msg to TRUE
> (send_msg is used just below where the context ends) otherwise if
> send_msg is set to false, then the message will not be pushed to the
> asyncq and thus the set_volume() function will never be called in
> pa_sink_process_msg()[2]
>

It looks like you are right. I am only wondering how the code
still seems to work. If I understand correctly the same problem
is there also without sync-volume if sink updates soft volume
within set_volume(). The updated soft volume would not be
propagated to IO-thread.

The problem would be there also if we were using soft-volume only,
but then we would not be using flat volume and there would be no
pa_sink_set_volume() calls with send_msg=FALSE.

This all seems clear in theory. However, it does not work like
that when I try to produce the problem by updating a sink-input
volume and check that HW volume remains unchanged. Everything
just seems to work as it should. I'll offer virtual beer to one
who can explain why the code still works :).

Anyway I did change the code as you proposed and tested it and
the code still work.

>> @@ -1474,18 +1509,22 @@ void pa_sink_set_volume(
>>  pa_subscription_post(s->core,
>> PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE,
>> s->index);
>>  }
>>
>> -/* Called from main thread. Only to be called by sink implementor */
>> +/* Called from the io thread if sync volume is used, otherwise from the
>> main thread.
>> + * Only to be called by sink implementor */
>>  void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
>>  pa_sink_assert_ref(s);
>> -pa_assert_ctl_context();
>> +if (s->flags & PA_SINK_SYNC_VOLUME)
>> +pa_sink_assert_io_context(s);
>> +else
>> +pa_assert_ctl_context();
>>
>>  if (!volume)
>>  pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
>>  else
>>  s->soft_volume = *volume;
>>
>> -if (PA_SINK_IS_LINKED(s->state))
>> -pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s),
>> PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
>> +if (PA_SINK_IS_LINKED(s->state) && !(s->flags &
>> PA_SINK_SYNC_VOLUME))
>> +pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s),
>> PA_SINK_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
>>  else
>>  s->thread_info.soft_volume = s->soft_volume;
>>  }
>
> This is a little concerning. If I have a sink (e.g. an roap-sink) whcih
> does not support PA_SINK_SYNC_VOLUME flag, then you are now sending me a
> different message to the one I got before.
>
> While there is nothing in the tree that does this, there may be external
> uses of this in private trees and I don't think there is any need to
> change the semantics of PA_SINK_MESSAGE_SET_VOLUME.
>
> Would it be better to instead define:
>  PA_SINK_MESSAGE_SET_VOLUME_SYNCED to go before
> PA_SINK_MESSAGE_SET_VOLUME, and not change the message here and instead
> change the o->process_msg() calls that use PA_SINK_MESSAGE_SET_VOLUME to
> use PA_SINK_MESSAGE_SET_VOLUME_SYNCED?
>
> I think this would be semantically the same with regards to your
> requirements and keeps any out-of-tree reliance on
> PA_SINK_MESSAGE_SET_VOLUME message semantically unchanged.[3]
>

Seems reasonable. Changed.

>> @@ -1555,6 +1594,16 @@ static void propagate_real_volume(pa_sink *s,
>> const pa_cvolume *old_real_volume)
>>  pa_subscription_post(s->core,
>> PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE,
>> s->index);
>>  }
>>
>> +/* Called from io thread */
>> +void pa_sink_update_volume_and_mute(pa_sink *s) {
>> +pa_assert(s);
>> +pa_sink_assert_io_context(s);
>> +
>> +pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s),
>> +  PA_SINK_MESSAGE_UPDATE_VOLUME_AND_MUTE,
>> +  

Re: [pulseaudio-discuss] [PATCH 0/5] HW and SW volume syncronization in IO-thread

2010-10-14 Thread Jyri Sarha
>> On 2010-10-13 18:40, o...@iki.fi wrote:
>>> From: Jyri Sarha
> ...
>> ...rather than trying to add explicit delays just for the volume sync.
>> Either that, or some kind of volume ramping. Just curious if you
>> considered that solution as well?
>>

Ah, only after reading my reply from the mailing list I
understand your concern.

The sync-volume is really not only using some explicit timers,
but it uses sinks latency information (got with
pa_sink_get_latency_within_thread()) for timing the HW volume
changes and adjust the timers when ever the DMA buffer is rewound.

The parameters given are there only to compensate for timer and
reported latency inaccuracy. The "safety margin" is for compensation
dynamic inaccuracy and "extra delay" is there to compensate
static errors. On most hardware "extra delay" should be set to
zero.

Cheers,
   Jyri


___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH 0/5] HW and SW volume syncronization in IO-thread

2010-10-14 Thread Jyri Sarha
>> On 2010-10-13 18:40, o...@iki.fi wrote:
>>> From: Jyri Sarha
> ...
>>
>> Thank you for your work! This is the main reason I've been advocating
>> against enabling flat-volumes by default in Ubuntu, so I'm glad to see
>> something that addresses the issue.
>>
>> The basic problem is that we can't have sample accurate volume changes,
>> because no HW supports it. Right?
>
> Yes. On on non real-time OS and having less than accurate audio
> pipeline latency information this is a best effort task. Making
> this perfect would require HW support.
>
>>
>> So about the implementation - what you're saying is that it is better to
>> have two guaranteed down-volume "snaps" rather than to risk an up-volume
>> "snap". That sounds reasonable, but are these down-volume transients
>> hearable? Perhaps more hearable with playing a sine wave, rather than
>> white noise?
>>
>
> Since implementing ramps on a HW mixer is really not applicable,
> this is the only solution that I can see and in practice it seems
> to work pretty well. I also think that most analog components
> have enough "slowness" in them which in effect causes a kind of
> ramp.
>
> BTW, ran the test from my previous mail, but using sine wave, and
> still I could not hear any snapping sound on my T60.
>
>> Anyway, I've been thinking of something like this but never looked more
>> closely at implementing a solution, but I would probably have tried to
>> do something like:
>> start:
>>   1) rewind
>>   2) write stream with lower SW volume
>>   3) wait until rewind margin has passed
>>   4) raise HW volume
>
> This is pretty much what my patch is doing, just in slightly
> different order:
>
> 1. Insert volume event to happen after sink's reported latency has
> expired (+ modifications).
> 2. rewind and adjust volume events
> 3. wait until volume event expires = rewind margin has passed
> 4. raise HW volume
>
> This approach works also with sinks that do not support
> rewinding (e.g. alsa-sink not using tsched).
>
>> end:
>>   1) lower HW volume
>>   2) rewind
>>   3) write stream with higher SW volume
>>
>
> Here you are forgetting that there may still be some samples left
> within the rewind margin. You should add the delay also there. In
> effect the both volume ups and downs become quite symmetrical.
>
>> ...rather than trying to add explicit delays just for the volume sync.
>> Either that, or some kind of volume ramping. Just curious if you
>> considered that solution as well?
>>
>
> Well, I can't think how you get past "wait until rewind margin
> has passed" without having explicit delays.
>
> This code is really only chaning the way HW mixers are
> used. Ramping to SW volume could be implemented separately and it
> would not interfere with this patch in fact they would
> complement each other.
>
> But, hey please try out my patch. At least it solved the problem
> on N900 (yes the earlier version of the patch is on all N900s out there)
> and it works quite well on my both Linux boxes.
>
> Cheers,
>   Jyri
>


___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH 0/5] HW and SW volume syncronization in IO-thread

2010-10-14 Thread Jyri Sarha
>> On 2010-10-13 18:40, o...@iki.fi wrote:
>>> From: Jyri Sarha
> ...
>> ...rather than trying to add explicit delays just for the volume sync.
>> Either that, or some kind of volume ramping. Just curious if you
>> considered that solution as well?
>>

Ah, only after reading my reply from the mailing list I
understand your concern.

The sync-volume is really not only using some explicit timers,
but it uses sinks latency information (got with
pa_sink_get_latency_within_thread()) for timing the HW volume
changes and adjust the timers when ever the DMA buffer is rewound.

The parameters given are there only to compensate for timer and
reported latency inaccuracy. The "safety margin" is for compensation
dynamic inaccuracy and "extra delay" is there to compensate
static errors. On most hardware "extra delay" should be set to
zero.

Cheers,
   Jyri



___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH 0/5] HW and SW volume syncronization in IO-thread

2010-10-14 Thread Jyri Sarha
> On 2010-10-13 18:40, o...@iki.fi wrote:
>> From: Jyri Sarha
...
>
> Thank you for your work! This is the main reason I've been advocating
> against enabling flat-volumes by default in Ubuntu, so I'm glad to see
> something that addresses the issue.
>
> The basic problem is that we can't have sample accurate volume changes,
> because no HW supports it. Right?

Yes. On on non real-time OS and having less than accurate audio
pipeline latency information this is a best effort task. Making
this perfect would require HW support.

>
> So about the implementation - what you're saying is that it is better to
> have two guaranteed down-volume "snaps" rather than to risk an up-volume
> "snap". That sounds reasonable, but are these down-volume transients
> hearable? Perhaps more hearable with playing a sine wave, rather than
> white noise?
>

Since implementing ramps on a HW mixer is really not applicable,
this is the only solution that I can see and in practice it seems
to work pretty well. I also think that most analog components
have enough "slowness" in them which in effect causes a kind of
ramp.

BTW, ran the test from my previous mail, but using sine wave, and
still I could not hear any snapping sound on my T60.

> Anyway, I've been thinking of something like this but never looked more
> closely at implementing a solution, but I would probably have tried to
> do something like:
> start:
>   1) rewind
>   2) write stream with lower SW volume
>   3) wait until rewind margin has passed
>   4) raise HW volume

This is pretty much what my patch is doing, just in slightly
different order:

1. Insert volume event to happen after sink's reported latency has
expired (+ modifications).
2. rewind and adjust volume events
3. wait until volume event expires = rewind margin has passed
4. raise HW volume

This approach works also with sinks that do not support
rewinding (e.g. alsa-sink not using tsched).

> end:
>   1) lower HW volume
>   2) rewind
>   3) write stream with higher SW volume
>

Here you are forgetting that there may still be some samples left
within the rewind margin. You should add the delay also there. In
effect the both volume ups and downs become quite symmetrical.

> ...rather than trying to add explicit delays just for the volume sync.
> Either that, or some kind of volume ramping. Just curious if you
> considered that solution as well?
>

Well, I can't think how you get past "wait until rewind margin
has passed" without having explicit delays.

This code is really only chaning the way HW mixers are
used. Ramping to SW volume could be implemented separately and it
would not interfere with this patch in fact they would
complement each other.

But, hey please try out my patch. At least it solved the problem
on N900 (yes the earlier version of the patch is on all N900s out there)
and it works quite well on my both Linux boxes.

Cheers,
  Jyri

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH] core: New LIFO style flist implementation v2.0

2010-09-01 Thread Jyri Sarha

On Tue, 31 Aug 2010, Shouqun Liu wrote:


After apply this patch, pulseaudio starts with segmentation fault..my
pulseadudio version is 0.9.21

thanks



Sorry about that. There was a clear bug in the patch. I must have been
running different code than I was testing. Any way I have fixed the
bug and I'll post yet another version of the patch shortly.

Cheers,

Cheers,
 Jyri
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH] core: New LIFO style flist implementation

2010-08-23 Thread Jyri Sarha

On Mon, 23 Aug 2010, Shouqun Liu wrote:


Hi Jyri,
I have applied the patch, but makes no effort to improve the performance,
the CPU usage is still high :)



Well, I originally created the patch to avoid pulseaudio getting stuck
while waiting swapped out memblocks on Nokia N900. After applying the
patch I also noticed that it slightly improved the performance in some
usecases. I think that was because of better CPU cache hit ratio, but I
guess you need to have a lot of concurrent streams or some audio filtering
ongoing on a limited memory-bandwidth device like N900 to notice the
difference.


I'm still confusing about this issue, there is no such problem in my PC, but
its critical in my netbook.
btw, the PA version on PC and netbook are both latest 0.9.21 release.



Do you have a constant high load on your netbook or do you see it for
instance while PA is rewinding streams? You should be able to decrease
the load spikes from rewinding by shortening the ALSA DMA buffer.

Do your streams have the same sample-rate as your default sink?
If no, relaxing your sample-rate-converter settings should help (or 
configuring your sink to match the samplerate of your stremas).


Cheers,
  Jyri

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] core: New LIFO style flist implementation

2010-08-19 Thread Jyri Sarha
I forgot to mail this patch earlier. Anyway like the comment says this
flist implementation improves performance at least on devices with limited
physical memory. In my opinion this version is also easier to understand.

Cheers,
Jyri
>From 76aa7522d415984dafd564f7395f403d4407e21a Mon Sep 17 00:00:00 2001
From: Jyri Sarha 
Date: Mon, 30 Nov 2009 16:55:27 +0200
Subject: [PATCH] core: New LIFO style flist implementation

The old free list implementation used objects in FIFO style. This is
bad because it tries keep all the objects ever used alive and in
memory. This minimizes the changes that an allocated object is already
in cache. When there is shortage of physical memory this may also
increase change that newly allocated object is swapped out. LIFO
(e.g. stack) style free list should help these issues. Like the old
one the new implementation is also lock free.
---
 src/pulsecore/flist.c |  211 +---
 1 files changed, 57 insertions(+), 154 deletions(-)

diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c
index 7e5ee24..47bfed8 100644
--- a/src/pulsecore/flist.c
+++ b/src/pulsecore/flist.c
@@ -1,7 +1,9 @@
 /***
   This file is part of PulseAudio.
 
-  Copyright 2006-2008 Lennart Poettering
+  Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+  Contact: Jyri Sarha 
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as
@@ -34,198 +36,99 @@
 
 #include "flist.h"
 
-/* Algorithm is not perfect, in a few corner cases it will fail to pop
- * from the flist although it isn't empty, and fail to push into the
- * flist, although it isn't full.
- *
- * We keep a fixed size array of entries, each item is an atomic
- * pointer.
- *
- * To accelerate finding of used/unused cells we maintain a read and a
- * write index which is used like a ring buffer. After each push we
- * increase the write index and after each pop we increase the read
- * index.
- *
- * The indexes are incremented atomically and are never truncated to
- * the buffer size. Instead we assume that the buffer size is a power
- * of two and that the truncation can thus be done by applying a
- * simple AND on read.
- *
- * To make sure that we do not look for empty cells indefinitely we
- * maintain a length value which stores the number of used cells. From
- * this value the number of unused cells is easily calculated. Please
- * note that the length value is not updated atomically with the read
- * and write index and might thus be a few cells off the real
- * value. To deal with this we always look for N_EXTRA_SCAN extra
- * cells when pushing/popping entries.
- *
- * It might make sense to replace this implementation with a link list
- * stack or queue, which however requires DCAS to be simple. Patches
- * welcome.
- *
- * Please note that this algorithm is home grown.*/
-
 #define FLIST_SIZE 128
-#define N_EXTRA_SCAN 3
 
-/* For debugging purposes we can define _Y to put and extra thread
- * yield between each operation. */
+struct pa_flist_elem {
+struct pa_flist_elem *next;
+void *ptr;
+};
 
-#ifdef PROFILE
-#define _Y pa_thread_yield()
-#else
-#define _Y do { } while(0)
-#endif
+typedef struct pa_flist_elem pa_flist_elem;
 
 struct pa_flist {
 unsigned size;
-pa_atomic_t length;
-pa_atomic_t read_idx;
-pa_atomic_t write_idx;
+pa_atomic_ptr_t stored;
+pa_atomic_ptr_t empty;
+pa_flist_elem table[0];
 };
 
-#define PA_FLIST_CELLS(x) ((pa_atomic_ptr_t*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_flist
+static pa_flist_elem *stack_pop(pa_atomic_ptr_t *list) {
+pa_flist_elem * poped;
+pa_assert(list);
+
+do {
+poped = (pa_flist_elem *) pa_atomic_ptr_load(list);
+} while (poped != NULL && !pa_atomic_ptr_cmpxchg(list, poped, poped->next));
+
+return poped;
+}
+
+static void stack_push(pa_atomic_ptr_t *list, pa_flist_elem *new_elem) {
+pa_assert(list);
+
+do {
+new_elem->next = (pa_flist_elem *) pa_atomic_ptr_load(list);
+} while (!pa_atomic_ptr_cmpxchg(list, new_elem->next, new_elem));
+}
 
 pa_flist *pa_flist_new(unsigned size) {
 pa_flist *l;
+unsigned i;
 
 if (!size)
 size = FLIST_SIZE;
 
-pa_assert(pa_is_power_of_two(size));
-
-l = pa_xmalloc0(PA_ALIGN(sizeof(pa_flist)) + (sizeof(pa_atomic_ptr_t) * size));
+l = pa_xmalloc0(sizeof(pa_flist) + sizeof(pa_flist_elem) * size);
 
 l->size = size;
-
-pa_atomic_store(&l->read_idx, 0);
-pa_atomic_store(&l->write_idx, 0);
-pa_atomic_store(&l->length, 0);
-
+pa_atomic_ptr_store(&l->stored, NULL);
+pa_atomic_ptr_store(&l->empty, NULL);
+for (i=0; i < size; i++) {
+stack_push(&l->empty, &l->table[i]);
+}
 return l;
 }
 
-static unsigned reduce(pa_flist *l, unsigned value) {
-return value & (l->

[pulseaudio-discuss] [PATCH 5/5] alsa-card: Add sync_volume parameter

2010-02-28 Thread Jyri Sarha
From: Jyri Sarha 

---
 src/modules/alsa/module-alsa-card.c |4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/src/modules/alsa/module-alsa-card.c 
b/src/modules/alsa/module-alsa-card.c
index 6bea33d..8e613e7 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -63,7 +63,8 @@ PA_MODULE_USAGE(
 "tsched_buffer_size= "
 "tsched_buffer_watermark= "
 "profile= "
-"ignore_dB=");
+"ignore_dB= "
+"sync_volume=");
 
 static const char* const valid_modargs[] = {
 "name",
@@ -84,6 +85,7 @@ static const char* const valid_modargs[] = {
 "tsched_buffer_watermark",
 "profile",
 "ignore_dB",
+"sync_volume",
 NULL
 };
 
-- 
1.7.0

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH 1/5] core: Add infrastructure for delayed HW volume setting

2010-02-28 Thread Jyri Sarha
From: Jyri Sarha 

To make concurrent use of SW and HW volume glitchles their application
needs to be synchronized. For accurate synchronization the HW volume
needs to be applied in IO thread. This patch adds infrastructure to
delay the applying of HW volume to match with SW volume timing. For
this patch to have any effect it needs to be taken into use by sink
implementor.
---
 src/pulse/def.h  |8 ++-
 src/pulsecore/sink.c |  201 +-
 src/pulsecore/sink.h |   39 ++-
 3 files changed, 245 insertions(+), 3 deletions(-)

diff --git a/src/pulse/def.h b/src/pulse/def.h
index 82106ef..e84edde 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -729,9 +729,14 @@ typedef enum pa_sink_flags {
 /**< This sink is in flat volume mode, i.e. always the maximum of
  * the volume of all connected inputs. \since 0.9.15 */
 
-PA_SINK_DYNAMIC_LATENCY = 0x0080U
+PA_SINK_DYNAMIC_LATENCY = 0x0080U,
 /**< The latency can be adjusted dynamically depending on the
  * needs of the connected streams. \since 0.9.15 */
+
+PA_SINK_SYNC_VOLUME = 0x0100U,
+/**< The HW volume changes are syncronized with SW volume.
+ * \since X.X.XX */
+
 } pa_sink_flags_t;
 
 /** \cond fulldocs */
@@ -743,6 +748,7 @@ typedef enum pa_sink_flags {
 #define PA_SINK_DECIBEL_VOLUME PA_SINK_DECIBEL_VOLUME
 #define PA_SINK_FLAT_VOLUME PA_SINK_FLAT_VOLUME
 #define PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY
+#define PA_SINK_SYNC_VOLUME PA_SINK_SYNC_VOLUME
 /** \endcond */
 
 /** Sink state. \since 0.9.15 */
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index d69f038..62f0d71 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -34,6 +34,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -43,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "sink.h"
 
@@ -51,6 +53,8 @@
 #define ABSOLUTE_MIN_LATENCY (500)
 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
+#define VOLUME_CHANGE_SAFETY_MARGIN_DEFAULT (8*PA_USEC_PER_MSEC)
+#define VOLUME_CHANGE_EXTRA_DELAY_DEFAULT (0*PA_USEC_PER_MSEC)
 
 PA_DEFINE_PUBLIC_CLASS(pa_sink, pa_msgobject);
 
@@ -310,6 +314,12 @@ pa_sink* pa_sink_new(
 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
 s->thread_info.fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : 
DEFAULT_FIXED_LATENCY;
 
+PA_LLIST_HEAD_INIT(pa_sink_volume_change, s->thread_info.volume_changes);
+s->thread_info.volume_changes_tail = NULL;
+pa_sw_cvolume_multiply(&s->thread_info.current_hw_volume, &s->soft_volume, 
&s->real_volume);
+s->thread_info.volume_change_safety_margin = 
VOLUME_CHANGE_SAFETY_MARGIN_DEFAULT;
+s->thread_info.volume_change_extra_delay = 
VOLUME_CHANGE_EXTRA_DELAY_DEFAULT;
+
 /* FIXME: This should probably be moved to pa_sink_put() */
 pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
 
@@ -444,6 +454,7 @@ void pa_sink_put(pa_sink* s) {
 
 s->thread_info.soft_volume = s->soft_volume;
 s->thread_info.soft_muted = s->muted;
+pa_sw_cvolume_multiply(&s->thread_info.current_hw_volume, &s->soft_volume, 
&s->real_volume);
 
 pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL) || (s->base_volume == 
PA_VOLUME_NORM && s->flags & PA_SINK_DECIBEL_VOLUME));
 pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == 
PA_VOLUME_NORM+1);
@@ -733,6 +744,10 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
 if (nbytes > 0)
 if (s->monitor_source && 
PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
 pa_source_process_rewind(s->monitor_source, nbytes);
+
+if (nbytes > 0) {
+pa_sink_volume_change_rewind(s, nbytes);
+}
 }
 
 /* Called from IO thread context */
@@ -1467,7 +1482,7 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume 
*volume) {
 s->soft_volume = *volume;
 
 if (PA_SINK_IS_LINKED(s->state))
-pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), 
PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
+pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), 
PA_SINK_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
 else
 s->thread_info.soft_volume = s->soft_volume;
 }
@@ -1975,6 +1990,13 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void 
*userdata, int64_t offse
 
 case PA_SINK_MESSAGE_SET_VOLUME:
 
+if (s->flags & PA_SINK_SYNC_VOLUME)
+pa_sink_volume_change_push(s);
+
+/* Fall through ... */
+
+case PA_SINK_MESSAGE_SET_SOFT_VOLUME:
+
 if (!pa_cvolume_equal(&s->thread_info.soft_volume, 
&s->soft_volume)) {
 s->thread_info.soft_volume = s->

[pulseaudio-discuss] [PATCH 2/5] alsa-sink: Take syncronized HW volume infra into use

2010-02-28 Thread Jyri Sarha
From: Jyri Sarha 

---
 src/modules/alsa/alsa-mixer.c   |   38 +---
 src/modules/alsa/alsa-mixer.h   |2 +-
 src/modules/alsa/alsa-sink.c|   81 +++---
 src/modules/alsa/alsa-source.c  |2 +-
 src/modules/alsa/module-alsa-sink.c |8 +++-
 5 files changed, 113 insertions(+), 18 deletions(-)

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 93f2ed0..0e77a4b 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -671,7 +671,13 @@ int pa_alsa_path_get_mute(pa_alsa_path *p, snd_mixer_t *m, 
pa_bool_t *muted) {
 return 0;
 }
 
-static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const 
pa_channel_map *cm, pa_cvolume *v) {
+static int element_set_volume(
+pa_alsa_element *e,
+snd_mixer_t *m,
+const pa_channel_map *cm,
+pa_cvolume *v,
+pa_bool_t write_to_hw) {
+
 snd_mixer_selem_id_t *sid;
 pa_cvolume rv;
 snd_mixer_elem_t *me;
@@ -720,14 +726,26 @@ static int element_set_volume(pa_alsa_element *e, 
snd_mixer_t *m, const pa_chann
  * if the channel is available, ALSA behaves ver
  * strangely and doesn't fail the call */
 if (snd_mixer_selem_has_playback_channel(me, c)) {
-if ((r = snd_mixer_selem_set_playback_dB(me, c, value, 
+1)) >= 0)
-r = snd_mixer_selem_get_playback_dB(me, c, &value);
+if (write_to_hw) {
+if ((r = snd_mixer_selem_set_playback_dB(me, c, value, 
+1)) >= 0)
+r = snd_mixer_selem_get_playback_dB(me, c, &value);
+} else {
+long alsa_val;
+if ((r = snd_mixer_selem_ask_playback_dB_vol(me, 
value, +1, &alsa_val)) >= 0)
+r = snd_mixer_selem_ask_playback_vol_dB(me, 
alsa_val, &value);
+}
 } else
 r = -1;
 } else {
 if (snd_mixer_selem_has_capture_channel(me, c)) {
-if ((r = snd_mixer_selem_set_capture_dB(me, c, value, +1)) 
>= 0)
-r = snd_mixer_selem_get_capture_dB(me, c, &value);
+if (write_to_hw) {
+if ((r = snd_mixer_selem_set_capture_dB(me, c, value, 
+1)) >= 0)
+r = snd_mixer_selem_get_capture_dB(me, c, &value);
+} else {
+long alsa_val;
+if ((r = snd_mixer_selem_ask_capture_dB_vol(me, value, 
+1, &alsa_val)) >= 0)
+r = snd_mixer_selem_ask_capture_vol_dB(me, 
alsa_val, &value);
+}
 } else
 r = -1;
 }
@@ -782,7 +800,13 @@ static int element_set_volume(pa_alsa_element *e, 
snd_mixer_t *m, const pa_chann
 return 0;
 }
 
-int pa_alsa_path_set_volume(pa_alsa_path *p, snd_mixer_t *m, const 
pa_channel_map *cm, pa_cvolume *v) {
+int pa_alsa_path_set_volume(
+pa_alsa_path *p,
+snd_mixer_t *m,
+const pa_channel_map *cm,
+pa_cvolume *v,
+pa_bool_t write_to_hw) {
+
 pa_alsa_element *e;
 pa_cvolume rv;
 
@@ -807,7 +831,7 @@ int pa_alsa_path_set_volume(pa_alsa_path *p, snd_mixer_t 
*m, const pa_channel_ma
 pa_assert(!p->has_dB || e->has_dB);
 
 ev = rv;
-if (element_set_volume(e, m, cm, &ev) < 0)
+if (element_set_volume(e, m, cm, &ev, write_to_hw) < 0)
 return -1;
 
 if (!p->has_dB) {
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index a0d4fcb..ce95edf 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -202,7 +202,7 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, 
pa_bool_t ignore_dB);
 void pa_alsa_path_dump(pa_alsa_path *p);
 int pa_alsa_path_get_volume(pa_alsa_path *p, snd_mixer_t *m, const 
pa_channel_map *cm, pa_cvolume *v);
 int pa_alsa_path_get_mute(pa_alsa_path *path, snd_mixer_t *m, pa_bool_t 
*muted);
-int pa_alsa_path_set_volume(pa_alsa_path *path, snd_mixer_t *m, const 
pa_channel_map *cm, pa_cvolume *v);
+int pa_alsa_path_set_volume(pa_alsa_path *path, snd_mixer_t *m, const 
pa_channel_map *cm, pa_cvolume *v, pa_bool_t write_to_hw);
 int pa_alsa_path_set_mute(pa_alsa_path *path, snd_mixer_t *m, pa_bool_t muted);
 int pa_alsa_path_select(pa_alsa_path *p, snd_mixer_t *m);
 void pa_alsa_path_set_callback(pa_alsa_path *p, snd_mixer_t *m, 
snd_mixer_elem_callback_t cb, void *userdata);
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 581b943..45ba24a 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1160,6 +1160,7 @@ static void sink_set_volume_cb(pa_sink *s) {
 struct userdata *u = s->userdata;
 pa_cvolu

[pulseaudio-discuss] [PATCH 4/5] udev-detect: Add sync_volume parameter

2010-02-28 Thread Jyri Sarha
From: Jyri Sarha 

---
 src/modules/module-udev-detect.c |   17 ++---
 1 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c
index 7695d3c..205c737 100644
--- a/src/modules/module-udev-detect.c
+++ b/src/modules/module-udev-detect.c
@@ -45,7 +45,8 @@ PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_LOAD_ONCE(TRUE);
 PA_MODULE_USAGE(
 "tsched= "
-"ignore_dB=");
+"ignore_dB= "
+"sync_volume=");
 
 struct device {
 char *path;
@@ -62,6 +63,7 @@ struct userdata {
 
 pa_bool_t use_tsched:1;
 pa_bool_t ignore_dB:1;
+pa_bool_t sync_volume:1;
 
 struct udev* udev;
 struct udev_monitor *monitor;
@@ -74,6 +76,7 @@ struct userdata {
 static const char* const valid_modargs[] = {
 "tsched",
 "ignore_dB",
+"sync_volume",
 NULL
 };
 
@@ -385,12 +388,14 @@ static void card_changed(struct userdata *u, struct 
udev_device *dev) {
 "card_name=\"%s\" "
 "tsched=%s "
 "ignore_dB=%s "
+"sync_volume=%s "
 
"card_properties=\"module-udev-detect.discovered=1\"",
 path_get_card_id(path),
 n,
 d->card_name,
 pa_yes_no(u->use_tsched),
-pa_yes_no(u->ignore_dB));
+pa_yes_no(u->ignore_dB),
+pa_yes_no(u->sync_volume));
 pa_xfree(n);
 
 pa_hashmap_put(u->devices, d->path, d);
@@ -660,7 +665,7 @@ int pa__init(pa_module *m) {
 struct udev_enumerate *enumerate = NULL;
 struct udev_list_entry *item = NULL, *first = NULL;
 int fd;
-pa_bool_t use_tsched = TRUE, ignore_dB = FALSE;
+pa_bool_t use_tsched = TRUE, ignore_dB = FALSE, sync_volume=FALSE;
 
 pa_assert(m);
 
@@ -686,6 +691,12 @@ int pa__init(pa_module *m) {
 }
 u->ignore_dB = ignore_dB;
 
+if (pa_modargs_get_value_boolean(ma, "sync_volume", &sync_volume) < 0) {
+pa_log("Failed to parse sync_volume= argument.");
+goto fail;
+}
+u->sync_volume = sync_volume;
+
 if (!(u->udev = udev_new())) {
 pa_log("Failed to initialize udev library.");
 goto fail;
-- 
1.7.0

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH 0/5] Synchronize HW and SW volume timing

2010-02-28 Thread Jyri Sarha
From: Jyri Sarha 

The first patch here is part of Maemo Fremantle release, so has gone 
trough considerable amount of testing already. However, the adaptation 
on top of the latest upstream is fairly recent.

Jyri Sarha (5):
  core: Add infrastructure for delayed HW volume setting
  alsa-sink: Take syncronized HW volume infra into use
  alsa-sink: Add locking to protect concurrent mixer and mixer_path
access
  udev-detect: Add sync_volume parameter
  alsa-card: Add sync_volume parameter

 src/modules/alsa/alsa-mixer.c   |   38 ++--
 src/modules/alsa/alsa-mixer.h   |2 +-
 src/modules/alsa/alsa-sink.c|  132 +--
 src/modules/alsa/alsa-source.c  |2 +-
 src/modules/alsa/module-alsa-card.c |4 +-
 src/modules/alsa/module-alsa-sink.c |8 ++-
 src/modules/module-udev-detect.c|   17 +++-
 src/pulse/def.h |8 ++-
 src/pulsecore/sink.c|  201 ++-
 src/pulsecore/sink.h|   39 +++-
 10 files changed, 424 insertions(+), 27 deletions(-)

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH 3/5] alsa-sink: Add locking to protect concurrent mixer and mixer_path access

2010-02-28 Thread Jyri Sarha
From: Jyri Sarha 

---
 src/modules/alsa/alsa-sink.c |   55 ++---
 1 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 45ba24a..43b0b09 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -98,6 +98,12 @@ struct userdata {
 snd_mixer_t *mixer_handle;
 pa_alsa_path_set *mixer_path_set;
 pa_alsa_path *mixer_path;
+/* NOTE: This lock is a crude way of protecting both mixer_path and 
mixer_element
+ *   when accessing them from main and IO-thread concurrently. 
Everything
+ *   seem to work fine even without this lock when stress testing the 
sync
+ *   volume with multiple concurrent transient streams, but better 
safe than
+ *   sorry. */
+pa_mutex *mixer_mutex;
 
 pa_cvolume hardware_volume;
 
@@ -1133,12 +1139,16 @@ static void sink_get_volume_cb(pa_sink *s) {
 struct userdata *u = s->userdata;
 pa_cvolume r;
 char t[PA_CVOLUME_SNPRINT_MAX];
+int status;
 
 pa_assert(u);
 pa_assert(u->mixer_path);
 pa_assert(u->mixer_handle);
 
-if (pa_alsa_path_get_volume(u->mixer_path, u->mixer_handle, 
&s->channel_map, &r) < 0)
+pa_mutex_lock(u->mixer_mutex);
+status = pa_alsa_path_get_volume(u->mixer_path, u->mixer_handle, 
&s->channel_map, &r);
+pa_mutex_unlock(u->mixer_mutex);
+if (status < 0)
 return;
 
 /* Shift down by the base volume, so that 0dB becomes maximum volume */
@@ -1161,6 +1171,7 @@ static void sink_set_volume_cb(pa_sink *s) {
 pa_cvolume r;
 char t[PA_CVOLUME_SNPRINT_MAX];
 pa_bool_t write_to_hw = (s->flags & PA_SINK_SYNC_VOLUME) ? FALSE : TRUE;
+int status;
 
 pa_assert(u);
 pa_assert(u->mixer_path);
@@ -1169,7 +1180,10 @@ static void sink_set_volume_cb(pa_sink *s) {
 /* Shift up by the base volume */
 pa_sw_cvolume_divide_scalar(&r, &s->real_volume, s->base_volume);
 
-if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, 
&s->channel_map, &r, write_to_hw) < 0)
+pa_mutex_lock(u->mixer_mutex);
+status = pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, 
&s->channel_map, &r, write_to_hw);
+pa_mutex_unlock(u->mixer_mutex);
+if (status < 0)
 return;
 
 /* Shift down by the base volume, so that 0dB becomes maximum volume */
@@ -1212,13 +1226,18 @@ static void sink_set_volume_cb(pa_sink *s) {
 static void sink_write_volume_cb(pa_sink *s) {
 struct userdata *u = s->userdata;
 pa_cvolume hw_vol = s->thread_info.current_hw_volume;
+int status;
 
 pa_assert(u);
 pa_assert(u->mixer_path);
 pa_assert(u->mixer_handle);
 pa_assert(s->flags & PA_SINK_SYNC_VOLUME);
 
-if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, 
&s->channel_map, &hw_vol, TRUE) < 0)
+pa_mutex_lock(u->mixer_mutex);
+status = pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, 
&s->channel_map, &hw_vol, TRUE);
+pa_mutex_unlock(u->mixer_mutex);
+
+if (status < 0)
 pa_log_error("Writting HW volume failed");
 else {
 pa_cvolume tmp_vol;
@@ -1239,12 +1258,16 @@ static void sink_write_volume_cb(pa_sink *s) {
 static void sink_get_mute_cb(pa_sink *s) {
 struct userdata *u = s->userdata;
 pa_bool_t b;
+int status;
 
 pa_assert(u);
 pa_assert(u->mixer_path);
 pa_assert(u->mixer_handle);
 
-if (pa_alsa_path_get_mute(u->mixer_path, u->mixer_handle, &b) < 0)
+pa_mutex_lock(u->mixer_mutex);
+status = pa_alsa_path_get_mute(u->mixer_path, u->mixer_handle, &b);
+pa_mutex_unlock(u->mixer_mutex);
+if (status < 0)
 return;
 
 s->muted = b;
@@ -1257,7 +1280,9 @@ static void sink_set_mute_cb(pa_sink *s) {
 pa_assert(u->mixer_path);
 pa_assert(u->mixer_handle);
 
+pa_mutex_lock(u->mixer_mutex);
 pa_alsa_path_set_mute(u->mixer_path, u->mixer_handle, s->muted);
+pa_mutex_unlock(u->mixer_mutex);
 }
 
 static int sink_set_port_cb(pa_sink *s, pa_device_port *p) {
@@ -1271,6 +1296,13 @@ static int sink_set_port_cb(pa_sink *s, pa_device_port 
*p) {
 data = PA_DEVICE_PORT_DATA(p);
 
 pa_assert_se(u->mixer_path = data->path);
+
+/* This forces flushing of pending volume change events */
+if (u->sink->flags & PA_SINK_SYNC_VOLUME)
+pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), 
PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
+
+pa_mutex_lock(u->mixer_mutex);
+
 pa_alsa_path_select(u->mixer_path, u->mixer_handle);
 
 if (u->mixer_path->has_volume && u->mixer_path->has_dB) {
@@ -1289,10 +1321,16 @@ static int sink_set_port_cb(pa_sin

[pulseaudio-discuss] [PATCH] optimization: Optimized pa_sink_render_full.

2009-05-13 Thread Jyri Sarha
From: Jyri Sarha 

This is finally the latest version of the patch.
---
 src/pulsecore/sink.c |5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 28b3440..bd4130f 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -1010,14 +1010,13 @@ void pa_sink_render_full(pa_sink *s, size_t length, 
pa_memchunk *result) {
pa_memchunk chunk;
size_t l, d;
pa_memchunk_make_writable(result, length);
-   result->length = length;
 
l = length - result->length;
d = result->index + result->length;
while (l > 0) {
chunk = *result;
-   chunk.index += d;
-   chunk.length -= d - result->index;
+   chunk.index = d;
+   chunk.length = l;
 
pa_sink_render_into(s, &chunk);
 
-- 
1.5.6.3

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] [PATCH] bluetooth-device: Add safe guard

2009-05-13 Thread Jyri Sarha

On Wed, 13 May 2009, Jyri Sarha wrote:



Sorryyy.. this is the same thing that I posted couple of days ago.
The second patch in this thread has the working version of the
optimized pa_sink_render_full(). And sorry for the typo in the comment,
I was working i bit too much of a hurry :).

BTW, patches are in clean order at:
 http://git.gitorious.org/~oku/pulseaudio/oku-clone.git

Cheers,
Jyri

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] bluetooth-device: Add safe guard against BT streaming irregularities.

2009-05-13 Thread Jyri Sarha
From: Jyri Sarha 

Some bad quality BT-headsets block bluez socket sometimes for hundreds
of milliseconds, especially when changing mode. When the module tries
catch up the lost time it may SBC encode up to half a second of audio
without yielding. On slow machine this may cause maximum RT time slice
to be exceeded. Cleaned out the minor fix that slipped into first version
of the patch.
---
 src/modules/bluetooth/module-bluetooth-device.c |   22 ++
 1 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/src/modules/bluetooth/module-bluetooth-device.c 
b/src/modules/bluetooth/module-bluetooth-device.c
index ecb5e83..1b42f4a 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -174,6 +174,8 @@ struct userdata {
 #define FIXED_LATENCY_PLAYBACK_HSP (125*PA_USEC_PER_MSEC)
 #define FIXED_LATENCY_RECORD_HSP (25*PA_USEC_PER_MSEC)
 
+#define MAX_PLAYBACK_CATCH_UP_USEC (100*PA_USEC_PER_MSEC)
+
 #ifdef NOKIA
 #define USE_SCO_OVER_PCM(u) (u->profile == PROFILE_HSP && (u->hsp.sco_sink && 
u->hsp.sco_source))
 #endif
@@ -1296,15 +1298,27 @@ static void thread_func(void *userdata) {
 
 if ((!u->source || 
!PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && do_write <= 0 && 
writable) {
 pa_usec_t time_passed;
-uint64_t should_have_written;
+pa_usec_t audio_sent;
 
 /* Hmm, there is no input stream we could synchronize
  * to. So let's do things by time */
 
 time_passed = pa_rtclock_usec() - u->started_at;
-should_have_written = pa_usec_to_bytes(time_passed, 
&u->sample_spec);
-
-do_write = u->write_index <= should_have_written;
+audio_sent = pa_bytes_to_usec(u->write_index, 
&u->sample_spec);
+
+if (audio_sent <= time_passed) {
+pa_usec_t audio_to_send = time_passed - audio_sent;
+if (u->write_index > 0 && audio_to_send > 
MAX_PLAYBACK_CATCH_UP_USEC) {
+pa_usec_t skip_usec = audio_to_send - 
MAX_PLAYBACK_CATCH_UP_USEC;
+uint64_t skip_bytes = pa_usec_to_bytes(skip_usec, 
&u->sample_spec);
+pa_memchunk tmp;
+pa_log_warn("Skipping %lld us (= %lld bytes) in 
audio stream", skip_usec, skip_bytes);
+pa_sink_render_full(u->sink, skip_bytes, &tmp);
+pa_memblock_unref(tmp.memblock);
+u->write_index += skip_bytes;
+}
+do_write = 1;
+}
 }
 
 if (writable && do_write > 0) {
-- 
1.5.6.3

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] optimization: Optimized pa_sink_render_full.

2009-05-13 Thread Jyri Sarha
From: Jyri Sarha 

This is finally the latest version of the patach.
---
 src/pulsecore/sink.c |   77 ++---
 1 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 30fa557..63752d9 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -933,22 +933,89 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk 
*target) {
 
 /* Called from IO thread context */
 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
+pa_mix_info info[MAX_MIX_CHANNELS];
+size_t length1st = length;
+unsigned n;
+
 pa_sink_assert_ref(s);
 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
 pa_assert(length > 0);
 pa_assert(pa_frame_aligned(length, &s->sample_spec));
 pa_assert(result);
 
+pa_sink_ref(s);
+
 pa_assert(!s->thread_info.rewind_requested);
 pa_assert(s->thread_info.rewind_nbytes == 0);
 
-/*** This needs optimization ***/
+pa_assert(length > 0);
+
+n = fill_mix_info(s, &length1st, info, MAX_MIX_CHANNELS);
+
+if (n == 0) {
+   pa_silence_memchunk_get(&s->core->silence_cache,
+   s->core->mempool,
+   result,
+   &s->sample_spec,
+   length1st);
+} else if (n == 1) {
+   pa_cvolume volume;
 
-result->index = 0;
-result->length = length;
-result->memblock = pa_memblock_new(s->core->mempool, length);
+   *result = info[0].chunk;
+   pa_memblock_ref(result->memblock);
+
+   if (result->length > length)
+   result->length = length;
+
+   pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, 
&info[0].volume);
+
+   if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
+pa_memchunk_make_writable(result, length);
+if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
+pa_silence_memchunk(result, &s->sample_spec);
+else
+pa_volume_memchunk(result, &s->sample_spec, &volume);
+   }
+} else {
+void *ptr;
 
-pa_sink_render_into_full(s, result);
+   result->index = 0;
+   result->memblock = pa_memblock_new(s->core->mempool, length);
+
+   ptr = pa_memblock_acquire(result->memblock);
+
+result->length = pa_mix(info, n,
+(uint8_t*) ptr + result->index, length1st,
+&s->sample_spec,
+&s->thread_info.soft_volume,
+s->thread_info.soft_muted);
+
+pa_memblock_release(result->memblock);
+}
+
+inputs_drop(s, info, n, result);
+
+if (result->length < length) {
+   pa_memchunk chunk;
+   size_t l, d;
+   pa_memchunk_make_writable(result, length);
+
+   l = length - result->length;
+   d = result->index + result->length;
+   while (l > 0) {
+   chunk = *result;
+   chunk.index = d;
+   chunk.length = l;
+
+   pa_sink_render_into(s, &chunk);
+
+   d += chunk.length;
+   l -= chunk.length;
+   }
+   result->length = length;
+}
+
+pa_sink_unref(s);
 }
 
 /* Called from main thread */
-- 
1.5.6.3

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] **Fwd: Re: [PATCH] optimization:

2009-05-13 Thread Jyri Sarha

On Sat, 9 May 2009, Lennart Poettering wrote:

On Thu, 07.05.09 19:55, Jyri Sarha (jyri.sa...@nokia.com) wrote:


I have used this fix for quite a while and I am pretty confident about
it. However, the performance gain was not what I expected.


Thanks. Looks good. Applied.



Damn, this was old version of the patch and does not work
correctly :(. I'll post the new version shortly. Sorry for the
inconvenience.

Cheers,
Jyri
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] bluetooth-device: Add safe guard against BT streaming irregularities.

2009-05-08 Thread Jyri Sarha
From: Jyri Sarha 

Some bad quality BT-headsets block bluez socket sometimes for hundreds
of milliseconds, especially when changing mode. When the module tries
catch up the lost time it may SBC encode up to half a second of audio
without yielding. On slow machine this may cause maximum RT time slice
to be exceeded. Cleaned out the minor fix that slipped into first version
of the patch.
---
 src/modules/bluetooth/module-bluetooth-device.c |   22 ++
 1 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/src/modules/bluetooth/module-bluetooth-device.c 
b/src/modules/bluetooth/module-bluetooth-device.c
index ecb5e83..1b42f4a 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -174,6 +174,8 @@ struct userdata {
 #define FIXED_LATENCY_PLAYBACK_HSP (125*PA_USEC_PER_MSEC)
 #define FIXED_LATENCY_RECORD_HSP (25*PA_USEC_PER_MSEC)
 
+#define MAX_PLAYBACK_CATCH_UP_USEC (100*PA_USEC_PER_MSEC)
+
 #ifdef NOKIA
 #define USE_SCO_OVER_PCM(u) (u->profile == PROFILE_HSP && (u->hsp.sco_sink && 
u->hsp.sco_source))
 #endif
@@ -1296,15 +1298,27 @@ static void thread_func(void *userdata) {
 
 if ((!u->source || 
!PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && do_write <= 0 && 
writable) {
 pa_usec_t time_passed;
-uint64_t should_have_written;
+pa_usec_t audio_sent;
 
 /* Hmm, there is no input stream we could synchronize
  * to. So let's do things by time */
 
 time_passed = pa_rtclock_usec() - u->started_at;
-should_have_written = pa_usec_to_bytes(time_passed, 
&u->sample_spec);
-
-do_write = u->write_index <= should_have_written;
+audio_sent = pa_bytes_to_usec(u->write_index, 
&u->sample_spec);
+
+if (audio_sent <= time_passed) {
+pa_usec_t audio_to_send = time_passed - audio_sent;
+if (u->write_index > 0 && audio_to_send > 
MAX_PLAYBACK_CATCH_UP_USEC) {
+pa_usec_t skip_usec = audio_to_send - 
MAX_PLAYBACK_CATCH_UP_USEC;
+uint64_t skip_bytes = pa_usec_to_bytes(skip_usec, 
&u->sample_spec);
+pa_memchunk tmp;
+pa_log_warn("Skipping %lld us (= %lld bytes) in 
audio stream", skip_usec, skip_bytes);
+pa_sink_render_full(u->sink, skip_bytes, &tmp);
+pa_memblock_unref(tmp.memblock);
+u->write_index += skip_bytes;
+}
+do_write = 1;
+}
 }
 
 if (writable && do_write > 0) {
-- 
1.5.6.3

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] optimization: Take samples from silence cache rather than write zeros.

2009-05-07 Thread Jyri Sarha
If the only stream to render from is muted take samples from the
silence cache. This should shrink memory/cache bandwidth. Again the
gain was not what I hoped for.
---
 src/pulsecore/sink.c |   32 ++--
 1 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index d3a6dc9..6cda8c8 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -788,11 +788,17 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk 
*result) {
 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, 
&info[0].volume);
 
 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
-pa_memchunk_make_writable(result, 0);
-if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
-pa_silence_memchunk(result, &s->sample_spec);
-else
+if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
+pa_memblock_unref(result->memblock);
+pa_silence_memchunk_get(&s->core->silence_cache,
+s->core->mempool,
+result, 
+&s->sample_spec, 
+result->length);
+} else {
+pa_memchunk_make_writable(result, 0);
 pa_volume_memchunk(result, &s->sample_spec, &volume);
+}
 }
 } else {
 void *ptr;
@@ -969,13 +975,19 @@ void pa_sink_render_full(pa_sink *s, size_t length, 
pa_memchunk *result) {
 
pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, 
&info[0].volume);

-   if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
-pa_memchunk_make_writable(result, length);
-if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
-pa_silence_memchunk(result, &s->sample_spec);
-else
+if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
+if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
+pa_memblock_unref(result->memblock);
+pa_silence_memchunk_get(&s->core->silence_cache,
+s->core->mempool,
+result, 
+&s->sample_spec, 
+result->length);
+} else {
+pa_memchunk_make_writable(result, length);
 pa_volume_memchunk(result, &s->sample_spec, &volume);
-   }
+}
+}
 } else {
 void *ptr;
 
-- 
1.5.6.3

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] optimization: Optimized pa_sink_render_full.

2009-05-07 Thread Jyri Sarha
I have used this fix for quite a while and I am pretty confident about
it. However, the performance gain was not what I expected.
---
 src/pulsecore/sink.c |   78 ++---
 1 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 30fa557..d3a6dc9 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -933,22 +933,90 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk 
*target) {
 
 /* Called from IO thread context */
 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
+pa_mix_info info[MAX_MIX_CHANNELS];
+size_t length1st = length;
+unsigned n;
+
 pa_sink_assert_ref(s);
 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
 pa_assert(length > 0);
 pa_assert(pa_frame_aligned(length, &s->sample_spec));
 pa_assert(result);
 
+pa_sink_ref(s);
+
 pa_assert(!s->thread_info.rewind_requested);
 pa_assert(s->thread_info.rewind_nbytes == 0);
 
-/*** This needs optimization ***/
+pa_assert(length > 0);
+
+n = fill_mix_info(s, &length1st, info, MAX_MIX_CHANNELS);
 
-result->index = 0;
-result->length = length;
-result->memblock = pa_memblock_new(s->core->mempool, length);
+if (n == 0) {
+   pa_silence_memchunk_get(&s->core->silence_cache,
+   s->core->mempool,
+   result, 
+   &s->sample_spec, 
+   length1st);
+} else if (n == 1) {
+   pa_cvolume volume;
 
-pa_sink_render_into_full(s, result);
+   *result = info[0].chunk;
+   pa_memblock_ref(result->memblock);
+
+   if (result->length > length)
+   result->length = length;
+
+   pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, 
&info[0].volume);
+   
+   if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
+pa_memchunk_make_writable(result, length);
+if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
+pa_silence_memchunk(result, &s->sample_spec);
+else
+pa_volume_memchunk(result, &s->sample_spec, &volume);
+   }
+} else {
+void *ptr;
+
+   result->index = 0;
+   result->memblock = pa_memblock_new(s->core->mempool, length);
+
+   ptr = pa_memblock_acquire(result->memblock);
+
+result->length = pa_mix(info, n,
+(uint8_t*) ptr + result->index, length1st,
+&s->sample_spec,
+&s->thread_info.soft_volume,
+s->thread_info.soft_muted);
+
+pa_memblock_release(result->memblock);
+}
+
+inputs_drop(s, info, n, result);
+
+if (result->length < length) {
+   pa_memchunk chunk;
+   size_t l, d;
+   pa_memchunk_make_writable(result, length);  
+   result->length = length;
+
+   l = length - result->length;
+   d = result->index + result->length;
+   while (l > 0) {
+   chunk = *result;
+   chunk.index += d;
+   chunk.length -= d - result->index;
+ 
+   pa_sink_render_into(s, &chunk);
+   
+   d += chunk.length;
+   l -= chunk.length;
+   }
+   result->length = length;
+}
+
+pa_sink_unref(s);
 }
 
 /* Called from main thread */
-- 
1.5.6.3

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] [PATCH] bluetooth-device: Add safe guard against BT streaming irregularities.

2009-05-07 Thread Jyri Sarha
Some bad quality BT-headsets block bluez socket sometimes for hundreds
of milliseconds, especially when changing mode. When the module tries
catch up the lost time it may SBC encode up to half a second of audio
without yielding. On slow machine this may cause maximum RT time slice
to be exceeded.
---
 src/modules/bluetooth/module-bluetooth-device.c |   27 ++
 1 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/src/modules/bluetooth/module-bluetooth-device.c 
b/src/modules/bluetooth/module-bluetooth-device.c
index ecb5e83..2a70496 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -174,6 +174,8 @@ struct userdata {
 #define FIXED_LATENCY_PLAYBACK_HSP (125*PA_USEC_PER_MSEC)
 #define FIXED_LATENCY_RECORD_HSP (25*PA_USEC_PER_MSEC)
 
+#define MAX_PLAYBACK_CATCH_UP_USEC (100*PA_USEC_PER_MSEC)
+
 #ifdef NOKIA
 #define USE_SCO_OVER_PCM(u) (u->profile == PROFILE_HSP && (u->hsp.sco_sink && 
u->hsp.sco_source))
 #endif
@@ -1296,15 +1298,27 @@ static void thread_func(void *userdata) {
 
 if ((!u->source || 
!PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && do_write <= 0 && 
writable) {
 pa_usec_t time_passed;
-uint64_t should_have_written;
+pa_usec_t audio_sent;
 
 /* Hmm, there is no input stream we could synchronize
  * to. So let's do things by time */
 
 time_passed = pa_rtclock_usec() - u->started_at;
-should_have_written = pa_usec_to_bytes(time_passed, 
&u->sample_spec);
-
-do_write = u->write_index <= should_have_written;
+audio_sent = pa_bytes_to_usec(u->write_index, 
&u->sample_spec);
+
+if (audio_sent <= time_passed) {
+pa_usec_t audio_to_send = time_passed - audio_sent;
+if (u->write_index > 0 && audio_to_send > 
MAX_PLAYBACK_CATCH_UP_USEC) {
+pa_usec_t skip_usec = audio_to_send - 
MAX_PLAYBACK_CATCH_UP_USEC;
+uint64_t skip_bytes = pa_usec_to_bytes(skip_usec, 
&u->sample_spec);
+pa_memchunk tmp;
+pa_log_warn("Skipping %lld us (= %lld bytes) in 
audio stream", skip_usec, skip_bytes);
+pa_sink_render_full(u->sink, skip_bytes, &tmp);
+pa_memblock_unref(tmp.memblock);
+u->write_index += skip_bytes;
+}
+do_write = 1;
+}
 }
 
 if (writable && do_write > 0) {
@@ -1822,8 +1836,11 @@ static int start_thread(struct userdata *u) {
 
 #ifdef NOKIA
 if (USE_SCO_OVER_PCM(u)) {
-if (start_stream_fd(u) < 0)
+if (start_stream_fd(u) < 0) {
+u->sink = NULL;
+u->source = NULL;
 return -1;
+}
 
 pa_sink_ref(u->sink);
 pa_source_ref(u->source);
-- 
1.5.6.3

___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] Couple problems when using 0.9.11 and fixes

2008-09-04 Thread Jyri Sarha
Hi,
I found couple of problems when upgrading to pulseaduio 0.9.11. The 
both are related to a case when tsched turned off on alsa-sink. First, 
problem appears when trying the select a specific number fragment with
module-alsa-sink parameters, for instance this:

load-module module-alsa-sink device=hw:0 rate=44100 fragment_size=882 
fragments=2 tsched=0

The above produces three fragments of 588 bytes each. The actual bug
appears to be in alsa-lib, but it can be by-passed without breaking
things when alsa-lib gets fixed. To do that apply
fix_incremented_number_of_fragments.patch.

The other problem appears when trying to use alsa-sink with tsched=0 on a 
slow CPU. After writing a set of samples to device alsa-sink checks whether
there is room to write some more samples. On a slow CPU there is always room
for couple of samples more and alsa-sink keeps busy looping in the write
function. "parameter_to_set_minimum_write_size.patch" adds a parameter to 
module-alsa-sink to set the minimum number of samples to write on device,
setting this parameter to a reasonable value fixes the above problem,
like this:

load-module module-alsa-sink device=hw:0 rate=44100 fragment_size=882 
fragments=2 tsched=0 hwbuf_min_frames_to_write=32

Alsa-source would need a similar patch too. In the end I decided
to forward port the old alsa- sink and source from 0.9.10 to 0.9.11,
because they seem to work more reliably and generate much less load, when
fragment-size and number of fragments is pushed to the minimum and 
tsched is not used. I can post those patches too if anybody is interested.

Cheers,
Jyri


===File ~/fix_incremented_number_of_fragments.patch=
diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index 8abf834..64b4eff 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -369,12 +369,15 @@ int pa_alsa_set_hw_params(
 goto finish;
 
 if (_periods > 0) {
-dir = 1;
-if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 
&_periods, &dir)) < 0) {
-dir = -1;
-if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, 
hwparams, &_periods, &dir)) < 0)
-goto finish;
-}
+   dir = 0;
+   if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 
&_periods, &dir)) < 0) {
+   dir = 1;
+   if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 
&_periods, &dir)) < 0) {
+   dir = -1;
+   if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, 
hwparams, &_periods, &dir)) < 0)
+   goto finish;
+   }
+   }
 }
 
 if (_period_size > 0)


===File ~/parameter_to_set_minimum_write_size.patch=
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
index 8e66f79..0135a0b 100644
--- a/src/modules/module-alsa-sink.c
+++ b/src/modules/module-alsa-sink.c
@@ -69,7 +69,8 @@ PA_MODULE_USAGE(
 "tsched= "
 "tsched_buffer_size= "
 "tsched_buffer_watermark= "
-"mixer_reset=");
+"mixer_reset="
+   "hwbuf_min_frames_to_write=");
 
 static const char* const valid_modargs[] = {
 "sink_name",
@@ -86,6 +87,7 @@ static const char* const valid_modargs[] = {
 "tsched_buffer_size",
 "tsched_buffer_watermark",
 "mixer_reset",
+"hwbuf_min_frames_to_write",
 NULL
 };
 
@@ -132,6 +134,7 @@ struct userdata {
 uint64_t since_start;
 
 snd_pcm_sframes_t hwbuf_unused_frames;
+snd_pcm_sframes_t hwbuf_min_frames_to_write;
 };
 
 static void fix_tsched_watermark(struct userdata *u) {
@@ -278,7 +281,7 @@ static int mmap_write(struct userdata *u, pa_usec_t 
*sleep_usec) {
 if (pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) > 
process_usec+max_sleep_usec/2)
 break;
 
-if (PA_UNLIKELY(n <= u->hwbuf_unused_frames))
+if (PA_UNLIKELY(n <= u->hwbuf_min_frames_to_write || n <= 
u->hwbuf_unused_frames))
 break;
 
 n -= u->hwbuf_unused_frames;
@@ -390,7 +393,7 @@ static int unix_write(struct userdata *u, pa_usec_t 
*sleep_usec) {
 if (pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) > 
process_usec+max_sleep_usec/2)
 break;
 
-if (PA_UNLIKELY(n <= u->hwbuf_unused_frames))
+if (PA_UNLIKELY(n <= u->hwbuf_min_frames_to_write || n <= 
u->hwbuf_unused_frames))
 break;
 
 n -= u->hwbuf_unused_frames;
@@ -1103,6 +1106,7 @@ int pa__init(pa_module*m) {
 pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, mixer_reset = TRUE;
 pa_usec_t usec;
 pa_sink_new_data data;
+int32_t hwbuf_min_frames_to_write = 0;
 
 snd_pcm_info_alloca(&pcm_info);
 
@@ -1162,6 +1166,11 @@ int pa__init(pa_module*m) {
 goto fail;
 }
 
+if (pa_modargs_get_value_s32(ma, "hwbuf_min_frames_to_write", 
&hwbuf_min_frames_to_write) < 0) {
+ 

Re: [pulseaudio-discuss] Atomic operations on ARM

2008-02-20 Thread Jyri Sarha

On Wed, 13 Feb 2008, Lennart Poettering wrote:


On Fri, 01.02.08 15:22, Jyri Sarha ([EMAIL PROTECTED]) wrote:


...


All code I saw that makes use of the kernel helper function calls it
in a loop. (At least that's what I remember)



The same is true in many cases for pa_atomic_cmpxchg too. That is 
why the idea of having another loop inside pa_atomic_cmpxchg felt a

bit ugly to me at first.


So what should be done?

1. Change the above line in pulsecore/async.c to use pa_atomic_store
instead and try to look if there are other similar places.

2. Write loops like above to ARM specific implementations atomic
compare and exchange.


I'd certainly vote for #2. I see no real drawbacks on this.


Any way I'll produce a proper ARM atomic ops patch as soon as I am happy
with it. However it may take a while because I am still only learning
the autoconf magic and I have some other tasks I should take care of too.


Every patch greatly appreciated!



Here is my atomic ops patch implemented according to option #2. The patch
should apply cleanly to 0.9.9 release and probably to PA SVN HEAD too. After
applying the patch the source compiles cleanly at least in our scratchbox
based development environment and what is most important the resulting binaries
seem to work correctly.

Arm binaries are usually cross compiled, thus trying to detect CPU or
operating system capabilities at compile time may give bad results. Because 
of this I added couple of configure flags so that wanted result can be

forced in all environments. Here are the options:

--enable-atomic-arm-memory-barrier
This should only be needed in SMP systems. Since I am not aware of any ARM
based SMP systems, this is disabled by default.

--disable-atomic-arm-linux-helpers
Disables usage of linux kernel helpers, inline assembler implementation or,
if that fails, libatomic_ops is used instead. By default kernel helpers are
always used when compiling for arm in a linux system.

Cheers,
    Jyri

// Jyri Sarha -- [EMAIL PROTECTED]diff --git a/configure.ac b/configure.ac
index 10111e1..e2b584e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -121,6 +121,43 @@ if test "x$GCC" = "xyes" ; then
 done
 fi
 
+# Native atomic operation support
+AC_ARG_ENABLE([atomic-arm-linux-helpers],
+AC_HELP_STRING([--disable-atomic-arm-linux-helpers], [use inline asm or 
libatomic_ops instead]),
+[
+case "${enableval}" in
+yes) atomic_arm_linux_helpers=yes ;;
+no) atomic_arm_linux_helpers=no ;;
+*) AC_MSG_ERROR(bad value ${enableval} for 
--disable-atomic-arm-linux-helpers) ;;
+esac
+],
+[atomic_arm_linux_helpers=auto])
+
+AC_ARG_ENABLE([atomic-arm-memory-barrier],
+AC_HELP_STRING([--enable-atomic-arm-memory-barrier], [only really needed 
in SMP arm systems]),
+[
+case "${enableval}" in
+yes) AC_DEFINE_UNQUOTED(ATOMIC_ARM_MEMORY_BARRIER_ENABLED, 1, 
[Enable memory barriers]) ;;
+no) ;;
+*) AC_MSG_ERROR(bad value ${enableval} for 
--disable-atomic-arm-linux-helpers) ;;
+esac
+],)
+
+AC_MSG_CHECKING([target operating system])
+case $host in
+   *-*-linux*)
+   AC_MSG_RESULT([linux]) 
+   pulse_target_os=linux
+   ;;
+   *)
+   AC_MSG_RESULT([unknown])   
+   pulse_target_os=unknown
+   ;;
+esac
+
+# If everything else fails use libatomic_ops
+need_libatomic_ops=yes
+
 AC_MSG_CHECKING([whether $CC knows __sync_bool_compare_and_swap()])
 AC_LANG_CONFTEST([int main() { int a = 4; __sync_bool_compare_and_swap(&a, 4, 
5); }])
 $CC conftest.c $CFLAGS -o conftest > /dev/null 2> /dev/null
@@ -129,8 +166,53 @@ rm -f conftest.o conftest
 if test $ret -eq 0 ; then
 AC_DEFINE([HAVE_ATOMIC_BUILTINS], 1, [Have __sync_bool_compare_and_swap() 
and friends.])
 AC_MSG_RESULT([yes])
+need_libatomic_ops=no
 else
 AC_MSG_RESULT([no])
+# HW specific atomic ops stuff 
+AC_MSG_CHECKING([architecture for native atomic operations])
+case $host_cpu in  
+arm*)
+   AC_MSG_RESULT([arm])
+   AC_MSG_CHECKING([whether we can use Linux kernel helpers])
+   # The Linux kernel helper functions have been there since 2.6.16. 
However
+   # compile time checking for kernel version in cross compile 
environment 
+   # (which is usually the case for arm cpu) is tricky (or impossible).
+   if test "x$pulse_target_os" = "xlinux" && test 
"x$atomic_arm_linux_helpers" != "xno"; then
+   AC_MSG_RESULT([yes])
+   AC_DEFINE_UNQUOTED(ATOMIC_ARM_LINUX_HELPERS, 1, [special arm 
linux implementation])
+   need_libatomic_ops=no
+   else
+  AC_MSG_RESULT([no])
+  AC_MSG_CHECKING([compiler support for arm inline asm atomic 

[pulseaudio-discuss] Atomic operations on ARM

2008-02-01 Thread Jyri Sarha

Hi,

I have written inline assembler implementations of pa_atomic
operations for arm for ARM6 and above. For compatibility with older
ARMs I have also written versions using ARM-Linux kernel helper
functions (see http://0pointer.de/blog#atomic-rt). 

The both implementations run almost perfectly now. However there is a
thing to note about compare and exchange implementations for 
ARM6 and above. The semantics of the usual ARM ldrex-strexeq instruction 
sequence is not identical to x86 implementations of the same thing, e.g.
the exchange is not totally atomic after all.

The strexeq-instruction has two conditions the equality to the old value 
and the exclusiveness of the operation (e.g. if the value in memory was 
tampered between the operations). The operation fails if either of
these conditions fail, e.g. the value in memory is unchanged. So it is 
possible that the old-value-condition is met, but the exclusiveness- 
condition fails, but even the tampered memory value would meet the 
old-value-condition.

The above applies also to kernel helper implementation of atomic exchange 
for ARM6 and above.

Because of the above problem (I suspect) this assertion in pulsecore/async.c 
fails sometimes under heavy load:
/* Guaranteed to succeed if we only have a single reader */
pa_assert_se(pa_atomic_ptr_cmpxchg(&cells[idx], ret, NULL));

The assertion failure has happened with the both kernel helper and inline asm 
versions (they are identical in ARM6 environment anyway). The failures
are not very common thou.


The atomic compare and exchange can also be written in a way that it retries
the operation if the exclusiveness-condition fails but the equality-condition
was ok, which would resemble real atomicity more. The inline assembler version
would then look like this:

static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
unsigned long not_equal, not_exclusive;

pa_memory_barrier();
do {
__asm__ __volatile__("@ pa_atomic_cmpxchg\n"
 "1: ldrex  %0, [%2]\n"
 "   subs   %0, %0, %3\n"
 "   mov%1, %0\n"
 "   strexeq %0, %4, [%2]\n"
 : "=&r" (not_exclusive), "=&r" (not_equal)
 : "r" (&a->value), "Ir" (old_i), "r" (new_i)
 : "cc");
} while(not_exclusive && !not_equal);
pa_memory_barrier();

return !not_equal;
}

A similar kind of external loop can also be added to kernel helper
function, but if the kernel helper in fact makes a systemcall it is
unnecessary. I wonder if all this is worth the trouble. 

So what should be done?

1. Change the above line in pulsecore/async.c to use pa_atomic_store
instead and try to look if there are other similar places.

2. Write loops like above to ARM specific implementations atomic
compare and exchange.

Any way I'll produce a proper ARM atomic ops patch as soon as I am happy 
with it. However it may take a while because I am still only learning
the autoconf magic and I have some other tasks I should take care of too.

Cheers,
   Jyri

// Jyri Sarha -- [EMAIL PROTECTED]
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] Rendering data from sink with 0.9.7

2007-10-24 Thread Jyri Sarha
 < 0)
 if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, 
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
 goto finish;
-
+   else
+ *use_mmap = 0;
 } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, 
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 
 goto finish;
-else if (*use_mmap)
-    *use_mmap = 0;
 
 if ((ret = set_format(pcm_handle, hwparams, &f)) < 0)
 goto finish;
<\patch>


Best regards,
 Jyri

// Jyri Sarha - okuAtikiDotfi
___
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss