mirror of
				https://github.com/alsa-project/alsa-tools.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			166 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/***************************************************************************/
 | 
						|
/*  This code has been fully inspired from various place                   */
 | 
						|
/*  I will give their name later. May they be bless .... It works   	   */
 | 
						|
/*                                                                         */
 | 
						|
/*	For the moment test it.                                            */   
 | 
						|
/*									   */
 | 
						|
/* 27-08-00 -- Ze'ev Maor -- fixed recovery from flase syncword detection  */
 | 
						|
/* 								           */
 | 
						|
/* 24-08-00 -- Ze'ev Maor -- Modified for integrtion with DXR3-OMS-plugin  */  
 | 
						|
/***************************************************************************/
 | 
						|
									   
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <string.h>
 | 
						|
#include <inttypes.h>
 | 
						|
 | 
						|
#include <libac3/ac3.h>
 | 
						|
#include <libac3/ac3_internal.h>
 | 
						|
#include <libac3/parse.h>
 | 
						|
#include <libac3/crc.h>
 | 
						|
 | 
						|
#include "output.h"
 | 
						|
 | 
						|
void swab(const void*, void*, size_t);
 | 
						|
 | 
						|
#define BLOCK_SIZE 6144
 | 
						|
 | 
						|
static unsigned char buf[BLOCK_SIZE];
 | 
						|
static uint32_t sbuffer_size;
 | 
						|
static syncinfo_t syncinfo;
 | 
						|
static char *sbuffer;
 | 
						|
static int done_banner;
 | 
						|
 | 
						|
static uint32_t
 | 
						|
buffer_syncframe(syncinfo_t *syncinfo, uint8_t **start, uint8_t *end)
 | 
						|
{
 | 
						|
  uint8_t *cur = *start;
 | 
						|
  uint16_t syncword = syncinfo->syncword;
 | 
						|
  uint32_t ret = 0;
 | 
						|
 
 | 
						|
  //
 | 
						|
  // Find an ac3 sync frame.
 | 
						|
  //
 | 
						|
  while(syncword != 0x0b77)
 | 
						|
    {
 | 
						|
      if(cur >= end)
 | 
						|
	goto done;
 | 
						|
      syncword = (syncword << 8) + *cur++;
 | 
						|
    }
 | 
						|
 
 | 
						|
  //need the next 3 bytes to decide how big the frame is
 | 
						|
  while(sbuffer_size < 3)
 | 
						|
    {
 | 
						|
      if(cur >= end)
 | 
						|
	goto done;
 | 
						|
 
 | 
						|
      sbuffer[sbuffer_size++] = *cur++;
 | 
						|
    }
 | 
						|
                                                                                    
 | 
						|
  parse_syncinfo_data(syncinfo,sbuffer);
 | 
						|
 
 | 
						|
  while(sbuffer_size < (uint32_t)syncinfo->frame_size * 2 - 2)
 | 
						|
    {
 | 
						|
      if(cur >= end)
 | 
						|
	goto done;
 | 
						|
 
 | 
						|
      sbuffer[sbuffer_size++] = *cur++;
 | 
						|
    }
 | 
						|
 
 | 
						|
  crc_init();
 | 
						|
  crc_process_frame(sbuffer,syncinfo->frame_size * 2 - 2);
 | 
						|
	
 | 
						|
  if(!crc_validate())
 | 
						|
    {
 | 
						|
      //error_flag = 1;
 | 
						|
      fprintf(stderr,"** CRC failed - skipping frame **\n");
 | 
						|
      syncword = 0xffff;
 | 
						|
      sbuffer_size = 0;
 | 
						|
      bzero(buf,BLOCK_SIZE);
 | 
						|
 | 
						|
      goto done;
 | 
						|
    }                                                                           
 | 
						|
  //
 | 
						|
  //if we got to this point, we found a valid ac3 frame to decode
 | 
						|
  //
 | 
						|
 
 | 
						|
  //reset the syncword for next time
 | 
						|
  syncword = 0xffff;
 | 
						|
  sbuffer_size = 0;
 | 
						|
  ret = 1;
 | 
						|
 
 | 
						|
 done:
 | 
						|
  syncinfo->syncword = syncword;
 | 
						|
  *start = cur;
 | 
						|
  return ret;
 | 
						|
}                                                                                  
 | 
						|
 | 
						|
void
 | 
						|
init_spdif(void)
 | 
						|
{
 | 
						|
  sbuffer_size = 0;
 | 
						|
  sbuffer = &buf[10];
 | 
						|
  done_banner = 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
output_spdif_zero(int frames)
 | 
						|
{
 | 
						|
  int res;
 | 
						|
 | 
						|
  buf[0] = 0x72; buf[1] = 0xf8;  // spdif syncword
 | 
						|
  buf[2] = 0x1f; buf[3] = 0x4e;  // ..............
 | 
						|
  buf[4] = 0x00;		 // null frame (no data) 
 | 
						|
  buf[5] = 7 << 5;		 // stream = 7
 | 
						|
  buf[6] = 0x00; buf[7] = 0x00;  // frame size
 | 
						|
  memset(&buf[8], 0, BLOCK_SIZE - 8);
 | 
						|
  while (frames-- > 0) {
 | 
						|
    res = output_play((short *)buf, BLOCK_SIZE / 2 / 2);	/* 2 channels, 16-bit samples */
 | 
						|
    if (res < 0)
 | 
						|
      return res;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
output_spdif_leadin(void)
 | 
						|
{
 | 
						|
  memset(buf, 0, 8);
 | 
						|
  return output_play((short *)buf, 8);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
output_spdif(uint8_t *data_start, uint8_t *data_end, int quiet)
 | 
						|
{
 | 
						|
  int ret = 0, res;
 | 
						|
  
 | 
						|
  while(buffer_syncframe(&syncinfo, &data_start, data_end))
 | 
						|
    {
 | 
						|
      buf[0] = 0x72; buf[1] = 0xf8;	// spdif syncword
 | 
						|
      buf[2] = 0x1f; buf[3] = 0x4e;	// ..............
 | 
						|
      buf[4] = 0x01;			// AC3 data
 | 
						|
      buf[5] = buf[13] & 7;		// bsmod, stream = 0
 | 
						|
      buf[6] = (syncinfo.frame_size * 16) & 0xff;
 | 
						|
      buf[7] = ((syncinfo.frame_size * 16) >> 8) & 0xff;
 | 
						|
      buf[8] = 0x77; buf[9] = 0x0b;	// AC3 syncwork
 | 
						|
      
 | 
						|
      if (!done_banner && !quiet) {
 | 
						|
        fprintf(stdout,"AC3 Stream ");
 | 
						|
	fprintf(stdout,"%2.1f KHz",syncinfo.sampling_rate * 1e-3);
 | 
						|
        fprintf(stdout,"%4d kbps",syncinfo.bit_rate);
 | 
						|
        fprintf(stdout,"\n");
 | 
						|
        done_banner = 1;
 | 
						|
      }
 | 
						|
      
 | 
						|
#ifndef _a_b_c_d_e_f /* WORDS_BIGENDIAN */
 | 
						|
      // extract_ac3 seems to write swabbed data
 | 
						|
      swab(&buf[10], &buf[10], syncinfo.frame_size * 2 - 2);
 | 
						|
#endif
 | 
						|
      res = output_play((short *)buf, BLOCK_SIZE / 2 / 2);	/* 2 channels, 16-bit samples */
 | 
						|
      ret = ret < 0 ? ret : res;
 | 
						|
      bzero(buf,BLOCK_SIZE);
 | 
						|
    }
 | 
						|
  return ret;
 | 
						|
}
 |