bluetooth headset doesn't work well(Motorola HS820)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I have a blue-tooth headset connected to Ubuntu 8.04. I've created
~/.asoundrc as below:

pcm.bluetooth {
  type bluetooth
  device 20:04:07:80:BC:89
  profile voice
}

ctl.bluetooth {
	type bluetooth
}

now I can use command `aplay -Dbluetooth -v 2.wav` to play sound to the
headset, but the sound is little bit wired. 

Playing WAVE '2.wav' : Signed 16 bit Little Endian, Rate 16000 Hz, Mono
Warning: rate is not accurate (requested = 16000Hz, got = 8000Hz)
         please, try the plug plugin (-Dplug:bluetooth)
Bluetooth Audio Device
Its setup is:
  stream       : PLAYBACK
  access       : RW_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 1
  rate         : 8000
  exact rate   : 8000 (8000/1)
  msbits       : 16
  buffer_size  : 4000
  period_size  : 1000
  period_time  : 125000
  tstamp_mode  : NONE
  period_step  : 1
  avail_min    : 1000
  period_event : 0
  start_threshold  : 4000
  stop_threshold   : 4000
  silence_threshold: 0
  silence_size : 0
  boundary     : 2097152000

So I input command according to the aplay's recommendation `aplay
-Dplug:bluetooth -v 2.wav`. The problem comes out.

 aplay -Dplug:bluetooth -v 2.wav 
Playing WAVE '2.wav' : Signed 16 bit Little Endian, Rate 16000 Hz, Mono
Plug PCM: Rate conversion PCM (8000, sformat=S16_LE)
Its setup is:
  stream       : PLAYBACK
  access       : RW_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 1
  rate         : 16000
  exact rate   : 16000 (16000/1)
  msbits       : 16
  buffer_size  : 8000
  period_size  : 2000
  period_time  : 125000
  tstamp_mode  : NONE
  period_step  : 1
  avail_min    : 2000
  period_event : 0
  start_threshold  : 8000
  stop_threshold   : 8000
  silence_threshold: 0
  silence_size : 0
  boundary     : 2097152000
Slave: Bluetooth Audio Device
Its setup is:
  stream       : PLAYBACK
  access       : MMAP_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 1
  rate         : 8000
  exact rate   : 8000 (8000/1)
  msbits       : 16
  buffer_size  : 4000
  period_size  : 1000
  period_time  : 125000
  tstamp_mode  : NONE
  period_step  : 1
  avail_min    : 1000
  period_event : 0
  start_threshold  : 4000
  stop_threshold   : 4000
  silence_threshold: 0
  silence_size : 0
  boundary     : 2097152000

It seems that ALSA plugs rate plugin. But I hear NOTHING from my headset
and aplay seems suspended. I turn on bluez debug flag and rebuild it. I
find the bluez suspending at 'bluetooth_playback_poll_descriptors'.


Sep  7 23:18:59 alex-laptop aplay: DEBUG: pcm_bluetooth.c 930
bluetooth_hsp_write: count=0 frames_to_read=24 
Sep  7 23:18:59 alex-laptop aplay: DEBUG: pcm_bluetooth.c 993
bluetooth_hsp_write: returning 24 
Sep  7 23:18:59 alex-laptop aplay: DEBUG: pcm_bluetooth.c 912
bluetooth_hsp_write: areas->step=16 areas->first=0 offset=0, size=1000
io->nonblock=0 io->hw_ptr=0 io->appl_ptr=0 stream.fd=8 link_mtu=48
data->count=0  
Sep  7 23:18:59 alex-laptop aplay: DEBUG: pcm_bluetooth.c 930
bluetooth_hsp_write: count=0 frames_to_read=24 
Sep  7 23:18:59 alex-laptop aplay: DEBUG: pcm_bluetooth.c 993
bluetooth_hsp_write: returning 24 
Sep  7 23:18:59 alex-laptop aplay: DEBUG: pcm_bluetooth.c 802
bluetooth_playback_poll_descriptors: Space =2 pfd[0].fd=5 pfd[1].fd=6 
Sep  7 23:19:01 alex-laptop audio[7979]: Received AT+VGS=11

Now I go deep into ALSA then I find ALSA suspending at:
int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout)
{
	struct pollfd *pfd;
	unsigned short *revents;
	int i, npfds, pollio, err, err_poll;
	npfds = snd_pcm_poll_descriptors_count(pcm);
	if (npfds <= 0 || npfds >= 16) {
		SNDERR("Invalid poll_fds %d\n", npfds);
		return -EIO;
	}
	pfd = alloca(sizeof(*pfd) * npfds);
	revents = alloca(sizeof(*revents) * npfds);
	syslog( LOG_INFO, "%s", __FUNCTION__ );	
	err = snd_pcm_poll_descriptors(pcm, pfd, npfds);
	if (err < 0)
		return err;
	if (err != npfds) {
		SNDMSG("invalid poll descriptors %d\n", err);
		return -EIO;
	}
	do {
		pollio = 0;
		err_poll = poll(pfd, npfds, timeout);    <-------------

It seems the bluez doesn't feed ALSA some signals. But why? I notice
'bluetooth_playback_start' haven't been invoked. Is it the point? Then I
keep tracing ALSA. I find in snd_pcm_rate_commit_area

		result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset,
slave_size);
		if (result < (snd_pcm_sframes_t)slave_size) {
			if (result < 0)
				return result;
			result = snd_pcm_rewind(rate->gen.slave, result);   <-----------
			if (result < 0)
				return result;
			return 0;
		} 


The snd_pcm_mmap_commit returns with 24 which indicates bluetooth SCO
link mtu(48bytes). And it causes snd_pcm_rewind being called after every
package sent by bluetooth SCO link. Look at this piece of code in
snd_pcm_write_areas:
		if (state == SND_PCM_STATE_PREPARED) {
			snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail;
			hw_avail += frames;
			/* some plugins might automatically start the stream */
			state = snd_pcm_state(pcm);

			
			if (state == SND_PCM_STATE_PREPARED &&
			    hw_avail >= (snd_pcm_sframes_t) pcm->start_threshold) {
				err = snd_pcm_start(pcm);
				if (err < 0)
					goto _end;
			}
		}

the 'avail' will be equal to pcm->buffer due to snd_pcm_rewind,
therefore the condition hw_avail>=pcm->start_threshold will not be
satisfied forever. That's why snd_pcm_start can't be called.



I don't know the mechanism of ALSA and I just assume ALSA wanna bluez
plugin sending whole period_size instead of only one 48bytes package. I
revise the bluez plugin:

#if 0 // this section is original bluez
	frame_size = areas->step / 8;
	if ((data->count + size * frame_size) <= data->link_mtu)
		frames_to_read = size;
	else
		frames_to_read = (data->link_mtu - data->count) / frame_size;

	DBG("count=%d frames_to_read=%lu", data->count, frames_to_read);

	/* Ready for more data */
	buff = (uint8_t *) areas->addr +
			(areas->first + areas->step * offset) / 8;
	memcpy(data->buffer + data->count, buff, frame_size * frames_to_read);

	/* Remember we have some frames in the pipe now */
	data->count += frames_to_read * frame_size;
	if (data->count != data->link_mtu) {
		ret = frames_to_read;
		goto done;
	}

	rsend = send(data->stream.fd, data->buffer, data->link_mtu,
			io->nonblock ? MSG_DONTWAIT : 0);
	if (rsend > 0) {
		/* Reset count pointer */
		data->count = 0;

		ret = frames_to_read;
	} else if (rsend < 0)
		ret = (errno == EPIPE) ? -EIO : -errno;
	else
		ret = -EIO;
#else		
	frame_size = areas->step / 8;

	buff = (uint8_t *) areas->addr +
			(areas->first + areas->step * offset) / 8;

	tobesent = frame_size*size;
	
	while( rsend<tobesent )
	{
		if( tobesent-rsend>data->link_mtu )
		sent = send(data->stream.fd, buff+counter*data->link_mtu,
data->link_mtu,
				io->nonblock ? MSG_DONTWAIT : 0);		
		else
		sent = send(data->stream.fd, buff+counter*data->link_mtu,
tobesent-rsend,
				io->nonblock ? MSG_DONTWAIT : 0);		

		if( sent > 0 )
		{
			if( sent != data->link_mtu && tobesent-rsend > data->link_mtu )
				DBG("got problem!");
			counter++;
			rsend+=sent;
		}
		else if (rsend < 0)
		{
			ret = (errno == EPIPE) ? -EIO : -errno;
			break;
		}
		else
		{
			ret = -EIO;
			break;
		}
	}
	ret = size;
#endif	



After this revision, the headset works but the performance isn't as good
as playing MONO 8000Hz wav directly to headset with 'aplay -Dbluetooth
1.wav'. Any hints would be appreciated.

Regards,
Galaha


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Alsa-user mailing list
Alsa-user@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-user

[Index of Archives]     [ALSA Devel]     [Linux Audio Users]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]

  Powered by Linux