PDA 수업 - 실은 컴퓨터 네트워크 수업인데; 실습과제를 하라고 PDA 를 하나 주는 바람에 이름지어진 - 의 마지막 과제는 IPV6 를 이용한 실시간 음성 통신입니다
무선랜 상태에서 IPV6 를 이용한 신뢰성있으면 혼잡제어가 가능한 데이터그램 통신보다는 쉬워보입니다만... 그래도 '실시간'과 '음성' 그리고 '통신'이 들어가니 나름 괴롭네요 = =)>
일단 리눅스에서 wave 파일 연주를 해야하기 때문에 VMWare Player 와 우분투를 설치했습니다. (흑흑-_- 이거 안하려고 운영체제 실습도 철회했는데 결국 리눅스를 깔아야하는군요)
요즘에는 우분투 이미지를 따로 올려주어서 설치하기는 편하더군요.
모양도 이쁘고... 백스페이스 두번 눌렀을때 다운만 안되면 정말 좋았을 겁니다 ㄱ-)/
일단 리눅스의 사운드 연주 소스입니다.
#!/usr/bin/python
import linuxaudiodev
import wave
src = wave.open("test.wav", "rb")
channels, bytes, freq, frameCount, compType, compName = src.getparams()
dsp = linuxaudiodev.open("/dev/dsp", "w")
dsp.setparameters(freq, bytes*8, channels, linuxaudiodev.AFMT_S16_LE, False)
frameStep = 1000
for pos in range(0, frameCount, frameStep):
buf = src.readframes(frameStep)
dsp.write(buf)
리눅스에서 사운드 플레이를 정말 쉽습니다 -_-)~ 그냥 모든게 파일이라 좋아요.
하지만 역발상의 대가 윈도우에서는 유닉스와는 다른길을 걷기 때문에
위의 코드로 작동이 되지 않습니다 -_-)> wav 파일이라면 winsound 라는 모듈을 지원하지만
지금 작업은 RAW 데이터를 플레이하는거라서 직접 wave파일에 접근해야합니다.
다행히 http://www.johnnypops.demon.co.uk/ 라는 사이트에서
녹음 기능을 ctypes 로 구현해놓은것이 있어서 (정말 좋은 사람이예요 >ㅁ<)/ )
이 소스를 활용해 같은 기능을 하는 프로그램을 만들어보았습니다.
(c++ 객체만 ctypes 로 꺼낼수 있으면 정말 행복할거예요)
more..
from ctypes import *
winmm = windll.winmm
kernel32 = windll.kernel32
kernel32.CreateEventW.restype = c_ulong
WAVE_FORMAT_PCM = 1
WAVE_MAPPER = -1
CALLBACK_NULL = 0x00000000
CALLBACK_WINDOW = 0x00010000
CALLBACK_TASK = 0x00020000
CALLBACK_FUNCTION = 0x00030000
CALLBACK_THREAD = CALLBACK_TASK
CALLBACK_EVENT = 0x00050000
WAVE_FORMAT_QUERY = 0x0001
WAVE_ALLOWSYNC = 0x0002
WAVE_MAPPED = 0x0004
WAVE_FORMAT_DIRECT = 0x0008
WAVE_INVALIDFORMAT = 0x00000000 # invalid format
WAVE_FORMAT_1M08 = 0x00000001 # 11.025 kHz, Mono, 8-bit
WAVE_FORMAT_1S08 = 0x00000002 # 11.025 kHz, Stereo, 8-bit
WAVE_FORMAT_1M16 = 0x00000004 # 11.025 kHz, Mono, 16-bit
WAVE_FORMAT_1S16 = 0x00000008 # 11.025 kHz, Stereo, 16-bit
WAVE_FORMAT_2M08 = 0x00000010 # 22.05 kHz, Mono, 8-bit
WAVE_FORMAT_2S08 = 0x00000020 # 22.05 kHz, Stereo, 8-bit
WAVE_FORMAT_2M16 = 0x00000040 # 22.05 kHz, Mono, 16-bit
WAVE_FORMAT_2S16 = 0x00000080 # 22.05 kHz, Stereo, 16-bit
WAVE_FORMAT_4M08 = 0x00000100 # 44.1 kHz, Mono, 8-bit
WAVE_FORMAT_4S08 = 0x00000200 # 44.1 kHz, Stereo, 8-bit
WAVE_FORMAT_4M16 = 0x00000400 # 44.1 kHz, Mono, 16-bit
WAVE_FORMAT_4S16 = 0x00000800 # 44.1 kHz, Stereo, 16-bit
WHDR_DONE = 0x00000001
WHDR_PREPARED = 0x00000002
WHDR_BEGINLOOP = 0x00000004
WHDR_ENDLOOP = 0x00000008
WHDR_INQUEUE = 0x00000010
MMSYSTEM_NOERROR = 0
class WAVEFORMATEX(Structure):
_fields_ = [
('FormatTag', c_ushort),
('Channels', c_ushort),
('SamplesPerSec', c_ulong),
('AvgBytesPerSec', c_ulong),
('BlockAlign', c_ushort),
('BitsPerSample', c_ushort),
('cbSize', c_ushort),
]
def SetFormat(self, bits, freq, channels):
self.FormatTag = WAVE_FORMAT_PCM
self.Channels = channels
self.BitsPerSample = bits
self.BlockAlign = channels*bits/8
self.SamplesPerSec = freq
self.AvgBytesPerSec = freq*self.BlockAlign
self.cbSize = 0
class AudioBuffer(Structure):
""" Wraps up a WAVEHDR and audio data."""
_fields_ = [
('lpData', c_void_p),
('BufferLength', c_ulong),
('BytesRecorded', c_ulong),
('User', c_ulong),
('Flags', c_ulong),
('Loops', c_ulong),
('lpNext', c_ulong),
('reserved', c_ulong),
]
def __init__(self, hWave, block_len):
Structure.__init__(self)
self.handle = hWave
self.membuf = create_string_buffer(block_len)
self.lpData = cast(self.membuf, c_void_p)
self.BufferLength = block_len
self.Flags = 0
self.BytesRecorded = 0
self.User = 0
self.Loops = 0
self.lpNext = 0
self.reserved = 0
def inPrepare(self):
return winmm.waveInPrepareHeader(self.handle, byref(self), sizeof(self))
def inAdd(self):
return winmm.waveInAddBuffer(self.handle, byref(self), sizeof(self))
def inUnprepare(self):
return winmm.waveInUnprepareHeader(self.handle, byref(self), sizeof(self))
def __len__(self):
return self.BytesRecorded
def read(self):
return self.membuf[:self.BytesRecorded]
def outPrepare(self):
print "prepare"
return winmm.waveOutPrepareHeader(self.handle, byref(self), sizeof(self))
def outDone(self):
self.Flags |= WHDR_DONE
def write(self, s):
memmove(self.membuf, s, len(s))
def outWrite(self):
return winmm.waveOutWrite(self.handle, byref(self), sizeof(self))
def outUnprepare(self):
return winmm.waveOutUnprepareHeader(self.handle, byref(self), sizeof(self))
class Audio:
def __init__(self, freq, bits, channels, bufsize, bufcount):
self.waveHdrList = []
self.waveHdrCount = bufcount
self.waveHdrNext = 0
self.hWaveOut = None
self.hDoneEvent = kernel32.CreateEventA(None, False, True, None)
wf = WAVEFORMATEX()
wf.SetFormat(bits, freq, channels)
self.hWaveOut = c_long()
res = winmm.waveOutOpen(byref(self.hWaveOut),
WAVE_MAPPER,
byref(wf),
self.hDoneEvent, 0, CALLBACK_EVENT)
if res != MMSYSTEM_NOERROR:
raise IOError, "CANNOT_OPEN_AUDIO_DEVICE"
for i in range(bufcount):
buff = AudioBuffer(self.hWaveOut, bufsize)
buff.outPrepare()
buff.outDone()
self.waveHdrList.append(buff)
def Write(self, buf):
if self.waveHdrNext >= self.waveHdrCount:
raise IOError, "AUDIO_DEVICE_NOT_READY"
wh = self.waveHdrList[self.waveHdrNext]
if not (wh.Flags & WHDR_DONE):
print "done"
return False
if wh.BufferLength != len(buf):
raise IOError, "BUFFER_SIZE_MISMATCH"
wh.Flags &= ~WHDR_DONE
wh.write(buf)
wh.outWrite()
self.waveHdrNext += 1
if self.waveHdrNext >= self.waveHdrCount:
self.waveHdrNext = 0
return True
def Wait(self, delay):
if self.waveHdrNext >= self.waveHdrCount:
raise IOError, "AUDIO_DEVICE_NOT_READY"
if delay < 0:
delayMSec = -1
else:
delayMSec = delay * 1000
while (not (self.waveHdrList[self.waveHdrNext].Flags & WHDR_DONE)):
kernel32.WaitForSingleObject(self.hDoneEvent, delayMSec)
def Close(self):
if self.hWaveOut:
winmm.waveOutReset(self.hWaveOut)
for wh in self.waveHdrList:
wh.outUnprepare()
winmm.waveOutClose(self.hWaveOut)
self.hWaveOut = None
def __del__(self):
self.Close()
if __name__ == "__main__":
import wave
import time
src = wave.open("test.wav", "rb")
channels, bytes, freq, frameCount, compType, compName = src.getparams()
print channels, bytes, freq, frameCount
audio = Audio(freq, 8*bytes, channels, 1000*bytes, 16)
data = src.readframes(1000)
for pos in range(len(data), frameCount, 1000):
if audio.Write(data):
data = src.readframes(1000)
else:
time.sleep(0.001)
raw_input()
audio.Close()
음; 웨이브 출력이 비동기라서 코드가 약간 달라져야 하더군요;

(
0)

(
0)
http://imp17.com/tc/myevan/trackback/95