File:  [Apple Darwin 0.x] / driverkit / libDriver / Kernel / snd_server.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:51 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * snd_server.m
 *
 * Copyright (c) 1991, NeXT Computer, Inc.  All rights reserved.
 *
 *	Field old SoundDSP driver user messages for audio driver.
 *
 * HISTORY
 *	08/10/92/mtm	Original coding.
 */

#import "audioLog.h"
#import "snd_reply.h"
#import "snd_server.h"
#import "audio_server.h"
#import <driverkit/IOAudioPrivate.h>
#import "AudioChannel.h"
#import "AudioStream.h"
#import "audio_kern_server.h"
#import <driverkit/NXSoundParameterTags.h>
#import <bsd/dev/snd_msgs.h>
#import <bsd/dev/audioTypes.h>
#import <mach/mach_types.h>
#import <kernserv/queue.h>
#import	<bsd/sys/time.h>
#import <driverkit/kernelDriver.h>	// for IOVmTaskSelf()

#define SND_DIR_PLAY	0
#define SND_DIR_RECORD	1

/*
 * DO NOT PUT ANY STATIC DATA IN THIS FILE.
 * These routines may be used by multiple AudioDevice instances
 * if more sound boards are added.
 */

static int snd_nx_encoding(int encoding)
{
    switch (encoding) {
      case SND_STREAM_FORMAT_ENCODING_LINEAR_16:
	return NX_SoundStreamDataEncoding_Linear16;
      case SND_STREAM_FORMAT_ENCODING_LINEAR_8:
	return NX_SoundStreamDataEncoding_Linear8;
      case SND_STREAM_FORMAT_ENCODING_MULAW_8:
      default:
	return NX_SoundStreamDataEncoding_Mulaw8;
    }
}
	
static void snd_set_stream_format(int dir, void *stream,
				  int srate, int encoding, int chans,
				  int low_water, int high_water)
{
    int parray[] = { NX_SoundStreamLowWaterMark,
                         NX_SoundStreamHighWaterMark,
                         NX_SoundStreamSamplingRate,
                         NX_SoundStreamDataEncoding,
                         NX_SoundStreamChannelCount };
    int pcount = sizeof(parray)/sizeof(int);
    int pvalues[pcount];
    kern_return_t kerr;
    
    pvalues[0] = low_water;
    pvalues[1] = high_water;
    pvalues[2] = srate;
    pvalues[3] = snd_nx_encoding(encoding);
    pvalues[4] = chans;
    kerr = _NXAudioSetStreamParameters(stream, parray, pcount, pvalues);
    if (kerr != KERN_SUCCESS)
	xpr_audio_user("AU: snd_set_stream_format: setStreamParams returns "
			"%d\n", kerr, 2,3,4,5);
}

/*
 * Handle stream port messages.
 */
