view libao2/ao_dxr2.c @ 12350:b8465343c991

sync
author wight
date Thu, 29 Apr 2004 16:48:56 +0000
parents 99798c3cdb93
children c1955840883d
line wrap: on
line source

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <inttypes.h>
#include <dxr2ioctl.h>
#include "../config.h"
#include "mp_msg.h"
#include "bswap.h"

#include "audio_out.h"
#include "audio_out_internal.h"

#include "afmt.h"


static ao_info_t info =
{
	"DXR2 audio output",
	"dxr2",
	"Tobias Diedrich <ranma@gmx.at>",
	""
};

LIBAO_EXTERN(dxr2)

static int volume=19;
extern int dxr2_fd;

// to set/get/query special features/parameters
static int control(int cmd,void *arg){
  switch(cmd){
  case AOCONTROL_GET_VOLUME:
    if(dxr2_fd > 0) {
      ao_control_vol_t* vol = (ao_control_vol_t*)arg;
      vol->left = vol->right = volume * 19.0 / 100.0;
      return CONTROL_OK;
    }
    return CONTROL_ERROR;
  case AOCONTROL_SET_VOLUME:
    if(dxr2_fd > 0) {
      dxr2_oneArg_t v;
      float diff;
      ao_control_vol_t* vol = (ao_control_vol_t*)arg;
      // We need this trick because the volume stepping is often too small
      diff = ((vol->left+vol->right) / 2 - (volume*19.0/100.0)) * 19.0 / 100.0;
      v.arg = volume + (diff > 0 ? ceil(diff) : floor(diff)); 
      if(v.arg > 19) v.arg = 19;
      if(v.arg < 0) v.arg = 0;
      if(v.arg != volume) {
	volume = v.arg;
	if( ioctl(dxr2_fd,DXR2_IOC_SET_AUDIO_VOLUME,&v) < 0) {
	  mp_msg(MSGT_AO,MSGL_ERR,"DXR2 : Setting volume to %d failed\n",volume);
	  return CONTROL_ERROR;
	}
      }
      return CONTROL_OK;
    }
    return CONTROL_ERROR;
  }
  return CONTROL_UNKNOWN;
}

static int freq=0;
static int freq_id=0;

// open & setup audio device
// return: 1=success 0=fail
static int init(int rate,int channels,int format,int flags){

	if(dxr2_fd <= 0)
	  return 0;

	ao_data.outburst=2048;
	ao_data.samplerate=rate;
	ao_data.channels=channels;
	ao_data.buffersize=2048;
	ao_data.bps=rate*4;
	ao_data.format=format;
	freq=rate;

	switch(rate){
	case 48000:
		freq_id=DXR2_AUDIO_FREQ_48;
		break;
	case 96000:
		freq_id=DXR2_AUDIO_FREQ_96;
		break;
	case 44100:
		freq_id=DXR2_AUDIO_FREQ_441;
		break;
	case 32000:
		freq_id=DXR2_AUDIO_FREQ_32;
		break;
	case 22050:
		freq_id=DXR2_AUDIO_FREQ_2205;
		break;
#ifdef DXR2_AUDIO_FREQ_24
	// This is not yet in the dxr2 driver CVS
	// you can get the patch at
	// http://www.ranmachan.dyndns.org/~ranma/patches/dxr2.pcm1723.20020513
	case 24000:
		freq_id=DXR2_AUDIO_FREQ_24;
		break;
	case 64000:
		freq_id=DXR2_AUDIO_FREQ_64;
		break;
	case 88200:
		freq_id=DXR2_AUDIO_FREQ_882;
		break;
#endif
	default:
		mp_msg(MSGT_AO,MSGL_ERR,"[AO] dxr2: %d Hz not supported, try \"-aop list=resample\"\n",rate);
		return 0;
	}

	return 1;
}

// close audio device
static void uninit(int immed){

}

// stop playing and empty buffers (for seeking/pause)
static void reset(){

}

// stop playing, keep buffers (for pause)
static void audio_pause()
{
    // for now, just call reset();
    reset();
}

// resume playing, after audio_pause()
static void audio_resume()
{
}

extern void dxr2_send_packet(unsigned char* data,int len,int id,int timestamp);
extern void dxr2_send_lpcm_packet(unsigned char* data,int len,int id,int timestamp,int freq_id);
extern int vo_pts;
// return: how many bytes can be played without blocking
static int get_space(){
    float x=(float)(vo_pts-ao_data.pts)/90000.0;
    int y;
    if(x<=0) return 0;
    y=freq*4*x;y/=ao_data.outburst;y*=ao_data.outburst;
    if(y>32768) y=32768;
    return y;
}

// plays 'len' bytes of 'data'
// it should round it down to outburst*n
// return: number of bytes played
static int play(void* data,int len,int flags){
  // MPEG and AC3 don't work :-(
    if(ao_data.format==AFMT_MPEG)
	dxr2_send_packet(data,len,0xC0,ao_data.pts);
    else if(ao_data.format==AFMT_AC3)
      	dxr2_send_packet(data,len,0x80,ao_data.pts);
    else {
	int i;
	//unsigned short *s=data;
	uint16_t *s=data;
#ifndef WORDS_BIGENDIAN
	for(i=0;i<len/2;i++) s[i] = bswap_16(s[i]);
#endif
	dxr2_send_lpcm_packet(data,len,0xA0,ao_data.pts-10000,freq_id);
    }
    return len;
}

// return: delay in seconds between first and last sample in buffer
static float get_delay(){

    return 0.0;
}