From: Andreas Beck <becka-bzdvl@bedatec.de>
To: bluez-devel@lists.sourceforge.net
Subject: [Bluez-devel] skype_bt_hijacker released/updated
Date: Sat, 27 Aug 2005 21:31:54 +0200 [thread overview]
Message-ID: <20050827193154.GA7618@uni-duesseldorf.de> (raw)
[-- Attachment #1: Type: text/plain, Size: 3858 bytes --]
Hi folks,
I've played around with integrating skype and btsco a little further,
and now it starts making some sense to publish the current state:
First of all, I updated the skype_pickup script at
http://www.acs.uni-duesseldorf.de/~becka/download/skype/skype_pickup.py
It features better parsing of the call IDs (thanks to Whoopie for the
idea) and cooperation with the skype_bt_hijacker library at
http://www.acs.uni-duesseldorf.de/~becka/download/skype/skype_bt_hijacker-0.1b.tgz
it is included in this tarball as well, so no need to download both.
Now what does that stuff do?
I wanted to use my headset as a handsfree unit for skype. Actually
this works, without any extra software, but it has some inconveniences
for me.
First of all, I don't want to wear the headset all day, just when using
it. Thus I want skype to ring on the speakers, and then switch it over
to the headset when I want to.
Secondly, I don't even want to leave the headset on all the time. So I
need something that connects the headset when it is available and also
tells the rest of the system about that.
Third I'd like to pick up and hang up calls using the headset buttons.
Forth skype has a nasty programming glitch, which will occasionally hang
it, as it forgets to close down the audio device.
Now how does the skype_bt_hijacker stuff overcome these obstacles?
1. There is a btscorunner script that will in a loop try to find
a known headset (most headsets are undiscoverable, unless explicitly
set to pairing mode) and start up btsco if it does.
As btsco terminates, if it looses connection, the loop will then
again seek for the headset.
I know btsco has the reconnect mode, but that defeats autodetection
of the channel. Maybe that should be done there.
Or maybe it should be done via some kind of Plug'n'Play stuff.
Comments welcome.
2. A patch to btsco which will create a file for as long as the headset
is available. This should probably rather be integrated in the
"action" stuff. I'd suggest to push some fixed strings into the
action parser (which should be put into its own function for this
to work nicely) that will cause "system" commands being run via
.btscorc. This is easier to customize and more generic than my
simplistic patch.
I can probably work out a patch for this, but I'd like to hear, if
you think it's a worthwhile addition.
3. A LD_PRELOAD-able library that will intercept skype calls to open,
close, ioctl and write will fix the skype bug and will also allow
to switch the audio device by just creating or removing a file.
and running scripts when skype opens or closes its audio device.
4. Skype_pickup, which will be run by .btscorc will handle switching
the audio device, picking up and hanging up calls.
All in all, it causes the following behaviour:
You just start btscorunner and the skype_bt_hijacker (which starts
skype).
If the configured headset is turned on, btscorunner will fire up btsco
to link it up.
If skype originates or receives a call, the headset will play a short
ringtone and then skype continues ringing on the main audio device.
You can use it normally there.
However if you press a button on the headset, skype_pickup will either
cause skype to pick up the call and transfer it to the headset, or just
do the latter, if the call is already in progress.
If you press the button again, Skype will be instructed to hang up the
call. If you want to transfer back, you need to remove a file. So if you
have more than one working button on the headset, you can map that
action there as easily.
So if you like that, go ahead, get it, test it, have fun.
CU, Andy
PS: The wrapper might work with other OSS apps, too. So test that, if
you like.
--
= Andreas Beck | Email : <becka-sig@bedatec.de> =
[-- Attachment #2: btsco.diff --]
[-- Type: text/plain, Size: 6145 bytes --]
Index: btsco.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/kernel/btsco.c,v
retrieving revision 1.6
diff -c -r1.6 btsco.c
*** btsco.c 19 Mar 2005 14:28:59 -0000 1.6
--- btsco.c 23 Aug 2005 15:01:19 -0000
***************
*** 21,26 ****
--- 21,46 ----
*
*/
+
+ /* note: defining these two independently is not tested,
+ * thus not recommended
+ */
+
+ /* enable dynamic compression */
+ #define DYNAMIC_COMPRESSION
+ /* enable automatic endianness fixup */
+ #define AUTO_FIXUP_ENDIANNESS
+
+
+ #ifdef DYNAMIC_COMPRESSION
+ /* Autoadjust mic at most this often in 1/8000s */
+ #define GRABSAMPLES 400
+ /* Maximum push for the mike 16= 1:1 - default 20:1 = 320 */
+ #define COMPRESSION_MAX_16 320
+ /* Minimum push for the mike 1= 1:16 */
+ #define COMPRESSION_MIN_16 1
+ #endif
+
#define chip_t snd_card_bt_sco_t
#include <sound/driver.h>
***************
*** 93,100 ****
snd_card_t *card;
spinlock_t mixer_lock;
int mixer_volume[MIXER_ADDR_LAST + 1];
! snd_kcontrol_t *mixer_controls[MIXER_ADDR_LAST + 2]; /* also loopback */
volatile int loopback;
atomic_t playback_count, capture_count;
volatile int count_changed;
spinlock_t count_changed_lock;
--- 113,127 ----
snd_card_t *card;
spinlock_t mixer_lock;
int mixer_volume[MIXER_ADDR_LAST + 1];
! #ifdef DYNAMIC_COMPRESSION
! snd_kcontrol_t *mixer_controls[MIXER_ADDR_LAST + 2 + 1]; /* also loopback and agc */
! #else
! snd_kcontrol_t *mixer_controls[MIXER_ADDR_LAST + 2 ]; /* also loopback */
! #endif
volatile int loopback;
+ #ifdef DYNAMIC_COMPRESSION
+ volatile int agc;
+ #endif
atomic_t playback_count, capture_count;
volatile int count_changed;
spinlock_t count_changed_lock;
***************
*** 569,574 ****
--- 596,632 ----
return changed;
}
+ #ifdef DYNAMIC_COMPRESSION
+ static int snd_bt_sco_agc_get(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+ {
+ snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bt_sco->mixer_lock, flags);
+ ucontrol->value.integer.value[0] = bt_sco->agc;
+ spin_unlock_irqrestore(&bt_sco->mixer_lock, flags);
+ return 0;
+ }
+
+ static int snd_bt_sco_agc_put(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+ {
+ snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int changed;
+ int agc;
+
+ agc = !!ucontrol->value.integer.value[0];
+
+ spin_lock_irqsave(&bt_sco->mixer_lock, flags);
+ changed = bt_sco->agc != agc;
+ bt_sco->agc = agc;
+ spin_unlock_irqrestore(&bt_sco->mixer_lock, flags);
+ return changed;
+ }
+ #endif
+
#define BT_SCO_CONTROLS (sizeof(snd_bt_sco_controls)/sizeof(snd_kcontrol_new_t))
static snd_kcontrol_new_t snd_bt_sco_controls[] = {
***************
*** 581,586 ****
--- 639,654 ----
.get = snd_bt_sco_loopback_get,
.put = snd_bt_sco_loopback_put,
}
+ #ifdef DYNAMIC_COMPRESSION
+ ,
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "AGC Switch",
+ .index = 0,
+ .info = snd_bt_sco_boolean_info,
+ .get = snd_bt_sco_agc_get,
+ .put = snd_bt_sco_agc_put,
+ }
+ #endif
};
int __init snd_card_bt_sco_new_mixer(snd_card_bt_sco_t * bt_sco)
***************
*** 790,795 ****
--- 858,874 ----
struct msghdr msg;
struct iovec iov;
sigset_t unblocked;
+ #if defined(DYNAMIC_COMPRESSION) || defined(AUTO_FIXUP_ENDIANNESS)
+ int i;
+ #endif
+ #ifdef DYNAMIC_COMPRESSION
+ static int factor=16;
+ static int maxvalsmoothed=0;
+ static int maxvalgrablen=GRABSAMPLES; /* adjust volume at most 4 times/second */
+ #endif
+ #ifdef AUTO_FIXUP_ENDIANNESS
+ static int swap=0;
+ #endif
lock_kernel();
***************
*** 839,844 ****
--- 918,1000 ----
len = sock_recvmsg(sock, &msg, BUF_SIZE, 0);
if (len > 0) {
+ #if defined (AUTO_FIXUP_ENDIANNESS) || defined (DYNAMIC_COMPRESSION)
+ int lostatcnt;
+ lostatcnt=0;
+
+ if (len&1) dprintk("odd len %d\n",len);
+ for(i=0;i<len-1;i+=2) {
+ short int j;
+ int k;
+
+ #ifdef AUTO_FIXUP_ENDIANNESS
+ if (swap) j=(buf[i]<<8)|buf[i+1];
+ else j=(buf[i+1]<<8)|buf[i];
+ #else
+ j=(buf[i+1]<<8)|buf[i];
+ #endif
+
+ #ifdef AUTO_FIXUP_ENDIANNESS
+ /* occasionally the Headset will loose a byte
+ * on startup. Thus swapping lo/hi.
+ * counting, if _all_ lo bytes (which are
+ * actually high bytes) are 0 or -1
+ * will detect this with a very high probability
+ */
+ if ((j&0xff)==0||(j&0xff)==0xff) {
+ lostatcnt++;
+ }
+ #endif
+ #ifdef DYNAMIC_COMPRESSION
+ /* scale the mic input - we do some kind
+ * of dynamics compression
+ */
+ k=((int)j*factor)/16;
+ /* clip overshoot. Better than just letting
+ * it wrap around. Immediately adjust factor.
+ */
+ if (k>0x7fff) {
+ k=0x7fff;
+ if (bt_sco->agc&&factor>COMPRESSION_MIN_16) factor--;
+ } else if (k<-0x8000) {
+ k=0x8000;
+ if (bt_sco->agc&&factor>COMPRESSION_MIN_16) factor--;
+ }
+ #else
+ k=j;
+ #endif
+ buf[i+1]=(k>>8)&0xff;
+ buf[i ]=k&0xff;
+ #ifdef DYNAMIC_COMPRESSION
+ /* find the highest absolute value in a
+ * GRABSAMPLES long interval.
+ */
+ if (k<0) k=-j;
+ if (k>maxvalsmoothed) maxvalsmoothed=k;
+ /* if the interval is over, recalculate
+ * the compression factor. Move it slowly.
+ */
+ if (maxvalgrablen--<=0) {
+ maxvalgrablen=GRABSAMPLES;
+ /* If the noise goes up over 1000, we stop
+ * pushing the software gain
+ */
+ if (maxvalsmoothed<1000&&factor<COMPRESSION_MAX_16) {
+ factor++;
+ // dprintk("Up to %d\n",factor);
+ }
+ if (!bt_sco->agc) factor=16;
+ maxvalsmoothed=0;
+ }
+ #endif
+ }
+ #ifdef AUTO_FIXUP_ENDIANNESS
+ if (lostatcnt==len/2&&len>32&&maxvalgrablen>GRABSAMPLES-len) {
+ dprintk("SWAP problem detected! Fixing.\n");
+ swap=!swap;
+ }
+ #endif
+ #endif /* any of them */
down(&bt_sco->capture_sem);
if (bt_sco->capture) {
snd_card_bt_sco_pcm_receive
next reply other threads:[~2005-08-27 19:31 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-08-27 19:31 Andreas Beck [this message]
2005-08-28 5:58 ` [Bluez-devel] skype_bt_hijacker released/updated Brad Midgley
2005-09-14 4:56 ` Brad Midgley
2005-09-15 11:57 ` AndreasBeckbecka-bzdvl
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20050827193154.GA7618@uni-duesseldorf.de \
--to=becka-bzdvl@bedatec.de \
--cc=bluez-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox