Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Gustavo da Silva Serra <gustavo.serra@tet.com.br>
To: Takashi Iwai <tiwai@suse.de>
Cc: alsa-devel@alsa-project.org
Subject: Re: Still have choppy audio using 1.0.17
Date: Tue, 01 Jul 2008 15:28:39 -0300	[thread overview]
Message-ID: <486A7757.4060907@tet.com.br> (raw)
In-Reply-To: <s5hprq5qz2t.wl%tiwai@suse.de>

[-- Attachment #1: Type: text/plain, Size: 1488 bytes --]

I have tried to implement the solution you proposed. However I still get 
choppy audio, just like before, otherwise the sound is clear.

Basically I moved the timer to the cable struct, and updated the timer 
function to update both playback and capture.
I am sending the code attached so you can see if I implemented what you 
suggested. The code is not very clean, nor completely functional, as I 
never programmed to kernel before, and might cause kernel panic when 
closing a stream.

Any other suggestions?
Thanks for the help and the attention.

Takashi Iwai escreveu:
> At Wed, 25 Jun 2008 08:24:33 -0300,
> Gustavo da Silva Serra wrote:
>   
>> If I keep the difference between the playback and capture pointers at 
>> one period, no choppy audio occurs. If the difference is 0, 2 or 5 
>> periods for example, choppy audio will always occur. Any ideas why?
>>     
>
> Through a quick look at the code, it's likely the problem of the
> timing of timer handlers for playback/capture streams.  In the current
> code, the timer handlers are invoked individually.
>
> One possible fix would be to force to synchronize the updates of both
> directions instead of individual timers.  That is, share the same
> timer for the connected streams so that the update order is
> guaranteed.
>
>
> Just my $0.02.
>
> Takashi
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[-- Attachment #2: aloop-kernel.c --]
[-- Type: text/plain, Size: 16887 bytes --]

/*
 *  Loopback soundcard
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
 *
 *   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
 *
 */

#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/initval.h>

MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("A loopback soundcard");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");

#define MAX_PCM_SUBSTREAMS	8

static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};

module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for loopback soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable this loopback soundcard.");
module_param_array(pcm_substreams, int, NULL, 0444);
MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");

struct snd_card_loopback_pcm;

typedef struct snd_card_loopback_cable {
	struct snd_card_loopback_pcm *playback;
	struct snd_card_loopback_pcm *capture;
	struct snd_dma_buffer *dma_buffer;
	struct snd_pcm_hardware hw;
	struct timer_list timer;
	spinlock_t lock;
	int playback_valid;
	int capture_valid;
	int playback_running;
	int capture_running;
	int playback_busy;
	int capture_busy;
} snd_card_loopback_cable_t;

typedef struct snd_card_loopback {
	struct snd_card *card;
	struct snd_card_loopback_cable cables[MAX_PCM_SUBSTREAMS][2];
} snd_card_loopback_t;

typedef struct snd_card_loopback_pcm {
	unsigned int pcm_buffer_size;
	unsigned int pcm_period_size;
	unsigned int pcm_bps;		/* bytes per second */
	unsigned int pcm_irq_pos;	/* IRQ position */
	unsigned int pcm_buf_pos;	/* position in buffer */
	struct snd_pcm_substream *substream;
	struct snd_card_loopback_cable *cable;
} snd_card_loopback_pcm_t;

static struct snd_card *snd_loopback_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
static DECLARE_MUTEX(gl_sem);

static void snd_card_loopback_timer_start(snd_card_loopback_cable_t* cable)
{
	printk("%s: initiated\n", __FUNCTION__);
	cable->timer.expires = 1 + jiffies;
	add_timer(&cable->timer);
}

static void snd_card_loopback_timer_stop(snd_card_loopback_cable_t* cable)
{
	printk("%s: stopped\n", __FUNCTION__);
	del_timer(&cable->timer);
}

static int snd_card_loopback_playback_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_card_loopback_pcm_t *dpcm = runtime->private_data;

	if (cmd == SNDRV_PCM_TRIGGER_START) {
		printk("%s: start\n", __FUNCTION__);
		dpcm->cable->playback_running = 1;
		if (!dpcm->cable->capture_running) {
			snd_card_loopback_timer_start(dpcm->cable);
		}
	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
		printk("%s: stop\n", __FUNCTION__);
		dpcm->cable->playback_running = 0;
		if (!dpcm->cable->capture_running) {
			snd_card_loopback_timer_stop(dpcm->cable);
			snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
				bytes_to_samples(runtime, runtime->dma_bytes));
		}
	} else {
		return -EINVAL;
	}
	return 0;
}

