Index: uspace/app/dplay/dplay.c
===================================================================
--- uspace/app/dplay/dplay.c	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/app/dplay/dplay.c	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -51,5 +51,5 @@
 
 #define DEFAULT_DEVICE "/hw/pci0/00:01.0/sb16/pcm"
-#define SUBBUFFERS 2
+#define BUFFER_PARTS 2
 
 typedef struct {
@@ -85,15 +85,15 @@
 	async_answer_0(iid, EOK);
 	playback_t *pb = arg;
-	const size_t buffer_part = pb->buffer.size / SUBBUFFERS;
+	const size_t buffer_part = pb->buffer.size / BUFFER_PARTS;
 	while (1) {
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
 		switch(IPC_GET_IMETHOD(call)) {
-		case PCM_EVENT_PLAYBACK_DONE:
-			printf("+");
+		case PCM_EVENT_FRAMES_PLAYED:
+			printf("%u frames\n", IPC_GET_ARG1(call));
 			async_answer_0(callid, EOK);
 			break;
 		case PCM_EVENT_PLAYBACK_TERMINATED:
-			printf("\nPlayback terminated\n");
+			printf("Playback terminated\n");
 			fibril_mutex_lock(&pb->mutex);
 			pb->playing = false;
@@ -136,6 +136,8 @@
 	printf("Buffer data ready.\n");
 	fibril_mutex_lock(&pb->mutex);
+	const unsigned frames = pb->buffer.size /
+	    (BUFFER_PARTS * channels * pcm_sample_format_size(format));
 	int ret = audio_pcm_start_playback(pb->device,
-	    SUBBUFFERS, channels, sampling_rate, format);
+	    frames, channels, sampling_rate, format);
 	if (ret != EOK) {
 		fibril_mutex_unlock(&pb->mutex);
Index: uspace/app/drec/drec.c
===================================================================
--- uspace/app/drec/drec.c	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/app/drec/drec.c	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -52,5 +52,5 @@
 
 #define DEFAULT_DEVICE "/hw/pci0/00:01.0/sb16/pcm"
-#define SUBBUFFERS 2
+#define BUFFER_PARTS 2
 
 const unsigned sampling_rate = 44100, channels = 2, sample_size = 16;
@@ -84,15 +84,15 @@
 	async_answer_0(iid, EOK);
 	record_t *rec = arg;
-	const size_t buffer_part = rec->buffer.size / SUBBUFFERS;
+	const size_t buffer_part = rec->buffer.size / BUFFER_PARTS;
 	while (1) {
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
 		switch(IPC_GET_IMETHOD(call)) {
-		case PCM_EVENT_RECORDING_DONE:
-			printf("+");
+		case PCM_EVENT_FRAMES_RECORDED:
+			printf("%u frames\n", IPC_GET_ARG1(call));
 			async_answer_0(callid, EOK);
 			break;
 		case PCM_EVENT_RECORDING_TERMINATED:
-			printf("\nRecording terminated\n");
+			printf("Recording terminated\n");
 			return;
 		default:
@@ -122,6 +122,8 @@
 	printf("Recording: %dHz, %s, %d channel(s).\n",
 	    sampling_rate, pcm_sample_format_str(format), channels);
+	const unsigned frames = rec->buffer.size /
+	    (BUFFER_PARTS * channels * pcm_sample_format_size(format));
 	int ret = audio_pcm_start_record(rec->device,
-	    SUBBUFFERS, channels, sampling_rate, format);
+	    frames, channels, sampling_rate, format);
 	if (ret != EOK) {
 		printf("Failed to start recording: %s.\n", str_error(ret));
Index: uspace/drv/audio/sb16/dsp.c
===================================================================
--- uspace/drv/audio/sb16/dsp.c	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/drv/audio/sb16/dsp.c	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -188,13 +188,16 @@
 {
 	assert(dsp);
+	dsp->active.frame_count +=
+	    dsp->active.samples / ((dsp->active.mode & DSP_MODE_STEREO) ? 2 : 1);
+
 	if (dsp->event_exchange) {
 		switch (dsp->status) {
 		case DSP_PLAYBACK:
-			async_msg_0(dsp->event_exchange,
-			    PCM_EVENT_PLAYBACK_DONE);
+			async_msg_1(dsp->event_exchange,
+			    PCM_EVENT_FRAMES_PLAYED, dsp->active.frame_count);
 			break;
 		case DSP_RECORDING:
-			async_msg_0(dsp->event_exchange,
-			    PCM_EVENT_RECORDING_DONE);
+			async_msg_1(dsp->event_exchange,
+			    PCM_EVENT_FRAMES_RECORDED, dsp->active.frame_count);
 			break;
 		default:
@@ -267,5 +270,5 @@
 }
 
-int sb_dsp_start_playback(sb_dsp_t *dsp, unsigned parts,
+int sb_dsp_start_playback(sb_dsp_t *dsp, unsigned frames,
     unsigned channels, unsigned sampling_rate, pcm_sample_format_t format)
 {
@@ -275,13 +278,7 @@
 		return EINVAL;
 
-	/* Play block size must be even number (we use DMA 16)*/
-	if (dsp->buffer.size % (parts * 2))
-		return EINVAL;
-
-	const unsigned play_block_size = dsp->buffer.size / parts;
-
 	/* Check supported parameters */
-	ddf_log_debug("Requested playback (%u parts): %uHz, %s, %u channel(s).",
-	    parts, sampling_rate, pcm_sample_format_str(format), channels);
+	ddf_log_debug("Requested playback: %u frames, %uHz, %s, %u channel(s).",
+	    frames, sampling_rate, pcm_sample_format_str(format), channels);
 	if (channels != 1 && channels != 2)
 		return ENOTSUP;
@@ -311,9 +308,11 @@
 #endif
 
-	dsp->active.mode = 0 |
-	    (sign ? DSP_MODE_SIGNED : 0) | (channels == 2 ? DSP_MODE_STEREO : 0);
+	dsp->active.mode = 0
+	    | (sign ? DSP_MODE_SIGNED : 0)
+	    | (channels == 2 ? DSP_MODE_STEREO : 0);
+	dsp->active.samples = frames * channels;
+	dsp->active.frame_count = 0;
+
 	sb_dsp_write(dsp, dsp->active.mode);
-
-	dsp->active.samples = sample_count(format, play_block_size);
 	sb_dsp_write(dsp, (dsp->active.samples - 1) & 0xff);
 	sb_dsp_write(dsp, (dsp->active.samples - 1) >> 8);
@@ -339,5 +338,5 @@
 }
 
-int sb_dsp_start_record(sb_dsp_t *dsp, unsigned parts,
+int sb_dsp_start_record(sb_dsp_t *dsp, unsigned frames,
     unsigned channels, unsigned sampling_rate, pcm_sample_format_t format)
 {
@@ -347,13 +346,7 @@
 		return EINVAL;
 
-	/* Play block size must be even number (we use DMA 16)*/
-	if (dsp->buffer.size % (parts * 2))
-		return EINVAL;
-
-	const unsigned play_block_size = dsp->buffer.size / parts;
-
 	/* Check supported parameters */
-	ddf_log_debug("Requested record (%u parts): %uHz, %s, %u channel(s).",
-	    parts, sampling_rate, pcm_sample_format_str(format), channels);
+	ddf_log_debug("Requested record: %u frames, %uHz, %s, %u channel(s).",
+	    frames, sampling_rate, pcm_sample_format_str(format), channels);
 	if (channels != 1 && channels != 2)
 		return ENOTSUP;
@@ -384,8 +377,10 @@
 
 	dsp->active.mode = 0 |
-	    (sign ? DSP_MODE_SIGNED : 0) | (channels == 2 ? DSP_MODE_STEREO : 0);
+	    (sign ? DSP_MODE_SIGNED : 0) |
+	    (channels == 2 ? DSP_MODE_STEREO : 0);
+	dsp->active.samples = frames * channels;
+	dsp->active.frame_count = 0;
+
 	sb_dsp_write(dsp, dsp->active.mode);
-
-	dsp->active.samples = sample_count(format, play_block_size);
 	sb_dsp_write(dsp, (dsp->active.samples - 1) & 0xff);
 	sb_dsp_write(dsp, (dsp->active.samples - 1) >> 8);
Index: uspace/drv/audio/sb16/dsp.h
===================================================================
--- uspace/drv/audio/sb16/dsp.h	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/drv/audio/sb16/dsp.h	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -57,4 +57,5 @@
 		uint8_t mode;
 		uint16_t samples;
+		unsigned frame_count;
 	} active;
 	enum {
@@ -75,8 +76,8 @@
 int sb_dsp_set_event_session(sb_dsp_t *dsp, async_sess_t *session);
 int sb_dsp_release_buffer(sb_dsp_t *dsp);
-int sb_dsp_start_playback(sb_dsp_t *dsp, unsigned parts,
+int sb_dsp_start_playback(sb_dsp_t *dsp, unsigned frames,
     unsigned channels, unsigned sample_rate, pcm_sample_format_t format);
 int sb_dsp_stop_playback(sb_dsp_t *dsp);
-int sb_dsp_start_record(sb_dsp_t *dsp, unsigned parts,
+int sb_dsp_start_record(sb_dsp_t *dsp, unsigned frames,
     unsigned channels, unsigned sample_rate, pcm_sample_format_t format);
 int sb_dsp_stop_record(sb_dsp_t *dsp);
Index: uspace/drv/audio/sb16/pcm_iface.c
===================================================================
--- uspace/drv/audio/sb16/pcm_iface.c	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/drv/audio/sb16/pcm_iface.c	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -70,5 +70,5 @@
 }
 
-static int sb_start_playback(ddf_fun_t *fun, unsigned parts,
+static int sb_start_playback(ddf_fun_t *fun, unsigned frames,
     unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
 {
@@ -77,5 +77,5 @@
 	sb_dsp_t *dsp = fun->driver_data;
 	return sb_dsp_start_playback(
-	    dsp, parts, channels, sample_rate, format);
+	    dsp, frames, channels, sample_rate, format);
 }
 
@@ -88,5 +88,5 @@
 }
 
-static int sb_start_record(ddf_fun_t *fun, unsigned parts,
+static int sb_start_record(ddf_fun_t *fun, unsigned frames,
     unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
 {
@@ -95,5 +95,5 @@
 	sb_dsp_t *dsp = fun->driver_data;
 	return sb_dsp_start_record(
-	    dsp, parts, channels, sample_rate, format);
+	    dsp, frames, channels, sample_rate, format);
 }
 
Index: uspace/lib/drv/generic/remote_audio_pcm.c
===================================================================
--- uspace/lib/drv/generic/remote_audio_pcm.c	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/lib/drv/generic/remote_audio_pcm.c	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -148,17 +148,16 @@
 }
 
-int audio_pcm_start_playback(audio_pcm_sess_t *sess, unsigned parts,
+int audio_pcm_start_playback(audio_pcm_sess_t *sess, unsigned frames,
     unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
 {
-	if (parts > UINT8_MAX || channels > UINT8_MAX)
+	if (channels > UINT16_MAX)
 		return EINVAL;
 	assert((format & UINT16_MAX) == format);
-	const sysarg_t packed =
-	    (parts << 24) | (channels << 16) | (format & UINT16_MAX);
-	async_exch_t *exch = async_exchange_begin(sess);
-	const int ret = async_req_3_0(exch,
+	const sysarg_t packed = (channels << 16) | (format & UINT16_MAX);
+	async_exch_t *exch = async_exchange_begin(sess);
+	const int ret = async_req_4_0(exch,
 	    DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
 	    IPC_M_AUDIO_PCM_START_PLAYBACK,
-	    sample_rate, packed);
+	    frames, sample_rate, packed);
 	async_exchange_end(exch);
 	return ret;
@@ -175,16 +174,15 @@
 }
 
-int audio_pcm_start_record(audio_pcm_sess_t *sess, unsigned parts,
+int audio_pcm_start_record(audio_pcm_sess_t *sess, unsigned frames,
     unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
 {
-	if (parts > UINT8_MAX || channels > UINT8_MAX)
+	if (channels > UINT16_MAX)
 		return EINVAL;
 	assert((format & UINT16_MAX) == format);
-	const sysarg_t packed =
-	    (parts << 24) | (channels << 16) | (format & UINT16_MAX);
-	async_exch_t *exch = async_exchange_begin(sess);
-	const int ret = async_req_3_0(exch,
+	const sysarg_t packed = (channels << 16) | (format & UINT16_MAX);
+	async_exch_t *exch = async_exchange_begin(sess);
+	const int ret = async_req_4_0(exch,
 	    DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_START_RECORD,
-	    sample_rate, packed);
+	    frames, sample_rate, packed);
 	async_exchange_end(exch);
 	return ret;
@@ -345,11 +343,11 @@
 	const audio_pcm_iface_t *pcm_iface = iface;
 
-	const unsigned rate = DEV_IPC_GET_ARG1(*call);
-	const unsigned parts = (DEV_IPC_GET_ARG2(*call) >> 24) & UINT8_MAX;
-	const unsigned channels = (DEV_IPC_GET_ARG2(*call) >> 16) & UINT8_MAX;
-	const pcm_sample_format_t format = DEV_IPC_GET_ARG2(*call) & UINT16_MAX;
+	const unsigned frames = DEV_IPC_GET_ARG1(*call);
+	const unsigned rate = DEV_IPC_GET_ARG2(*call);
+	const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 16) & UINT8_MAX;
+	const pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call) & UINT16_MAX;
 
 	const int ret = pcm_iface->start_playback
-	    ? pcm_iface->start_playback(fun, parts, channels, rate, format)
+	    ? pcm_iface->start_playback(fun, frames, channels, rate, format)
 	    : ENOTSUP;
 	async_answer_0(callid, ret);
@@ -371,11 +369,11 @@
 	const audio_pcm_iface_t *pcm_iface = iface;
 
-	const unsigned rate = DEV_IPC_GET_ARG1(*call);
-	const unsigned parts = (DEV_IPC_GET_ARG2(*call) >> 24) & UINT8_MAX;
-	const unsigned channels = (DEV_IPC_GET_ARG2(*call) >> 16) & UINT8_MAX;
-	const pcm_sample_format_t format = DEV_IPC_GET_ARG2(*call) & UINT16_MAX;
+	const unsigned frames = DEV_IPC_GET_ARG1(*call);
+	const unsigned rate = DEV_IPC_GET_ARG2(*call);
+	const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 16) & UINT16_MAX;
+	const pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call) & UINT16_MAX;
 
 	const int ret = pcm_iface->start_record
-	    ? pcm_iface->start_record(fun, parts, channels, rate, format)
+	    ? pcm_iface->start_record(fun, frames, channels, rate, format)
 	    : ENOTSUP;
 	async_answer_0(callid, ret);
Index: uspace/lib/drv/include/audio_pcm_iface.h
===================================================================
--- uspace/lib/drv/include/audio_pcm_iface.h	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/lib/drv/include/audio_pcm_iface.h	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -45,6 +45,6 @@
 
 enum {
-	PCM_EVENT_PLAYBACK_DONE = IPC_FIRST_USER_METHOD,
-	PCM_EVENT_RECORDING_DONE,
+	PCM_EVENT_FRAMES_PLAYED = IPC_FIRST_USER_METHOD,
+	PCM_EVENT_FRAMES_RECORDED,
 	PCM_EVENT_PLAYBACK_TERMINATED,
 	PCM_EVENT_RECORDING_TERMINATED
Index: uspace/srv/audio/hound/audio_device.c
===================================================================
--- uspace/srv/audio/hound/audio_device.c	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/srv/audio/hound/audio_device.c	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -46,5 +46,5 @@
 #include "log.h"
 
-#define BUFFER_BLOCKS 2
+#define BUFFER_PARTS 2
 
 static int device_sink_connection_callback(audio_sink_t *sink, bool new);
@@ -107,5 +107,7 @@
 		    dev->buffer.base, dev->buffer.size);
 
-		ret = audio_pcm_start_playback(dev->sess, BUFFER_BLOCKS,
+		const unsigned frames = dev->buffer.size /
+		    (BUFFER_PARTS * audio_format_frame_size(&dev->sink.format));
+		ret = audio_pcm_start_playback(dev->sess, frames,
 		    dev->sink.format.channels, dev->sink.format.sampling_rate,
 		    dev->sink.format.sample_format);
@@ -148,5 +150,7 @@
 			return ret;
 		}
-		ret = audio_pcm_start_record(dev->sess, BUFFER_BLOCKS,
+		const unsigned frames = dev->buffer.size /
+		    (BUFFER_PARTS * audio_format_frame_size(&dev->sink.format));
+		ret = audio_pcm_start_record(dev->sess, frames,
 		    dev->sink.format.channels, dev->sink.format.sampling_rate,
 		    dev->sink.format.sample_format);
@@ -187,8 +191,9 @@
 		async_answer_0(callid, EOK);
 		switch(IPC_GET_IMETHOD(call)) {
-		case PCM_EVENT_PLAYBACK_DONE: {
+		case PCM_EVENT_FRAMES_PLAYED: {
+			//TODO add underrun protection.
 			if (dev->buffer.position) {
 				dev->buffer.position +=
-				    (dev->buffer.size / BUFFER_BLOCKS);
+				    (dev->buffer.size / BUFFER_PARTS);
 			}
 			if ((!dev->buffer.position) ||
@@ -199,5 +204,5 @@
 			}
 			audio_sink_mix_inputs(&dev->sink, dev->buffer.position,
-			    dev->buffer.size / BUFFER_BLOCKS);
+			    dev->buffer.size / BUFFER_PARTS);
 			break;
 		}
@@ -206,5 +211,5 @@
 			return;
 		}
-		case PCM_EVENT_RECORDING_DONE: {
+		case PCM_EVENT_FRAMES_RECORDED: {
 			//TODO implement
 			break;
Index: uspace/srv/audio/hound/audio_format.h
===================================================================
--- uspace/srv/audio/hound/audio_format.h	(revision 2cc5c8357bcdbc4c5d0ca79839a7c7e2aadfde62)
+++ uspace/srv/audio/hound/audio_format.h	(revision 57e8b3ba054d7a008b430e7b6b67994b03197240)
@@ -61,5 +61,8 @@
 
 
-
+static inline size_t audio_format_frame_size(const audio_format_t *a)
+{
+	return a->channels * pcm_sample_format_size(a->sample_format);
+}
 
 bool audio_format_same(const audio_format_t *a, const audio_format_t* b);
