From: Sergey Krivov <krivov@yahoo.com>
To: BlueZ development <bluez-devel@lists.sourceforge.net>
Subject: [Bluez-devel] python a2dp
Date: Tue, 14 Nov 2006 04:19:14 -0800 (PST) [thread overview]
Message-ID: <947020.38780.qm@web31012.mail.mud.yahoo.com> (raw)
In-Reply-To: <200611131424.06615.mhilzinger@linuxnewmedia.de>
[-- Attachment #1: Type: text/plain, Size: 472 bytes --]
Hi,
this is a partial realization of AVDTP, A2DP and AVRCP
profiles in python with simple example of a2dp-avrcp
server. it is probably far from a2dp alsa-plugin theme
since it is not written in C, but it might be useful
for prototype development. Anyway, have a look.
All the feedback is welcome.
____________________________________________________________________________________
Yahoo! Music Unlimited
Access over 1 million songs.
http://music.yahoo.com/unlimited
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 831489387-avdtp.py --]
[-- Type: text/x-python; name="avdtp.py", Size: 21091 bytes --]
#! /usr/bin/env python
"""
Partial realization of AVDTP, A2DP and AVRCP profiles
and simple A2DP-AVRCP server
* Copyright (C) 2006 Sergei Krivov <krivov@yahoo.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""
"""
install libsbc; check for /usr/lib/libsbc.so. http://sbc.sf.net
put this in your .asoundrc file
pcm.a2dpipe {
type plug
slave {
pcm "tee:default,'/tmp/a2dpipe', raw"
}
}
select alsa output pcm device a2dpipe
make pipe by: mkfifo /tmp/a2dpipe
start by python avdtp.py
stop by killing the process
A2DP server can work with many ACP given in the beginning.
dynamical management of ACP is restricted to a single ACP
to initiate connection with the server press PLAY button on headphones
server starts as soon as some sound appeared in the pipe.
server uses alsa timing, so some dropouts can be experienced if timing
in alsa and headphones is different.
"""
import ctypes
from ctypes import Structure,c_uint8,c_uint16,c_ulong,c_uint32,c_void_p
import bluetooth
import struct
import time
import sys
import array
import os
import threading
#//Signal ids
AVDTP_DISCOVER=1
AVDTP_GET_CAPABILITIES=2
AVDTP_SET_CONFIGURATION=3
AVDTP_GET_CONFIGURATION=4
AVDTP_RECONFIGURE=5
AVDTP_OPEN =6
AVDTP_START =7
AVDTP_CLOSE =8
AVDTP_SUSPEND =9
AVDTP_ABORT =10
AVDTP_SECURITY_CONTROL =11
MEDIA_TRANSPORT_CATEGORY =1
MEDIA_CODEC =7
SBC_MEDIA_CODEC_TYPE =0
AUDIO_MEDIA_TYPE =0
#//Packet types
PACKET_TYPE_SINGLE =0
PACKET_TYPE_START =1
PACKET_TYPE_CONTINUE =2
PACKET_TYPE_END =3
#//Message Types
MESSAGE_TYPE_COMMAND =0
MESSAGE_TYPE_ACCEPT =2
MESSAGE_TYPE_REJECT =3
MEDIA_PACKET_HEADER_LENGTH =14
MAX_ADDITIONAL_CODEC=4
deb=1
tran=0
class message_header_single(Structure):
_pack_=1
_fields_=[("message_type",c_uint8,2),("packet_type",c_uint8,2)\
,("transaction_label",c_uint8,4),("signal_id",c_uint8,6),("rfa0",c_uint8,2)]
class message_header_start(Structure):
_pack_=1
_fields_=[("message_type",c_uint8,2),("packet_type",c_uint8,2),("nsop",c_uint8,8)\
,("transaction_label",c_uint8,4),("signal_id",c_uint8,6),("rfa0",c_uint8,2)]
class message_header_continue(Structure):
_pack_=1
_fields_=[("message_type",c_uint8,2),("packet_type",c_uint8,2)\
,("transaction_label",c_uint8,4)]
class message_single(Structure):
_pack_=1
_fields_=[("header",message_header_single),("rfa0",c_uint8,2),("acp_seid",c_uint8,6)]
class sbc_codec_elements(Structure):
_pack_=1
_fields_=[("channel_mode",c_uint8,4),("frequency",c_uint8,4)\
,("allocation_method",c_uint8,2),("subbands",c_uint8,2)\
,("block_length",c_uint8,4),("min_bitpool",c_uint8,8),("max_bitpool",c_uint8,8)]
class acp_seid_info(Structure):
_pack_=1
_fields_=[("rfa0",c_uint8,1),("inuse",c_uint8,1),("acp_seid",c_uint8,6)\
,("rfa1",c_uint8,3),("tsep",c_uint8,1),("media_type",c_uint8,4)]
class sepd_resp(Structure):
_pack_=1
_fields_=[("header",message_header_single)]
for i in range(1+MAX_ADDITIONAL_CODEC):_fields_.append(("n%i" %(i),acp_seid_info))
class sepd_reject(Structure):
_pack_=1
_fields_=[("header",message_header_single),("error",c_uint8)]
class getcap_resp(Structure):
_pack_=1
_fields_=[("header",message_header_single)]
for s in ("serv_cat","serv_cap_len","cap_type","length","media_type"\
,"media_codec_type"): _fields_.append((s,c_uint8,8))
_fields_.append(("sbc_elements",sbc_codec_elements))
class set_sbc_req(Structure):
_pack_=1
_fields_=[("header",message_header_single),("rfa0",c_uint8,2)\
,("acp_seid",c_uint8,6),("rfa1",c_uint8,2),("int_seid",c_uint8,6)]
for s in ("serv_cap","serv_cap_len","cap_type","length","media_type"\
,"media_codec_type"): _fields_.append((s,c_uint8,8))
_fields_.append(("sbc_elements",sbc_codec_elements))
class set_sbc_resp(Structure):
_pack_=1
_fields_=[("header",message_header_single),("serv_cap",c_uint8,8),("acp_seid",c_uint8,8)]
class open_strm_resp(Structure):
_pack_=1
_fields_=[("header",message_header_single),("error",c_uint8,8)]
class start_strm_resp(Structure):
_pack_=1
_fields_=[("header",message_header_single),("rfa0",c_uint8,2),("acp_seid",c_uint8,6)\
,("error",c_uint8,8)]
def print_fields(st,gap=''):
print gap+str(st.__class__)+':'
for f in st._fields_:
a=st.__getattribute__(f[0])
try:
b=a.__getattribute__("_fields_")
print f[0]+":"
print_fields(a,gap+' ')
except: print gap+str(f[0]),a
def avdtp_connect(dst,psm=25):
sock=bluetooth.BluetoothSocket( bluetooth.L2CAP )
sock.bind(("",psm))
sock.connect((dst,psm))
if deb: print "connected to ",dst,psm
bluetooth.set_l2cap_mtu(sock,672)
return sock
def avdtp_disconnect(sock):
sock.close()
def init_command_single(req):
global tran
req.header.packet_type=PACKET_TYPE_SINGLE
req.header.message_type=MESSAGE_TYPE_COMMAND
req.header.transaction_label=tran
req.header.rfa0=0
tran=(tran+1) & 0xf
return req
def send_packet(sock,packet):
size=ctypes.sizeof(packet)
if deb>1:
print "sending packet",size,struct.unpack("%iB" %(size),packet)
print_fields(packet)
l=sock.send(packet)
if l!=size: raise IOError('transmission error')
def receive_response(sock,resp_class,resp_error_class=None):
data=sock.recv(1024)
size=ctypes.sizeof(resp_class)
if len(data)>size:
if deb>1:print "warning, possibly wrong responce class ",len(data),size
if len(data)<size:
if deb>1:print "warning, got partial responce, pad with zeros",len(data),size
dl=size-len(data)
l0=[0 for i in range(dl)]
data+=struct.pack("%iB" %(dl),*l0)
resp=ctypes.cast(data,ctypes.POINTER(resp_class))
resp=resp.contents
if deb>1:
print "received",struct.unpack("%iB" %(len(data)),data)
print_fields(resp)
return resp
def avdtp_get_capabilities(sock,seid):
cmd=message_single()
cmd=init_command_single(cmd)
cmd.header.signal_id=AVDTP_GET_CAPABILITIES
cmd.acp_seid=seid
send_packet(sock,cmd)
resp=receive_response(sock,getcap_resp)
return resp
def avdtp_discover(sock):
cmd=message_single()
cmd=init_command_single(cmd)
cmd.header.signal_id=AVDTP_DISCOVER
send_packet(sock,cmd)
resp=receive_response(sock,sepd_resp)
lseid=[]
for i in range(1+MAX_ADDITIONAL_CODEC):
sep=resp.__getattribute__("n%i" %(i))
seid=sep.acp_seid
if seid:lseid.append(seid) # take non zero seid
if deb:print "got %i seid" %(len(lseid))
lsep=[(avdtp_get_capabilities(sock,seid),seid) for seid in lseid]
return lsep
def avdtp_discover_rsp(sock):
global tran
cmd=receive_response(sock,message_single)
tran=cmd.header.transaction_label
rsp=sepd_resp()
rsp=init_command_single(rsp)
rsp.header.message_type=MESSAGE_TYPE_ACCEPT
rsp.header.signal_id=AVDTP_DISCOVER
sbc=rsp.n0
sbc.acp_seid=1
sbc.inuse=0
sbc.tsep=1
sbc.media_type=SBC_MEDIA_CODEC_TYPE
send_packet(sock,rsp)
def set_sbc_configuration(sock,capb_resp,seid,sbc_codec):
cmd=set_sbc_req()
cmd=init_command_single(cmd)
cmd.header.signal_id=AVDTP_SET_CONFIGURATION
cmd.serv_cap=MEDIA_TRANSPORT_CATEGORY
cmd.acp_seid=seid
cmd.int_seid=1
cmd.cap_type=MEDIA_CODEC
cmd.length=6
cmd.media_type=AUDIO_MEDIA_TYPE
cmd.media_codec_type=SBC_MEDIA_CODEC_TYPE
cmd.sbc_elements=capb_resp.sbc_elements
cmd.sbc_elements.allocation_method=2
# values of parameters in sbc routine and here are different
for par,vals in sbc_codec.conf_dict.items():
codec_att=sbc_codec.par.__getattribute__(par)
code=vals[codec_att]
resp_att=capb_resp.sbc_elements.__getattribute__(par)
if resp_att & code:
if deb: print 'setting %s=%i, %i' %(par,code,codec_att)
cmd.sbc_elements.__setattr__(par,code)
else:
if deb: print 'can not set %s=%i, %i' %(par,code,codec_att)
send_packet(sock,cmd)
resp=receive_response(sock,set_sbc_resp)
if resp.header.message_type!=MESSAGE_TYPE_ACCEPT:
raise IOError('Can not set SBC codec parameters')
if deb: print "Successfully set SBC codec parameters"
return seid,sbc_codec
def avdtp_set_configuration(sock,lsep,codecs):
""" select codec from available codecs
and sets codec configuration
just SBC codec is implemented
return seid, codec
"""
lsbc=[(resp,seid) for resp,seid in lsep if \
resp.header.message_type!=MESSAGE_TYPE_REJECT and\
resp.media_codec_type==SBC_MEDIA_CODEC_TYPE and\
resp.media_type==AUDIO_MEDIA_TYPE]
if not lsbc: raise IOError('ACP site dose not have SBC codec')
if len(lsbc)>1 and deb: print 'ACP site has more then one SBC codec, take first' # if ever possible
resp,seid=lsbc[0]
if deb: print "seid=",seid
return set_sbc_configuration(sock,resp,seid,codecs[SBC_MEDIA_CODEC_TYPE])
def avdtp_open(dst,sock,seid):
"""open the audio stream"""
cmd=message_single()
cmd=init_command_single(cmd)
cmd.header.signal_id=AVDTP_OPEN
cmd.acp_seid=seid
send_packet(sock,cmd)
resp=receive_response(sock,open_strm_resp)
if resp.error: raise IOError('Can not open stream')
if deb: print "opened stream"
return avdtp_connect(dst,25)
def avdtp_start(sock,seid):
cmd=message_single()
cmd=init_command_single(cmd)
cmd.header.signal_id=AVDTP_START
cmd.acp_seid=seid
send_packet(sock,cmd)
resp=receive_response(sock,start_strm_resp)
if resp.error: raise IOError('Can not start stream')
if deb: print "started stream"
def avdtp_suspend(sock,seid):
cmd=message_single()
cmd=init_command_single(cmd)
cmd.header.signal_id=AVDTP_SUSPEND
cmd.acp_seid=seid
send_packet(sock,cmd)
resp=receive_response(sock,start_strm_resp)
if resp.error: raise IOError('Can not stop stream')
if deb: print "suspended stream"
def avdtp_close(sock,seid):
cmd=message_single()
cmd=init_command_single(cmd)
cmd.header.signal_id=AVDTP_CLOSE
cmd.acp_seid=seid
send_packet(sock,cmd)
resp=receive_response(sock,open_strm_resp)
if resp.error: raise IOError('Can not close stream')
if deb: print "closed steam"
class media_packet_header(Structure):
_pack_=1
_fields_=[("cc",c_uint8,4),("x",c_uint8,1),("p",c_uint8,1),("v",c_uint8,2)\
,("pt",c_uint8,7),("m",c_uint8,1)\
,("sequence_number",c_uint16),("time_stamp",c_uint32),("ssrc",c_uint32)]
class media_payload_header(Structure):
_pack_=1
_fields_=[("frame_count",c_uint8,4),("rfa01",c_uint8,1),("is_last_fragment",c_uint8,1)\
,("is_first_fragment",c_uint8,1),("is_fragmented",c_uint8,1)]
def media_packet(data,timestamp,frame_count,seq_number):
mtu=672
if len(data)+ctypes.sizeof(media_payload_header)+ctypes.sizeof(media_packet_header)>mtu:
raise ValueError('Media packet size >mtu')
class _media_packet(Structure):
_pack_=1
_fields_=[("media_packet_header",media_packet_header)\
,("media_payload_header",media_payload_header)\
,("data",c_uint8*ctypes.sizeof(data))]
packet=_media_packet()
packet.media_packet_header.v=2
packet.media_packet_header.pt=1
packet.media_packet_header.sequence_number=seq_number
packet.media_packet_header.time_stamp=timestamp
packet.media_packet_header.ssrc=1
packet.media_payload_header.frame_count=frame_count
packet.media_payload_header.is_fragmented=0
packet.media_payload_header.rfa=0
packet.data=data
return packet
##### AVCTP & AVRCP ##################################################################################
# Message types
AVCTP_COMMAND_FRAME=0
AVCTP_RESPONSE_FRAME=1
CMD_PASSTHROUGH=0
CMD_ACCEPTED=9
PLAY_OP=68 #0x44
STOP_OP=69 #0x45
PAUSE_OP=70 #0x46
NEXT_OP=75 #0x4b
PREV_OP=76 #0x4c
class avctp_header(Structure):
_pack_=1
_fields_=[("ipid",c_uint8,1),("cr",c_uint8,1),("packet_type",c_uint8,2),\
("transaction_label",c_uint8,4),("pid",c_uint16)]
class avctp_frame(Structure):
_pack_=1
_fields_=[("header",avctp_header),("ctype",c_uint8,4),("zeros",c_uint8,4),\
("subunit_id",c_uint8,3),("subunit_type",c_uint8,5),("opcode",c_uint8,8),\
("operand0",c_uint8,8),("operand1",c_uint8,8)]
def avrcp_accept_connection():
sock=bluetooth.BluetoothSocket( bluetooth.L2CAP )
port=23
sock.bind(("",port))
sock.listen(1)
client_sock,address = sock.accept()
print "Accepted connection from ",address
return client_sock
def avrcp_receive_commands(sock,callback):
while True:
data=sock.recv(1024)
if len(data)==0:break
cmd=ctypes.cast(data,ctypes.POINTER(avctp_frame))
cmd=cmd.contents
if cmd.header.packet_type!=PACKET_TYPE_SINGLE: raise ValueError('packet type != PACKET_TYPE_SINGLE')
if cmd.ctype==CMD_PASSTHROUGH: callback(cmd.operand0)
cmd.header.ipid=0 # use the same packet for responce
cmd.header.cr=AVCTP_RESPONSE_FRAME
cmd.header.packet_type=PACKET_TYPE_SINGLE
cmd.ctype=CMD_ACCEPTED
send_packet(sock,cmd)
sock.close()
#####SBC codec, libscb #################################################################################
class sbc_struct(Structure):
_fields_=[("flags",c_ulong),("frequency",c_uint32),("channel_mode",c_uint32),("joint",c_uint32)
,('block_length',c_uint32),('subbands',c_uint32),('bitpool',c_uint32)\
,('data',c_void_p),('size',c_uint32),('len',c_uint32)\
,('duration',c_ulong), ('priv',c_void_p)]
class sbc:
def __init__(self,*arg,**kwd):
self.par=sbc_struct()
self.libsbc=ctypes.CDLL('libsbc.so')
err=self.libsbc.sbc_init(ctypes.byref(self.par),c_ulong(1))
if err: print 'error initializing sbc coder',err
self.configure(*arg,**kwd)
def configure(self,frequency=44100,channels=2):
self.par.subbands=8
self.par.block_length=16
self.par.bitpool=32
self.par.frequency=frequency
self.par.channel_mode=channels
self.conf_dict={}
self.conf_dict['frequency']={48000:1,44100:2,32000:4,16000:8}
self.conf_dict['subbands']={8:1,4:2}
self.conf_dict['block_length']={16:1,12:2,8:4,4:8}
self.conf_dict['channel_mode']={2:2,1:1}
def encode(self,data):
l=self.libsbc.sbc_encode(ctypes.byref(self.par),data,len(data))
return l,self.par.data,self.par.len,self.par.duration
def fin(self):
self.libsbc.sbc_finish(ctypes.byref(self.par))
##### useful functions ################################################################################
class timer:
def __init__(self):
self.time=time.time()
def dt_has_elapsed(self,dt):
return (time.time()-self.time)*1000000>dt-5000
def dt(self):
return (time.time()-self.time)*1000000
def start(self):
self.time=time.time()
def stream_pcm_pipe(f,lacp,commands,extimer=None):
""" streaming audio by reading pcm from a pipe or file.
if extimer==None relays on pipe's timer, all packets are
send as soon as read from the pipe.
if extimer!=None the given timer is used to send packets.
"""
packet_header_size=13
min_encoding_size=512
mtu=672
lpackets=[]
seq_number=0
frame_count=0
timestamp=0
elapsedtime=0
buf=(c_uint8*mtu)()
lenbuf=0
data=""
if extimer!=None:timer0=extimer()
if deb: timer1=timer()
timer2=timer()
while True:
time.sleep(0.00001) # some sleep
rdata=f.read(1000) # read
if 'quit' in commands: break
if len(lacp)==0 or 'pause' in commands:
if extimer!=None:timer0.start()
if deb: timer1.start()
timestamp=0
frame_count=0
lpackets=[]
continue # no streams: just read data from pipe
if len(rdata)>0:#change endiannes
adata=array.array('H')
adata.fromstring(rdata)
adata.byteswap()
rdata=adata.tostring()
data+=rdata
while len(data)>min_encoding_size: #encode
l,pendata,lendata,duration=lacp[0].codec.encode(data)
data=data[l:]
if lenbuf+lendata+packet_header_size>mtu: #enough for packet
packetdata=(c_uint8*lenbuf)()
ctypes.memmove(packetdata,buf,lenbuf)
lpackets.append(media_packet(packetdata,timestamp,frame_count,seq_number))
timestamp=elapsedtime # for following packet
frame_count=0
seq_number+=1
if deb and seq_number%1000==0:
print "sent 1000 packets, elapsed time is %g ms" %(timer1.dt())
timer1.start()
buf=(c_uint8*mtu)()
lenbuf=0
ctypes.memmove(ctypes.addressof(buf)+lenbuf,pendata,lendata)
lenbuf+=lendata
frame_count+=1
elapsedtime+=duration
while lpackets: #send packets while there are any
packet=lpackets[0]
if extimer==None or timer0.dt_has_elapsed(packet.timestamp):
for acp in lacp:
try:send_packet(acp.stream,packet)
except bluetooth.BluetoothError: # close and remove dead ACP
if deb: print "stream error ",acp.addr
acp.stream.close()
acp.sock.close()
if deb: print "close stream ",acp.addr
lacp.remove(acp)
if deb:
print "remove stream, number of streams left",len(lacp)
del lpackets[0]
class acp: # container class to keep information about ACP
def __init__(self,addr):
self.addr=addr
self.stream,self.sock,self.seid,self.codec=connect(addr)
def connect(addr,psm=25):
"""connects to a2dp sink on address addr """
sbc_codec=sbc(44100,2) # initialize sbc codec
codecs={SBC_MEDIA_CODEC_TYPE:sbc_codec} # list the available codecs
sock=avdtp_connect(addr,psm) # connect to the ACP side
lsep=avdtp_discover(sock) # discover set of codec on ACP side
seid,codec=avdtp_set_configuration(sock,lsep,codecs) # select and set codec parameters
stream=avdtp_open(addr,sock,seid) # open audio stream
avdtp_start(sock,seid) #start audio stream
return stream,sock,seid,codec
def avdtp_discover_abort(sock):
cmd=receive_response(sock,message_single)
cmd.header.message_type=MESSAGE_TYPE_COMMAND
cmd.header.signal_id=AVDTP_ABORT
send_packet(sock,cmd)
def advertise_a2dp():
"""advertise a2dp source"""
server_sock=bluetooth.BluetoothSocket( bluetooth.L2CAP )
port=25
server_sock.bind(("",port))
server_sock.listen(1)
print "listening on port %d" % port
uuid = "110a"
profile=[bluetooth.ADVANCED_AUDIO_PROFILE]
classes=[bluetooth.AUDIO_SOURCE_CLASS,]
bluetooth.advertise_service( server_sock, "Audio Source", service_id = "", service_classes = [], \
profiles = [], provider = "", description = "")
client_sock,(address,port) = server_sock.accept()
print "Accepted connection from ",address
return client_sock,address,port
##### simple multiple client A2DP & AVRCP streaming server ##########################################
class a2dp_streamer ( threading.Thread ):
def __init__ ( self, pipename, lacp,commands,timer=None):
self.pipename=pipename
self.lacp=lacp # list of ACP
self.timer=timer
self.commands=commands
threading.Thread.__init__ ( self )
def run (self):
stream_pcm_pipe(self.pipename,self.lacp,self.commands,self.timer)
def callback_xmms(com):
if deb: print 'received command code',com
if com==PLAY_OP: os.popen('xmms --play')
elif com==STOP_OP: os.popen('xmms --stop')
elif com==PAUSE_OP:os.popen('xmms --pause')
elif com==NEXT_OP: os.popen('xmms --fwd')
elif com==PREV_OP: os.popen('xmms --rew')
else:
if deb: print "unknown command code",com
return 1
class avrcp_server ( threading.Thread ):
def __init__ ( self):
threading.Thread.__init__ ( self )
def run ( self ):
while True:
sock=avrcp_accept_connection()
avrcp_receive_commands(sock,callback_xmms)
if __name__=="__main__":
"""instructions are in the beginning of the file"""
deb=1
control=avrcp_server() # start avrcp
control.start() #
lacp=[]
# addr="00:0D:44:2A:A1:4C" # can start with online acp
# lacp.append(acp(addr)) #
# addr="00:07:A4:00:17:FD" # works with many acp simultaneously
# lacp.append(acp(addr)) # but only if they are discovered at the beginning
commands=[]
f=open('/tmp/a2dpipe','rb',0)
while True:
# dynamically manages new ACP
# to initiate connection press PLAY button on headphones
# works only with single ACP
# discovery of second ACP destroys sound completely.
# maybe bluetooth is not thread safe?
streamer=a2dp_streamer(f,lacp,commands)
streamer.start()
try:
sock2,addr,port=advertise_a2dp()
commands.append('quit') #stop streamer
streamer.join()
avdtp_discover_abort(sock2)
sock2.close()
lacp.append(acp(addr))
except bluetooth.BluetoothError,what: print 'BluetoothError: ', what
commands.remove('quit')
print 'number of ACP', len(lacp)
[-- Attachment #3: Type: text/plain, Size: 373 bytes --]
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
[-- Attachment #4: Type: text/plain, Size: 164 bytes --]
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
next prev parent reply other threads:[~2006-11-14 12:19 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-11-09 10:02 [Bluez-devel] Quality of a2dp sound Marcel Hilzinger
2006-11-09 10:42 ` Adrian Glaubitz
2006-11-09 10:07 ` Reiner Klenk
2006-11-10 8:01 ` Marcel Hilzinger
2006-11-10 8:41 ` [Bluez-devel] RE : " Frederic Dalleau
2006-11-10 9:46 ` Marcel Hilzinger
2006-11-10 9:59 ` Mayank BATRA
2006-11-10 10:04 ` Marcel Hilzinger
2006-11-11 8:21 ` Reiner Klenk
2006-11-12 18:38 ` Marcel Hilzinger
2006-11-12 20:31 ` Brad Midgley
2006-11-13 9:39 ` Frédéric DALLEAU
2006-11-13 18:26 ` Reiner Klenk
2006-11-13 18:37 ` Reiner Klenk
2006-11-10 10:06 ` Marcel Hilzinger
2006-11-10 10:17 ` Marcel Hilzinger
2006-11-13 13:24 ` Marcel Hilzinger
2006-11-14 12:19 ` Sergey Krivov [this message]
2006-11-14 14:40 ` [Bluez-devel] python a2dp Frédéric DALLEAU
2006-11-14 15:25 ` Sergey Krivov
2006-11-14 15:34 ` Frédéric DALLEAU
2006-11-14 15:40 ` Sergey Krivov
2006-11-13 15:32 ` [Bluez-devel] Quality of a2dp sound Brad Midgley
2006-11-09 17:43 ` Marcel Hilzinger
2006-11-09 19:31 ` Thomas Kear
2006-11-10 8:24 ` [Bluez-devel] RE : " Frederic Dalleau
2006-11-10 13:50 ` Adrian Glaubitz
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=947020.38780.qm@web31012.mail.mud.yahoo.com \
--to=krivov@yahoo.com \
--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