static int snd_card_loopback_capture_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_card_loopback_pcm_t *dpcm = runtime->private_data;

	if (cmd == SNDRV_PCM_TRIGGER_START) {
		printk("%s: start\n", __FUNCTION__);
		dpcm->cable->capture_running = 1;
		if (!dpcm->cable->playback_running) {
			snd_card_loopback_timer_start(dpcm->cable);
		}
	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
		printk("%s: stop\n", __FUNCTION__);
		dpcm->cable->capture_running = 0;
		if (!dpcm->cable->playback_running) {
			snd_card_loopback_timer_stop(dpcm->cable);
		}
	} else {
		return -EINVAL;
	}
	return 0;
}

static int snd_card_loopback_prepare(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_card_loopback_pcm_t *dpcm = runtime->private_data;
	snd_card_loopback_cable_t *cable = dpcm->cable;
	unsigned int bps;

	printk("%s\n", __FUNCTION__);

	bps = runtime->rate * runtime->channels;
	bps *= snd_pcm_format_width(runtime->format);
	bps /= 8;
	if (bps <= 0)
		return -EINVAL;
	dpcm->pcm_bps = bps;
	dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
	dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
	dpcm->pcm_irq_pos = 0;
	dpcm->pcm_buf_pos = 0;

	cable->hw.formats = (1ULL << runtime->format);
	cable->hw.rate_min = runtime->rate;
	cable->hw.rate_max = runtime->rate;
	cable->hw.channels_min = runtime->channels;
	cable->hw.channels_max = runtime->channels;
	cable->hw.buffer_bytes_max = frames_to_bytes(runtime, runtime->buffer_size);
	cable->hw.period_bytes_min = frames_to_bytes(runtime, runtime->period_size);
	cable->hw.period_bytes_max = frames_to_bytes(runtime, runtime->period_size);
	cable->hw.periods_min = runtime->periods;
	cable->hw.periods_max = runtime->periods;

	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
		snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
				bytes_to_samples(runtime, runtime->dma_bytes));
		cable->playback_valid = 1;
	} else {
		if (!cable->playback_running) {
			snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
					bytes_to_samples(runtime, runtime->dma_bytes));
		}
		cable->capture_valid = 1;
	}

	return 0;
}

static void snd_card_loopback_timer_function(unsigned long data)
{
	snd_card_loopback_cable_t* cable = (snd_card_loopback_cable_t*)data;
	snd_card_loopback_pcm_t *dpcm = NULL;

	down_interruptible(&gl_sem);
	dpcm = cable->playback;
	if (dpcm) {
		spin_lock_irq(&cable->lock);
		dpcm->pcm_irq_pos += dpcm->pcm_bps;
		dpcm->pcm_buf_pos += dpcm->pcm_bps;
		dpcm->pcm_buf_pos %= dpcm->pcm_buffer_size * HZ;
		if (dpcm->pcm_irq_pos >= dpcm->pcm_period_size * HZ) {
			dpcm->pcm_irq_pos %= dpcm->pcm_period_size * HZ;
			spin_unlock_irq(&cable->lock);
			snd_pcm_period_elapsed(dpcm->substream);
		} else {
			spin_unlock_irq(&cable->lock);
		}
	}

	dpcm = cable->capture;
	if (dpcm) {
		spin_lock_irq(&cable->lock);
		dpcm->pcm_irq_pos += dpcm->pcm_bps;
		dpcm->pcm_buf_pos += dpcm->pcm_bps;
		dpcm->pcm_buf_pos %= dpcm->pcm_buffer_size * HZ;
		if (dpcm->pcm_irq_pos >= dpcm->pcm_period_size * HZ) {
			dpcm->pcm_irq_pos %= dpcm->pcm_period_size * HZ;
			spin_unlock_irq(&cable->lock);
			snd_pcm_period_elapsed(dpcm->substream);
		} else {
			spin_unlock_irq(&cable->lock);
		}
	}

	up(&gl_sem);
	cable->timer.expires = 1 + jiffies;
	add_timer(&cable->timer);

}