static int snd_stream_msg(msg_header_t *in_msg, msg_header_t *out_msg)
{
    kern_return_t kerr;
    int size;
    snd_msg_type_t *msg_type;
    vm_address_t snd_data = 0;
    vm_size_t snd_size = 0;
    int snd_control = 0;
    int options = 0;
    int error = 0;
    int direction = -1;
    int high_water = 0;
    int low_water = 0;
    u_int dma_size, dma_count;
    struct timeval time_now;
    snd_stream_msg_t *stream_msg = (snd_stream_msg_t *)in_msg;
    int data_tag = stream_msg->data_tag;
    port_t reply_port = PORT_NULL;
    u_int bytes_processed, time_stamp;
    int sample_rate = 0, data_encoding = 0, chan_count = 0;
    boolean_t set_format = FALSE;
    AudioStream *audioStream = [AudioChannel
			           streamForUserPort:in_msg->msg_local_port];

    xpr_audio_user("AU: snd_stream_msg: stream 0x%x\n", audioStream, 
    		2,3,4,5);

    if (in_msg->msg_id == SND_MSG_STREAM_NSAMPLES) {
	xpr_audio_user("AU: snd_stream_msg: nsamples\n", 1,2,3,4,5);
	kerr = _NXAudioStreamInfo(audioStream, &bytes_processed, 
				&time_stamp);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_stream_msg: streamInfo returns %d\n", 
	    		kerr, 2,3,4,5);
	audio_snd_reply_ret_samples(out_msg, in_msg->msg_remote_port,
			      bytes_processed, time_stamp);
	return 0;
    }

    /*
     * NOTE: snddriver_client.c sends options and play/record data
     * in the same message.
     */
    size = in_msg->msg_size - sizeof(*stream_msg);
    msg_type = (snd_msg_type_t *)(stream_msg + 1);
    while (size > 0) {
	switch (msg_type->type) {
	  case SND_MT_PLAY_DATA: {
#ifdef DDM_DEBUG
	      snd_stream_play_data_t *stream_play_data =
		  (snd_stream_play_data_t *)msg_type;
#endif DDM_DEBUG
	      
	      *(int *)&msg_type += sizeof(snd_stream_play_data_t);
	      size -= sizeof(snd_stream_play_data_t);
	      
	      if (!error && direction == SND_DIR_RECORD)
		  error = SND_BAD_PARM;
#ifdef DDM_DEBUG
	      options = stream_play_data->options;
	      snd_data = (vm_address_t)stream_play_data->data;
	      snd_size = (vm_size_t)
		  stream_play_data->dataType.msg_type_long_number;
#endif DDM_DEBUG
	      xpr_audio_user("AU: snd_stream_msg: play data=0x%x, size=%d\n", 
	      	snd_data, snd_size, 3,4,5);
	      direction = SND_DIR_PLAY;
	      break;
	  }
	  case SND_MT_RECORD_DATA: {
	      int r;
	      //char *filename;
	      int filename_len;
	      snd_stream_record_data_t *record_data =
		  (snd_stream_record_data_t *)msg_type;

	      filename_len = record_data->filenameType.msg_type_number;
	      r = sizeof(*record_data) + filename_len;
	      *(int *)&msg_type += r;
	      size -= r;
	      xpr_audio_user("AU: snd_stream_msg: record data\n", 1,2,3,4,5);
	      break;
	  }
	  case SND_MT_CONTROL: {
	      snd_stream_control_t *stream_control =
		  (snd_stream_control_t *)msg_type;

	      xpr_audio_user("AU: snd_stream_msg: control\n", 1,2,3,4,5);
	      *(int *)&msg_type += sizeof(snd_stream_control_t);
	      size -= sizeof(snd_stream_control_t);

	      xpr_audio_user("AU: snd_stream_msg: control 0x%x\n",
			     stream_control->snd_control, 2,3,4,5);
	      snd_control |= stream_control->snd_control;
	      break;
	  }
	  case SND_MT_FORMAT: {
	      snd_stream_format_t *stream_format =
		  (snd_stream_format_t *)msg_type;
	      *(int *)&msg_type += sizeof(snd_stream_format_t);
	      size -= sizeof(snd_stream_format_t);
	      
	      sample_rate = stream_format->rate;
	      data_encoding = stream_format->encoding;
	      chan_count = stream_format->chan_count;
	      set_format = TRUE;
	      xpr_audio_user("AU: snd_stream_msg: format sr=%d de=%d cc=%d\n",
			     stream_format->rate,
			     stream_format->encoding,
			     stream_format->chan_count, 4,5);
	      break;
	  }
	  case SND_MT_OPTIONS: {
	      snd_stream_options_t *stream_options =
		  (snd_stream_options_t *)msg_type;
	      xpr_audio_user("AU: snd_stream_msg: options hw=%d lw=%d "
	      		     "size=%d\n",
			     stream_options->high_water,
			     stream_options->low_water,
			     stream_options->dma_size, 4,5);
	      *(int *)&msg_type += sizeof(snd_stream_options_t);
	      size -= sizeof(snd_stream_options_t);
	      /*
	       * Save water marks for later use by play/record stream call.
	       */
	      high_water = stream_options->high_water;
	      low_water = stream_options->low_water;
	      
	      kerr = _NXAudioGetBufferOptions([audioStream channel],
					      &dma_size, &dma_count);
	      if (kerr != KERN_SUCCESS)
		  xpr_audio_user("AU: snd_stream_msg: getBufferOpts returns "
		  		"%d\n", kerr, 2,3,4,5);
	      kerr = _NXAudioSetBufferOptions([audioStream channel], 0,
					      stream_options->dma_size,
					      dma_count);
	      if (kerr != KERN_SUCCESS)
		  xpr_audio_user("AU: snd_stream_msg: setBufferOpts returns "
		  		"%d\n", kerr, 2,3,4,5);
	      break;
	  }
	  case SND_MT_NDMA: {
	      snd_stream_ndma_t *stream_ndma = (snd_stream_ndma_t *)msg_type;
	      xpr_audio_user("AU: snd_stream_msg: ndma %d\n", 
	      		     stream_ndma->ndma, 2,3,4,5);
	      *(int *)&msg_type += sizeof(snd_stream_ndma_t);
	      size -= sizeof(snd_stream_ndma_t);
	      kerr = _NXAudioGetBufferOptions([audioStream channel],
					      &dma_size, &dma_count);
	      if (kerr != KERN_SUCCESS)
		  xpr_audio_user("AU: snd_stream_msg: getBufferOpts returns "
		  		"%d\n",kerr, 2,3,4,5);
	      kerr = _NXAudioSetBufferOptions([audioStream channel], 0,
					      dma_size,
					      stream_ndma->ndma);
	      if (kerr != KERN_SUCCESS)
		  xpr_audio_user("AU: snd_stream_msg: setBufferOpts returns "
		  		"%d\n", kerr, 2,3,4,5);
	      break;
	  }
	  default:
	    error = SND_BAD_MSG;
	    size = 0;
	    break;
	}
    }
       
    /*
     * If we found any errors, cleanup and return an error.
     */
    if (error) {
	size = in_msg->msg_size - sizeof(*stream_msg);
	msg_type = (snd_msg_type_t *)(stream_msg + 1);
	while (size > 0) {
	    switch (msg_type->type) {
	      case SND_MT_PLAY_DATA: {
		  snd_stream_play_data_t *stream_play_data =
		      (snd_stream_play_data_t *)msg_type;
		  
		  *(int *)&msg_type +=
		      sizeof(snd_stream_play_data_t);
		  size -= sizeof(snd_stream_play_data_t);
		  
		  vm_deallocate(IOVmTaskSelf(),
				(vm_address_t)stream_play_data->data,
				stream_play_data->
				dataType.msg_type_long_number);
		  break;
	      }
	      case SND_MT_RECORD_DATA:
		*(int *)&msg_type +=
		    sizeof(snd_stream_record_data_t);
		size -= sizeof(snd_stream_record_data_t);
		break;
	      case SND_MT_CONTROL:
		*(int *)&msg_type +=
		    sizeof(snd_stream_control_t);
		size -= sizeof(snd_stream_control_t);
		break;
	      case SND_MT_FORMAT:
		*(int *)&msg_type +=
		    sizeof(snd_stream_format_t);
		size -= sizeof(snd_stream_format_t);
		break;
	      case SND_MT_OPTIONS:
		*(int *)&msg_type +=
		    sizeof(snd_stream_options_t);
		size -= sizeof(snd_stream_options_t);
		break;
	      case SND_MT_NDMA:
		*(int *)&msg_type +=
		    sizeof(snd_stream_ndma_t);
		size -= sizeof(snd_stream_ndma_t);
		break;
	      default:
		/*
		 * This shouldn't happen.
		 */
		break;
	    }
	}
	return error;
    }
    
    /*
     * Process control requests.
     */
    timerclear(&time_now);

    if (snd_control&SND_DC_ABORT) {
	kerr = _NXAudioStreamControl(audioStream, _NXAUDIO_STREAM_ABORT,
				    time_now);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_stream_msg: streamControl returns %d\n", 
	    		   kerr,2,3,4,5);
    }
    if (snd_control&SND_DC_AWAIT) {
	kerr = _NXAudioStreamControl(audioStream, _NXAUDIO_STREAM_RETURN_DATA,
				    time_now);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_stream_msg: streamControl returns %d\n", 
	    		   kerr,2,3,4,5);
    }
    if (snd_control&SND_DC_PAUSE) {
	kerr = _NXAudioStreamControl(audioStream, _NXAUDIO_STREAM_PAUSE,
				    time_now);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_stream_msg: streamControl returns %d\n", 
	    	           kerr, 2,3,4,5);
    }
    /*
     * Resume control handled below after (possible) data enqueue.
     */

    /*
     * This time for sure.
     */
    size = in_msg->msg_size - sizeof(*stream_msg);
    msg_type = (snd_msg_type_t *)(stream_msg + 1);
    while (size > 0) {
	snd_size = 0;
	switch (msg_type->type) {
	  case SND_MT_PLAY_DATA: {
	      snd_stream_play_data_t *stream_play_data =
		  (snd_stream_play_data_t *)msg_type;
	      
	      *(int *)&msg_type += sizeof(snd_stream_play_data_t);
	      size -= sizeof(snd_stream_play_data_t);
	      
	      options = stream_play_data->options;
	      snd_data = (vm_address_t)stream_play_data->data;
	      snd_size = (vm_size_t)
		  stream_play_data->dataType.msg_type_long_number;
	      reply_port = stream_play_data->reg_port;
	      break;
	  }
	  case SND_MT_RECORD_DATA: {
	      snd_stream_record_data_t *record_data =
		  (snd_stream_record_data_t *)msg_type;

	      *(int *)&msg_type += sizeof(*record_data);
	      size -= sizeof(*record_data);

	      options = record_data->options;
	      snd_size = (vm_size_t)record_data->nbytes;
	      /*
	       * Note: record data is allocated in audio_server.
	       */
	      reply_port = record_data->reg_port;
	      break;
	  }
	  case SND_MT_CONTROL:
	    *(int *)&msg_type += sizeof(snd_stream_control_t);
	    size -= sizeof(snd_stream_control_t);
	    break;
	  case SND_MT_FORMAT:
	    *(int *)&msg_type += sizeof(snd_stream_format_t);
	    size -= sizeof(snd_stream_format_t);
	    break;
	  case SND_MT_OPTIONS:
	    *(int *)&msg_type += sizeof(snd_stream_options_t);
	    size -= sizeof(snd_stream_options_t);
	    break;
	  case SND_MT_NDMA:
	    *(int *)&msg_type += sizeof(snd_stream_ndma_t);
	    size -= sizeof(snd_stream_ndma_t);
	    break;
	  default:
	    /*
	     * This shouldn't happen.
	     */
	    break;
	}

	/*
	 * Enqueue the region.
	 */
	if (snd_size) {
	    u_int messages = 0;

	    if ((options&SND_DM_STARTED_MSG) != 0)
		messages |= _NXAUDIO_MSG_STARTED;
	    /*
	     * Old recording code cannot handle completed msg.
	     */
	    if (direction == SND_DIR_PLAY &&
		(options&SND_DM_COMPLETED_MSG) != 0)
		messages |= _NXAUDIO_MSG_COMPLETED;
	    if ((options&SND_DM_PAUSED_MSG) != 0)
		messages |= _NXAUDIO_MSG_PAUSED;
	    if ((options&SND_DM_RESUMED_MSG) != 0)
		messages |= _NXAUDIO_MSG_RESUMED;
	    if ((options&SND_DM_ABORTED_MSG) != 0)
		messages |= _NXAUDIO_MSG_ABORTED;
	    if ((options&SND_DM_OVERFLOW_MSG) != 0)
		messages |= _NXAUDIO_MSG_UNDERRUN;
	    
	    if (direction == SND_DIR_PLAY) {
		if (set_format) {
		    snd_set_stream_format(direction, audioStream,
					  sample_rate,
					  data_encoding,
					  chan_count,
					  low_water, high_water);
		    kerr = _NXAudioPlayStreamData((OutputStream *)audioStream,
						  snd_data,
						  snd_size, data_tag,
						  reply_port, messages);
		    if (kerr != KERN_SUCCESS) {
			xpr_audio_user("AU: snd_stream_msg: playStreamD "
				       "returns %d\n", kerr, 2,3,4,5);
		    }
		} else {
		    if ([audioStream type] == _NXAUDIO_STREAM_TYPE_SND_22)
			sample_rate = _NXAUDIO_RATE_22050;
		    else
			sample_rate = _NXAUDIO_RATE_44100;
		    kerr = _NXAudioPlayStream((OutputStream *)audioStream,
					      snd_data,
					      snd_size,
					      data_tag, 2, sample_rate,
					      32768, 32768,	/* gains */
					      low_water, high_water,
					      reply_port, messages);
		    if (kerr != KERN_SUCCESS) {
			/* audio_server deallocs data if error */
			xpr_audio_user("AU: snd_stream_msg: playStream returns"
				       " %d\n",kerr, 2,3,4,5);
		    }
		}
		/*
		 * Data has been enqueued. Send a message to the client
		 * telling that it is okay to enqueue more data. 
		 */
	    } else {
		if (set_format) {
		    snd_set_stream_format(direction, audioStream,
					  sample_rate,
					  data_encoding,
					  chan_count,
					  low_water, high_water);
		    kerr = _NXAudioRecordStreamData((InputStream *)audioStream,
						    snd_size, data_tag,
						    reply_port, messages);
		    if (kerr != KERN_SUCCESS) {
			xpr_audio_user("AU: snd_stream_msg: recStreamD returns"
				       " %d\n",kerr, 2,3,4,5);
		    }
		} else {
		    kerr = _NXAudioRecordStream((InputStream *)audioStream,
						snd_size,
						data_tag,
						low_water, high_water,
						reply_port, messages);
		    if (kerr != KERN_SUCCESS)
			xpr_audio_user("AU: snd_stream_msg: recordStream "
					"returns %d\n", kerr, 2,3,4,5);
		}
	    }
	}
    }
       
    if (snd_control&SND_DC_RESUME) {
	kerr = _NXAudioStreamControl(audioStream, _NXAUDIO_STREAM_RESUME,
				    time_now);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_stream_msg: streamControl returns %d\n",
	    		   kerr, 2,3,4,5);
    }

    return (error ? error : SND_NO_ERROR);
}

