Index: uspace/app/dplay/dplay.c
===================================================================
--- uspace/app/dplay/dplay.c	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/app/dplay/dplay.c	(revision 1240bb95c3c231d45558da9d7acd93c3557996db)
@@ -91,9 +91,23 @@
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
-		if (IPC_GET_IMETHOD(call) != IPC_FIRST_USER_METHOD) {
-			printf("Unknown event.\n");
+		switch(IPC_GET_IMETHOD(call)) {
+		case PCM_EVENT_PLAYBACK_DONE:
+			printf("+");
+			async_answer_0(callid, EOK);
 			break;
+		case PCM_EVENT_PLAYBACK_TERMINATED:
+			printf("\nPlayback terminated\n");
+			fibril_mutex_lock(&pb->mutex);
+			pb->playing = false;
+			fibril_condvar_signal(&pb->cv);
+			async_answer_0(callid, EOK);
+			fibril_mutex_unlock(&pb->mutex);
+			return;
+		default:
+			printf("Unknown event %d.\n", IPC_GET_IMETHOD(call));
+			async_answer_0(callid, ENOTSUP);
+			continue;
+
 		}
-		printf("+");
 		const size_t bytes = fread(pb->buffer.position, sizeof(uint8_t),
 		   buffer_part, pb->source);
@@ -103,8 +117,9 @@
 		if (pb->buffer.position >= (pb->buffer.base + pb->buffer.size))
 			pb->buffer.position = pb->buffer.base;
-		async_answer_0(callid, EOK);
 		if (bytes == 0) {
+			fibril_mutex_lock(&pb->mutex);
 			pb->playing = false;
 			fibril_condvar_signal(&pb->cv);
+			fibril_mutex_unlock(&pb->mutex);
 		}
 	}
@@ -138,5 +153,7 @@
 
 	audio_pcm_stop_playback(pb->device, pb->buffer.id);
-	fibril_condvar_wait(&pb->cv, &pb->mutex);
+	for (pb->playing = true; pb->playing;
+		fibril_condvar_wait(&pb->cv, &pb->mutex));
+	fibril_mutex_unlock(&pb->mutex);
 	printf("\n");
 }
Index: uspace/app/drec/drec.c
===================================================================
--- uspace/app/drec/drec.c	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/app/drec/drec.c	(revision 1240bb95c3c231d45558da9d7acd93c3557996db)
@@ -89,7 +89,17 @@
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
-		if (IPC_GET_IMETHOD(call) != IPC_FIRST_USER_METHOD) {
-			printf("Unknown event.\n");
+		switch(IPC_GET_IMETHOD(call)) {
+		case PCM_EVENT_RECORDING_DONE:
+			printf("+");
+			async_answer_0(callid, EOK);
 			break;
+		case PCM_EVENT_RECORDING_TERMINATED:
+			printf("\nRecording terminated\n");
+			return;
+		default:
+			printf("Unknown event %d.\n", IPC_GET_IMETHOD(call));
+			async_answer_0(callid, ENOTSUP);
+			continue;
+
 		}
 		const size_t bytes = fwrite(rec->buffer.position,
@@ -207,5 +217,5 @@
 	};
 	fwrite(&header, sizeof(header), 1, rec.file);
-	record(&rec, sampling_rate, channels, format);
+	record(&rec, channels, sampling_rate, format);
 	fclose(rec.file);
 
Index: uspace/drv/audio/sb16/dsp.c
===================================================================
--- uspace/drv/audio/sb16/dsp.c	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/drv/audio/sb16/dsp.c	(revision 1240bb95c3c231d45558da9d7acd93c3557996db)
@@ -33,4 +33,5 @@
  */
 
+#include <bool.h>
 #include <devman.h>
 #include <device/hw_res.h>
@@ -38,5 +39,5 @@
 #include <libarch/barrier.h>
 #include <str_error.h>
-#include <bool.h>
+#include <audio_pcm_iface.h>
 
 #include "dma.h"
@@ -162,4 +163,5 @@
 	dsp->event_exchange = NULL;
 	dsp->sb_dev = dev;
+	dsp->status = DSP_STOPPED;
 	sb_dsp_reset(dsp);
 	/* "DSP takes about 100 microseconds to initialize itself" */
@@ -188,5 +190,20 @@
 	assert(dsp);
 	if (dsp->event_exchange) {
-		async_msg_0(dsp->event_exchange, IPC_FIRST_USER_METHOD);
+		switch (dsp->status) {
+		case DSP_PLAYBACK:
+			async_msg_0(dsp->event_exchange,
+			    PCM_EVENT_PLAYBACK_DONE);
+			break;
+		case DSP_RECORDING:
+			async_msg_0(dsp->event_exchange,
+			    PCM_EVENT_RECORDING_DONE);
+			break;
+		default:
+		case DSP_STOPPED:
+			ddf_log_warning("Interrupt while DSP stopped and "
+			    "event exchange present. Terminating exchange");
+			async_exchange_end(dsp->event_exchange);
+			dsp->event_exchange = NULL;
+		}
 	} else {
 		ddf_log_warning("Interrupt with no event consumer.");
@@ -316,5 +333,5 @@
 	    sampling_rate / (dsp->active.samples * channels));
 
-	dsp->active.playing = true;
+	dsp->status = DSP_PLAYBACK;
 
 	return EOK;
@@ -326,6 +343,9 @@
 	if (id != BUFFER_ID)
 		return ENOENT;
+	sb_dsp_write(dsp, DMA_16B_EXIT);
+	ddf_log_debug("Stopping playback on buffer %u.", id);
+	async_msg_0(dsp->event_exchange, PCM_EVENT_PLAYBACK_TERMINATED);
 	async_exchange_end(dsp->event_exchange);
-	sb_dsp_write(dsp, DMA_16B_EXIT);
+	dsp->event_exchange = NULL;
 	return EOK;
 }