static snd_pcm_uframes_t snd_card_loopback_pointer(struct snd_pcm_substream *substream)
{
	snd_card_loopback_pcm_t *dpcm = substream->runtime->private_data;

	printk("%s: %s = %lu\n", __FUNCTION__, (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", bytes_to_frames(substream->runtime, dpcm->pcm_buf_pos / HZ));

	return bytes_to_frames(substream->runtime, dpcm->pcm_buf_pos / HZ);
}

static struct snd_pcm_hardware snd_card_loopback_info =
{
	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
				 SNDRV_PCM_INFO_MMAP_VALID),
	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
				 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT_LE),
	.rates =		(SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000),
	.rate_min =		8000,
	.rate_max =		192000,
	.channels_min =		1,
	.channels_max =		32,
	.buffer_bytes_max =	64 * 1024,
	.period_bytes_min =	64,
	.period_bytes_max =	64 * 1024,
	.periods_min =		1,
	.periods_max =		1024,
	.fifo_size =		0,
};

static void snd_card_loopback_runtime_free(struct snd_pcm_runtime *runtime)
{
	snd_card_loopback_pcm_t *dpcm = runtime->private_data;

	printk("%s: freeing pointer %p\n", __FUNCTION__, dpcm);

	kfree(dpcm);

	printk("%s: END\n", __FUNCTION__);
}

static int snd_card_loopback_hw_params(struct snd_pcm_substream *substream,
				    struct snd_pcm_hw_params *hw_params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_card_loopback_pcm_t *dpcm = runtime->private_data;
	struct snd_dma_buffer *dmab = NULL;

	printk("%s\n", __FUNCTION__);

	if (NULL == dpcm->cable->dma_buffer) {
		dmab = kzalloc(sizeof(*dmab), GFP_KERNEL);
		if (NULL == dmab)
			return -ENOMEM;

		if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_CONTINUOUS,
					snd_dma_continuous_data(GFP_KERNEL),
					params_buffer_bytes(hw_params),
					dmab) < 0) {
			kfree(dmab);
			return -ENOMEM;
		}
		dpcm->cable->dma_buffer = dmab;
	}
	snd_pcm_set_runtime_buffer(substream, dpcm->cable->dma_buffer);

	printk("%s: END\n", __FUNCTION__);
	return 0;
}

static int snd_card_loopback_hw_free(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_card_loopback_pcm_t *dpcm = runtime->private_data;
	snd_card_loopback_cable_t *cable = dpcm->cable;

	// TODO: Should we free timer?
	printk("%s\n", __FUNCTION__);
	snd_pcm_set_runtime_buffer(substream, NULL);

	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
		if (cable->capture_busy)
			return 0;
	} else {
		if (cable->playback_busy)
			return 0;
	}

	if (NULL == cable->dma_buffer)
		return 0;

	snd_dma_free_pages(cable->dma_buffer);
	kfree(cable->dma_buffer);
	cable->dma_buffer = NULL;
	return 0;
}