static void snd_get_stream_formats(void *dev, int *rates,
				   int *low_rate, int *high_rate,
				   int *encodings, int *chans)
{
    int parms[_NXAUDIO_PARAM_MAX];
    int count, continuous, i;
    kern_return_t kerr;

    kerr = _NXAudioGetSamplingRates(dev, &continuous, low_rate,
				    high_rate, parms, &count);
    if (kerr != KERN_SUCCESS)
	xpr_audio_user("AU: snd_get_stream_formats: getSamplingRates returns "
		       "%d\n", kerr, 2,3,4,5);

    *rates = 0;
    if (continuous)
	*rates |= SND_STREAM_FORMAT_RATE_CONTINUOUS;
    for (i = 0; i < count; i++) {
	if (parms[i] >= 8000 && parms[i] <= 8013)
	    *rates |= SND_STREAM_FORMAT_RATE_8000;
        else switch (parms[i]) {
	  case 11025:
	    *rates |= SND_STREAM_FORMAT_RATE_11025;
	    break;
	  case 16000:
	    *rates |= SND_STREAM_FORMAT_RATE_16000;
	    break;
	  case 22050:
	    *rates |= SND_STREAM_FORMAT_RATE_22050;
	    break;
	  case 32000:
	    *rates |= SND_STREAM_FORMAT_RATE_32000;
	    break;
	  case 44100:
	    *rates |= SND_STREAM_FORMAT_RATE_44100;
	    break;
	  case 48000:
	    *rates |= SND_STREAM_FORMAT_RATE_48000;
	    break;
	  default:
	    break;
	}
    }

    kerr = _NXAudioGetDataEncodings(dev, parms, &count);
    if (kerr != KERN_SUCCESS)
	xpr_audio_user("AU: snd_get_stream_formats: getDataEncodings returns "
		       "%d\n", kerr,2,3,4,5);

    *encodings = 0;
    for (i = 0; i < count; i++)
	switch (parms[i]) {
	  case NX_SoundStreamDataEncoding_Mulaw8:
	    *encodings |= SND_STREAM_FORMAT_ENCODING_MULAW_8;
	    break;
	  case NX_SoundStreamDataEncoding_Linear8:
	    *encodings |= SND_STREAM_FORMAT_ENCODING_LINEAR_8;
	    break;
	  case NX_SoundStreamDataEncoding_Linear16:
	    *encodings |= SND_STREAM_FORMAT_ENCODING_LINEAR_16;
	    break;
	  default:
	    break;
	}
    kerr = _NXAudioGetChannelCountLimit(dev, chans);
    if (kerr != KERN_SUCCESS)
	xpr_audio_user("AU: snd_get_stream_formats: getChanCount returns %d\n", 
			kerr, 2,3,4,5);
}