@@ -389,5 +409,5 @@
 	    "(~1/%u sec)", dsp->active.samples,
 	    sampling_rate / (dsp->active.samples * channels));
-	dsp->active.playing = false;
+	dsp->status = DSP_RECORDING;
 
 	return EOK;
@@ -399,6 +419,9 @@
 	if (id != BUFFER_ID)
 		return ENOENT;
+	sb_dsp_write(dsp, DMA_16B_EXIT);
+	ddf_log_debug("Stopping playback on buffer %u.", id);
+	async_msg_0(dsp->event_exchange, PCM_EVENT_RECORDING_TERMINATED);
 	async_exchange_end(dsp->event_exchange);
-	sb_dsp_write(dsp, DMA_16B_EXIT);
+	dsp->event_exchange = NULL;
 	return EOK;
 }
Index: uspace/drv/audio/sb16/dsp.h
===================================================================
--- uspace/drv/audio/sb16/dsp.h	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/drv/audio/sb16/dsp.h	(revision 1240bb95c3c231d45558da9d7acd93c3557996db)
@@ -57,6 +57,10 @@
 		uint8_t mode;
 		uint16_t samples;
-		bool playing;
 	} active;
+	enum {
+		DSP_PLAYBACK,
+		DSP_RECORDING,
+		DSP_STOPPED,
+	} status;
 	async_sess_t *event_session;
 	async_exch_t *event_exchange;
Index: uspace/lib/drv/include/audio_pcm_iface.h
===================================================================
--- uspace/lib/drv/include/audio_pcm_iface.h	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/lib/drv/include/audio_pcm_iface.h	(revision 1240bb95c3c231d45558da9d7acd93c3557996db)
@@ -43,4 +43,12 @@
 #include "ddf/driver.h"
 
+enum {
+	PCM_EVENT_PLAYBACK_DONE = IPC_FIRST_USER_METHOD,
+	PCM_EVENT_RECORDING_DONE,
+	PCM_EVENT_PLAYBACK_TERMINATED,
+	PCM_EVENT_RECORDING_TERMINATED
+};
+
+
 int audio_pcm_get_info_str(async_exch_t *, const char **);
 int audio_pcm_get_buffer(async_exch_t *, void **, size_t *, unsigned *,
