/***************************************************************************
 *   Copyright (C) 2008 by SK Communications.                              *
 *   http://kldp.net/projects/nateon/                                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "config.h"

#include <kmessagebox.h>
#include <kdebug.h>

#include "sound.h"
#include "knateoncommon.h"

#define	SCERR_NO_FILE		-10	// 파일이 없음
#define	SCERR_NOT_OPEN		-11	// 파일이 열 수 없음
#define	SCERR_NOT_WAV_FILE	-12	// WAV 파일이 아님
#define	SCERR_NO_wav_info	-13	// WAV 포맷 정보가 없음
#define	BUFF_SIZE		1024

void MyClass::run()
{
	KMessageBox::information( 0, UTF8("KDE 시스템의 소리설정(arts)에 문제가 있는것 같습니다. 이 메시지를 보기 원하지 않으시면, 버디 목록 창의 '설정' 메뉴에서 '환경설정'의 '알림/소리' 탭의 '알림 시 소리사용' 선택을 없애주십시요."), UTF8("소리 알림 에러"), "OnlyOneShowSoundError" );
}


Sound::Sound()
{
}

Sound::~Sound()
{
}

bool Sound::soundInitiated = false;
QString Sound::fileName;
pthread_t Sound::soundThread;

fd_sound_format_t Sound::soundcard_open_file(QString filename) {
	unsigned long data_offset = 0;       // wav 플레이용 파일 오프셋
	int read_size;
	unsigned char buff[BUFF_SIZE+5];
	
	unsigned char *ptr;
	
	fd_sound_format_t wave_info;

	if ( 0 != access(filename, R_OK ) ) {                             // 파일이 없음
		wave_info.fd = SCERR_NO_FILE;
		return wave_info;
	}
	
	wave_info.fd = open(filename, O_RDONLY );
	if ( 0 > wave_info.fd) {                                             // 파일 열기 실패
		wave_info.fd = SCERR_NOT_OPEN;
		return wave_info;
	}
	
	// 헤더 부분 처리
	memset(buff, 0, BUFF_SIZE);
	read_size = read(wave_info.fd, buff, BUFF_SIZE);
	
	if ( 0 == memmem( buff, BUFF_SIZE, "RIFF", 4 )) {               // "RIFF" 문자열이 있는가를 검사한다.
		wave_info.fd = SCERR_NOT_WAV_FILE;
		return wave_info;
	}

	if ( 0 == memmem( buff, BUFF_SIZE, "WAVE", 4 )) {               // "WAVE" 문자열이 있는가를 검사한다.
		wave_info.fd = SCERR_NOT_WAV_FILE;
		return wave_info;
	}

	ptr = (unsigned char *)memmem( buff, BUFF_SIZE, "fmt ", 4 ); // 포맷 정보를 구한다.
	if ( NULL == ptr) {
		wave_info.fd = SCERR_NO_wav_info;
		return wave_info;
	}
	
	// 각 속성을 구한다
	ptr += 10;
	memcpy(&wave_info.channels, ptr, sizeof(int));
	wave_info.channels &= 0x00FF;
	
	ptr += 2;
	memcpy(&wave_info.rate, ptr, sizeof(int));
	wave_info.rate &= 0xFFFF;
	
	ptr += 10;
	memcpy(&wave_info.data_bit, ptr, sizeof(int));
	wave_info.data_bit &= 0x00FF;
	
	//printf( "CHANNEL   = %d\n", wave_info.channels );
	//printf( "DATA BITS = %d\n", wave_info.data_bit);
	//printf( "RATE      = %d\n", wave_info.rate);
	
	ptr = (unsigned char *)memmem( buff, BUFF_SIZE, "data", 4 );
	ptr += 8;
	
	data_offset = (unsigned long)( ptr - buff );
	
	lseek( wave_info.fd, data_offset , SEEK_SET );                      // 파일 읽기 위치를 데이터 위치로 이동 시킨다.
	
	return wave_info;
}

void* Sound::soundPlay(void* p) {
	/* libao 사용 */
	int default_driver;
	ao_device *device;
	
	default_driver = ao_default_driver_id();
	

	// 원하는 파일을 오픈한다.
	fd_sound_format_t wav_info;
	
	wav_info = soundcard_open_file(fileName);
	int fd = wav_info.fd;
	//printf("opening FD= %d\n", fd);
	switch( fd) {
		case  SCERR_NO_FILE        :  printf( "WAV 파일이 없음");
		case  SCERR_NOT_OPEN       :  printf( "WAV 파일을 열 수 없음");
		case  SCERR_NOT_WAV_FILE   :  printf( "WAV 파일이 아님");
		case  SCERR_NO_wav_info  :  printf( "WAV 정보가 없음");
	}
	
	/* format 설정 */	
	ao_sample_format format;
	format.channels = wav_info.channels;
	format.bits = wav_info.data_bit;
	format.rate = wav_info.rate;
	format.byte_format = AO_FMT_LITTLE;
	
	int buf_size;
	char* buffer;
	
	buf_size = format.bits/8 * format.channels * format.rate;
	
	buffer = (char *) malloc(buf_size);

	ssize_t bytes;
	
	/* -- Open driver -- */
	device = ao_open_live(default_driver, &format, NULL /* no options */);
	if (device == NULL) {
		fprintf(stderr, "Error opening device.\n");
		pthread_exit(NULL);
	}
	
	// 파일을 읽어서 쓴다
	while((bytes = read(fd, buffer, buf_size)) > 0) {
		int i;
		ao_play(device, buffer, buf_size);
		for(i=0;i<buf_size;i++) buffer[i]=NULL; /* 버퍼를 비운다 */
	}
	
	free(buffer);
	close(fd);
	//printf("closing file FD= %d\n", fd);
	
	ao_close(device);
	
	pthread_exit(0);
}

void Sound::shutdown(void* p) {
	ao_shutdown();
}

void Sound::play(QString sFile) {	
	//printf("Testing AO\n");
	fileName = sFile;
	
	if(!soundInitiated) {
		ao_initialize(); /* 초기화 */
		soundInitiated = true;
	}
	else {
		pthread_create(&soundThread, NULL, Sound::soundPlay, NULL);
	}
	//pthread_join(soundThread, NULL);
	return;
}