/*
 * Handle device port messages.
 */
static int snd_device_msg(msg_header_t *in_msg, msg_header_t *out_msg)
{
    int ret = SND_NO_ERROR;
    snd_get_stream_t *get_stream;
    snd_set_parms_t *set_parms;
    snd_get_volume_t *get_volume;
    snd_set_volume_t *set_volume;
    snd_set_owner_t *set_owner;
    snd_get_stream_formats_t *get_formats;
    snd_reset_owner_t *reset_owner;
    snd_new_device_t *new_device;
    u_int new_parms = 0, parms = 0;
    u_int vol;
    int lv, rv;
    int rates, low, high, encodings, chans;
    kern_return_t kerr;
    id audioChan;
    port_t new_stream, new_port;
    int stream_type;
    struct timeval time_now;
    AudioStream *audioStream;

    timerclear(&time_now);

    /*
     * The return values mean:
     * SND_NO_ERROR - no error but need a reply msg sent
     * 0 - no error, and no reply needed (we sent a reply)
     * other - error, send a reply message
     */

    switch (in_msg->msg_id) {
      case SND_MSG_GET_STREAM:
	if (in_msg->msg_size != sizeof(snd_get_stream_t))
	    return SND_BAD_PARM;
	get_stream = (snd_get_stream_t *)in_msg;
	xpr_audio_user("AU: snd_dev_msg: get_stream 0x%x\n", 
			get_stream->stream,2,3,4,5);

	if (get_stream->stream == SND_GD_SIN) {
	    audioChan =
		[IOAudio _inputChannelForSndPort:in_msg->msg_local_port];
	    xpr_audio_user("AU: snd_dev_msg: input chan 0x%x\n", audioChan, 
	    			2,3,4,5);
	    if (!(new_stream =
		  [audioChan streamUserForOwnerPort:get_stream->owner])) {
		kerr = _NXAudioAddStream(audioChan, &new_stream,
					 get_stream->owner, 0, /* id */
					 _NXAUDIO_STREAM_TYPE_SND);
		if (kerr != KERN_SUCCESS)
		    xpr_audio_user("AU: snd_dev_msg: addStream returns %d\n", 
		    			kerr, 2,3,4,5);
	    }
	} else {
	    if (get_stream->stream == SND_GD_SOUT_22)
		stream_type = _NXAUDIO_STREAM_TYPE_SND_22;
	    else
		stream_type = _NXAUDIO_STREAM_TYPE_SND_44;
	    audioChan =
		[IOAudio _outputChannelForSndPort:in_msg->msg_local_port];
	    xpr_audio_user("AU: snd_dev_msg: output chan 0x%x\n", audioChan, 
	    			2,3,4,5);
	    if (!(new_stream =
		 [audioChan streamUserForOwnerPort:get_stream->owner])) {
		kerr = _NXAudioAddStream(audioChan, &new_stream,
					 get_stream->owner, 0, /* id */
					 stream_type);
		if (kerr != KERN_SUCCESS)
		    xpr_audio_user("AU: snd_dev_msg: addStream returns %d\n", 
		    			kerr,2,3,4,5);
	    }
	}
	audio_snd_reply_ret_stream(out_msg, in_msg->msg_remote_port, new_stream);
	ret = 0;
	break;
      case SND_MSG_SET_PARMS:
	xpr_audio_user("AU: snd_dev_msg: set_parms\n", 1,2,3,4,5);
	if (in_msg->msg_size != sizeof(snd_set_parms_t))
	    return SND_BAD_PARM;
	set_parms = (snd_set_parms_t *)in_msg;

	audioChan = [IOAudio _outputChannelForSndPort:in_msg->msg_local_port];
	kerr = _NXAudioGetSndoutOptions(audioChan, &new_parms);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: getSndoutOptions returns %d\n", 
	    			kerr, 2,3,4,5);
	if (set_parms->parms&SND_PARM_ZEROFILL)
	    new_parms |= _NXAUDIO_SNDOUT_ZEROFILL;
	else
	    new_parms &= ~_NXAUDIO_SNDOUT_ZEROFILL;
	if (set_parms->parms&SND_PARM_SPEAKER)
	    new_parms |= _NXAUDIO_SNDOUT_SPEAKER_ON;	
	else
	    new_parms &= ~_NXAUDIO_SNDOUT_SPEAKER_ON;
	if (set_parms->parms&SND_PARM_LOWPASS)
	    new_parms |= _NXAUDIO_SNDOUT_DEEMPHASIS;
	else
	    new_parms &= ~_NXAUDIO_SNDOUT_DEEMPHASIS;

	kerr = _NXAudioSetSndoutOptions(audioChan, 0, new_parms);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: setSndoutOptions returns %d\n",
	    			 kerr, 2,3,4,5);
	break;
      case SND_MSG_GET_PARMS:
	xpr_audio_user("AU: snd_dev_msg: get_parms\n", 1,2,3,4,5);
	if (in_msg->msg_size != sizeof(snd_get_parms_t))
	    return SND_BAD_PARM;

	audioChan = [IOAudio _outputChannelForSndPort:in_msg->msg_local_port];
	kerr = _NXAudioGetSndoutOptions(audioChan, &new_parms);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: getSndoutOptions returns %d\n", 
	    			kerr,2,3,4,5);
	if (new_parms&_NXAUDIO_SNDOUT_ZEROFILL)
	    parms |= SND_PARM_ZEROFILL;
	if (new_parms&_NXAUDIO_SNDOUT_SPEAKER_ON)
	    parms |= SND_PARM_SPEAKER;
	if (new_parms&_NXAUDIO_SNDOUT_DEEMPHASIS)
	    parms |= SND_PARM_LOWPASS;

	audio_snd_reply_ret_parms(out_msg, in_msg->msg_remote_port, parms);
	ret = 0;
	break;
      case SND_MSG_SET_VOLUME:
	xpr_audio_user("AU: snd_dev_msg: set_vol\n", 1,2,3,4,5);
	if (in_msg->msg_size != sizeof(snd_set_volume_t))
	    return SND_BAD_PARM;
	set_volume = (snd_set_volume_t *)in_msg;

	vol = set_volume->volume;
	lv = ((vol&SND_VOLUME_LCHAN_MASK) >>SND_VOLUME_LCHAN_SHIFT);
	rv = ((vol&SND_VOLUME_RCHAN_MASK) >>SND_VOLUME_RCHAN_SHIFT);
	xpr_audio_user("AU: snd_dev_msg: set_vol: %d %d\n", lv, rv, 3,4,5);
	/*
	 * Convert from range [1,43] to [-84,0].
	 */
	lv = ((lv-1)*2)-84;
	rv = ((rv-1)*2)-84;
	audioChan = [IOAudio _outputChannelForSndPort:in_msg->msg_local_port];
	kerr = _NXAudioSetSpeaker(audioChan, 0, lv, rv);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: setSpeaker returns %d\n", kerr,
			   2,3,4,5);
	break;
      case SND_MSG_GET_VOLUME:
	xpr_audio_user("AU: snd_dev_msg: get_vol\n", 1,2,3,4,5);
	if (in_msg->msg_size != sizeof(snd_get_volume_t))
	    return SND_BAD_PARM;
	get_volume = (snd_get_volume_t *)in_msg;

	audioChan = [IOAudio _outputChannelForSndPort:in_msg->msg_local_port];
	kerr = _NXAudioGetSpeaker(audioChan, &lv, &rv);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: getSpeaker returns %d\n", kerr,
			   2,3,4,5);
	/*
	 * Convert from range [-84,0] to [1,43].
	 */
	lv = 43 + (lv/2);
	rv = 43 + (rv/2);
	vol = (lv<<SND_VOLUME_LCHAN_SHIFT) | (rv<<SND_VOLUME_RCHAN_SHIFT);

	xpr_audio_user("AU: snd_dev_msg: get_vol: %d %d\n", lv, rv, 3,4,5);
	audio_snd_reply_ret_volume(out_msg, in_msg->msg_remote_port, vol);
	ret = 0;
	break;
	/* New for 3.1 */
      case SND_MSG_GET_SNDOUT_FORMATS:
	xpr_audio_user("AU: snd_dev_msg: get_sndout_formats\n", 1,2,3,4,5);
	if (in_msg->msg_size != sizeof(snd_get_stream_formats_t))
	    return SND_BAD_PARM;
	get_formats = (snd_get_stream_formats_t *)in_msg;
	  
	audioChan = [IOAudio _outputChannelForSndPort:in_msg->msg_local_port];
	snd_get_stream_formats(audioChan, &rates, &low, &high,
			       &encodings, &chans);
	audio_snd_reply_ret_formats(out_msg, in_msg->msg_remote_port,
			      rates, low, high,
			      encodings, chans);
	ret = 0;
	break;
      case SND_MSG_GET_SNDIN_FORMATS:
	xpr_audio_user("AU: snd_dev_msg: get_sndin_formats\n", 1,2,3,4,5);
	if (in_msg->msg_size != sizeof(snd_get_stream_formats_t))
	    return SND_BAD_PARM;
	get_formats = (snd_get_stream_formats_t *)in_msg;
	  
	audioChan = [IOAudio _inputChannelForSndPort:in_msg->msg_local_port];
	snd_get_stream_formats(audioChan, &rates, &low, &high,
			       &encodings, &chans);
	audio_snd_reply_ret_formats(out_msg, in_msg->msg_remote_port,
			      rates, low, high,
			      encodings, chans);
	ret = 0;
	break;
      case SND_MSG_SET_RAMP:
	xpr_audio_user("AU: snd_dev_msg: set_ramp\n", 1,2,3,4,5);
	if (in_msg->msg_size != sizeof(snd_set_parms_t))
	    return SND_BAD_PARM;
	set_parms = (snd_set_parms_t *)in_msg;

	audioChan = [IOAudio _outputChannelForSndPort:in_msg->msg_local_port];
	kerr = _NXAudioGetSndoutOptions(audioChan, &new_parms);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: getSndoutOptions returns %d\n", 
	    		kerr, 2,3,4,5);
	if (set_parms->parms&SND_PARM_RAMPUP)
	    new_parms |= _NXAUDIO_SNDOUT_RAMPUP;
	else
	    new_parms &= ~_NXAUDIO_SNDOUT_RAMPUP;
	if (set_parms->parms&SND_PARM_RAMPDOWN)
	    new_parms |= _NXAUDIO_SNDOUT_RAMPDOWN;
	else
	    new_parms &= ~_NXAUDIO_SNDOUT_RAMPDOWN;

	kerr = _NXAudioSetSndoutOptions(audioChan, 0, new_parms);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: setSndoutOptions returns %d\n", 
	    		kerr,2,3,4,5);
	break;
      case SND_MSG_SET_DSPOWNER:
	xpr_audio_user("AU: snd_dev_msg: set_dspowner\n", 1,2,3,4,5);
	/*
	 * DSP is never available.
	 */
	return SND_SEARCH;
	break;
      case SND_MSG_SET_SNDINOWNER:
	if (in_msg->msg_size != sizeof(snd_set_owner_t))
	    return SND_BAD_PARM;
	set_owner = (snd_set_owner_t *)in_msg;
	xpr_audio_user("AU: snd_dev_msg: set_sndinowner 0x%x\n", 
			set_owner->owner,2,3,4,5);
	/*
	 * Abort (reset) stream if asserting same owner port.
	 */
	if ((audioStream =
	     [AudioChannel streamForOwnerPort:set_owner->owner])) {
	    kerr = _NXAudioStreamControl(audioStream,
					 _NXAUDIO_STREAM_ABORT, time_now);
	    if (kerr != KERN_SUCCESS)
		xpr_audio_user("AU: snd_dev_msg: streamControl returns %d\n", 
				kerr,2,3,4,5);
	}
	break;
      case SND_MSG_SET_SNDOUTOWNER:
	if (in_msg->msg_size != sizeof(snd_set_owner_t))
	    return SND_BAD_PARM;
	set_owner = (snd_set_owner_t *)in_msg;
	xpr_audio_user("AU: snd_dev_msg: set_sndoutowner 0x%x\n", 
			set_owner->owner, 2,3,4,5);
	/*
	 * Abort (reset) stream if asserting same owner port.
	 */
	if ((audioStream =
	     [AudioChannel streamForOwnerPort:set_owner->owner])) {
	    kerr = _NXAudioStreamControl(audioStream,
					 _NXAUDIO_STREAM_ABORT, time_now);
	    if (kerr != KERN_SUCCESS)
		xpr_audio_user("AU: snd_dev_msg: streamControl returns %d\n", 
				kerr, 2,3,4,5);
	}
	break;
      case SND_MSG_NEW_DEVICE_PORT:
	/*
	 * This is only marginally useful now, since the NXSound device
	 * ports do NOT get reset by this message.
	 */
	if (in_msg->msg_size != sizeof(snd_new_device_t))
	    return SND_BAD_PARM;
	new_device = (snd_new_device_t *)in_msg;
	xpr_audio_user("AU: snd_dev_msg: new_device_port\n", 1,2,3,4,5);
	/*
	 * Note: input and output chans share the same user msg device port.
	 */
	audioChan = [IOAudio _outputChannelForSndPort: in_msg->msg_local_port];
	new_port = audio_reset_snd_dev_port([audioChan audioDevice],
					    new_device->priv);
	if (new_port == PORT_NULL)
	    return SND_BAD_HOST_PRIV;

	[audioChan removeSndStreams];
	audioChan = [IOAudio _inputChannelForSndPort: in_msg->msg_local_port];
	[audioChan removeSndStreams];

	audio_snd_reply_ret_device(out_msg, in_msg->msg_remote_port, new_port);
	ret = 0;
	break;
      case SND_MSG_RESET_SNDINOWNER:
	if (in_msg->msg_size != sizeof(snd_reset_owner_t))
	    return SND_BAD_PARM;
	reset_owner = (snd_reset_owner_t *)in_msg;
	xpr_audio_user("AU: snd_dev_msg: reset_sndinowner 0x%x\n",
		       reset_owner->old_owner, 2,3,4,5);
	audioStream = [AudioChannel streamForOwnerPort:reset_owner->old_owner];
	if (!audioStream)
	    return SND_NOT_OWNER;
	kerr = _NXAudioRemoveStream(audioStream);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: removeStream returns %d\n", kerr,
			   2,3,4,5);
	break;
      case SND_MSG_RESET_SNDOUTOWNER:
	if (in_msg->msg_size != sizeof(snd_reset_owner_t))
	    return SND_BAD_PARM;
	reset_owner = (snd_reset_owner_t *)in_msg;
	xpr_audio_user("AU: snd_dev_msg: reset_sndoutowner 0x%x\n",
		       reset_owner->old_owner, 2,3,4,5);
	audioStream = [AudioChannel streamForOwnerPort:reset_owner->old_owner];
	if (!audioStream)
	    return SND_NOT_OWNER;
	kerr = _NXAudioRemoveStream(audioStream);
	if (kerr != KERN_SUCCESS)
	    xpr_audio_user("AU: snd_dev_msg: removeStream returns %d\n", kerr,
			   2,3,4,5);
	break;
      case SND_MSG_DSP_PROTO:
      case SND_MSG_GET_DSP_CMD_PORT:
      case SND_MSG_RESET_DSPOWNER:
	xpr_audio_user("AU: snd_dev_msg: dsp msg\n", 1,2,3,4,5);
	/*
	 * DSP is never available.
	 */
	return SND_SEARCH;
	break;
      default:
	/* impossible */
	break;
    }
    return ret;
}