static int snd_card_loopback_open(struct snd_pcm_substream *substream)
{
	int half;
	snd_card_loopback_pcm_t *dpcm;
	struct snd_card_loopback *loopback = substream->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_card_loopback_cable_t* cable;

	printk("%s\n", __FUNCTION__);

	if (0 == substream->pcm->device) {
		if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream)
			half = 1;
		else
			half = 0;
	} else {
		if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream)
			half = 0;
		else
			half = 1;
	}
	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
		printk("%s: Opening PLAYBACK device\n", __FUNCTION__);
		if (loopback->cables[substream->number][half].playback_busy)
			return -EBUSY;
	} else {
		printk("%s: Opening CAPTURE device\n", __FUNCTION__);
		if (loopback->cables[substream->number][half].capture_busy)
			return -EBUSY;
	}

	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
	if (dpcm == NULL)
		return -ENOMEM;

	dpcm->substream = substream;
	dpcm->cable = &loopback->cables[substream->number][half];
	runtime->private_data = dpcm;
	runtime->private_free = snd_card_loopback_runtime_free;
	runtime->hw = snd_card_loopback_info;

	cable = dpcm->cable;
	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
		cable->playback = dpcm;
	}
	else {
		cable->capture = dpcm;
	}

	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
		dpcm->cable->playback_valid = 0;
		dpcm->cable->playback_running = 0;
		dpcm->cable->playback_busy = 1;
		if (dpcm->cable->capture_valid)
			runtime->hw = dpcm->cable->hw;
		else
			dpcm->cable->hw = snd_card_loopback_info;
	} else {
		dpcm->cable->capture_valid = 0;
		dpcm->cable->capture_running = 0;
		dpcm->cable->capture_busy = 1;
		if (dpcm->cable->playback_valid)
			runtime->hw = dpcm->cable->hw;
		else
			dpcm->cable->hw = snd_card_loopback_info;
	}
	printk("%s: END\n", __FUNCTION__);

	return 0;
}

static int snd_card_loopback_close(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_card_loopback_pcm_t *dpcm = runtime->private_data;

	down_interruptible(&gl_sem);

	printk("%s\n", __FUNCTION__);

	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
		printk("%s: Closing PLAYBACK device\n", __FUNCTION__);
		dpcm->cable->playback_valid = 0;
		dpcm->cable->playback_running = 0;
		dpcm->cable->playback_busy = 0;
		dpcm->cable->playback = NULL;
	} else {
		printk("%s: Closing CAPTURE device\n", __FUNCTION__);
		dpcm->cable->capture_valid = 0;
		dpcm->cable->capture_running = 0;
		dpcm->cable->capture_busy = 0;
		dpcm->cable->capture = NULL;
	}

	printk("%s: END\n", __FUNCTION__);

	up(&gl_sem);
	return 0;
}

static struct snd_pcm_ops snd_card_loopback_playback_ops = {
	.open =			snd_card_loopback_open,
	.close =		snd_card_loopback_close,
	.ioctl =		snd_pcm_lib_ioctl,
	.hw_params =	snd_card_loopback_hw_params,
	.hw_free =		snd_card_loopback_hw_free,
	.prepare =		snd_card_loopback_prepare,
	.trigger =		snd_card_loopback_playback_trigger,
	.pointer =		snd_card_loopback_pointer,
};

static struct snd_pcm_ops snd_card_loopback_capture_ops = {
	.open =			snd_card_loopback_open,
	.close =		snd_card_loopback_close,
	.ioctl =		snd_pcm_lib_ioctl,
	.hw_params =	snd_card_loopback_hw_params,
	.hw_free =		snd_card_loopback_hw_free,
	.prepare =		snd_card_loopback_prepare,
	.trigger =		snd_card_loopback_capture_trigger,
	.pointer =		snd_card_loopback_pointer,
};

static int __init snd_card_loopback_pcm(snd_card_loopback_t *loopback, int device, int substreams)
{
	struct snd_pcm *pcm;
	int err;

	printk("%s\n", __FUNCTION__);

	if ((err = snd_pcm_new(loopback->card, "Loopback PCM", device, substreams, substreams, &pcm)) < 0)
		return err;
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_loopback_playback_ops);
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_loopback_capture_ops);

	pcm->private_data = loopback;
	pcm->info_flags = 0;
	strcpy(pcm->name, "Loopback PCM");
	return 0;
}

static int __init snd_card_loopback_new_mixer(snd_card_loopback_t *loopback)
{
	struct snd_card *card = loopback->card;

	printk("%s\n", __FUNCTION__);

	snd_assert(loopback != NULL, return -EINVAL);
	strcpy(card->mixername, "Loopback Mixer");
	return 0;
}

