Пример #1
0
static void __consumer_drain_and_stop(void)
{
	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
		op_close();
		__consumer_status_update(CS_STOPPED);
	}
}
Пример #2
0
static int change_sf(int drop)
{
	int old_sf = buffer_sf;
	CHANNEL_MAP(old_channel_map);
	channel_map_copy(old_channel_map, buffer_channel_map);

	set_buffer_sf();
	if (buffer_sf != old_sf || !channel_map_equal(buffer_channel_map, old_channel_map, sf_get_channels(buffer_sf))) {
		/* reopen */
		int rc;

		if (drop)
			op_drop();
		op_close();
		rc = op_open(buffer_sf, buffer_channel_map);
		if (rc) {
			player_op_error(rc, "opening audio device");
			__consumer_status_update(CS_STOPPED);
			__producer_stop();
			return rc;
		}
	} else if (consumer_status == CS_PAUSED) {
		op_drop();
		op_unpause();
	}
	__consumer_status_update(CS_PLAYING);
	return 0;
}
Пример #3
0
void file_input_close(void)
{
	mval            pars, val;
	unsigned char   no_param = (unsigned char)iop_eol;

	val.mvtype = pars.mvtype = MV_STR;
	val.str.addr = (char *)load_fn_ptr;
	val.str.len = load_fn_len;
	pars.str.len = SIZEOF(iop_eol);
	pars.str.addr = (char *)&no_param;
	op_close(&val, &pars);
}
Пример #4
0
void close_list_file(void)
{
	mval param,list_file;
	unsigned char charspace;

	param.str.len = 1;
	charspace = (char) iop_eol;
	param.str.addr = &charspace;
	list_file.mvtype = param.mvtype = MV_STR;
	list_file.str.len = io_curr_device.in->trans_name->len;
	list_file.str.addr = &io_curr_device.in->trans_name->dollar_io[0];
	op_close(&list_file, &param);
	io_curr_device = dev_in_use;
}
Пример #5
0
/*
 * change output plugin without stopping playback
 */