/*
 * Handle in_msg and setup out_msg for reply.
 */
boolean_t snd_server(msg_header_t *in_msg, msg_header_t *out_msg)
{
    boolean_t ret = TRUE;
    int reply_val = 0;

    /*
     * Standard reply header.
     */
    out_msg->msg_simple = TRUE;
    out_msg->msg_size = sizeof(msg_header_t);
    out_msg->msg_type = MSG_TYPE_NORMAL;
    out_msg->msg_local_port = PORT_NULL;
    out_msg->msg_remote_port = PORT_NULL;
    out_msg->msg_id = 0;

    if (in_msg->msg_id >= SND_MSG_STREAM_BASE &&
	in_msg->msg_id <= SND_MSG_STREAM_NSAMPLES)
	reply_val = snd_stream_msg(in_msg, out_msg);
    else if (in_msg->msg_id >= SND_MSG_DEVICE_BASE &&
	     in_msg->msg_id <= SND_MSG_GET_SNDIN_FORMATS)
	reply_val = snd_device_msg(in_msg, out_msg);
    else if (in_msg->msg_id >= SND_MSG_DSP_BASE &&
	     in_msg->msg_id <= SND_MSG_DSP_REQ_ERR) {
	/*
	 * Should not happen since you can't set a dsp owner port.
	 */
	log_error(("Audio: received dsp cmd port msg!\n"));
	audio_snd_reply_illegal_msg(out_msg, PORT_NULL, in_msg->msg_remote_port,
			      in_msg->msg_id, SND_BAD_MSG);
	ret = FALSE;
    } else {
	audio_snd_reply_illegal_msg(out_msg, PORT_NULL, in_msg->msg_remote_port,
			      in_msg->msg_id, SND_BAD_MSG);
	ret = FALSE;
    }
    /*
     * Send a reply if msg handler routine didn't.
     */
    if (reply_val)
	audio_snd_reply_illegal_msg(out_msg, PORT_NULL, in_msg->msg_remote_port,
			      in_msg->msg_id, reply_val);
    return ret;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.