static int __init snd_card_loopback_probe(int dev)
{
	struct snd_card *card;
	struct snd_card_loopback *loopback;
	struct snd_card_loopback_cable *cable;
	int subdev, half, err;

	printk("%s\n", __FUNCTION__);

	if (!enable[dev])
		return -ENODEV;
	card = snd_card_new(index[dev], id[dev], THIS_MODULE,
			    sizeof(struct snd_card_loopback));
	if (card == NULL)
		return -ENOMEM;
	loopback = (struct snd_card_loopback *)card->private_data;

	if (pcm_substreams[dev] < 1)
		pcm_substreams[dev] = 1;
	if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
		pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;

	for (subdev = 0; subdev < pcm_substreams[dev]; subdev++) {
		for (half = 0; half < 2; half++) {
			cable = &loopback->cables[subdev][half];
			cable->playback = NULL;
			cable->capture = NULL;
			cable->dma_buffer = NULL;
			cable->playback_valid = 0;
			cable->capture_valid = 0;
			cable->playback_running = 0;
			cable->capture_running = 0;
			cable->playback_busy = 0;
			cable->capture_busy = 0;
			cable->timer.function = 0;

			init_timer(&cable->timer);
			spin_lock_init(&cable->lock);
			cable->timer.data = (unsigned long)cable;
			cable->timer.function = snd_card_loopback_timer_function;
		}
	}

	loopback->card = card;
	if ((err = snd_card_loopback_pcm(loopback, 0, pcm_substreams[dev])) < 0)
		goto __nodev;
	if ((err = snd_card_loopback_pcm(loopback, 1, pcm_substreams[dev])) < 0)
		goto __nodev;
	if ((err = snd_card_loopback_new_mixer(loopback)) < 0)
		goto __nodev;
	strcpy(card->driver, "Loopback");
	strcpy(card->shortname, "Loopback");
	sprintf(card->longname, "Loopback %i", dev + 1);
	if ((err = snd_card_register(card)) == 0) {
		snd_loopback_cards[dev] = card;
		return 0;
	}
      __nodev:
	snd_card_free(card);
	return err;
}

static int __init alsa_card_loopback_init(void)
{
	int dev, cards;

	printk("%s\n", __FUNCTION__);

	for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
		if (snd_card_loopback_probe(dev) < 0) {
#ifdef MODULE
			printk(KERN_ERR "Loopback soundcard #%i not found or device busy\n", dev + 1);
#endif
			break;
		}
		cards++;
	}
	if (!cards) {
#ifdef MODULE
		printk(KERN_ERR "Loopback soundcard not found or device busy\n");
#endif
		return -ENODEV;
	}
	return 0;
}

static void __exit alsa_card_loopback_exit(void)
{
	int idx;

	for (idx = 0; idx < SNDRV_CARDS; idx++)
		snd_card_free(snd_loopback_cards[idx]);
}

module_init(alsa_card_loopback_init)
module_exit(alsa_card_loopback_exit)

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

  parent reply	other threads:[~2008-07-01 18:28 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-06-16 20:04 Still have choppy audio using 1.0.17 Gustavo da Silva Serra
2008-06-18 18:24 ` Gustavo da Silva Serra
2008-06-18 19:44   ` Gustavo da Silva Serra
2008-06-19 13:01     ` Gustavo da Silva Serra
2008-06-20 19:07       ` Gustavo da Silva Serra
2008-06-25 11:24       ` Gustavo da Silva Serra
2008-06-25 16:06         ` Takashi Iwai
2008-06-25 18:34           ` Gustavo da Silva Serra
2008-07-01 18:28           ` Gustavo da Silva Serra [this message]
2008-07-04 12:40             ` Gustavo da Silva Serra
2008-07-14 17:57               ` Gustavo da Silva Serra
2008-07-15  0:50                 ` stan
2008-07-15 11:56                   ` Gustavo da Silva Serra
2008-07-15 18:40                     ` Gustavo da Silva Serra
2008-07-15 21:31                       ` stan
2008-07-16 14:19                         ` Gustavo da Silva Serra
2008-07-16 15:30                           ` Takashi Iwai
2008-07-16 15:43                             ` Gustavo da Silva Serra

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=486A7757.4060907@tet.com.br \
    --to=gustavo.serra@tet.com.br \
    --cc=alsa-devel@alsa-project.org \
    --cc=tiwai@suse.de \
    /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