void player_set_op(const char *name)
{
	int rc;

	player_lock();

	/* drop needed because close drains the buffer */
	if (consumer_status == CS_PAUSED)
		op_drop();

	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED)
		op_close();

	if (name) {
		d_print("setting op to '%s'\n", name);
		rc = op_select(name);
	} else {
		/* first initialized plugin */
		d_print("selecting first initialized op\n");
		rc = op_select_any();
	}
	if (rc) {
		__consumer_status_update(CS_STOPPED);

		__producer_stop();
		if (name)
			player_op_error(rc, "selecting output plugin '%s'", name);
		else
			player_op_error(rc, "selecting any output plugin");
		player_unlock();
		return;
	}

	if (consumer_status == CS_PLAYING || consumer_status == CS_PAUSED) {
		set_buffer_sf();
		rc = op_open(buffer_sf, buffer_channel_map);
		if (rc) {
			__consumer_status_update(CS_STOPPED);
			__producer_stop();
			player_op_error(rc, "opening audio device");
			player_unlock();
			return;
		}
		if (consumer_status == CS_PAUSED)
			op_pause();
	}

	player_unlock();
}
Пример #6
0
void	close_source_file (void)
{
	mval		val;
	mval		pars;
	unsigned char	no_param;

	no_param = (unsigned char)iop_eol;
	pars.mvtype = MV_STR;
	pars.str.len = sizeof(no_param);
	pars.str.addr = (char *)&no_param;
	val.mvtype = MV_STR;
	val.str.len = source_name_len;
	val.str.addr = (char *)source_file_name;
	op_close(&val, &pars);
	io_curr_device = tmp_list_dev;	/*	not dev_in_use to make sure list file works	*/
	return;
}
Пример #7
0
void close_ceprep_file(void)
{
#ifdef VMS
/* stub except for VMS */
	unsigned char	charspace;
	mval		param, ceprep_file;

	param.str.len = 1;
	charspace = (char)iop_eol;
	param.str.addr = &charspace;
	ceprep_file.mvtype = param.mvtype = MV_STR;
	ceprep_file.str.len = io_curr_device.in->trans_name->len;
	ceprep_file.str.addr = io_curr_device.in->trans_name->dollar_io;
	op_close(&ceprep_file, &param);
	io_curr_device = dev_in_use;
#endif
	return;
}
Пример #8
0
void	dse_close(void)
{
	mval		val;
	mval		pars;
	unsigned char	no_param = (unsigned char)iop_eol;

	if (CLOSED_FMT != dse_dmp_format)
	{
		util_out_print("Closing output file:  !AD",TRUE,LEN_AND_STR(patch_ofile));
		val.mvtype = pars.mvtype = MV_STR;
		val.str.addr = (char *)patch_ofile;
		val.str.len = patch_len;
		pars.str.len = SIZEOF(iop_eol);
		pars.str.addr = (char *)&no_param;
		op_close(&val, &pars);
		dse_dmp_format = CLOSED_FMT;
	} else
		util_out_print("Error:  no current output file.",TRUE);
	return;
}
Пример #9
0
static void *consumer_loop(void *arg)
{
	while (1) {
		int rc, space;
		int size;
		char *rpos;

		consumer_lock();
		if (!consumer_running)
			break;

		if (consumer_status == CS_PAUSED || consumer_status == CS_STOPPED) {
			pthread_cond_wait(&consumer_playing, &consumer_mutex);
			consumer_unlock();
			continue;
		}
		space = op_buffer_space();
		if (space < 0) {
			d_print("op_buffer_space returned %d %s\n", space,
					space == -1 ? strerror(errno) : "");

			/* try to reopen */
			op_close();
			__consumer_status_update(CS_STOPPED);
			__consumer_play();

			consumer_unlock();
			continue;
		}
/* 		d_print("BS: %6d %3d\n", space, space * 1000 / (44100 * 2 * 2)); */

		while (1) {
			if (space == 0) {
				__consumer_position_update();
				consumer_unlock();
				ms_sleep(25);
				break;
			}
			size = buffer_get_rpos(&rpos);
			if (size == 0) {
				producer_lock();
				if (producer_status != PS_PLAYING) {
					producer_unlock();
					consumer_unlock();
					break;
				}
				/* must recheck rpos */
				size = buffer_get_rpos(&rpos);
				if (size == 0) {
					/* OK. now it's safe to check if we are at EOF */
					if (ip_eof(ip)) {
						/* EOF */
						__consumer_handle_eof();
						producer_unlock();
						consumer_unlock();
						break;
					} else {
						/* possible underrun */
						producer_unlock();
						__consumer_position_update();
						consumer_unlock();
/* 						d_print("possible underrun\n"); */
						ms_sleep(10);
						break;
					}
				}

				/* player_buffer and ip.eof were inconsistent */
				producer_unlock();
			}
			if (size > space)
				size = space;
			if (soft_vol || replaygain)
				scale_samples(rpos, (unsigned int *)&size);
			rc = op_write(rpos, size);
			if (rc < 0) {
				d_print("op_write returned %d %s\n", rc,
						rc == -1 ? strerror(errno) : "");

				/* try to reopen */
				op_close();
				__consumer_status_update(CS_STOPPED);
				__consumer_play();

				consumer_unlock();
				break;
			}
			buffer_consume(rc);
			consumer_pos += rc;
			space -= rc;
		}
	}
	__consumer_stop();
	consumer_unlock();
	return NULL;
}
Пример #10
0
void mu_extract(void)
{
	int 				stat_res, truncate_res;
	int				reg_max_rec, reg_max_key, reg_max_blk, reg_std_null_coll;
	int				iter, format, local_errno, int_nlen;
	boolean_t			freeze = FALSE, logqualifier, success;
	char				format_buffer[FORMAT_STR_MAX_SIZE],  ch_set_name[MAX_CHSET_NAME], cli_buff[MAX_LINE],
					label_buff[LABEL_STR_MAX_SIZE], gbl_name_buff[MAX_MIDENT_LEN + 2]; /* 2 for null and '^' */
	glist				gl_head, *gl_ptr;
	gd_region			*reg, *region_top;
	mu_extr_stats			global_total, grand_total;
	uint4				item_code, devbufsiz, maxfield;
	unsigned short			label_len, n_len, ch_set_len, buflen;
	unsigned char			*outbuf, *outptr, *chptr, *leadptr;
	struct stat                     statbuf;
	mval				val, curr_gbl_name, op_val, op_pars;
	mstr				chset_mstr;
	gtm_chset_t 			saved_out_set;
	static unsigned char		ochset_set = FALSE;
	static readonly unsigned char	open_params_list[] =
	{
		(unsigned char)iop_noreadonly,
		(unsigned char)iop_nowrap,
		(unsigned char)iop_stream,
		(unsigned char)iop_eol
	};
	static readonly unsigned char no_param = (unsigned char)iop_eol;
	coll_hdr	extr_collhdr;

	error_def(ERR_NOSELECT);
	error_def(ERR_GTMASSERT);
	error_def(ERR_EXTRACTCTRLY);
	error_def(ERR_EXTRACTFILERR);
	error_def(ERR_MUPCLIERR);
	error_def(ERR_MUNOACTION);
	error_def(ERR_MUNOFINISH);
	error_def(ERR_RECORDSTAT);
	error_def(ERR_NULLCOLLDIFF);

        /* Initialize all local character arrays to zero before using */

        memset(cli_buff, 0, sizeof(cli_buff));
        memset(outfilename, 0, sizeof(outfilename));
        memset(label_buff, 0, sizeof(label_buff));
        memset(format_buffer, 0, sizeof(format_buffer));
	active_device = io_curr_device.out;

	mu_outofband_setup();

	if (CLI_PRESENT == cli_present("OCHSET"))
	{
		ch_set_len = sizeof(ch_set_name);
		if (cli_get_str("OCHSET", ch_set_name, &ch_set_len))
		{
			if (0 == ch_set_len)
				mupip_exit(ERR_MUNOACTION);	/* need to change to OPCHSET error when added */
			ch_set_name[ch_set_len] = '\0';
#ifdef KEEP_zOS_EBCDIC
			if ( (iconv_t)0 != active_device->output_conv_cd)
				ICONV_CLOSE_CD(active_device->output_conv_cd);
			if (DEFAULT_CODE_SET != active_device->out_code_set)
				ICONV_OPEN_CD(active_device->output_conv_cd, INSIDE_CH_SET, ch_set_name);
#else
			chset_mstr.addr = ch_set_name;
			chset_mstr.len = ch_set_len;
			SET_ENCODING(active_device->ochset, &chset_mstr);
			get_chset_desc(&chset_names[active_device->ochset]);
#endif
			ochset_set = TRUE;
		}
	}
	logqualifier = (CLI_NEGATED != cli_present("LOG"));
	if (CLI_PRESENT == cli_present("FREEZE"))
		freeze = TRUE;

	n_len = sizeof(format_buffer);
	if (FALSE == cli_get_str("FORMAT", format_buffer, &n_len))
	{
		n_len = sizeof("ZWR") - 1;
		memcpy(format_buffer, "ZWR", n_len);
	}
	int_nlen = n_len;
	lower_to_upper((uchar_ptr_t)format_buffer, (uchar_ptr_t)format_buffer, int_nlen);
	if (0 == memcmp(format_buffer, "ZWR", n_len))
	        format = MU_FMT_ZWR;
	else if (0 == memcmp(format_buffer, "GO", n_len))
	{
		if (gtm_utf8_mode)
		{
			util_out_print("Extract error: GO format is not supported in UTF-8 mode. Use ZWR format.", TRUE);
			mupip_exit(ERR_MUPCLIERR);
		}
	        format = MU_FMT_GO;
	} else if (0 == memcmp(format_buffer, "BINARY", n_len))
		format = MU_FMT_BINARY;
	else
	{
		util_out_print("Extract error: bad format type", TRUE);
		mupip_exit(ERR_MUPCLIERR);
	}
	n_len = sizeof(cli_buff);
	if (FALSE == cli_get_str((char *)select_text, cli_buff, &n_len))
	{
		n_len = 1;
		cli_buff[0] = '*';
	}
	/* gv_select will select globals */
        gv_select(cli_buff, n_len, freeze, (char *)select_text, &gl_head, &reg_max_rec, &reg_max_key, &reg_max_blk);
 	if (!gl_head.next)
        {
                rts_error(VARLSTCNT(1) ERR_NOSELECT);
                mupip_exit(ERR_NOSELECT);
        }
	/* For binary format, check whether all regions have same null collation order */
	if (MU_FMT_BINARY == format)
	{
		for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions, reg_std_null_coll = -1;
			reg < region_top ; reg++)
		{
			if (reg->open)
			{
				if (reg_std_null_coll != reg->std_null_coll)
				{
					if (reg_std_null_coll == -1)
						reg_std_null_coll = reg->std_null_coll;
					else
					{
						rts_error(VARLSTCNT(1) ERR_NULLCOLLDIFF);
						mupip_exit(ERR_NULLCOLLDIFF);
					}
				}
			}
		}
		assert(-1 != reg_std_null_coll);
	}
	grand_total.recknt = grand_total.reclen = grand_total.keylen = grand_total.datalen = 0;
	global_total.recknt = global_total.reclen = global_total.keylen = global_total.datalen = 0;

	n_len = sizeof(outfilename);
	if (FALSE == cli_get_str("FILE", outfilename, &n_len))
	{
		rts_error(VARLSTCNT(1) ERR_MUPCLIERR);
		mupip_exit(ERR_MUPCLIERR);
	}
	if (-1 == Stat((char *)outfilename, &statbuf))
        {
		if (ENOENT != errno)
		{
			local_errno = errno;
			perror("Error opening output file");
			mupip_exit(local_errno);
		}
	}
	else
	{
		util_out_print("Error opening output file: !AD -- File exists", TRUE, n_len, outfilename);
		mupip_exit(ERR_MUNOACTION);
	}
	op_pars.mvtype = MV_STR;
	op_pars.str.len = sizeof(open_params_list);
	op_pars.str.addr = (char *)open_params_list;
	op_val.mvtype = MV_STR;
	op_val.str.len = filename_len = n_len;
	op_val.str.addr = (char *)outfilename;
	(*op_open_ptr)(&op_val, &op_pars, 0, 0);
	ESTABLISH(mu_extract_handler);
	op_use(&op_val, &op_pars);
	if (MU_FMT_BINARY == format)
	{
		/* binary header label format:
		 *	fixed length text, fixed length date & time,
		 *	fixed length max blk size, fixed length max rec size, fixed length max key size, fixed length std_null_coll
		 *	32-byte padded user-supplied string
		 */
		outbuf = (unsigned char *)malloc(sizeof(BIN_HEADER_LABEL) + sizeof(BIN_HEADER_DATEFMT) - 1 +
				4 * BIN_HEADER_NUMSZ + BIN_HEADER_LABELSZ);
		outptr = outbuf;

		MEMCPY_LIT(outptr, BIN_HEADER_LABEL);
		outptr += STR_LIT_LEN(BIN_HEADER_LABEL);

		stringpool.free = stringpool.base;
		op_horolog(&val);
		stringpool.free = stringpool.base;
		op_fnzdate(&val, (mval *)&mu_bin_datefmt, &null_str, &null_str, &val);
		memcpy(outptr, val.str.addr, val.str.len);
		outptr += val.str.len;

		WRITE_NUMERIC(reg_max_blk);
		WRITE_NUMERIC(reg_max_rec);
		WRITE_NUMERIC(reg_max_key);
		WRITE_NUMERIC(reg_std_null_coll);

		if (gtm_utf8_mode)
		{
			MEMCPY_LIT(outptr, UTF8_NAME);
			label_len = STR_LIT_LEN(UTF8_NAME);
			outptr[label_len++] = ' ';
		} else
			label_len = 0;
		buflen = sizeof(label_buff);
		if (FALSE == cli_get_str("LABEL", label_buff, &buflen))
		{
			MEMCPY_LIT(&outptr[label_len], EXTR_DEFAULT_LABEL);
			buflen = STR_LIT_LEN(EXTR_DEFAULT_LABEL);
		} else
			memcpy(&outptr[label_len], label_buff, buflen);
		label_len += buflen;
		if (label_len > BIN_HEADER_LABELSZ)
		{ /* Label size exceeds the space, so truncate the label and back off to
		     the valid beginning (i.e. to the leading byte) of the last character
		     that can entirely fit in the space */
			label_len = BIN_HEADER_LABELSZ;
			chptr = &outptr[BIN_HEADER_LABELSZ];
			UTF8_LEADING_BYTE(chptr, outptr, leadptr);
			assert(chptr - leadptr < 4);
			if (leadptr < chptr)
				label_len -= (chptr - leadptr);
		}
		outptr += label_len;
		for (iter = label_len;  iter < BIN_HEADER_LABELSZ;  iter++)
			*outptr++ = ' ';

		label_len = outptr - outbuf;
		if (!ochset_set)
		{
#ifdef KEEP_zOS_EBCDIC
			/* extract ascii header for binary by default */
			/* Do we need to restore it somewhere? */
			saved_out_set = (io_curr_device.out)->out_code_set;
			(io_curr_device.out)->out_code_set = DEFAULT_CODE_SET;
#else
			saved_out_set = (io_curr_device.out)->ochset;
			(io_curr_device.out)->ochset = CHSET_M;
#endif
		}
		op_val.str.addr = (char *)(&label_len);
		op_val.str.len = sizeof(label_len);
		op_write(&op_val);
		op_val.str.addr = (char *)outbuf;
		op_val.str.len = label_len;
		op_write(&op_val);
	} else
	{
		assert((MU_FMT_GO == format) || (MU_FMT_ZWR == format));
		label_len = sizeof(label_buff);
		if (FALSE == cli_get_str("LABEL", label_buff, &label_len))
		{
			MEMCPY_LIT(label_buff, EXTR_DEFAULT_LABEL);
			label_len = STR_LIT_LEN(EXTR_DEFAULT_LABEL);
		}
		if (gtm_utf8_mode)
		{
			label_buff[label_len++] = ' ';
			MEMCPY_LIT(&label_buff[label_len], UTF8_NAME);
			label_len += STR_LIT_LEN(UTF8_NAME);
		}
		label_buff[label_len++] = '\n';
		op_val.mvtype = MV_STR;
		op_val.str.len = label_len;
		op_val.str.addr = label_buff;
		op_write(&op_val);
		stringpool.free = stringpool.base;
		op_horolog(&val);
		stringpool.free = stringpool.base;
		op_fnzdate(&val, &datefmt, &null_str, &null_str, &val);
		op_val = val;
		op_val.mvtype = MV_STR;
		op_write(&op_val);
		if (MU_FMT_ZWR == format)
		{
			op_val.str.addr = " ZWR";
			op_val.str.len = sizeof(" ZWR") - 1;
			op_write(&op_val);
		}
		op_wteol(1);
	}
	REVERT;

	ESTABLISH(mu_extract_handler1);
	success = TRUE;
	for (gl_ptr = gl_head.next; gl_ptr; gl_ptr = gl_ptr->next)
	{
		if (mu_ctrly_occurred)
			break;
		if (mu_ctrlc_occurred)
		{
			gbl_name_buff[0]='^';
			memcpy(&gbl_name_buff[1], gl_ptr->name.str.addr, gl_ptr->name.str.len);
			gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff,
				global_total.recknt, global_total.keylen, global_total.datalen, global_total.reclen);
			mu_ctrlc_occurred = FALSE;
		}
		gv_bind_name(gd_header, &gl_ptr->name.str);
		if (MU_FMT_BINARY == format)
		{
			label_len = sizeof(extr_collhdr);
			op_val.mvtype = MV_STR;
			op_val.str.addr = (char *)(&label_len);
			op_val.str.len = sizeof(label_len);
			op_write(&op_val);
			extr_collhdr.act = gv_target->act;
			extr_collhdr.nct = gv_target->nct;
			extr_collhdr.ver = gv_target->ver;
			op_val.str.addr = (char *)(&extr_collhdr);
			op_val.str.len = sizeof(extr_collhdr);
			op_write(&op_val);
		}
		/* Note: Do not change the order of the expression below.
		 * Otherwise if success is FALSE, mu_extr_gblout() will not be called at all.
		 * We want mu_extr_gblout() to be called irrespective of the value of success */
		success = mu_extr_gblout(&gl_ptr->name, &global_total, format) && success;
		if (logqualifier)
		{
			gbl_name_buff[0]='^';
			memcpy(&gbl_name_buff[1], gl_ptr->name.str.addr, gl_ptr->name.str.len);
			gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff,
				global_total.recknt, global_total.keylen, global_total.datalen, global_total.reclen);
			mu_ctrlc_occurred = FALSE;
		}
		grand_total.recknt += global_total.recknt;
		if (grand_total.reclen < global_total.reclen)
			grand_total.reclen = global_total.reclen;
		if (grand_total.keylen < global_total.keylen)
			grand_total.keylen = global_total.keylen;
		if (grand_total.datalen < global_total.datalen)
			grand_total.datalen = global_total.datalen;

	}
	op_val.mvtype = op_pars.mvtype = MV_STR;
	op_val.str.addr = (char *)outfilename;;
	op_val.str.len = filename_len;
	op_pars.str.len = sizeof(no_param);
	op_pars.str.addr = (char *)&no_param;
	op_close(&op_val, &op_pars);
	REVERT;
	if (mu_ctrly_occurred)
	{
		gtm_putmsg(VARLSTCNT(1) ERR_EXTRACTCTRLY);
		mupip_exit(ERR_MUNOFINISH);
	}
	gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT(gt_lit),
		grand_total.recknt, grand_total.keylen, grand_total.datalen, grand_total.reclen);
	if (MU_FMT_BINARY == format)
	{
		/*      truncate the last newline charactor flushed by op_close */
		STAT_FILE((char *)outfilename, &statbuf, stat_res);
		if (-1 == stat_res)
			rts_error(VARLSTCNT(1) errno);
		TRUNCATE_FILE((const char *)outfilename, statbuf.st_size - 1, truncate_res);
		if (-1 == truncate_res)
			rts_error(VARLSTCNT(1) errno);
	}
	mupip_exit(success ? SS_NORMAL : ERR_MUNOFINISH);
}
Пример #11
0
static int
op_open (AFormat fmt, int rate, int nch)
{
	struct sio_par askpar;

	pthread_mutex_lock (&mutex);

	hdl = sio_open (strlen (audiodev) > 0 ? audiodev : NULL, SIO_PLAY, 0);
	if (hdl == NULL) {
		fprintf (stderr, "%s: failed to open audio device\n", __func__);
		goto error;
	}

	sio_initpar (&par);
	afmt = fmt;
	switch (fmt) {
	case FMT_U8:
		par.bits = 8;
		par.sig = 0;
		break;
	case FMT_S8:
		par.bits = 8;
		par.sig = 1;
		break;
	case FMT_U16_LE:
		par.bits = 16;
		par.sig = 0;
		par.le = 1;
		break;
	case FMT_U16_BE:
		par.bits = 16;
		par.sig = 0;
		par.le = 0;
		break;
	case FMT_U16_NE:
		par.bits = 16;
		par.sig = 0;
		par.le = SIO_LE_NATIVE;
		break;
	case FMT_S16_LE:
		par.bits = 16;
		par.sig = 1;
		par.le = 1;
		break;
	case FMT_S16_BE:
		par.bits = 16;
		par.sig = 1;
		par.le = 0;
	case FMT_S16_NE:
		par.bits = 16;
		par.sig = 1;
		par.le = SIO_LE_NATIVE;
		break;
	default:
		fprintf (stderr, "%s: unknown format requested\n", __func__);
		goto error;
	}
	par.pchan = nch;
	par.rate = rate;

	/* 250 ms buffer */
	par.appbufsz = par.rate / 4;

	askpar = par;
	if (!sio_setpar (hdl, &par) || !sio_getpar (hdl, &par)) {
		fprintf (stderr, "%s: failed to set parameters\n", __func__);
		goto error;
	}

	if ((par.bits == 16 && par.le != askpar.le) ||
	    par.bits != askpar.bits ||
	    par.sig != askpar.sig ||
	    par.pchan != askpar.pchan ||
            par.rate != askpar.rate) {
		fprintf (stderr, "%s: parameters not supported\n", __func__);
		xmms_show_message ("Unsupported format", "XMMS requested a "
			"format that is not supported by the audio device.\n\n"
			"Please try again with the aucat(1) server running.",
			"OK", FALSE, NULL, NULL);
		goto error;
	}

	rdpos = 0;
	wrpos = 0;
	sio_onmove (hdl, onmove_cb, NULL);

	paused = 0;
	if (!sio_start (hdl)) {
		fprintf (stderr, "%s: failed to start audio device\n",
			__func__);
		goto error;
	}

	bytes_per_sec = par.bps * par.pchan * par.rate;
	pthread_mutex_unlock (&mutex);
	op_set_volume (volume, volume);
	return TRUE;

error:
	pthread_mutex_unlock (&mutex);
	op_close ();
	return FALSE;
}