From 247750abcbf6760bbc52aa5d64fc375d6fbee8a3 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Sun, 6 Dec 2020 19:28:06 +0900 Subject: Renaming of files in preparation for code style tools. Signed-off-by: Michele Calgaro (cherry picked from commit 00d4f92b717fbcbed6f9eee361975d6ee5380d59) --- artsc/CMakeLists.txt | 2 +- artsc/artscbackend.cc | 805 -------- artsc/artscbackend.cpp | 805 ++++++++ doc/TODO | 4 +- examples/catfile.cc | 55 - examples/catfile.cpp | 55 + examples/dcasttest.cc | 72 - examples/dcasttest.cpp | 72 + examples/flow.cc | 56 - examples/flow.cpp | 56 + examples/hello_impl.cc | 76 - examples/hello_impl.cpp | 76 + examples/helloclient.cc | 76 - examples/helloclient.cpp | 76 + examples/hellodynamic.cc | 94 - examples/hellodynamic.cpp | 94 + examples/hellodynamic2.cc | 124 -- examples/hellodynamic2.cpp | 124 ++ examples/hellomain.cc | 77 - examples/hellomain.cpp | 77 + examples/helloserver.cc | 52 - examples/helloserver.cpp | 52 + examples/irdemo.cc | 155 -- examples/irdemo.cpp | 155 ++ examples/playtofile_impl.cc | 99 - examples/playtofile_impl.cpp | 99 + examples/playtofile_main.cc | 147 -- examples/playtofile_main.cpp | 147 ++ examples/referenceinfo.cc | 57 - examples/referenceinfo.cpp | 57 + examples/streamsound.cc | 106 - examples/streamsound.cpp | 106 + examples/testaggregation.cc | 73 - examples/testaggregation.cpp | 73 + examples/testasubsys.cc | 142 -- examples/testasubsys.cpp | 142 ++ examples/testdhandle.cc | 115 -- examples/testdhandle.cpp | 115 ++ examples/testthreads.cc | 64 - examples/testthreads.cpp | 64 + examples/x11commtest.cc | 76 - examples/x11commtest.cpp | 76 + flow/CMakeLists.txt | 30 +- flow/asyncschedule.cc | 553 ------ flow/asyncschedule.cpp | 553 ++++++ flow/audioio.cc | 165 -- flow/audioio.cpp | 165 ++ flow/audioioaix.cc | 390 ---- flow/audioioaix.cpp | 390 ++++ flow/audioioalsa.cc | 561 ------ flow/audioioalsa.cpp | 561 ++++++ flow/audioioalsa9.cc | 590 ------ flow/audioioalsa9.cpp | 590 ++++++ flow/audioiocsl.cc | 640 ------- flow/audioiocsl.cpp | 640 +++++++ flow/audioioesd.cc | 227 --- flow/audioioesd.cpp | 227 +++ flow/audioiojack.cc | 345 ---- flow/audioiojack.cpp | 345 ++++ flow/audioiolibaudioio.cc | 236 --- flow/audioiolibaudioio.cpp | 236 +++ flow/audioiomas.cc | 619 ------ flow/audioiomas.cpp | 619 ++++++ flow/audioionas.cc | 260 --- flow/audioionas.cpp | 260 +++ flow/audioionull.cc | 184 -- flow/audioionull.cpp | 184 ++ flow/audioiooss.cc | 485 ----- flow/audioiooss.cpp | 485 +++++ flow/audioioossthreaded.cc | 681 ------- flow/audioioossthreaded.cpp | 681 +++++++ flow/audioiosgi.cc | 274 --- flow/audioiosgi.cpp | 274 +++ flow/audioiosndio.cc | 310 --- flow/audioiosndio.cpp | 310 +++ flow/audioiosun.cc | 442 ----- flow/audioiosun.cpp | 442 +++++ flow/audiomanager_impl.cc | 323 ---- flow/audiomanager_impl.cpp | 323 ++++ flow/audiosubsys.cc | 645 ------- flow/audiosubsys.cpp | 645 +++++++ flow/audiotobytestream_impl.cc | 223 --- flow/audiotobytestream_impl.cpp | 223 +++ flow/bus.cc | 367 ---- flow/bus.cpp | 367 ++++ flow/bytestreamtoaudio_impl.cc | 119 -- flow/bytestreamtoaudio_impl.cpp | 119 ++ flow/cache.cc | 274 --- flow/cache.cpp | 274 +++ flow/convert.cc | 418 ---- flow/convert.cpp | 418 ++++ flow/cpuinfo.cc | 232 --- flow/cpuinfo.cpp | 232 +++ flow/datahandle_impl.cc | 499 ----- flow/datahandle_impl.cpp | 499 +++++ flow/gsl/CMakeLists.txt | 2 +- flow/gsl/dummy.cc | 3 - flow/gsl/dummy.cpp | 3 + flow/gsl/gslartsthreads.cc | 203 -- flow/gsl/gslartsthreads.cpp | 203 ++ flow/gsl/gslglibhash.cc | 149 -- flow/gsl/gslglibhash.cpp | 149 ++ flow/gsl/gslglibhashtest.cc | 123 -- flow/gsl/gslglibhashtest.cpp | 123 ++ flow/gslschedule.cc | 1195 ------------ flow/gslschedule.cpp | 1195 ++++++++++++ flow/pipebuffer.cc | 166 -- flow/pipebuffer.cpp | 166 ++ flow/resample.cc | 305 --- flow/resample.cpp | 305 +++ flow/stdsynthmodule.cc | 92 - flow/stdsynthmodule.cpp | 92 + flow/stereoeffectstack_impl.cc | 179 -- flow/stereoeffectstack_impl.cpp | 179 ++ flow/stereofftscope_impl.cc | 131 -- flow/stereofftscope_impl.cpp | 131 ++ flow/stereovolumecontrol_impl.cc | 195 -- flow/stereovolumecontrol_impl.cpp | 195 ++ flow/synth_add_impl.cc | 44 - flow/synth_add_impl.cpp | 44 + flow/synth_frequency_impl.cc | 70 - flow/synth_frequency_impl.cpp | 70 + flow/synth_mul_impl.cc | 44 - flow/synth_mul_impl.cpp | 44 + flow/synth_multi_add_impl.cc | 64 - flow/synth_multi_add_impl.cpp | 64 + flow/synth_play_impl.cc | 284 --- flow/synth_play_impl.cpp | 284 +++ flow/synth_play_wav_impl.cc | 579 ------ flow/synth_play_wav_impl.cpp | 579 ++++++ flow/synth_record_impl.cc | 182 -- flow/synth_record_impl.cpp | 182 ++ flow/synth_wave_sin_impl.cc | 44 - flow/synth_wave_sin_impl.cpp | 44 + flow/virtualports.cc | 491 ----- flow/virtualports.cpp | 491 +++++ gmcop/CMakeLists.txt | 2 +- gmcop/giomanager.cc | 506 ----- gmcop/giomanager.cpp | 506 +++++ mcop/CMakeLists.txt | 20 +- mcop/anyref.cc | 310 --- mcop/anyref.cpp | 310 +++ mcop/asyncstream.cc | 46 - mcop/asyncstream.cpp | 46 + mcop/buffer.cc | 386 ---- mcop/buffer.cpp | 386 ++++ mcop/connect.cc | 149 -- mcop/connect.cpp | 149 ++ mcop/connection.cc | 196 -- mcop/connection.cpp | 196 ++ mcop/core.cc | 3191 ------------------------------- mcop/core.cpp | 3191 +++++++++++++++++++++++++++++++ mcop/datapacket.cc | 65 - mcop/datapacket.cpp | 65 + mcop/debug.cc | 822 -------- mcop/debug.cpp | 822 ++++++++ mcop/delayedreturn.cc | 71 - mcop/delayedreturn.cpp | 71 + mcop/dispatcher.cc | 1090 ----------- mcop/dispatcher.cpp | 1090 +++++++++++ mcop/dynamicrequest.cc | 152 -- mcop/dynamicrequest.cpp | 152 ++ mcop/dynamicskeleton.cc | 204 -- mcop/dynamicskeleton.cpp | 204 ++ mcop/extensionloader.cc | 116 -- mcop/extensionloader.cpp | 116 ++ mcop/factory.cc | 36 - mcop/factory.cpp | 36 + mcop/flowsystem.cc | 180 -- mcop/flowsystem.cpp | 180 ++ mcop/idlfilereg.cc | 44 - mcop/idlfilereg.cpp | 44 + mcop/ifacerepo_impl.cc | 305 --- mcop/ifacerepo_impl.cpp | 305 +++ mcop/iomanager.cc | 494 ----- mcop/iomanager.cpp | 494 +++++ mcop/loopback.cc | 57 - mcop/loopback.cpp | 57 + mcop/mcopconfig.cc | 67 - mcop/mcopconfig.cpp | 67 + mcop/mcoputils.cc | 590 ------ mcop/mcoputils.cpp | 590 ++++++ mcop/md5auth.cc | 213 --- mcop/md5auth.cpp | 213 +++ mcop/namedstore.h | 2 +- mcop/notification.cc | 101 - mcop/notification.cpp | 101 + mcop/object.cc | 1528 --------------- mcop/object.cpp | 1528 +++++++++++++++ mcop/objectmanager.cc | 289 --- mcop/objectmanager.cpp | 289 +++ mcop/reference.cc | 32 - mcop/reference.cpp | 32 + mcop/referenceclean.cc | 87 - mcop/referenceclean.cpp | 87 + mcop/socketconnection.cc | 205 -- mcop/socketconnection.cpp | 205 ++ mcop/startupmanager.cc | 150 -- mcop/startupmanager.cpp | 150 ++ mcop/tcpconnection.cc | 153 -- mcop/tcpconnection.cpp | 153 ++ mcop/tcpserver.cc | 191 -- mcop/tcpserver.cpp | 191 ++ mcop/thread.cc | 169 -- mcop/thread.cpp | 169 ++ mcop/tmpglobalcomm.cc | 82 - mcop/tmpglobalcomm.cpp | 82 + mcop/trader_impl.cc | 345 ---- mcop/trader_impl.cpp | 345 ++++ mcop/type.cc | 31 - mcop/type.cpp | 31 + mcop/unixconnection.cc | 115 -- mcop/unixconnection.cpp | 115 ++ mcop/unixserver.cc | 152 -- mcop/unixserver.cpp | 152 ++ mcop_mt/CMakeLists.txt | 2 +- mcop_mt/threads_posix.cc | 398 ---- mcop_mt/threads_posix.cpp | 398 ++++ mcopidl/CMakeLists.txt | 2 +- mcopidl/mcopidl.cc | 2651 ------------------------- mcopidl/mcopidl.cpp | 2651 +++++++++++++++++++++++++ mcopidl/namespace.cc | 208 -- mcopidl/namespace.cpp | 208 ++ mcopidl/scanner.cc | 2090 -------------------- mcopidl/scanner.cpp | 2090 ++++++++++++++++++++ mcopidl/scanner.ll | 2 +- mcopidl/yacc.cc | 1507 --------------- mcopidl/yacc.cc.h | 75 - mcopidl/yacc.cpp | 1507 +++++++++++++++ mcopidl/yacc.cpp.h | 75 + qtmcop/CMakeLists.txt | 2 +- qtmcop/qiomanager.cc | 299 --- qtmcop/qiomanager.cpp | 299 +++ soundserver/CMakeLists.txt | 28 +- soundserver/artscat.cc | 244 --- soundserver/artscat.cpp | 244 +++ soundserver/artsd.cc | 377 ---- soundserver/artsd.cpp | 377 ++++ soundserver/artsplay.cc | 83 - soundserver/artsplay.cpp | 83 + soundserver/artsrec.cc | 194 -- soundserver/artsrec.cpp | 194 ++ soundserver/artsshell.cc | 669 ------- soundserver/artsshell.cpp | 669 +++++++ soundserver/cpuusage.cc | 137 -- soundserver/cpuusage.cpp | 137 ++ soundserver/crashhandler.cc | 236 --- soundserver/crashhandler.cpp | 236 +++ soundserver/fileinputstream_impl.cc | 193 -- soundserver/fileinputstream_impl.cpp | 193 ++ soundserver/gslplayobject_impl.cc | 235 --- soundserver/gslplayobject_impl.cpp | 235 +++ soundserver/samplestorage_impl.cc | 202 -- soundserver/samplestorage_impl.cpp | 202 ++ soundserver/simplesoundserver_impl.cc | 453 ----- soundserver/simplesoundserver_impl.cpp | 453 +++++ soundserver/soundserver_impl.cc | 90 - soundserver/soundserver_impl.cpp | 90 + soundserver/soundserverstartup_impl.cc | 99 - soundserver/soundserverstartup_impl.cpp | 99 + soundserver/soundserverv2_impl.cc | 386 ---- soundserver/soundserverv2_impl.cpp | 386 ++++ soundserver/stdoutwriter_impl.cc | 52 - soundserver/stdoutwriter_impl.cpp | 52 + soundserver/tradercheck.cc | 213 --- soundserver/tradercheck.cpp | 213 +++ soundserver/wavplayobject_impl.cc | 172 -- soundserver/wavplayobject_impl.cpp | 172 ++ tests/README.test | 4 +- tests/testanyref.cc | 97 - tests/testanyref.cpp | 97 + tests/testbuffer.cc | 139 -- tests/testbuffer.cpp | 139 ++ tests/testchangenotify.cc | 195 -- tests/testchangenotify.cpp | 195 ++ tests/testdispatcher.cc | 41 - tests/testdispatcher.cpp | 41 + tests/testflowsystem.cc | 83 - tests/testflowsystem.cpp | 83 + tests/testifacerepo.cc | 84 - tests/testifacerepo.cpp | 84 + tests/testnotification.cc | 146 -- tests/testnotification.cpp | 146 ++ tests/testremote.cc | 176 -- tests/testremote.cpp | 176 ++ tests/testwrapper.cc | 211 -- tests/testwrapper.cpp | 211 ++ tests/value_impl.cc | 94 - tests/value_impl.cpp | 94 + x11/x11globalcomm_impl.cc | 184 -- x11/x11globalcomm_impl.cpp | 184 ++ 291 files changed, 42810 insertions(+), 42810 deletions(-) delete mode 100644 artsc/artscbackend.cc create mode 100644 artsc/artscbackend.cpp delete mode 100644 examples/catfile.cc create mode 100644 examples/catfile.cpp delete mode 100644 examples/dcasttest.cc create mode 100644 examples/dcasttest.cpp delete mode 100644 examples/flow.cc create mode 100644 examples/flow.cpp delete mode 100644 examples/hello_impl.cc create mode 100644 examples/hello_impl.cpp delete mode 100644 examples/helloclient.cc create mode 100644 examples/helloclient.cpp delete mode 100644 examples/hellodynamic.cc create mode 100644 examples/hellodynamic.cpp delete mode 100644 examples/hellodynamic2.cc create mode 100644 examples/hellodynamic2.cpp delete mode 100644 examples/hellomain.cc create mode 100644 examples/hellomain.cpp delete mode 100644 examples/helloserver.cc create mode 100644 examples/helloserver.cpp delete mode 100644 examples/irdemo.cc create mode 100644 examples/irdemo.cpp delete mode 100644 examples/playtofile_impl.cc create mode 100644 examples/playtofile_impl.cpp delete mode 100644 examples/playtofile_main.cc create mode 100644 examples/playtofile_main.cpp delete mode 100644 examples/referenceinfo.cc create mode 100644 examples/referenceinfo.cpp delete mode 100644 examples/streamsound.cc create mode 100644 examples/streamsound.cpp delete mode 100644 examples/testaggregation.cc create mode 100644 examples/testaggregation.cpp delete mode 100644 examples/testasubsys.cc create mode 100644 examples/testasubsys.cpp delete mode 100644 examples/testdhandle.cc create mode 100644 examples/testdhandle.cpp delete mode 100644 examples/testthreads.cc create mode 100644 examples/testthreads.cpp delete mode 100644 examples/x11commtest.cc create mode 100644 examples/x11commtest.cpp delete mode 100644 flow/asyncschedule.cc create mode 100644 flow/asyncschedule.cpp delete mode 100644 flow/audioio.cc create mode 100644 flow/audioio.cpp delete mode 100644 flow/audioioaix.cc create mode 100644 flow/audioioaix.cpp delete mode 100644 flow/audioioalsa.cc create mode 100644 flow/audioioalsa.cpp delete mode 100644 flow/audioioalsa9.cc create mode 100644 flow/audioioalsa9.cpp delete mode 100644 flow/audioiocsl.cc create mode 100644 flow/audioiocsl.cpp delete mode 100644 flow/audioioesd.cc create mode 100644 flow/audioioesd.cpp delete mode 100644 flow/audioiojack.cc create mode 100644 flow/audioiojack.cpp delete mode 100644 flow/audioiolibaudioio.cc create mode 100644 flow/audioiolibaudioio.cpp delete mode 100644 flow/audioiomas.cc create mode 100644 flow/audioiomas.cpp delete mode 100644 flow/audioionas.cc create mode 100644 flow/audioionas.cpp delete mode 100644 flow/audioionull.cc create mode 100644 flow/audioionull.cpp delete mode 100644 flow/audioiooss.cc create mode 100644 flow/audioiooss.cpp delete mode 100644 flow/audioioossthreaded.cc create mode 100644 flow/audioioossthreaded.cpp delete mode 100644 flow/audioiosgi.cc create mode 100644 flow/audioiosgi.cpp delete mode 100644 flow/audioiosndio.cc create mode 100644 flow/audioiosndio.cpp delete mode 100644 flow/audioiosun.cc create mode 100644 flow/audioiosun.cpp delete mode 100644 flow/audiomanager_impl.cc create mode 100644 flow/audiomanager_impl.cpp delete mode 100644 flow/audiosubsys.cc create mode 100644 flow/audiosubsys.cpp delete mode 100644 flow/audiotobytestream_impl.cc create mode 100644 flow/audiotobytestream_impl.cpp delete mode 100644 flow/bus.cc create mode 100644 flow/bus.cpp delete mode 100644 flow/bytestreamtoaudio_impl.cc create mode 100644 flow/bytestreamtoaudio_impl.cpp delete mode 100644 flow/cache.cc create mode 100644 flow/cache.cpp delete mode 100644 flow/convert.cc create mode 100644 flow/convert.cpp delete mode 100644 flow/cpuinfo.cc create mode 100644 flow/cpuinfo.cpp delete mode 100644 flow/datahandle_impl.cc create mode 100644 flow/datahandle_impl.cpp delete mode 100644 flow/gsl/dummy.cc create mode 100644 flow/gsl/dummy.cpp delete mode 100644 flow/gsl/gslartsthreads.cc create mode 100644 flow/gsl/gslartsthreads.cpp delete mode 100644 flow/gsl/gslglibhash.cc create mode 100644 flow/gsl/gslglibhash.cpp delete mode 100644 flow/gsl/gslglibhashtest.cc create mode 100644 flow/gsl/gslglibhashtest.cpp delete mode 100644 flow/gslschedule.cc create mode 100644 flow/gslschedule.cpp delete mode 100644 flow/pipebuffer.cc create mode 100644 flow/pipebuffer.cpp delete mode 100644 flow/resample.cc create mode 100644 flow/resample.cpp delete mode 100644 flow/stdsynthmodule.cc create mode 100644 flow/stdsynthmodule.cpp delete mode 100644 flow/stereoeffectstack_impl.cc create mode 100644 flow/stereoeffectstack_impl.cpp delete mode 100644 flow/stereofftscope_impl.cc create mode 100644 flow/stereofftscope_impl.cpp delete mode 100644 flow/stereovolumecontrol_impl.cc create mode 100644 flow/stereovolumecontrol_impl.cpp delete mode 100644 flow/synth_add_impl.cc create mode 100644 flow/synth_add_impl.cpp delete mode 100644 flow/synth_frequency_impl.cc create mode 100644 flow/synth_frequency_impl.cpp delete mode 100644 flow/synth_mul_impl.cc create mode 100644 flow/synth_mul_impl.cpp delete mode 100644 flow/synth_multi_add_impl.cc create mode 100644 flow/synth_multi_add_impl.cpp delete mode 100644 flow/synth_play_impl.cc create mode 100644 flow/synth_play_impl.cpp delete mode 100644 flow/synth_play_wav_impl.cc create mode 100644 flow/synth_play_wav_impl.cpp delete mode 100644 flow/synth_record_impl.cc create mode 100644 flow/synth_record_impl.cpp delete mode 100644 flow/synth_wave_sin_impl.cc create mode 100644 flow/synth_wave_sin_impl.cpp delete mode 100644 flow/virtualports.cc create mode 100644 flow/virtualports.cpp delete mode 100644 gmcop/giomanager.cc create mode 100644 gmcop/giomanager.cpp delete mode 100644 mcop/anyref.cc create mode 100644 mcop/anyref.cpp delete mode 100644 mcop/asyncstream.cc create mode 100644 mcop/asyncstream.cpp delete mode 100644 mcop/buffer.cc create mode 100644 mcop/buffer.cpp delete mode 100644 mcop/connect.cc create mode 100644 mcop/connect.cpp delete mode 100644 mcop/connection.cc create mode 100644 mcop/connection.cpp delete mode 100644 mcop/core.cc create mode 100644 mcop/core.cpp delete mode 100644 mcop/datapacket.cc create mode 100644 mcop/datapacket.cpp delete mode 100644 mcop/debug.cc create mode 100644 mcop/debug.cpp delete mode 100644 mcop/delayedreturn.cc create mode 100644 mcop/delayedreturn.cpp delete mode 100644 mcop/dispatcher.cc create mode 100644 mcop/dispatcher.cpp delete mode 100644 mcop/dynamicrequest.cc create mode 100644 mcop/dynamicrequest.cpp delete mode 100644 mcop/dynamicskeleton.cc create mode 100644 mcop/dynamicskeleton.cpp delete mode 100644 mcop/extensionloader.cc create mode 100644 mcop/extensionloader.cpp delete mode 100644 mcop/factory.cc create mode 100644 mcop/factory.cpp delete mode 100644 mcop/flowsystem.cc create mode 100644 mcop/flowsystem.cpp delete mode 100644 mcop/idlfilereg.cc create mode 100644 mcop/idlfilereg.cpp delete mode 100644 mcop/ifacerepo_impl.cc create mode 100644 mcop/ifacerepo_impl.cpp delete mode 100644 mcop/iomanager.cc create mode 100644 mcop/iomanager.cpp delete mode 100644 mcop/loopback.cc create mode 100644 mcop/loopback.cpp delete mode 100644 mcop/mcopconfig.cc create mode 100644 mcop/mcopconfig.cpp delete mode 100644 mcop/mcoputils.cc create mode 100644 mcop/mcoputils.cpp delete mode 100644 mcop/md5auth.cc create mode 100644 mcop/md5auth.cpp delete mode 100644 mcop/notification.cc create mode 100644 mcop/notification.cpp delete mode 100644 mcop/object.cc create mode 100644 mcop/object.cpp delete mode 100644 mcop/objectmanager.cc create mode 100644 mcop/objectmanager.cpp delete mode 100644 mcop/reference.cc create mode 100644 mcop/reference.cpp delete mode 100644 mcop/referenceclean.cc create mode 100644 mcop/referenceclean.cpp delete mode 100644 mcop/socketconnection.cc create mode 100644 mcop/socketconnection.cpp delete mode 100644 mcop/startupmanager.cc create mode 100644 mcop/startupmanager.cpp delete mode 100644 mcop/tcpconnection.cc create mode 100644 mcop/tcpconnection.cpp delete mode 100644 mcop/tcpserver.cc create mode 100644 mcop/tcpserver.cpp delete mode 100644 mcop/thread.cc create mode 100644 mcop/thread.cpp delete mode 100644 mcop/tmpglobalcomm.cc create mode 100644 mcop/tmpglobalcomm.cpp delete mode 100644 mcop/trader_impl.cc create mode 100644 mcop/trader_impl.cpp delete mode 100644 mcop/type.cc create mode 100644 mcop/type.cpp delete mode 100644 mcop/unixconnection.cc create mode 100644 mcop/unixconnection.cpp delete mode 100644 mcop/unixserver.cc create mode 100644 mcop/unixserver.cpp delete mode 100644 mcop_mt/threads_posix.cc create mode 100644 mcop_mt/threads_posix.cpp delete mode 100644 mcopidl/mcopidl.cc create mode 100644 mcopidl/mcopidl.cpp delete mode 100644 mcopidl/namespace.cc create mode 100644 mcopidl/namespace.cpp delete mode 100644 mcopidl/scanner.cc create mode 100644 mcopidl/scanner.cpp delete mode 100644 mcopidl/yacc.cc delete mode 100644 mcopidl/yacc.cc.h create mode 100644 mcopidl/yacc.cpp create mode 100644 mcopidl/yacc.cpp.h delete mode 100644 qtmcop/qiomanager.cc create mode 100644 qtmcop/qiomanager.cpp delete mode 100644 soundserver/artscat.cc create mode 100644 soundserver/artscat.cpp delete mode 100644 soundserver/artsd.cc create mode 100644 soundserver/artsd.cpp delete mode 100644 soundserver/artsplay.cc create mode 100644 soundserver/artsplay.cpp delete mode 100644 soundserver/artsrec.cc create mode 100644 soundserver/artsrec.cpp delete mode 100644 soundserver/artsshell.cc create mode 100644 soundserver/artsshell.cpp delete mode 100644 soundserver/cpuusage.cc create mode 100644 soundserver/cpuusage.cpp delete mode 100644 soundserver/crashhandler.cc create mode 100644 soundserver/crashhandler.cpp delete mode 100644 soundserver/fileinputstream_impl.cc create mode 100644 soundserver/fileinputstream_impl.cpp delete mode 100644 soundserver/gslplayobject_impl.cc create mode 100644 soundserver/gslplayobject_impl.cpp delete mode 100644 soundserver/samplestorage_impl.cc create mode 100644 soundserver/samplestorage_impl.cpp delete mode 100644 soundserver/simplesoundserver_impl.cc create mode 100644 soundserver/simplesoundserver_impl.cpp delete mode 100644 soundserver/soundserver_impl.cc create mode 100644 soundserver/soundserver_impl.cpp delete mode 100644 soundserver/soundserverstartup_impl.cc create mode 100644 soundserver/soundserverstartup_impl.cpp delete mode 100644 soundserver/soundserverv2_impl.cc create mode 100644 soundserver/soundserverv2_impl.cpp delete mode 100644 soundserver/stdoutwriter_impl.cc create mode 100644 soundserver/stdoutwriter_impl.cpp delete mode 100644 soundserver/tradercheck.cc create mode 100644 soundserver/tradercheck.cpp delete mode 100644 soundserver/wavplayobject_impl.cc create mode 100644 soundserver/wavplayobject_impl.cpp delete mode 100644 tests/testanyref.cc create mode 100644 tests/testanyref.cpp delete mode 100644 tests/testbuffer.cc create mode 100644 tests/testbuffer.cpp delete mode 100644 tests/testchangenotify.cc create mode 100644 tests/testchangenotify.cpp delete mode 100644 tests/testdispatcher.cc create mode 100644 tests/testdispatcher.cpp delete mode 100644 tests/testflowsystem.cc create mode 100644 tests/testflowsystem.cpp delete mode 100644 tests/testifacerepo.cc create mode 100644 tests/testifacerepo.cpp delete mode 100644 tests/testnotification.cc create mode 100644 tests/testnotification.cpp delete mode 100644 tests/testremote.cc create mode 100644 tests/testremote.cpp delete mode 100644 tests/testwrapper.cc create mode 100644 tests/testwrapper.cpp delete mode 100644 tests/value_impl.cc create mode 100644 tests/value_impl.cpp delete mode 100644 x11/x11globalcomm_impl.cc create mode 100644 x11/x11globalcomm_impl.cpp diff --git a/artsc/CMakeLists.txt b/artsc/CMakeLists.txt index 6a5955e..0966a45 100644 --- a/artsc/CMakeLists.txt +++ b/artsc/CMakeLists.txt @@ -104,7 +104,7 @@ set_property( TARGET artsc-shared APPEND PROPERTY COMPILE_DEFINITIONS ARTSC_BACK ##### artscbackend (shared lib) ################# tde_add_library( artscbackend SHARED - SOURCES artscbackend.cc + SOURCES artscbackend.cpp VERSION 0.0.0 LINK soundserver_idl-shared artsflow-shared DESTINATION ${LIB_INSTALL_DIR} diff --git a/artsc/artscbackend.cc b/artsc/artscbackend.cc deleted file mode 100644 index 56d0868..0000000 --- a/artsc/artscbackend.cc +++ /dev/null @@ -1,805 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - 2001 Matthias Kretz - kretz@kde.org - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#include "artsc.h" -#include "soundserver.h" -#include "stdsynthmodule.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "arts_export.h" - -#define arts_backend_debug(x) ; - -using namespace std; -using namespace Arts; - -/** - * Base class for streams - */ -class Stream -{ -protected: - SoundServer server; - float serverBufferTime; - - bool _finished, isAttached; - int _samplingRate, _bits, _channels, pos; - string _name; - queue< DataPacket* > streamqueue; - - int packetCount, packetCapacity; - int blockingIO; - - /** - * returns the amount of bytes that will be played in a given amount of - * time in milliseconds - */ - int timeToBytes(float time) - { - float playSpeed = _channels * _samplingRate * _bits / 8; - return (int)(playSpeed * (time / 1000.0)); - } - - /** - * returns the time in milliseconds it takes with the current parameters - * to play a given amount of bytes - */ - float bytesToTime(int size) - { - float playSpeed = _channels * _samplingRate * _bits / 8; - return (1000.0 * ((float)size) / playSpeed); - } - - int bufferSize() { - return packetCount * packetCapacity; - } - - float bufferTime() { - return bytesToTime(bufferSize()); - } - - int bufferSpace() { - int space = 0; - - attach(); - - /* make sure that our information is up-to-date */ - Dispatcher::the()->ioManager()->processOneEvent(false); - - if(!streamqueue.empty()) - { - space += packetCapacity - pos; /* the first, half filled packet */ - - if(streamqueue.size() > 1) /* and the other, empty packets */ - space += (streamqueue.size()-1)*packetCapacity; - } - return space; - } - - int setBufferSize(int size) - { - /* don't change sizes when already streaming */ - if(isAttached) - return ARTS_E_NOIMPL; - - /* - * these parameters are usually a bad idea ;-) however we have to start - * somewhere, and maybe in two years, with a highly optimized kernel - * this is possible - for now, don't request the impossible or don't - * complain if it doesn't work - */ - packetCount = 3; - packetCapacity = 128; - - /* - * - do not configure stream buffers smaller than the server - * recommended value - * - try to get more or less close to the value the application - * wants - */ - int needSize = max(size, timeToBytes(server.minStreamBufferTime())); - - while(bufferSize() < needSize) - { - packetCount++; - if(packetCount == 8) - { - packetCount /= 2; - packetCapacity *= 2; - } - } - - return bufferSize(); - } - - int packetSettings() - { - int settings = 0; - - int cap = packetCapacity; - while(cap > 1) - { - settings++; - cap /= 2; - } - - settings |= packetCount << 16; - return settings; - } - - int setPacketSettings(int settings) - { - /* don't change sizes when already streaming */ - if(isAttached) - return ARTS_E_NOIMPL; - - packetCount = settings >> 16; - - packetCapacity = 1; - int c = settings & 0xffff; - while(c > 0) { - packetCapacity *= 2; - c--; - } - - /* - * - do not configure stream buffers smaller than the server - * recommended value - * - keep the packetSize the applications specified - */ - int needSize = timeToBytes(server.minStreamBufferTime()); - - while(bufferSize() < needSize) - packetCount++; - - return packetSettings(); - } - - /** - * the stream has to attach itself - */ - virtual void attach() = 0; - -public: - Stream(SoundServer server, int rate, int bits, int channels, - string name) : server(server), _finished(false), isAttached(false), - _samplingRate(rate), _bits(bits), _channels(channels), pos(0), - _name(name) - { - serverBufferTime = server.serverBufferTime(); - stream_set(ARTS_P_BUFFER_SIZE,64*1024); - stream_set(ARTS_P_BLOCKING,1); - } - virtual ~Stream() - { - // - } - - virtual int stream_set(arts_parameter_t param, int value) - { - int result; - - switch(param) { - case ARTS_P_BUFFER_SIZE: - return setBufferSize(value); - - case ARTS_P_BUFFER_TIME: - result = setBufferSize(timeToBytes(value)); - if(result < 0) return result; - return (int)bufferTime(); - - case ARTS_P_PACKET_SETTINGS: - return setPacketSettings(value); - - case ARTS_P_BLOCKING: - if(value != 0 && value != 1) return ARTS_E_NOIMPL; - - blockingIO = value; - return blockingIO; - /* - * maybe ARTS_P_TOTAL_LATENCY _could_ be made writeable, the - * others are of course useless - */ - case ARTS_P_BUFFER_SPACE: - case ARTS_P_SERVER_LATENCY: - case ARTS_P_TOTAL_LATENCY: - case ARTS_P_PACKET_SIZE: - case ARTS_P_PACKET_COUNT: - return ARTS_E_NOIMPL; - } - return ARTS_E_NOIMPL; - } - - virtual int stream_get(arts_parameter_t param) - { - switch(param) { - case ARTS_P_BUFFER_SIZE: - return bufferSize(); - - case ARTS_P_BUFFER_TIME: - return (int)bufferTime(); - - case ARTS_P_BUFFER_SPACE: - return bufferSpace(); - - case ARTS_P_PACKET_SETTINGS: - return packetSettings(); - - case ARTS_P_SERVER_LATENCY: - return (int)serverBufferTime; - - case ARTS_P_TOTAL_LATENCY: - return stream_get(ARTS_P_SERVER_LATENCY) - + stream_get(ARTS_P_BUFFER_TIME); - - case ARTS_P_BLOCKING: - return blockingIO; - - case ARTS_P_PACKET_SIZE: - return packetCapacity; - - case ARTS_P_PACKET_COUNT: - return packetCount; - } - return ARTS_E_NOIMPL; - } - - virtual int write(const mcopbyte * /*data*/, int /*size*/) - { - return ARTS_E_NOIMPL; - } - - virtual int read(mcopbyte * /*data*/, int /*size*/) - { - return ARTS_E_NOIMPL; - } - - virtual void close() = 0; - - int suspend() - { - if(isAttached) - { - return server.suspend(); - } - return 0; - } - - int suspended() - { - if(isAttached) - { - return 0; - } - return server.suspended(); - } -}; - -class Receiver : public ByteSoundReceiver_skel, - public StdSynthModule, - virtual public Stream -{ - /* - * FIXME: bsWrapper is a more or less ugly trick to be able to use - * this object although not using smartwrappers to access it - */ - ByteSoundReceiver bsWrapper; - -protected: - virtual void attach() - { - if(!isAttached) - { - isAttached = true; - - server.attachRecorder(bsWrapper); - start(); - - /* - * TODO: this processOneEvent looks a bit strange here... it is - * there since StdIOManager does block 5 seconds on the first - * arts_write if it isn't - although notifications are pending - * - * Probably the real solution is to rewrite the - * StdIOManager::processOneEvent function. (And maybe drop the - * assumption that aRts will not block when an infinite amount - * of notifications is pending - I mean: will it ever happen?) - */ - Dispatcher::the()->ioManager()->processOneEvent(false); - } - } - -public: - Receiver(SoundServer server, int rate, int bits, int channels, - string name) : Stream( server, rate, bits, channels, name) - { - bsWrapper = ByteSoundReceiver::_from_base(this); - } - - virtual ~Receiver() { - // - } - - long samplingRate() { return _samplingRate; } - long channels() { return _channels; } - long bits() { return _bits; } - bool finished() { return _finished; } - string title() { return _name; } - - void process_indata(DataPacket *packet) - { - streamqueue.push(packet); - } - - void close() - { - if(isAttached) - { - /* remove all packets from the streamqueue */ - while(!streamqueue.empty()) - { - DataPacket *packet = streamqueue.front(); - packet->processed(); - streamqueue.pop(); - } - - server.detachRecorder(bsWrapper); - } - // similar effect like "delete this;" - bsWrapper = ByteSoundReceiver::null(); - } - - int read(mcopbyte *data, int size) - { - attach(); - - int remaining = size; - while(remaining) - { - if(blockingIO) - { - /* C API blocking style read */ - while(streamqueue.empty()) - Dispatcher::the()->ioManager()->processOneEvent(true); - } - else - { - /* non blocking I/O */ - if(streamqueue.empty()) - Dispatcher::the()->ioManager()->processOneEvent(false); - - /* still no more packets to read? */ - if(streamqueue.empty()) - return size - remaining; - } - - /* get a packet */ - DataPacket *packet = streamqueue.front(); - - /* copy some data from there */ - int tocopy = min(remaining,packet->size-pos); - memcpy(data,&packet->contents[pos],tocopy); - pos += tocopy; - data += tocopy; - remaining -= tocopy; - - /* have we read the whole packet? then get rid of it */ - if(pos == packet->size) - { - packet->processed(); - streamqueue.pop(); - pos = 0; - } - } - - /* no possible error conditions */ - return size; - } -}; - -class Sender : public ByteSoundProducerV2_skel, - public StdSynthModule, - virtual public Stream -{ - /* - * FIXME: bsWrapper is a more or less ugly trick to be able to use - * this object although not using smartwrappers to access it - */ - ByteSoundProducerV2 bsWrapper; - -protected: - virtual void attach() - { - if(!isAttached) - { - isAttached = true; - - server.attach(bsWrapper); - start(); - - /* - * TODO: this processOneEvent looks a bit strange here... it is - * there since StdIOManager does block 5 seconds on the first - * arts_write if it isn't - although notifications are pending - * - * Probably the real solution is to rewrite the - * StdIOManager::processOneEvent function. (And maybe drop the - * assumption that aRts will not block when an infinite amount - * of notifications is pending - I mean: will it ever happen?) - */ - Dispatcher::the()->ioManager()->processOneEvent(false); - } - } - -public: - Sender(SoundServer server, int rate, int bits, int channels, - string name) : Stream( server, rate, bits, channels, name) - { - bsWrapper = ByteSoundProducerV2::_from_base(this); - } - - virtual ~Sender() { - // - } - - long samplingRate() { return _samplingRate; } - long channels() { return _channels; } - long bits() { return _bits; } - bool finished() { return _finished; } - string title() { return _name; } - - void streamStart() - { - /* - * start streaming - */ - outdata.setPull(packetCount, packetCapacity); - } - - void request_outdata(DataPacket *packet) - { - streamqueue.push(packet); - } - - void close() - { - if(isAttached) - { - if(pos != 0) - { - /* send the last half-filled packet */ - DataPacket *packet = streamqueue.front(); - packet->size = pos; - packet->send(); - streamqueue.pop(); - } - outdata.endPull(); - - /* remove all packets from the streamqueue */ - while(!streamqueue.empty()) - { - DataPacket *packet = streamqueue.front(); - packet->size = 0; - packet->send(); - streamqueue.pop(); - } - - server.detach(bsWrapper); - } - // similar effect like "delete this;" - Arts::ByteSoundProducerV2_base* x = _copy(); - bsWrapper = ByteSoundProducerV2::null(); - x->_release(); - } - - int write(const mcopbyte *data, int size) - { - attach(); - - int remaining = size; - while(remaining) - { - if(blockingIO) - { - /* C API blocking style write */ - /* we're not waiting for any data here, but rather for - * DataPackets that we can fill */ - while(streamqueue.empty()) - Dispatcher::the()->ioManager()->processOneEvent(true); - } - else - { - /* non blocking I/O */ - if(streamqueue.empty()) - Dispatcher::the()->ioManager()->processOneEvent(false); - - /* still no more space to write? */ - if(streamqueue.empty()) - return size - remaining; - } - - /* get a packet */ - DataPacket *packet = streamqueue.front(); - - /* copy some data there */ - int tocopy = min(remaining,packetCapacity-pos); - memcpy(&packet->contents[pos],data,tocopy); - pos += tocopy; - data += tocopy; - remaining -= tocopy; - - /* have we filled up the packet? then send it */ - if(pos == packetCapacity) - { - packet->size = packetCapacity; - packet->send(); - streamqueue.pop(); - pos = 0; - } - } - - /* no possible error conditions */ - return size; - } -}; - -class ArtsCApi { -protected: - static ArtsCApi *instance; - int refcnt; - - Dispatcher dispatcher; - SoundServer server; - - ArtsCApi() : refcnt(1), server(Reference("global:Arts_SoundServer")) - { - // - } - -public: -// C Api commands - int init() { - if(server.isNull()) - return ARTS_E_NOSERVER; - - return 0; - } - - int suspend() { - if(!server.isNull()) - return server.suspend()? 1:0; - return ARTS_E_NOSERVER; - } - - int suspended() { - if(!server.isNull()) - return server.suspended()? 1:0; - return ARTS_E_NOSERVER; - } - - void free() { - // nothing to do - } - - arts_stream_t play_stream(int rate, int bits, int channels, const char *name) - { - if(server.isNull()) - return 0; - - return (arts_stream_t)static_cast(new Sender(server,rate,bits,channels,name)); - } - - arts_stream_t record_stream(int rate, int bits, int channels, const char *name) - { - if(server.isNull()) - return 0; - - return (arts_stream_t)static_cast(new Receiver(server,rate,bits,channels,name)); - } - - void close_stream(arts_stream_t stream) - { - if(server.isNull()) - return; - - if(!stream) - return; - - static_cast(stream)->close(); - } - - int write(arts_stream_t stream, const void *data, int size) - { - if(server.isNull()) - return ARTS_E_NOSERVER; - - if(!stream) - return ARTS_E_NOSTREAM; - - return static_cast(stream)->write((const mcopbyte *)data,size); - } - - int read(arts_stream_t stream, void *data, int size) - { - if(server.isNull()) - return ARTS_E_NOSERVER; - - if(!stream) - return ARTS_E_NOSTREAM; - - return static_cast(stream)->read((mcopbyte *)data,size); - } - - int stream_set(arts_stream_t stream, arts_parameter_t param, int value) - { - if(server.isNull()) - return ARTS_E_NOSERVER; - - if(!stream) - return ARTS_E_NOSTREAM; - - return static_cast(stream)->stream_set(param,value); - } - - int stream_get(arts_stream_t stream, arts_parameter_t param) - { - if(server.isNull()) - return ARTS_E_NOSERVER; - - if(!stream) - return ARTS_E_NOSTREAM; - - return static_cast(stream)->stream_get(param); - } - -// allocation and freeing of the class - static ArtsCApi *the() { - return instance; - } - static void ref() { - if(!instance) - instance = new ArtsCApi(); - else - instance->refcnt++; - } - static void release() { - assert(instance); - assert(instance->refcnt > 0); - instance->refcnt--; - if(instance->refcnt == 0) - { - delete instance; - instance = 0; - } - } -}; - -//----------------------------- static members ------------------------------- - -ArtsCApi *ArtsCApi::instance = 0; - -//------------------ wrappers from C to C++ class ---------------------------- - -extern "C" ARTSC_EXPORT int arts_backend_init() -{ - arts_backend_debug("arts_backend_init"); - ArtsCApi::ref(); - - // if init fails, don't expect free, and don't expect that the user - // continues using other API functions - int rc = ArtsCApi::the()->init(); - if(rc < 0) ArtsCApi::release(); - return rc; -} - -extern "C" ARTSC_EXPORT int arts_backend_suspend() -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - arts_backend_debug("arts_backend_suspend"); - return ArtsCApi::the()->suspend(); -} - -extern "C" ARTSC_EXPORT int arts_backend_suspended() -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - arts_backend_debug("arts_backend_suspended"); - return ArtsCApi::the()->suspended(); -} - -extern "C" ARTSC_EXPORT void arts_backend_free() -{ - if(!ArtsCApi::the()) return; - - arts_backend_debug("arts_backend_free"); - ArtsCApi::the()->free(); - ArtsCApi::release(); -} - -extern "C" ARTSC_EXPORT arts_stream_t arts_backend_play_stream(int rate, int bits, int channels, const char *name) -{ - if(!ArtsCApi::the()) return 0; - - arts_backend_debug("arts_backend_play_stream"); - return ArtsCApi::the()->play_stream(rate,bits,channels,name); -} - -extern "C" ARTSC_EXPORT arts_stream_t arts_backend_record_stream(int rate, int bits, int channels, const char *name) -{ - if(!ArtsCApi::the()) return 0; - - arts_backend_debug("arts_backend_record_stream"); - return ArtsCApi::the()->record_stream(rate,bits,channels,name); -} - -extern "C" ARTSC_EXPORT void arts_backend_close_stream(arts_stream_t stream) -{ - if(!ArtsCApi::the()) return; - - arts_backend_debug("arts_backend_close_stream"); - ArtsCApi::the()->close_stream(stream); -} - -extern "C" ARTSC_EXPORT int arts_backend_read(arts_stream_t stream, void *buffer, int count) -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - - arts_backend_debug("arts_backend_read"); - return ArtsCApi::the()->read(stream,buffer,count); -} - -extern "C" ARTSC_EXPORT int arts_backend_write(arts_stream_t stream, const void *buffer, - int count) -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - - arts_backend_debug("arts_backend_write"); - return ArtsCApi::the()->write(stream,buffer,count); -} - -extern "C" ARTSC_EXPORT int arts_backend_stream_set(arts_stream_t stream, - arts_parameter_t param, int value) -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - - arts_backend_debug("arts_stream_set"); - return ArtsCApi::the()->stream_set(stream,param,value); -} - -extern "C" ARTSC_EXPORT int arts_backend_stream_get(arts_stream_t stream, - arts_parameter_t param) -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - - arts_backend_debug("arts_stream_get"); - return ArtsCApi::the()->stream_get(stream,param); -} diff --git a/artsc/artscbackend.cpp b/artsc/artscbackend.cpp new file mode 100644 index 0000000..56d0868 --- /dev/null +++ b/artsc/artscbackend.cpp @@ -0,0 +1,805 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + 2001 Matthias Kretz + kretz@kde.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "artsc.h" +#include "soundserver.h" +#include "stdsynthmodule.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "arts_export.h" + +#define arts_backend_debug(x) ; + +using namespace std; +using namespace Arts; + +/** + * Base class for streams + */ +class Stream +{ +protected: + SoundServer server; + float serverBufferTime; + + bool _finished, isAttached; + int _samplingRate, _bits, _channels, pos; + string _name; + queue< DataPacket* > streamqueue; + + int packetCount, packetCapacity; + int blockingIO; + + /** + * returns the amount of bytes that will be played in a given amount of + * time in milliseconds + */ + int timeToBytes(float time) + { + float playSpeed = _channels * _samplingRate * _bits / 8; + return (int)(playSpeed * (time / 1000.0)); + } + + /** + * returns the time in milliseconds it takes with the current parameters + * to play a given amount of bytes + */ + float bytesToTime(int size) + { + float playSpeed = _channels * _samplingRate * _bits / 8; + return (1000.0 * ((float)size) / playSpeed); + } + + int bufferSize() { + return packetCount * packetCapacity; + } + + float bufferTime() { + return bytesToTime(bufferSize()); + } + + int bufferSpace() { + int space = 0; + + attach(); + + /* make sure that our information is up-to-date */ + Dispatcher::the()->ioManager()->processOneEvent(false); + + if(!streamqueue.empty()) + { + space += packetCapacity - pos; /* the first, half filled packet */ + + if(streamqueue.size() > 1) /* and the other, empty packets */ + space += (streamqueue.size()-1)*packetCapacity; + } + return space; + } + + int setBufferSize(int size) + { + /* don't change sizes when already streaming */ + if(isAttached) + return ARTS_E_NOIMPL; + + /* + * these parameters are usually a bad idea ;-) however we have to start + * somewhere, and maybe in two years, with a highly optimized kernel + * this is possible - for now, don't request the impossible or don't + * complain if it doesn't work + */ + packetCount = 3; + packetCapacity = 128; + + /* + * - do not configure stream buffers smaller than the server + * recommended value + * - try to get more or less close to the value the application + * wants + */ + int needSize = max(size, timeToBytes(server.minStreamBufferTime())); + + while(bufferSize() < needSize) + { + packetCount++; + if(packetCount == 8) + { + packetCount /= 2; + packetCapacity *= 2; + } + } + + return bufferSize(); + } + + int packetSettings() + { + int settings = 0; + + int cap = packetCapacity; + while(cap > 1) + { + settings++; + cap /= 2; + } + + settings |= packetCount << 16; + return settings; + } + + int setPacketSettings(int settings) + { + /* don't change sizes when already streaming */ + if(isAttached) + return ARTS_E_NOIMPL; + + packetCount = settings >> 16; + + packetCapacity = 1; + int c = settings & 0xffff; + while(c > 0) { + packetCapacity *= 2; + c--; + } + + /* + * - do not configure stream buffers smaller than the server + * recommended value + * - keep the packetSize the applications specified + */ + int needSize = timeToBytes(server.minStreamBufferTime()); + + while(bufferSize() < needSize) + packetCount++; + + return packetSettings(); + } + + /** + * the stream has to attach itself + */ + virtual void attach() = 0; + +public: + Stream(SoundServer server, int rate, int bits, int channels, + string name) : server(server), _finished(false), isAttached(false), + _samplingRate(rate), _bits(bits), _channels(channels), pos(0), + _name(name) + { + serverBufferTime = server.serverBufferTime(); + stream_set(ARTS_P_BUFFER_SIZE,64*1024); + stream_set(ARTS_P_BLOCKING,1); + } + virtual ~Stream() + { + // + } + + virtual int stream_set(arts_parameter_t param, int value) + { + int result; + + switch(param) { + case ARTS_P_BUFFER_SIZE: + return setBufferSize(value); + + case ARTS_P_BUFFER_TIME: + result = setBufferSize(timeToBytes(value)); + if(result < 0) return result; + return (int)bufferTime(); + + case ARTS_P_PACKET_SETTINGS: + return setPacketSettings(value); + + case ARTS_P_BLOCKING: + if(value != 0 && value != 1) return ARTS_E_NOIMPL; + + blockingIO = value; + return blockingIO; + /* + * maybe ARTS_P_TOTAL_LATENCY _could_ be made writeable, the + * others are of course useless + */ + case ARTS_P_BUFFER_SPACE: + case ARTS_P_SERVER_LATENCY: + case ARTS_P_TOTAL_LATENCY: + case ARTS_P_PACKET_SIZE: + case ARTS_P_PACKET_COUNT: + return ARTS_E_NOIMPL; + } + return ARTS_E_NOIMPL; + } + + virtual int stream_get(arts_parameter_t param) + { + switch(param) { + case ARTS_P_BUFFER_SIZE: + return bufferSize(); + + case ARTS_P_BUFFER_TIME: + return (int)bufferTime(); + + case ARTS_P_BUFFER_SPACE: + return bufferSpace(); + + case ARTS_P_PACKET_SETTINGS: + return packetSettings(); + + case ARTS_P_SERVER_LATENCY: + return (int)serverBufferTime; + + case ARTS_P_TOTAL_LATENCY: + return stream_get(ARTS_P_SERVER_LATENCY) + + stream_get(ARTS_P_BUFFER_TIME); + + case ARTS_P_BLOCKING: + return blockingIO; + + case ARTS_P_PACKET_SIZE: + return packetCapacity; + + case ARTS_P_PACKET_COUNT: + return packetCount; + } + return ARTS_E_NOIMPL; + } + + virtual int write(const mcopbyte * /*data*/, int /*size*/) + { + return ARTS_E_NOIMPL; + } + + virtual int read(mcopbyte * /*data*/, int /*size*/) + { + return ARTS_E_NOIMPL; + } + + virtual void close() = 0; + + int suspend() + { + if(isAttached) + { + return server.suspend(); + } + return 0; + } + + int suspended() + { + if(isAttached) + { + return 0; + } + return server.suspended(); + } +}; + +class Receiver : public ByteSoundReceiver_skel, + public StdSynthModule, + virtual public Stream +{ + /* + * FIXME: bsWrapper is a more or less ugly trick to be able to use + * this object although not using smartwrappers to access it + */ + ByteSoundReceiver bsWrapper; + +protected: + virtual void attach() + { + if(!isAttached) + { + isAttached = true; + + server.attachRecorder(bsWrapper); + start(); + + /* + * TODO: this processOneEvent looks a bit strange here... it is + * there since StdIOManager does block 5 seconds on the first + * arts_write if it isn't - although notifications are pending + * + * Probably the real solution is to rewrite the + * StdIOManager::processOneEvent function. (And maybe drop the + * assumption that aRts will not block when an infinite amount + * of notifications is pending - I mean: will it ever happen?) + */ + Dispatcher::the()->ioManager()->processOneEvent(false); + } + } + +public: + Receiver(SoundServer server, int rate, int bits, int channels, + string name) : Stream( server, rate, bits, channels, name) + { + bsWrapper = ByteSoundReceiver::_from_base(this); + } + + virtual ~Receiver() { + // + } + + long samplingRate() { return _samplingRate; } + long channels() { return _channels; } + long bits() { return _bits; } + bool finished() { return _finished; } + string title() { return _name; } + + void process_indata(DataPacket *packet) + { + streamqueue.push(packet); + } + + void close() + { + if(isAttached) + { + /* remove all packets from the streamqueue */ + while(!streamqueue.empty()) + { + DataPacket *packet = streamqueue.front(); + packet->processed(); + streamqueue.pop(); + } + + server.detachRecorder(bsWrapper); + } + // similar effect like "delete this;" + bsWrapper = ByteSoundReceiver::null(); + } + + int read(mcopbyte *data, int size) + { + attach(); + + int remaining = size; + while(remaining) + { + if(blockingIO) + { + /* C API blocking style read */ + while(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(true); + } + else + { + /* non blocking I/O */ + if(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(false); + + /* still no more packets to read? */ + if(streamqueue.empty()) + return size - remaining; + } + + /* get a packet */ + DataPacket *packet = streamqueue.front(); + + /* copy some data from there */ + int tocopy = min(remaining,packet->size-pos); + memcpy(data,&packet->contents[pos],tocopy); + pos += tocopy; + data += tocopy; + remaining -= tocopy; + + /* have we read the whole packet? then get rid of it */ + if(pos == packet->size) + { + packet->processed(); + streamqueue.pop(); + pos = 0; + } + } + + /* no possible error conditions */ + return size; + } +}; + +class Sender : public ByteSoundProducerV2_skel, + public StdSynthModule, + virtual public Stream +{ + /* + * FIXME: bsWrapper is a more or less ugly trick to be able to use + * this object although not using smartwrappers to access it + */ + ByteSoundProducerV2 bsWrapper; + +protected: + virtual void attach() + { + if(!isAttached) + { + isAttached = true; + + server.attach(bsWrapper); + start(); + + /* + * TODO: this processOneEvent looks a bit strange here... it is + * there since StdIOManager does block 5 seconds on the first + * arts_write if it isn't - although notifications are pending + * + * Probably the real solution is to rewrite the + * StdIOManager::processOneEvent function. (And maybe drop the + * assumption that aRts will not block when an infinite amount + * of notifications is pending - I mean: will it ever happen?) + */ + Dispatcher::the()->ioManager()->processOneEvent(false); + } + } + +public: + Sender(SoundServer server, int rate, int bits, int channels, + string name) : Stream( server, rate, bits, channels, name) + { + bsWrapper = ByteSoundProducerV2::_from_base(this); + } + + virtual ~Sender() { + // + } + + long samplingRate() { return _samplingRate; } + long channels() { return _channels; } + long bits() { return _bits; } + bool finished() { return _finished; } + string title() { return _name; } + + void streamStart() + { + /* + * start streaming + */ + outdata.setPull(packetCount, packetCapacity); + } + + void request_outdata(DataPacket *packet) + { + streamqueue.push(packet); + } + + void close() + { + if(isAttached) + { + if(pos != 0) + { + /* send the last half-filled packet */ + DataPacket *packet = streamqueue.front(); + packet->size = pos; + packet->send(); + streamqueue.pop(); + } + outdata.endPull(); + + /* remove all packets from the streamqueue */ + while(!streamqueue.empty()) + { + DataPacket *packet = streamqueue.front(); + packet->size = 0; + packet->send(); + streamqueue.pop(); + } + + server.detach(bsWrapper); + } + // similar effect like "delete this;" + Arts::ByteSoundProducerV2_base* x = _copy(); + bsWrapper = ByteSoundProducerV2::null(); + x->_release(); + } + + int write(const mcopbyte *data, int size) + { + attach(); + + int remaining = size; + while(remaining) + { + if(blockingIO) + { + /* C API blocking style write */ + /* we're not waiting for any data here, but rather for + * DataPackets that we can fill */ + while(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(true); + } + else + { + /* non blocking I/O */ + if(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(false); + + /* still no more space to write? */ + if(streamqueue.empty()) + return size - remaining; + } + + /* get a packet */ + DataPacket *packet = streamqueue.front(); + + /* copy some data there */ + int tocopy = min(remaining,packetCapacity-pos); + memcpy(&packet->contents[pos],data,tocopy); + pos += tocopy; + data += tocopy; + remaining -= tocopy; + + /* have we filled up the packet? then send it */ + if(pos == packetCapacity) + { + packet->size = packetCapacity; + packet->send(); + streamqueue.pop(); + pos = 0; + } + } + + /* no possible error conditions */ + return size; + } +}; + +class ArtsCApi { +protected: + static ArtsCApi *instance; + int refcnt; + + Dispatcher dispatcher; + SoundServer server; + + ArtsCApi() : refcnt(1), server(Reference("global:Arts_SoundServer")) + { + // + } + +public: +// C Api commands + int init() { + if(server.isNull()) + return ARTS_E_NOSERVER; + + return 0; + } + + int suspend() { + if(!server.isNull()) + return server.suspend()? 1:0; + return ARTS_E_NOSERVER; + } + + int suspended() { + if(!server.isNull()) + return server.suspended()? 1:0; + return ARTS_E_NOSERVER; + } + + void free() { + // nothing to do + } + + arts_stream_t play_stream(int rate, int bits, int channels, const char *name) + { + if(server.isNull()) + return 0; + + return (arts_stream_t)static_cast(new Sender(server,rate,bits,channels,name)); + } + + arts_stream_t record_stream(int rate, int bits, int channels, const char *name) + { + if(server.isNull()) + return 0; + + return (arts_stream_t)static_cast(new Receiver(server,rate,bits,channels,name)); + } + + void close_stream(arts_stream_t stream) + { + if(server.isNull()) + return; + + if(!stream) + return; + + static_cast(stream)->close(); + } + + int write(arts_stream_t stream, const void *data, int size) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->write((const mcopbyte *)data,size); + } + + int read(arts_stream_t stream, void *data, int size) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->read((mcopbyte *)data,size); + } + + int stream_set(arts_stream_t stream, arts_parameter_t param, int value) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->stream_set(param,value); + } + + int stream_get(arts_stream_t stream, arts_parameter_t param) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->stream_get(param); + } + +// allocation and freeing of the class + static ArtsCApi *the() { + return instance; + } + static void ref() { + if(!instance) + instance = new ArtsCApi(); + else + instance->refcnt++; + } + static void release() { + assert(instance); + assert(instance->refcnt > 0); + instance->refcnt--; + if(instance->refcnt == 0) + { + delete instance; + instance = 0; + } + } +}; + +//----------------------------- static members ------------------------------- + +ArtsCApi *ArtsCApi::instance = 0; + +//------------------ wrappers from C to C++ class ---------------------------- + +extern "C" ARTSC_EXPORT int arts_backend_init() +{ + arts_backend_debug("arts_backend_init"); + ArtsCApi::ref(); + + // if init fails, don't expect free, and don't expect that the user + // continues using other API functions + int rc = ArtsCApi::the()->init(); + if(rc < 0) ArtsCApi::release(); + return rc; +} + +extern "C" ARTSC_EXPORT int arts_backend_suspend() +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + arts_backend_debug("arts_backend_suspend"); + return ArtsCApi::the()->suspend(); +} + +extern "C" ARTSC_EXPORT int arts_backend_suspended() +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + arts_backend_debug("arts_backend_suspended"); + return ArtsCApi::the()->suspended(); +} + +extern "C" ARTSC_EXPORT void arts_backend_free() +{ + if(!ArtsCApi::the()) return; + + arts_backend_debug("arts_backend_free"); + ArtsCApi::the()->free(); + ArtsCApi::release(); +} + +extern "C" ARTSC_EXPORT arts_stream_t arts_backend_play_stream(int rate, int bits, int channels, const char *name) +{ + if(!ArtsCApi::the()) return 0; + + arts_backend_debug("arts_backend_play_stream"); + return ArtsCApi::the()->play_stream(rate,bits,channels,name); +} + +extern "C" ARTSC_EXPORT arts_stream_t arts_backend_record_stream(int rate, int bits, int channels, const char *name) +{ + if(!ArtsCApi::the()) return 0; + + arts_backend_debug("arts_backend_record_stream"); + return ArtsCApi::the()->record_stream(rate,bits,channels,name); +} + +extern "C" ARTSC_EXPORT void arts_backend_close_stream(arts_stream_t stream) +{ + if(!ArtsCApi::the()) return; + + arts_backend_debug("arts_backend_close_stream"); + ArtsCApi::the()->close_stream(stream); +} + +extern "C" ARTSC_EXPORT int arts_backend_read(arts_stream_t stream, void *buffer, int count) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_backend_read"); + return ArtsCApi::the()->read(stream,buffer,count); +} + +extern "C" ARTSC_EXPORT int arts_backend_write(arts_stream_t stream, const void *buffer, + int count) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_backend_write"); + return ArtsCApi::the()->write(stream,buffer,count); +} + +extern "C" ARTSC_EXPORT int arts_backend_stream_set(arts_stream_t stream, + arts_parameter_t param, int value) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_stream_set"); + return ArtsCApi::the()->stream_set(stream,param,value); +} + +extern "C" ARTSC_EXPORT int arts_backend_stream_get(arts_stream_t stream, + arts_parameter_t param) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_stream_get"); + return ArtsCApi::the()->stream_get(stream,param); +} diff --git a/doc/TODO b/doc/TODO index 679af8e..29d2123 100644 --- a/doc/TODO +++ b/doc/TODO @@ -151,7 +151,7 @@ ## Misc -- put streamwise blocking into MCOP, see artscat.cc to read really ugly +- put streamwise blocking into MCOP, see artscat.cpp to read really ugly source which lives without that feature - implement plugins that transfer non-standard datatypes such as midi events, video frames, fft packets, oscilloscope views, ... (which was impossible @@ -185,7 +185,7 @@ Flowsystem transactions: Example: problematic assertion - assert(done[i] <= samples); /* synthschedule.cc:998 */ + assert(done[i] <= samples); /* synthschedule.cpp:998 */ the problem with the assertion here is this - suppose some object reacts in a way on some signal that will lead to the creation of new objects, diff --git a/examples/catfile.cc b/examples/catfile.cc deleted file mode 100644 index 3da8f75..0000000 --- a/examples/catfile.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - - Copyright (C) 2001 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include -#include -#include - -using namespace std; -using namespace Arts; - -int main(int argc, char **argv) -{ - if(argc != 2) - { - fprintf(stderr, "usage: catfile \n"); - exit(1); - } - - Dispatcher dispatcher; - FileInputStream file; - StdoutWriter writer; - - if(!file.open(argv[1])) - { - printf("can't open file %s\n",argv[1]); - exit(1); - } - - connect(file, writer); - - file.start(); - writer.start(); - - while(!file.eof()) - dispatcher.ioManager()->processOneEvent(false); -} diff --git a/examples/catfile.cpp b/examples/catfile.cpp new file mode 100644 index 0000000..3da8f75 --- /dev/null +++ b/examples/catfile.cpp @@ -0,0 +1,55 @@ +/* + + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include + +using namespace std; +using namespace Arts; + +int main(int argc, char **argv) +{ + if(argc != 2) + { + fprintf(stderr, "usage: catfile \n"); + exit(1); + } + + Dispatcher dispatcher; + FileInputStream file; + StdoutWriter writer; + + if(!file.open(argv[1])) + { + printf("can't open file %s\n",argv[1]); + exit(1); + } + + connect(file, writer); + + file.start(); + writer.start(); + + while(!file.eof()) + dispatcher.ioManager()->processOneEvent(false); +} diff --git a/examples/dcasttest.cc b/examples/dcasttest.cc deleted file mode 100644 index 5066cd7..0000000 --- a/examples/dcasttest.cc +++ /dev/null @@ -1,72 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include -#include -#include - -using namespace std; -using namespace Arts; - -/* - * This is a little test program that illustrates remote dynamic casting. - * Arts_SimpleSoundServer is a global object that is a SimpleSoundServer, - * so the first dynamic cast should succeed, while it is no Synth_PLAY, - * so the second dynamic cast should fail. - */ - -int main() -{ - Dispatcher dispatcher; - Object obj = Reference("global:Arts_SimpleSoundServer"); - - if(obj.isNull()) - { - cerr << "this test will only work if artsd is running" << endl; - exit(1); - } - - /* - * TODO: fix this. This fails currently as in the first line only an - * Object_stub will get created, no SimpleSoundServer_stub, and _cast - * which is used by DynamicCast wil only try to cast the _stub object, - * not do any further tricks. - */ - SimpleSoundServer server = DynamicCast(obj); - if(server.isNull()) - { - cerr << "remote dynamic casting is too restrictive" << endl; - exit(1); - } - - Synth_PLAY play = DynamicCast(obj); - if(!play.isNull()) - { - cerr << "remote dynamic casting doesn't do proper checks" << endl; - exit(1); - } - - cout << "remote dynamic casting seems to be fine" << endl; - return 0; -} diff --git a/examples/dcasttest.cpp b/examples/dcasttest.cpp new file mode 100644 index 0000000..5066cd7 --- /dev/null +++ b/examples/dcasttest.cpp @@ -0,0 +1,72 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld stefan@space.twc.de + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include +#include +#include + +using namespace std; +using namespace Arts; + +/* + * This is a little test program that illustrates remote dynamic casting. + * Arts_SimpleSoundServer is a global object that is a SimpleSoundServer, + * so the first dynamic cast should succeed, while it is no Synth_PLAY, + * so the second dynamic cast should fail. + */ + +int main() +{ + Dispatcher dispatcher; + Object obj = Reference("global:Arts_SimpleSoundServer"); + + if(obj.isNull()) + { + cerr << "this test will only work if artsd is running" << endl; + exit(1); + } + + /* + * TODO: fix this. This fails currently as in the first line only an + * Object_stub will get created, no SimpleSoundServer_stub, and _cast + * which is used by DynamicCast wil only try to cast the _stub object, + * not do any further tricks. + */ + SimpleSoundServer server = DynamicCast(obj); + if(server.isNull()) + { + cerr << "remote dynamic casting is too restrictive" << endl; + exit(1); + } + + Synth_PLAY play = DynamicCast(obj); + if(!play.isNull()) + { + cerr << "remote dynamic casting doesn't do proper checks" << endl; + exit(1); + } + + cout << "remote dynamic casting seems to be fine" << endl; + return 0; +} diff --git a/examples/flow.cc b/examples/flow.cc deleted file mode 100644 index eaddf32..0000000 --- a/examples/flow.cc +++ /dev/null @@ -1,56 +0,0 @@ - /* - - Copyright (C) 1999 Stefan Westerfeld, stefan@space.twc.de - Nicolas Brodu, nicolas.brodu@free.fr - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "artsflow.h" -#include "connect.h" - -using namespace Arts; - -int main() -{ - Dispatcher dispatcher; - - // object creation - Synth_FREQUENCY freq; - Synth_WAVE_SIN sin; - Synth_PLAY play; - - // object initialization - setValue(freq, 440.0); - - // object connection - connect(freq, sin); - connect(sin, play, "invalue_left"); - connect(sin, play, "invalue_right"); - - // start all objects (maybe we should group objects like with QWidget - // parents and such?) - freq.start(); - sin.start(); - play.start(); - - // go - dispatcher.run(); -} diff --git a/examples/flow.cpp b/examples/flow.cpp new file mode 100644 index 0000000..eaddf32 --- /dev/null +++ b/examples/flow.cpp @@ -0,0 +1,56 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld, stefan@space.twc.de + Nicolas Brodu, nicolas.brodu@free.fr + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "artsflow.h" +#include "connect.h" + +using namespace Arts; + +int main() +{ + Dispatcher dispatcher; + + // object creation + Synth_FREQUENCY freq; + Synth_WAVE_SIN sin; + Synth_PLAY play; + + // object initialization + setValue(freq, 440.0); + + // object connection + connect(freq, sin); + connect(sin, play, "invalue_left"); + connect(sin, play, "invalue_right"); + + // start all objects (maybe we should group objects like with QWidget + // parents and such?) + freq.start(); + sin.start(); + play.start(); + + // go + dispatcher.run(); +} diff --git a/examples/hello_impl.cc b/examples/hello_impl.cc deleted file mode 100644 index 5f7bb68..0000000 --- a/examples/hello_impl.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - - Copyright (C) 1999 Stefan Westerfeld - stefan@space.twc.de - Modified by Nicolas Brodu, nicolas.brodu@free.fr - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. -*/ - -#include "hello_impl.h" -#include - -using namespace std; - -void Hello_impl::hellobase(const string& s) -{ - printf("Hellobase '%s'!\n",s.c_str()); -} - -void Hello_impl::hello(const string& s) -{ - printf("Hello '%s'!\n",s.c_str()); -} - -void Hello_impl::constructor(long i) -{ - myvalue=i; -} - -long Hello_impl::myValue() -{ - return myvalue; -} - -void Hello_impl::myValue(long newValue) -{ - myvalue=newValue; -} - -void Hello_impl::add(long a) -{ - myvalue += a; -} - -void Hello_impl::printTotal() -{ - printf("Total=%ld\n",myvalue); -} - -long Hello_impl::sum(long a, long b) -{ - return a+b; -} - -string Hello_impl::concat(const string& s1, const string& s2) -{ - return s1+s2; -} - -REGISTER_IMPLEMENTATION(Hello_impl); diff --git a/examples/hello_impl.cpp b/examples/hello_impl.cpp new file mode 100644 index 0000000..5f7bb68 --- /dev/null +++ b/examples/hello_impl.cpp @@ -0,0 +1,76 @@ +/* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + Modified by Nicolas Brodu, nicolas.brodu@free.fr + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. +*/ + +#include "hello_impl.h" +#include + +using namespace std; + +void Hello_impl::hellobase(const string& s) +{ + printf("Hellobase '%s'!\n",s.c_str()); +} + +void Hello_impl::hello(const string& s) +{ + printf("Hello '%s'!\n",s.c_str()); +} + +void Hello_impl::constructor(long i) +{ + myvalue=i; +} + +long Hello_impl::myValue() +{ + return myvalue; +} + +void Hello_impl::myValue(long newValue) +{ + myvalue=newValue; +} + +void Hello_impl::add(long a) +{ + myvalue += a; +} + +void Hello_impl::printTotal() +{ + printf("Total=%ld\n",myvalue); +} + +long Hello_impl::sum(long a, long b) +{ + return a+b; +} + +string Hello_impl::concat(const string& s1, const string& s2) +{ + return s1+s2; +} + +REGISTER_IMPLEMENTATION(Hello_impl); diff --git a/examples/helloclient.cc b/examples/helloclient.cc deleted file mode 100644 index f5f3410..0000000 --- a/examples/helloclient.cc +++ /dev/null @@ -1,76 +0,0 @@ - /* - - Copyright (C) 1999 Stefan Westerfeld - stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "hello.h" - -#include -#include - -using namespace Arts; - -int main(int argc, char **argv) -{ - if(argc != 2) - { - fprintf(stderr,"usage: %s \n",argv[0]); - exit(1); - } - - Dispatcher dispatcher; - - Hello h = Reference(argv[1]); - if(h.isNull()) - { - fprintf(stderr,"can't connect to the object\n"); - exit(1); - } - - const char *who = getenv("LOGNAME"); - if(!who) who = "stefan"; - - printf("calling h.hello(\"%s\")\n", who); - h.hello(who); -/* - printf("h->sum(2,4) is %ld\n", - h->sum2(2,4)); - - printf("h->sum(2,4,6) is %ld\n", - h->sum3(2,4,6)); -*/ - h.myValue(6); - printf("h.myValue(6), h.myValue() is %ld\n", - h.myValue()); - - printf("h.concat(\"MCOP \",\"is great!\") is \"%s\"\n", - h.concat("MCOP ","is great!").c_str()); - - /* - int i,j = 0; - for(i=0;i<100000;i++) - j += h->sum2(2,4); - printf("%d\n",j); - */ - return 0; -} diff --git a/examples/helloclient.cpp b/examples/helloclient.cpp new file mode 100644 index 0000000..f5f3410 --- /dev/null +++ b/examples/helloclient.cpp @@ -0,0 +1,76 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "hello.h" + +#include +#include + +using namespace Arts; + +int main(int argc, char **argv) +{ + if(argc != 2) + { + fprintf(stderr,"usage: %s \n",argv[0]); + exit(1); + } + + Dispatcher dispatcher; + + Hello h = Reference(argv[1]); + if(h.isNull()) + { + fprintf(stderr,"can't connect to the object\n"); + exit(1); + } + + const char *who = getenv("LOGNAME"); + if(!who) who = "stefan"; + + printf("calling h.hello(\"%s\")\n", who); + h.hello(who); +/* + printf("h->sum(2,4) is %ld\n", + h->sum2(2,4)); + + printf("h->sum(2,4,6) is %ld\n", + h->sum3(2,4,6)); +*/ + h.myValue(6); + printf("h.myValue(6), h.myValue() is %ld\n", + h.myValue()); + + printf("h.concat(\"MCOP \",\"is great!\") is \"%s\"\n", + h.concat("MCOP ","is great!").c_str()); + + /* + int i,j = 0; + for(i=0;i<100000;i++) + j += h->sum2(2,4); + printf("%d\n",j); + */ + return 0; +} diff --git a/examples/hellodynamic.cc b/examples/hellodynamic.cc deleted file mode 100644 index b55cbf4..0000000 --- a/examples/hellodynamic.cc +++ /dev/null @@ -1,94 +0,0 @@ - /* - - Copyright (C) 1999 Stefan Westerfeld - stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "hello.h" -#include "dynamicrequest.h" - -#include -#include -#include - -using namespace std; -using namespace Arts; - -/* - * Hellodynamic illustrates the usage of the DynamicRequest class to perform - * dynamic requests. There are two things you can try - * - * hellodynamic - * - * which will use a local implementation of a hello object, and - * - * hellodynamic - * - * which will use a remote implementation of a hello object. - */ -int main(int argc, char **argv) -{ - Dispatcher dispatcher; - Hello h; - - // Check if we should connect to a remote server: - if(argc == 2) - { - h = Reference(argv[1]); - if(h.isNull()) - { - fprintf(stderr,"can't connect to the object\n"); - exit(1); - } - } - - // find out logname - const char *who = getenv("LOGNAME"); - if(!who) who = "stefan"; - - printf("calling h.hello(\"%s\")\n", who); - - // the dynamic equivalent to h.hello(who) - DynamicRequest hellorequest(h); - - if(!hellorequest.method("hello").param(who).invoke()) - cout << "dynamic invocation to h.hello(...) failed" << endl; - - /* - Note: you could reuse hellorequest here, and indeed, if you - call the _same_ method over and over again, you'll get quite - some speed gain as the signature is only looked up once. - */ - - // set a value (no error checking here, I am lazy ;) - DynamicRequest(h).method("_set_myValue").param(42).invoke(); - - // get a value via "normal" interface - printf("h.myValue() is %ld (after setting it to 42)\n", h.myValue()); - - // call h.concat("MCOP ","rules.") dynamically - string s; - DynamicRequest(h).method("concat").param("MCOP ").param("rules.").invoke(s); - cout << "Conclusion of this test: " << s << endl; - - return 0; -} diff --git a/examples/hellodynamic.cpp b/examples/hellodynamic.cpp new file mode 100644 index 0000000..b55cbf4 --- /dev/null +++ b/examples/hellodynamic.cpp @@ -0,0 +1,94 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "hello.h" +#include "dynamicrequest.h" + +#include +#include +#include + +using namespace std; +using namespace Arts; + +/* + * Hellodynamic illustrates the usage of the DynamicRequest class to perform + * dynamic requests. There are two things you can try + * + * hellodynamic + * + * which will use a local implementation of a hello object, and + * + * hellodynamic + * + * which will use a remote implementation of a hello object. + */ +int main(int argc, char **argv) +{ + Dispatcher dispatcher; + Hello h; + + // Check if we should connect to a remote server: + if(argc == 2) + { + h = Reference(argv[1]); + if(h.isNull()) + { + fprintf(stderr,"can't connect to the object\n"); + exit(1); + } + } + + // find out logname + const char *who = getenv("LOGNAME"); + if(!who) who = "stefan"; + + printf("calling h.hello(\"%s\")\n", who); + + // the dynamic equivalent to h.hello(who) + DynamicRequest hellorequest(h); + + if(!hellorequest.method("hello").param(who).invoke()) + cout << "dynamic invocation to h.hello(...) failed" << endl; + + /* + Note: you could reuse hellorequest here, and indeed, if you + call the _same_ method over and over again, you'll get quite + some speed gain as the signature is only looked up once. + */ + + // set a value (no error checking here, I am lazy ;) + DynamicRequest(h).method("_set_myValue").param(42).invoke(); + + // get a value via "normal" interface + printf("h.myValue() is %ld (after setting it to 42)\n", h.myValue()); + + // call h.concat("MCOP ","rules.") dynamically + string s; + DynamicRequest(h).method("concat").param("MCOP ").param("rules.").invoke(s); + cout << "Conclusion of this test: " << s << endl; + + return 0; +} diff --git a/examples/hellodynamic2.cc b/examples/hellodynamic2.cc deleted file mode 100644 index 0647564..0000000 --- a/examples/hellodynamic2.cc +++ /dev/null @@ -1,124 +0,0 @@ - /* - - Copyright (C) 2001 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#include "hello.h" -#include "dynamicskeleton.h" -#include "debug.h" -#include "stdio.h" - -using namespace Arts; -using namespace std; - -namespace Arts { typedef DynamicSkeleton Object_dskel; } - -class HelloDynamic : public Arts::Object_dskel { -protected: - long myValue; - -public: - HelloDynamic() : Arts::Object_dskel("Hello") { - } - void process(long methodID, Arts::Buffer *request, Arts::Buffer *result) - { - const Arts::MethodDef& methodDef = getMethodDef(methodID); - - if(methodDef.name == "hello") // void hello(string); - { - string s; request->readString(s); - printf("Hello '%s'!\n",s.c_str()); - } - else if(methodDef.name == "_set_myValue") // attribute long myValue; - { - myValue = request->readLong(); - } - else if(methodDef.name == "_get_myValue") - { - result->writeLong(myValue); - } - else if(methodDef.name == "concat") - { - string s1; request->readString(s1); - string s2; request->readString(s2); - result->writeString(s1+s2); - } - else if(methodDef.name == "sum") - { - long a = request->readLong(); - long b = request->readLong(); - result->writeLong(a+b); - } - else - { - arts_fatal("method %s unimplemented", methodDef.name.c_str()); - } - } -}; - -/* - * this program illustrates that you /can/ implement an interface without - * using the IDL compiler skeleton do to so - this is useful if you want - * to create a language or object system binding, where you don't know - * all interfaces that are present at compile time - * - * however, it's definitely advanced stuff, and not for daily use ;) - */ -int main() -{ - Dispatcher dispatcher; - - Object obj = Object::_from_base(new HelloDynamic()); - if(obj.isNull()) - arts_fatal("dimpl is no object?"); - - HelloBase b = DynamicCast(obj); - if(b.isNull()) - arts_fatal("can't cast the object to HelloBase"); - - - Hello h = DynamicCast(obj); - /*arts_info("%d",obj.isCompatibleWith("Hello"));*/ - - if(h.isNull()) - arts_fatal("can't destringify to the object"); - - const char *who = getenv("LOGNAME"); - if(!who) who = "stefan"; - - arts_info("calling h.hello(\"%s\")", who); - h.hello(who); - - h.myValue(6); - arts_info("h.myValue(6), h.myValue() is %ld", - h.myValue()); - - arts_info("h.concat(\"MCOP \",\"is great!\") is \"%s\"", - h.concat("MCOP ","is great!").c_str()); - - /* - int i,j = 0; - for(i=0;i<100000;i++) - j += h.sum(2,4); - printf("%d\n",j); - */ - - return 0; -} diff --git a/examples/hellodynamic2.cpp b/examples/hellodynamic2.cpp new file mode 100644 index 0000000..0647564 --- /dev/null +++ b/examples/hellodynamic2.cpp @@ -0,0 +1,124 @@ + /* + + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "hello.h" +#include "dynamicskeleton.h" +#include "debug.h" +#include "stdio.h" + +using namespace Arts; +using namespace std; + +namespace Arts { typedef DynamicSkeleton Object_dskel; } + +class HelloDynamic : public Arts::Object_dskel { +protected: + long myValue; + +public: + HelloDynamic() : Arts::Object_dskel("Hello") { + } + void process(long methodID, Arts::Buffer *request, Arts::Buffer *result) + { + const Arts::MethodDef& methodDef = getMethodDef(methodID); + + if(methodDef.name == "hello") // void hello(string); + { + string s; request->readString(s); + printf("Hello '%s'!\n",s.c_str()); + } + else if(methodDef.name == "_set_myValue") // attribute long myValue; + { + myValue = request->readLong(); + } + else if(methodDef.name == "_get_myValue") + { + result->writeLong(myValue); + } + else if(methodDef.name == "concat") + { + string s1; request->readString(s1); + string s2; request->readString(s2); + result->writeString(s1+s2); + } + else if(methodDef.name == "sum") + { + long a = request->readLong(); + long b = request->readLong(); + result->writeLong(a+b); + } + else + { + arts_fatal("method %s unimplemented", methodDef.name.c_str()); + } + } +}; + +/* + * this program illustrates that you /can/ implement an interface without + * using the IDL compiler skeleton do to so - this is useful if you want + * to create a language or object system binding, where you don't know + * all interfaces that are present at compile time + * + * however, it's definitely advanced stuff, and not for daily use ;) + */ +int main() +{ + Dispatcher dispatcher; + + Object obj = Object::_from_base(new HelloDynamic()); + if(obj.isNull()) + arts_fatal("dimpl is no object?"); + + HelloBase b = DynamicCast(obj); + if(b.isNull()) + arts_fatal("can't cast the object to HelloBase"); + + + Hello h = DynamicCast(obj); + /*arts_info("%d",obj.isCompatibleWith("Hello"));*/ + + if(h.isNull()) + arts_fatal("can't destringify to the object"); + + const char *who = getenv("LOGNAME"); + if(!who) who = "stefan"; + + arts_info("calling h.hello(\"%s\")", who); + h.hello(who); + + h.myValue(6); + arts_info("h.myValue(6), h.myValue() is %ld", + h.myValue()); + + arts_info("h.concat(\"MCOP \",\"is great!\") is \"%s\"", + h.concat("MCOP ","is great!").c_str()); + + /* + int i,j = 0; + for(i=0;i<100000;i++) + j += h.sum(2,4); + printf("%d\n",j); + */ + + return 0; +} diff --git a/examples/hellomain.cc b/examples/hellomain.cc deleted file mode 100644 index 024f97a..0000000 --- a/examples/hellomain.cc +++ /dev/null @@ -1,77 +0,0 @@ - /* - - Copyright (C) 1999 Stefan Westerfeld stefan@space.twc.de - Nicolas Brodu, brodu@kde.org - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "hello.h" -#include - -using namespace std; -using namespace Arts; - -int main() -{ - Dispatcher dispatcher; - - // Just use plain C++! - Hello server; - server.hello("server"); - - // creation from MCOP reference - Hello client( Reference( server.toString() ) ); - if (!client.isNull()) client.hello("local test"); - else cout << "fatal: a valid reference can't be decoded" << endl; - - // creation from wrong reference - Hello xclient( Reference("fdshjkhdsf") ); - - // check result => should be null - if (xclient.isNull()) cout << "passed invalid reference test" << endl; - else cout << "fatal: an invalid reference can be decoded" << endl; - - // using a constructor - Hello hint(3); - cout << hint.myValue() << endl; - - - Hello castsrc; - HelloBase casthint = castsrc; - casthint.hellobase("cast test passed"); - if(castsrc.isNull()) cout << "cast problem with auto creation" << endl; - castsrc.hello("second cast test passed"); - - // Can copy (or here copy constructor) the objects - Hello hcopy = hint; - hcopy.add(5); - hcopy.printTotal(); - - // dynamic creation is OK - Hello* dyn = new Hello; - cout << dyn->concat("I am"," a dynamic hello") << endl; - dyn->hellobase("dynamic hellobase hello"); - delete dyn; - -// dispatcher.run(); - return 0; - -} diff --git a/examples/hellomain.cpp b/examples/hellomain.cpp new file mode 100644 index 0000000..024f97a --- /dev/null +++ b/examples/hellomain.cpp @@ -0,0 +1,77 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld stefan@space.twc.de + Nicolas Brodu, brodu@kde.org + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "hello.h" +#include + +using namespace std; +using namespace Arts; + +int main() +{ + Dispatcher dispatcher; + + // Just use plain C++! + Hello server; + server.hello("server"); + + // creation from MCOP reference + Hello client( Reference( server.toString() ) ); + if (!client.isNull()) client.hello("local test"); + else cout << "fatal: a valid reference can't be decoded" << endl; + + // creation from wrong reference + Hello xclient( Reference("fdshjkhdsf") ); + + // check result => should be null + if (xclient.isNull()) cout << "passed invalid reference test" << endl; + else cout << "fatal: an invalid reference can be decoded" << endl; + + // using a constructor + Hello hint(3); + cout << hint.myValue() << endl; + + + Hello castsrc; + HelloBase casthint = castsrc; + casthint.hellobase("cast test passed"); + if(castsrc.isNull()) cout << "cast problem with auto creation" << endl; + castsrc.hello("second cast test passed"); + + // Can copy (or here copy constructor) the objects + Hello hcopy = hint; + hcopy.add(5); + hcopy.printTotal(); + + // dynamic creation is OK + Hello* dyn = new Hello; + cout << dyn->concat("I am"," a dynamic hello") << endl; + dyn->hellobase("dynamic hellobase hello"); + delete dyn; + +// dispatcher.run(); + return 0; + +} diff --git a/examples/helloserver.cc b/examples/helloserver.cc deleted file mode 100644 index 01ffa41..0000000 --- a/examples/helloserver.cc +++ /dev/null @@ -1,52 +0,0 @@ - /* - - Copyright (C) 1999 Stefan Westerfeld - stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "common.h" -#include "hello_impl.h" - -#include -#include -#include - -using namespace std; -using namespace Arts; - -int main() -{ - Dispatcher dispatcher(0,Dispatcher::startUnixServer); - Hello server; - - string reference = server.toString(); - printf("%s\n",reference.c_str()); - - Hello h = Reference(reference); - if(!h.isNull()) - h.hello("local test"); - else - printf("Local access to the Hello_impl object failed?\n"); - - dispatcher.run(); - return 0; -} diff --git a/examples/helloserver.cpp b/examples/helloserver.cpp new file mode 100644 index 0000000..01ffa41 --- /dev/null +++ b/examples/helloserver.cpp @@ -0,0 +1,52 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "common.h" +#include "hello_impl.h" + +#include +#include +#include + +using namespace std; +using namespace Arts; + +int main() +{ + Dispatcher dispatcher(0,Dispatcher::startUnixServer); + Hello server; + + string reference = server.toString(); + printf("%s\n",reference.c_str()); + + Hello h = Reference(reference); + if(!h.isNull()) + h.hello("local test"); + else + printf("Local access to the Hello_impl object failed?\n"); + + dispatcher.run(); + return 0; +} diff --git a/examples/irdemo.cc b/examples/irdemo.cc deleted file mode 100644 index aedd832..0000000 --- a/examples/irdemo.cc +++ /dev/null @@ -1,155 +0,0 @@ - /* - - Copyright (C) 1999 Stefan Westerfeld - stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "common.h" - -#include -#include -#include -#include - -using namespace std; -using namespace Arts; - -static void printInterface(InterfaceDef id) -{ - string inherit; - if(id.inheritedInterfaces.size()) - { - vector::iterator ii; - bool first = true; - inherit = ": "; - for(ii = id.inheritedInterfaces.begin(); ii != id.inheritedInterfaces.end(); ii++) - { - if(!first) inherit +=","; - first = false; - inherit += (*ii)+" "; - } - } - printf("interface %s %s{\n",id.name.c_str(),inherit.c_str()); - // attributes, streams - vector::iterator ai; - for(ai = id.attributes.begin(); ai != id.attributes.end(); ai++) - { - const AttributeDef& ad = *ai; - if(ad.flags & attributeAttribute) - { - /* readwrite */ - if(ad.flags & (streamOut|streamIn) == (streamOut|streamIn)) - { - printf(" attribute %s %s;\n",ad.type.c_str(), ad.name.c_str()); - } - else - { - if(ad.flags & streamOut) /* readable from outside */ - { - printf(" readonly attribute %s %s;\n", - ad.type.c_str(), ad.name.c_str()); - } - if(ad.flags & streamIn) /* writeable from outside */ - { - printf(" ?writeonly? attribute %s %s;\n", - ad.type.c_str(), ad.name.c_str()); - } - } - } - if(ad.flags & attributeStream) - { - const char *dir = (ad.flags & streamOut)?"out":"in"; - const char *async = (ad.flags & streamAsync)?"async ":""; - string type = ad.type; - if(type == "float" && !(ad.flags & streamAsync)) type = "audio"; - - printf(" %s%s %s stream %s;\n",async,dir, - type.c_str(),ad.name.c_str()); - } - } - - // methods - vector::iterator mi; - for(mi = id.methods.begin();mi != id.methods.end(); mi++) - { - MethodDef& md = *mi; - printf(" %s %s(",md.type.c_str(),md.name.c_str()); - - bool first = true; - vector::iterator pi; - for(pi = md.signature.begin(); pi != md.signature.end(); pi++) - { - ParamDef& pd = *pi; - if(!first) printf(", "); - printf("%s %s",pd.type.c_str(),pd.name.c_str()); - first = false; - } - printf(");\n"); - } - printf("}\n"); -} - -/* - * This demo shows that you can find out what interface an object has and - * what types it needs to work without knowing anything but the object - * reference. - * - * The reason for that is that every object offers the _interfaceName - * _queryInterface and _queryType methods, which you can use to find out - * anything you need to know to talk to that object. - * - * Just pass this programm an MCOP object reference, and it will print out - * the corresponding interface. - * - * (TODO: one could make it print out all inherited interfaces and the - * types that are used in the interface, too. Ports, etc could be shown - * as well). - */ - -/** - * Interface repository demo - reasonable testcase: - * - * - make sure artsd is running - * - irdemo global:Arts_SimpleSoundServer - */ -int main(int argc, char **argv) -{ - if(argc != 2) - { - fprintf(stderr,"usage: %s \n",argv[0]); - exit(1); - } - - Dispatcher dispatcher; - Object o = Reference(argv[1]); - if(o.isNull()) - { - fprintf(stderr,"can't connect to the object\n"); - exit(1); - } - - string iname = o._interfaceName(); - InterfaceDef idef = o._queryInterface(iname); - printInterface(idef); - - return 0; -} diff --git a/examples/irdemo.cpp b/examples/irdemo.cpp new file mode 100644 index 0000000..aedd832 --- /dev/null +++ b/examples/irdemo.cpp @@ -0,0 +1,155 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "common.h" + +#include +#include +#include +#include + +using namespace std; +using namespace Arts; + +static void printInterface(InterfaceDef id) +{ + string inherit; + if(id.inheritedInterfaces.size()) + { + vector::iterator ii; + bool first = true; + inherit = ": "; + for(ii = id.inheritedInterfaces.begin(); ii != id.inheritedInterfaces.end(); ii++) + { + if(!first) inherit +=","; + first = false; + inherit += (*ii)+" "; + } + } + printf("interface %s %s{\n",id.name.c_str(),inherit.c_str()); + // attributes, streams + vector::iterator ai; + for(ai = id.attributes.begin(); ai != id.attributes.end(); ai++) + { + const AttributeDef& ad = *ai; + if(ad.flags & attributeAttribute) + { + /* readwrite */ + if(ad.flags & (streamOut|streamIn) == (streamOut|streamIn)) + { + printf(" attribute %s %s;\n",ad.type.c_str(), ad.name.c_str()); + } + else + { + if(ad.flags & streamOut) /* readable from outside */ + { + printf(" readonly attribute %s %s;\n", + ad.type.c_str(), ad.name.c_str()); + } + if(ad.flags & streamIn) /* writeable from outside */ + { + printf(" ?writeonly? attribute %s %s;\n", + ad.type.c_str(), ad.name.c_str()); + } + } + } + if(ad.flags & attributeStream) + { + const char *dir = (ad.flags & streamOut)?"out":"in"; + const char *async = (ad.flags & streamAsync)?"async ":""; + string type = ad.type; + if(type == "float" && !(ad.flags & streamAsync)) type = "audio"; + + printf(" %s%s %s stream %s;\n",async,dir, + type.c_str(),ad.name.c_str()); + } + } + + // methods + vector::iterator mi; + for(mi = id.methods.begin();mi != id.methods.end(); mi++) + { + MethodDef& md = *mi; + printf(" %s %s(",md.type.c_str(),md.name.c_str()); + + bool first = true; + vector::iterator pi; + for(pi = md.signature.begin(); pi != md.signature.end(); pi++) + { + ParamDef& pd = *pi; + if(!first) printf(", "); + printf("%s %s",pd.type.c_str(),pd.name.c_str()); + first = false; + } + printf(");\n"); + } + printf("}\n"); +} + +/* + * This demo shows that you can find out what interface an object has and + * what types it needs to work without knowing anything but the object + * reference. + * + * The reason for that is that every object offers the _interfaceName + * _queryInterface and _queryType methods, which you can use to find out + * anything you need to know to talk to that object. + * + * Just pass this programm an MCOP object reference, and it will print out + * the corresponding interface. + * + * (TODO: one could make it print out all inherited interfaces and the + * types that are used in the interface, too. Ports, etc could be shown + * as well). + */ + +/** + * Interface repository demo - reasonable testcase: + * + * - make sure artsd is running + * - irdemo global:Arts_SimpleSoundServer + */ +int main(int argc, char **argv) +{ + if(argc != 2) + { + fprintf(stderr,"usage: %s \n",argv[0]); + exit(1); + } + + Dispatcher dispatcher; + Object o = Reference(argv[1]); + if(o.isNull()) + { + fprintf(stderr,"can't connect to the object\n"); + exit(1); + } + + string iname = o._interfaceName(); + InterfaceDef idef = o._queryInterface(iname); + printInterface(idef); + + return 0; +} diff --git a/examples/playtofile_impl.cc b/examples/playtofile_impl.cc deleted file mode 100644 index ff7602a..0000000 --- a/examples/playtofile_impl.cc +++ /dev/null @@ -1,99 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#include "playtofile.h" -#include "flowsystem.h" -#include "stdsynthmodule.h" -#include "convert.h" -#include "stdio.h" - -using namespace Arts; -using namespace std; - -namespace Arts { - class PlayToFile_impl : virtual public PlayToFile_skel, - virtual public StdSynthModule - { - typedef unsigned char uchar; - unsigned char *outblock; - unsigned long maxsamples; - string _filename; - FILE *out; - public: - PlayToFile_impl() : _filename("-") - { - } - void filename(const string& newfilename) { - _filename = newfilename; - filename_changed(_filename); - } - - string filename() { return _filename; } - - void streamInit() { - maxsamples = 0; - outblock = 0; - if(_filename == "-") - out = stdout; - else - out = fopen(_filename.c_str(),"w"); - } - void streamEnd() { - if(outblock) - { - delete[] outblock; - outblock = 0; - } - if(out != stdout) - { - fclose(out); - } - } - - void calculateBlock(unsigned long samples) - { - if(samples > maxsamples) - { - maxsamples = samples; - - if(outblock) delete[] outblock; - outblock = new uchar[maxsamples * 4]; // 2 channels, 16 bit - } - - convert_stereo_2float_i16le(samples,left,right, outblock); - fwrite(outblock, 1, 4 * samples,out); - } - - /* - * this is the most tricky part here - since we will run in a context - * where no audio hardware will play the "give me more data role", - * we'll have to request things ourselves (requireFlow() tells the - * flowsystem that more signal flow should happen, so that - * calculateBlock will get called - */ - void goOn() - { - _node()->requireFlow(); - } - }; - REGISTER_IMPLEMENTATION(PlayToFile_impl); -}; diff --git a/examples/playtofile_impl.cpp b/examples/playtofile_impl.cpp new file mode 100644 index 0000000..ff7602a --- /dev/null +++ b/examples/playtofile_impl.cpp @@ -0,0 +1,99 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "playtofile.h" +#include "flowsystem.h" +#include "stdsynthmodule.h" +#include "convert.h" +#include "stdio.h" + +using namespace Arts; +using namespace std; + +namespace Arts { + class PlayToFile_impl : virtual public PlayToFile_skel, + virtual public StdSynthModule + { + typedef unsigned char uchar; + unsigned char *outblock; + unsigned long maxsamples; + string _filename; + FILE *out; + public: + PlayToFile_impl() : _filename("-") + { + } + void filename(const string& newfilename) { + _filename = newfilename; + filename_changed(_filename); + } + + string filename() { return _filename; } + + void streamInit() { + maxsamples = 0; + outblock = 0; + if(_filename == "-") + out = stdout; + else + out = fopen(_filename.c_str(),"w"); + } + void streamEnd() { + if(outblock) + { + delete[] outblock; + outblock = 0; + } + if(out != stdout) + { + fclose(out); + } + } + + void calculateBlock(unsigned long samples) + { + if(samples > maxsamples) + { + maxsamples = samples; + + if(outblock) delete[] outblock; + outblock = new uchar[maxsamples * 4]; // 2 channels, 16 bit + } + + convert_stereo_2float_i16le(samples,left,right, outblock); + fwrite(outblock, 1, 4 * samples,out); + } + + /* + * this is the most tricky part here - since we will run in a context + * where no audio hardware will play the "give me more data role", + * we'll have to request things ourselves (requireFlow() tells the + * flowsystem that more signal flow should happen, so that + * calculateBlock will get called + */ + void goOn() + { + _node()->requireFlow(); + } + }; + REGISTER_IMPLEMENTATION(PlayToFile_impl); +}; diff --git a/examples/playtofile_main.cc b/examples/playtofile_main.cc deleted file mode 100644 index ba049da..0000000 --- a/examples/playtofile_main.cc +++ /dev/null @@ -1,147 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#include "playtofile.h" -#include "kmedia2.h" -#include "debug.h" -#include "dynamicrequest.h" -#include "connect.h" -#include "flowsystem.h" -#include -#include - -using namespace Arts; -using namespace std; - -/* copypasted from simplesoundserver_impl.cc */ -PlayObject createPlayObject(const string& filename) -{ - string objectType = ""; - - /* - * figure out extension (as lowercased letters) - */ - string extension = ""; - bool extensionok = false; - string::const_reverse_iterator i; - for(i = filename.rbegin(); i != filename.rend() && !extensionok; i++) - { - if(*i == '.') - extensionok = true; - else - extension = (char)tolower(*i) + extension; - } - - /* - * query trader for PlayObjects which support this - */ - if(extensionok) - { - arts_debug("search playobject, extension = %s",extension.c_str()); - - TraderQuery query; - query.supports("Interface","Arts::PlayObject"); - query.supports("Extension",extension); - - vector *offers = query.query(); - if(!offers->empty()) - objectType = offers->front().interfaceName(); // first offer - - delete offers; - } - - /* - * create a PlayObject and connect it - */ - if(!objectType.empty()) - { - arts_debug("creating %s to play file", objectType.c_str()); - - PlayObject result = SubClass(objectType); - if(result.loadMedia(filename)) - { - result._node()->start(); - return result; - } - else arts_warning("couldn't load file %s", filename.c_str()); - } - else arts_warning("file format extension %s unsupported",extension.c_str()); - - return PlayObject::null(); -} - -/* - * This is an example for dumping things to a file. It demonstates, that - * - * a) you can use all aRts objects in a non-realtime environment (i.e. - * the time in the PlayObject will pass much faster than the outside - * time when dumping things to a file) - * - * b) complayObjectnents will be dynamically loaded as needed - * - * c) you need to do small tricks to get the signal flow going when you are - * not having audio modules around - * - * d) by implementing aRts modules, you can easily grab and insert data from/to - * arbitary non-aRts sources - for instance, a wave editor might implement - * own modules to get the wave from/to memory - */ -int main(int argc, char **argv) -{ - Dispatcher d; - - if(argc != 2 && argc != 3) - { - cerr << "usage: playtofile [ ]" << endl; - exit(1); - } - PlayObject playObject = createPlayObject(argv[1]); - if(playObject.isNull()) - { - cerr << "can't read inputfile " << argv[1] << endl; - exit(1); - } - - playObject.play(); - - PlayToFile playToFile; - if(argc == 3) playToFile.filename(argv[2]); - - connect(playObject, "left", playToFile,"left"); - connect(playObject, "right", playToFile,"right"); - - // - // special case when using mpeglib, do tell it not to block (internal - // interface) - we also put an usleep here to ensure that the threads - // and everything is fully initialized as soon as we start - usleep(100000); - if(playObject._base()->_isCompatibleWith("DecoderBaseObject")) - if(!DynamicRequest(playObject).method("_set_blocking").param(true).invoke()) - cerr << "mpeglib, and blocking attribute can't be changed?" << endl; - // - - playToFile.start(); - while(playObject.state() != posIdle) - playToFile.goOn(); - - return 0; -} diff --git a/examples/playtofile_main.cpp b/examples/playtofile_main.cpp new file mode 100644 index 0000000..bd47185 --- /dev/null +++ b/examples/playtofile_main.cpp @@ -0,0 +1,147 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "playtofile.h" +#include "kmedia2.h" +#include "debug.h" +#include "dynamicrequest.h" +#include "connect.h" +#include "flowsystem.h" +#include +#include + +using namespace Arts; +using namespace std; + +/* copypasted from simplesoundserver_impl.cpp */ +PlayObject createPlayObject(const string& filename) +{ + string objectType = ""; + + /* + * figure out extension (as lowercased letters) + */ + string extension = ""; + bool extensionok = false; + string::const_reverse_iterator i; + for(i = filename.rbegin(); i != filename.rend() && !extensionok; i++) + { + if(*i == '.') + extensionok = true; + else + extension = (char)tolower(*i) + extension; + } + + /* + * query trader for PlayObjects which support this + */ + if(extensionok) + { + arts_debug("search playobject, extension = %s",extension.c_str()); + + TraderQuery query; + query.supports("Interface","Arts::PlayObject"); + query.supports("Extension",extension); + + vector *offers = query.query(); + if(!offers->empty()) + objectType = offers->front().interfaceName(); // first offer + + delete offers; + } + + /* + * create a PlayObject and connect it + */ + if(!objectType.empty()) + { + arts_debug("creating %s to play file", objectType.c_str()); + + PlayObject result = SubClass(objectType); + if(result.loadMedia(filename)) + { + result._node()->start(); + return result; + } + else arts_warning("couldn't load file %s", filename.c_str()); + } + else arts_warning("file format extension %s unsupported",extension.c_str()); + + return PlayObject::null(); +} + +/* + * This is an example for dumping things to a file. It demonstates, that + * + * a) you can use all aRts objects in a non-realtime environment (i.e. + * the time in the PlayObject will pass much faster than the outside + * time when dumping things to a file) + * + * b) complayObjectnents will be dynamically loaded as needed + * + * c) you need to do small tricks to get the signal flow going when you are + * not having audio modules around + * + * d) by implementing aRts modules, you can easily grab and insert data from/to + * arbitary non-aRts sources - for instance, a wave editor might implement + * own modules to get the wave from/to memory + */ +int main(int argc, char **argv) +{ + Dispatcher d; + + if(argc != 2 && argc != 3) + { + cerr << "usage: playtofile [ ]" << endl; + exit(1); + } + PlayObject playObject = createPlayObject(argv[1]); + if(playObject.isNull()) + { + cerr << "can't read inputfile " << argv[1] << endl; + exit(1); + } + + playObject.play(); + + PlayToFile playToFile; + if(argc == 3) playToFile.filename(argv[2]); + + connect(playObject, "left", playToFile,"left"); + connect(playObject, "right", playToFile,"right"); + + // + // special case when using mpeglib, do tell it not to block (internal + // interface) - we also put an usleep here to ensure that the threads + // and everything is fully initialized as soon as we start + usleep(100000); + if(playObject._base()->_isCompatibleWith("DecoderBaseObject")) + if(!DynamicRequest(playObject).method("_set_blocking").param(true).invoke()) + cerr << "mpeglib, and blocking attribute can't be changed?" << endl; + // + + playToFile.start(); + while(playObject.state() != posIdle) + playToFile.goOn(); + + return 0; +} diff --git a/examples/referenceinfo.cc b/examples/referenceinfo.cc deleted file mode 100644 index b980378..0000000 --- a/examples/referenceinfo.cc +++ /dev/null @@ -1,57 +0,0 @@ - /* - - Copyright (C) 1999 Stefan Westerfeld - stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "common.h" -#include - -using namespace Arts; - -int main(int argc, char **argv) -{ - Dispatcher dispatcher; - ObjectReference r; - - if(argc != 2) - { - fprintf(stderr,"usage: %s \n",argv[0]); - exit(1); - } - - if(!dispatcher.stringToObjectReference(r,argv[1])) - { - fprintf(stderr, - "Can't read this object reference (invalid?)\n"); - exit(1); - } - printf("serverID: %s\n",r.serverID.c_str()); - printf("objectID: %ld\n\n",r.objectID); - - printf("URLs:\n"); - std::vector::iterator ui; - for(ui = r.urls.begin(); ui != r.urls.end();ui++) - printf(" - %s\n",ui->c_str()); - - return 0; -} diff --git a/examples/referenceinfo.cpp b/examples/referenceinfo.cpp new file mode 100644 index 0000000..b980378 --- /dev/null +++ b/examples/referenceinfo.cpp @@ -0,0 +1,57 @@ + /* + + Copyright (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "common.h" +#include + +using namespace Arts; + +int main(int argc, char **argv) +{ + Dispatcher dispatcher; + ObjectReference r; + + if(argc != 2) + { + fprintf(stderr,"usage: %s \n",argv[0]); + exit(1); + } + + if(!dispatcher.stringToObjectReference(r,argv[1])) + { + fprintf(stderr, + "Can't read this object reference (invalid?)\n"); + exit(1); + } + printf("serverID: %s\n",r.serverID.c_str()); + printf("objectID: %ld\n\n",r.objectID); + + printf("URLs:\n"); + std::vector::iterator ui; + for(ui = r.urls.begin(); ui != r.urls.end();ui++) + printf(" - %s\n",ui->c_str()); + + return 0; +} diff --git a/examples/streamsound.cc b/examples/streamsound.cc deleted file mode 100644 index 170d6de..0000000 --- a/examples/streamsound.cc +++ /dev/null @@ -1,106 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "soundserver.h" -#include "stdsynthmodule.h" - -#include -#include -#include -#include -#include - -using namespace std; -using namespace Arts; - -class Sender : public ByteSoundProducer_skel, - public StdSynthModule -{ - bool _finished; - int pos; -public: - Sender() : _finished(false), pos(0) - { - } - long samplingRate() { return 44100; } - long channels() { return 2; } - long bits() { return 16; } - bool finished() { return _finished; } - - static const int packetCount = 10, packetCapacity = 1024; - void streamStart() - { - /* - * start streaming - */ - outdata.setPull(packetCount, packetCapacity); - } - - void request_outdata(DataPacket *packet) - { - /* - * fill the packet with new data - */ - // ----------------- audio fill up start ----------------- - - int j; - mcopbyte *to = &packet->contents[0]; - for(j=0;j> 8) & 0xff; - *to++ = right & 0xff; - *to++ = (right >> 8) & 0xff; - } - - // ------------------ audio fill up end ------------------ - packet->send(); - } -}; - -int main(int argc, char **argv) -{ - Dispatcher dispatcher; - SimpleSoundServer server = Reference("global:Arts_SimpleSoundServer"); - - if(server.isNull()) - { - cerr << "Can't connect to sound server" << endl; - return 1; - } - - ByteSoundProducer sender = ByteSoundProducer::_from_base(new Sender()); - server.attach(sender); - sender.start(); - dispatcher.run(); - server.detach(sender); // in this example: not reached -} diff --git a/examples/streamsound.cpp b/examples/streamsound.cpp new file mode 100644 index 0000000..170d6de --- /dev/null +++ b/examples/streamsound.cpp @@ -0,0 +1,106 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include "soundserver.h" +#include "stdsynthmodule.h" + +#include +#include +#include +#include +#include + +using namespace std; +using namespace Arts; + +class Sender : public ByteSoundProducer_skel, + public StdSynthModule +{ + bool _finished; + int pos; +public: + Sender() : _finished(false), pos(0) + { + } + long samplingRate() { return 44100; } + long channels() { return 2; } + long bits() { return 16; } + bool finished() { return _finished; } + + static const int packetCount = 10, packetCapacity = 1024; + void streamStart() + { + /* + * start streaming + */ + outdata.setPull(packetCount, packetCapacity); + } + + void request_outdata(DataPacket *packet) + { + /* + * fill the packet with new data + */ + // ----------------- audio fill up start ----------------- + + int j; + mcopbyte *to = &packet->contents[0]; + for(j=0;j> 8) & 0xff; + *to++ = right & 0xff; + *to++ = (right >> 8) & 0xff; + } + + // ------------------ audio fill up end ------------------ + packet->send(); + } +}; + +int main(int argc, char **argv) +{ + Dispatcher dispatcher; + SimpleSoundServer server = Reference("global:Arts_SimpleSoundServer"); + + if(server.isNull()) + { + cerr << "Can't connect to sound server" << endl; + return 1; + } + + ByteSoundProducer sender = ByteSoundProducer::_from_base(new Sender()); + server.attach(sender); + sender.start(); + dispatcher.run(); + server.detach(sender); // in this example: not reached +} diff --git a/examples/testaggregation.cc b/examples/testaggregation.cc deleted file mode 100644 index c1a73bf..0000000 --- a/examples/testaggregation.cc +++ /dev/null @@ -1,73 +0,0 @@ -/* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "aggregation.h" -#include - -using namespace std; -using namespace Arts; - -class String_impl : virtual public String_skel { - string _value; -public: - void constructor(const std::string& value) { _value = value; } - string value() { return _value; } - void value(const std::string& newValue) { _value = newValue; } -}; - -REGISTER_IMPLEMENTATION(String_impl); - -void printall(Arts::Object o, std::string pre = "") -{ - String s; - s = DynamicCast(o); - if(!s.isNull()) - cout << pre << " - " << s.value() << endl; - - vector *children = s._queryChildren(); - vector::iterator i; - for(i = children->begin(); i != children->end(); i++) - printall(s._getChild(*i), pre+" "); -} - -/* - * Small test case for aggregation - * - * The idea behind all this is that you can add children to objects, building - * a tree (or if you like graph) of objects without the objects knowing anything - * about this. Aggregation has strong references, that means, the objects you - * add together in a tree will stay this way, as long as you keep a reference - * to the root. - */ -int main() -{ - Dispatcher d; - - String s("spreadsheet"); - s._addChild(String("chart"),"child1"); - s._addChild(String("image"),"child2"); - printall(s); - - cout << "deleting \"child1\"" << endl; - if(!s._removeChild("child1")) cout << "FAIL" << endl; - printall(s); -} diff --git a/examples/testaggregation.cpp b/examples/testaggregation.cpp new file mode 100644 index 0000000..c1a73bf --- /dev/null +++ b/examples/testaggregation.cpp @@ -0,0 +1,73 @@ +/* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "aggregation.h" +#include + +using namespace std; +using namespace Arts; + +class String_impl : virtual public String_skel { + string _value; +public: + void constructor(const std::string& value) { _value = value; } + string value() { return _value; } + void value(const std::string& newValue) { _value = newValue; } +}; + +REGISTER_IMPLEMENTATION(String_impl); + +void printall(Arts::Object o, std::string pre = "") +{ + String s; + s = DynamicCast(o); + if(!s.isNull()) + cout << pre << " - " << s.value() << endl; + + vector *children = s._queryChildren(); + vector::iterator i; + for(i = children->begin(); i != children->end(); i++) + printall(s._getChild(*i), pre+" "); +} + +/* + * Small test case for aggregation + * + * The idea behind all this is that you can add children to objects, building + * a tree (or if you like graph) of objects without the objects knowing anything + * about this. Aggregation has strong references, that means, the objects you + * add together in a tree will stay this way, as long as you keep a reference + * to the root. + */ +int main() +{ + Dispatcher d; + + String s("spreadsheet"); + s._addChild(String("chart"),"child1"); + s._addChild(String("image"),"child2"); + printall(s); + + cout << "deleting \"child1\"" << endl; + if(!s._removeChild("child1")) cout << "FAIL" << endl; + printall(s); +} diff --git a/examples/testasubsys.cc b/examples/testasubsys.cc deleted file mode 100644 index b70bf9d..0000000 --- a/examples/testasubsys.cc +++ /dev/null @@ -1,142 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include -#include -#include "audiosubsys.h" -#include "convert.h" -#include "dispatcher.h" - -using namespace std; -using namespace Arts; - -class SinTest : public ASProducer { -protected: - int audiofd; - int done; - AudioSubSystem *as; - bool attached; - -public: - SinTest(); - virtual ~SinTest(); - void needMore(); - void run(long samples); -}; - -SinTest::SinTest() : done(0), as(AudioSubSystem::the()) -{ - // initialize and open audio subsystem (defaults to 44kHz, 16bit, stereo) - attached = as->attachProducer(this); - if(!attached) - { - cout << "audio subsystem is already used?" << endl; - } - else - { - if(as->open() == false) - { - cout << "audio subsystem init failed (" - << as->error() << ")" << endl; - audiofd = -1; - } - else - audiofd = as->selectWriteFD(); - } -} - -SinTest::~SinTest() -{ - // deinitialize the audio subsystem - if(attached) - as->detachProducer(); -} - -void SinTest::run(long samples) -{ - // run this loop until enough samples are produced - while(attached && audiofd >= 0 && (done < samples)) - { - fd_set wfds, efds; - FD_ZERO(&wfds); - FD_ZERO(&efds); - FD_SET(audiofd, &wfds); - FD_SET(audiofd, &efds); - - // look if the audio filedescriptor becomes writeable - int result = select(audiofd+1,0,&wfds,&efds,0); - if(result > 0) - { - // if yes, tell the audio subsystem to do something about it - if(FD_ISSET(audiofd, &wfds)) - as->handleIO(AudioSubSystem::ioWrite); - if(FD_ISSET(audiofd, &efds)) - as->handleIO(AudioSubSystem::ioExcept); - } - else - { - cout << "select returned " << result << endl; - } - } -} - -/* - * needMore is a callback by the audio subsystem, which is made as soon as - * the internal buffers need a refill - */ -void SinTest::needMore() -{ - float left[100], right[100]; - unsigned char out[400]; - - // generate two waves, one 440 Hz (left), one 880Hz (right) - for(int i=0;i<100;i++) - { - left[i] = sin((float)i*6.28/100.0); - right[i] = sin((float)i*6.28/50.0); - } - convert_stereo_2float_i16le(100, left, right, out); - - // write them to the audio subsystem - as->write(out,400); - done += 100; -} - -/* - * This is intended to help testing the audio subsystem with different - * hardware without needing to use the whole server. - * - * Warning: this is *not* an example how to use aRts (there are others), - * but a simple test program for debugging purposes. - */ -int main() -{ - Dispatcher d; // to get startup classes executed - - // the test, generate 88100 samples (2 seconds) of pure sine wave test data - SinTest s; - s.run(88100); - return 0; -} diff --git a/examples/testasubsys.cpp b/examples/testasubsys.cpp new file mode 100644 index 0000000..b70bf9d --- /dev/null +++ b/examples/testasubsys.cpp @@ -0,0 +1,142 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include +#include +#include "audiosubsys.h" +#include "convert.h" +#include "dispatcher.h" + +using namespace std; +using namespace Arts; + +class SinTest : public ASProducer { +protected: + int audiofd; + int done; + AudioSubSystem *as; + bool attached; + +public: + SinTest(); + virtual ~SinTest(); + void needMore(); + void run(long samples); +}; + +SinTest::SinTest() : done(0), as(AudioSubSystem::the()) +{ + // initialize and open audio subsystem (defaults to 44kHz, 16bit, stereo) + attached = as->attachProducer(this); + if(!attached) + { + cout << "audio subsystem is already used?" << endl; + } + else + { + if(as->open() == false) + { + cout << "audio subsystem init failed (" + << as->error() << ")" << endl; + audiofd = -1; + } + else + audiofd = as->selectWriteFD(); + } +} + +SinTest::~SinTest() +{ + // deinitialize the audio subsystem + if(attached) + as->detachProducer(); +} + +void SinTest::run(long samples) +{ + // run this loop until enough samples are produced + while(attached && audiofd >= 0 && (done < samples)) + { + fd_set wfds, efds; + FD_ZERO(&wfds); + FD_ZERO(&efds); + FD_SET(audiofd, &wfds); + FD_SET(audiofd, &efds); + + // look if the audio filedescriptor becomes writeable + int result = select(audiofd+1,0,&wfds,&efds,0); + if(result > 0) + { + // if yes, tell the audio subsystem to do something about it + if(FD_ISSET(audiofd, &wfds)) + as->handleIO(AudioSubSystem::ioWrite); + if(FD_ISSET(audiofd, &efds)) + as->handleIO(AudioSubSystem::ioExcept); + } + else + { + cout << "select returned " << result << endl; + } + } +} + +/* + * needMore is a callback by the audio subsystem, which is made as soon as + * the internal buffers need a refill + */ +void SinTest::needMore() +{ + float left[100], right[100]; + unsigned char out[400]; + + // generate two waves, one 440 Hz (left), one 880Hz (right) + for(int i=0;i<100;i++) + { + left[i] = sin((float)i*6.28/100.0); + right[i] = sin((float)i*6.28/50.0); + } + convert_stereo_2float_i16le(100, left, right, out); + + // write them to the audio subsystem + as->write(out,400); + done += 100; +} + +/* + * This is intended to help testing the audio subsystem with different + * hardware without needing to use the whole server. + * + * Warning: this is *not* an example how to use aRts (there are others), + * but a simple test program for debugging purposes. + */ +int main() +{ + Dispatcher d; // to get startup classes executed + + // the test, generate 88100 samples (2 seconds) of pure sine wave test data + SinTest s; + s.run(88100); + return 0; +} diff --git a/examples/testdhandle.cc b/examples/testdhandle.cc deleted file mode 100644 index 564687d..0000000 --- a/examples/testdhandle.cc +++ /dev/null @@ -1,115 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include "gslpp/datahandle.h" -#include "soundserver.h" -#include "stdsynthmodule.h" -#include "artsflow.h" -#include "connect.h" - -#include -#include -#include -#include -#include - -using namespace std; -using namespace Arts; - -int main(int argc, char **argv) -{ - if(argc<2) - { - cerr << "USAGE: " << argv[0] << " [filename]\n"; - exit(1); - } - - Dispatcher dispatcher; - SoundServer server = Reference("global:Arts_SoundServer"); - - cout << "opening '" << argv[1] << "' locally...\n"; - - GSL::WaveFileInfo info(argv[1]); - if(info.error()) - { - cerr << "GSL error " << info.error() << - " (" << gsl_strerror(info.error()) << ") while loading info.\n"; - exit(1); - } - cout << "file contains " << info.waveCount() << " waves:\n"; - for(int i=0; i +#include +#include +#include +#include + +using namespace std; +using namespace Arts; + +int main(int argc, char **argv) +{ + if(argc<2) + { + cerr << "USAGE: " << argv[0] << " [filename]\n"; + exit(1); + } + + Dispatcher dispatcher; + SoundServer server = Reference("global:Arts_SoundServer"); + + cout << "opening '" << argv[1] << "' locally...\n"; + + GSL::WaveFileInfo info(argv[1]); + if(info.error()) + { + cerr << "GSL error " << info.error() << + " (" << gsl_strerror(info.error()) << ") while loading info.\n"; + exit(1); + } + cout << "file contains " << info.waveCount() << " waves:\n"; + for(int i=0; i -#include -#include -#include "dispatcher.h" -#include "thread.h" - -using namespace Arts; -using namespace std; - -class Counter : public Arts::Thread -{ - string name; -public: - Counter(const string& name) :name(name) {} - - void run() { - for(int i = 0;i < 10;i++) - { - printf("[%s] %d\n",name.c_str(),i+1); - sleep(1); - } - printf("[%s] terminating.\n", static_cast - (SystemThreads::the()->getCurrentThread())->name.c_str()); - } -}; - -int main() -{ - Dispatcher dispatcher; - Counter c1("counter1"), c2("counter2"); - - if(SystemThreads::supported()) - printf("We have a system threads (counters should count parallel).\n"); - else - printf("No system threads (counters will not count parallel).\n"); - - c1.start(); - c2.start(); - c1.waitDone(); - c2.waitDone(); - return 0; -} diff --git a/examples/testthreads.cpp b/examples/testthreads.cpp new file mode 100644 index 0000000..ad2e428 --- /dev/null +++ b/examples/testthreads.cpp @@ -0,0 +1,64 @@ +/* + + Copyright (C) 2001-2002 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include "dispatcher.h" +#include "thread.h" + +using namespace Arts; +using namespace std; + +class Counter : public Arts::Thread +{ + string name; +public: + Counter(const string& name) :name(name) {} + + void run() { + for(int i = 0;i < 10;i++) + { + printf("[%s] %d\n",name.c_str(),i+1); + sleep(1); + } + printf("[%s] terminating.\n", static_cast + (SystemThreads::the()->getCurrentThread())->name.c_str()); + } +}; + +int main() +{ + Dispatcher dispatcher; + Counter c1("counter1"), c2("counter2"); + + if(SystemThreads::supported()) + printf("We have a system threads (counters should count parallel).\n"); + else + printf("No system threads (counters will not count parallel).\n"); + + c1.start(); + c2.start(); + c1.waitDone(); + c2.waitDone(); + return 0; +} diff --git a/examples/x11commtest.cc b/examples/x11commtest.cc deleted file mode 100644 index c1b27dd..0000000 --- a/examples/x11commtest.cc +++ /dev/null @@ -1,76 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - Modified by Nicolas Brodu, brodu@kde.org - - 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Permission is also granted to link this program with the Qt - library, treating Qt like a library that normally accompanies the - operating system kernel, whether or not that is in fact the case. - - */ - -#include -#include "common.h" - -using namespace std; -using namespace Arts; - -/* - * Test program for X11GlobalComm (communication over X11 root window - * properties), and since X11GlobalComm is an dynamically extension, - * extension loading is tested as well. - */ -int main(int argc, char **argv) -{ - Dispatcher dispatcher; - GlobalComm gcomm( SubClass("Arts::X11GlobalComm") ); - - if (gcomm.isNull()) { - cerr << "Cannot create a X11GlobalComm object" << endl; - return 2; - } - - if(argc == 4) - { - if(string(argv[1]) == "put") - { - gcomm.put(argv[2],argv[3]); - return 0; - } - } - if(argc == 3) - { - if(string(argv[1]) == "get") - { - cout << gcomm.get(argv[2]) << endl; - return 0; - } - if(string(argv[1]) == "erase") - { - gcomm.erase(argv[2]); - return 0; - } - } - - cerr << "This is a test for the X11GlobalComm class. Use" << endl << endl - << " " << argv[0] << " put " << endl - << " " << argv[0] << " get " << endl - << " " << argv[0] << " erase " << endl << endl - << "to test the communication via X11 RootWindow properties." << endl; - return 1; -} diff --git a/examples/x11commtest.cpp b/examples/x11commtest.cpp new file mode 100644 index 0000000..c1b27dd --- /dev/null +++ b/examples/x11commtest.cpp @@ -0,0 +1,76 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + Modified by Nicolas Brodu, brodu@kde.org + + 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the Qt + library, treating Qt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + + */ + +#include +#include "common.h" + +using namespace std; +using namespace Arts; + +/* + * Test program for X11GlobalComm (communication over X11 root window + * properties), and since X11GlobalComm is an dynamically extension, + * extension loading is tested as well. + */ +int main(int argc, char **argv) +{ + Dispatcher dispatcher; + GlobalComm gcomm( SubClass("Arts::X11GlobalComm") ); + + if (gcomm.isNull()) { + cerr << "Cannot create a X11GlobalComm object" << endl; + return 2; + } + + if(argc == 4) + { + if(string(argv[1]) == "put") + { + gcomm.put(argv[2],argv[3]); + return 0; + } + } + if(argc == 3) + { + if(string(argv[1]) == "get") + { + cout << gcomm.get(argv[2]) << endl; + return 0; + } + if(string(argv[1]) == "erase") + { + gcomm.erase(argv[2]); + return 0; + } + } + + cerr << "This is a test for the X11GlobalComm class. Use" << endl << endl + << " " << argv[0] << " put " << endl + << " " << argv[0] << " get " << endl + << " " << argv[0] << " erase " << endl << endl + << "to test the communication via X11 RootWindow properties." << endl; + return 1; +} diff --git a/flow/CMakeLists.txt b/flow/CMakeLists.txt index 4a8492d..48fb330 100644 --- a/flow/CMakeLists.txt +++ b/flow/CMakeLists.txt @@ -48,19 +48,19 @@ install( FILES set( target artsflow ) set( ${target}_SRCS - synth_play_impl.cc gslschedule.cc audiosubsys.cc - pipebuffer.cc convert.cc synth_wave_sin_impl.cc - synth_frequency_impl.cc synth_multi_add_impl.cc - synth_add_impl.cc synth_mul_impl.cc synth_play_wav_impl.cc - stdsynthmodule.cc cache.cc asyncschedule.cc bytestreamtoaudio_impl.cc - stereovolumecontrol_impl.cc stereoeffectstack_impl.cc - fft.c stereofftscope_impl.cc virtualports.cc bus.cc - audiomanager_impl.cc synth_record_impl.cc resample.cc - audioio.cc audioiooss.cc audioioalsa.cc audioioalsa9.cc - audioionull.cc audioiolibaudioio.cc audioioesd.cc audioiosndio.cc - audioiojack.cc audioiosun.cc audioioaix.cc audioionas.cc - cpuinfo.cc audioioossthreaded.cc audiotobytestream_impl.cc - audioiosgi.cc audioiocsl.cc audioiomas.cc datahandle_impl.cc + synth_play_impl.cpp gslschedule.cpp audiosubsys.cpp + pipebuffer.cpp convert.cpp synth_wave_sin_impl.cpp + synth_frequency_impl.cpp synth_multi_add_impl.cpp + synth_add_impl.cpp synth_mul_impl.cpp synth_play_wav_impl.cpp + stdsynthmodule.cpp cache.cpp asyncschedule.cpp bytestreamtoaudio_impl.cpp + stereovolumecontrol_impl.cpp stereoeffectstack_impl.cpp + fft.c stereofftscope_impl.cpp virtualports.cpp bus.cpp + audiomanager_impl.cpp synth_record_impl.cpp resample.cpp + audioio.cpp audioiooss.cpp audioioalsa.cpp audioioalsa9.cpp + audioionull.cpp audioiolibaudioio.cpp audioioesd.cpp audioiosndio.cpp + audioiojack.cpp audioiosun.cpp audioioaix.cpp audioionas.cpp + cpuinfo.cpp audioioossthreaded.cpp audiotobytestream_impl.cpp + audioiosgi.cpp audioiocsl.cpp audioiomas.cpp datahandle_impl.cpp ) tde_add_library( ${target} SHARED @@ -73,13 +73,13 @@ tde_add_library( ${target} SHARED ##### artsflow_idl (shared lib) ################# add_custom_command( - OUTPUT artsflow.cc + OUTPUT artsflow.cpp COMMAND ../mcopidl/mcopidl ARGS -t ${CMAKE_CURRENT_SOURCE_DIR}/artsflow.idl DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/artsflow.idl ) tde_add_library( artsflow_idl SHARED - SOURCES artsflow.cc + SOURCES artsflow.cpp VERSION 1.0.0 LINK mcop-shared ${ALSA_LIBRARIES} DESTINATION ${LIB_INSTALL_DIR} diff --git a/flow/asyncschedule.cc b/flow/asyncschedule.cc deleted file mode 100644 index 66ae48b..0000000 --- a/flow/asyncschedule.cc +++ /dev/null @@ -1,553 +0,0 @@ - /* - - Copyright (C) 2000,2001 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#include -#include "asyncschedule.h" - -using namespace std; -using namespace Arts; - -#include "debug.h" -#include - -/* Since this file is a tad bit more complex, here is some basic documentation: - -1) ASyncPort: There are asynchronous ports which are parts of the standard- - flowsystem schedule nodes. Their lifetime starts whenever an asynchronous - stream gets created by the flow system, and ends when the schedule node - gets destroyed. Basically, an ASyncPort has two functions: - - * it is a "Port", which means that it gets connect(), disconnect() and - other calls from the flowsystem - - * it is a "GenericDataChannel", which means that DataPackets can interact - with it - - Although there will be ASyncPorts which only send data and ASyncPorts which - only receive data (there are none that do both), there are no distinct - classes for this. - -2) Standard case: a DataPacket that gets transported over a datachannel locally: - - 1. the user allocates himself a datapacket "packet" - 2. the user calls "packet->send()", which in turn calls - ASyncPort::sendPacket(packet) - 3. the ASyncPort sends the DataPacket to every subscriber (incrementing the - useCount) over the NotificationManager - 4. the NotificationManager delivers the DataPackets to the receiver - 5. eventually, the receiver confirms using "packet->processed()" - 6. the packet informs the ASyncPort::processedPacket() - 7. the packet is freed - -variant (pulling): - - 1. the user gets told by the ASyncPort: produce some data, here is a "packet" - 2. the user calls "packet->send()", which in turn calls - ASyncPort::sendPacket(packet) - 3. the ASyncPort sends the DataPacket to every subscriber (incrementing the - useCount) over the NotificationManager - 4. the NotificationManager delivers the DataPackets to the receiver - 5. eventually, the receiver confirms using "packet->processed()" - 6. the packet informs the ASyncPort::processedPacket() - 7. the ASyncPort restarts with 1. - -3) Remote case: the remote case follows from the local case by adding two extra -things: one object that converts packets from their packet form to a message -(ASyncNetSend), and one object that converts packets from the message form -to a packet again. Effectively, the sending of a single packet looks like -this, then: - - 1-S. the user allocates himself a datapacket "packet" - 2-S. the user calls "packet->send()", which in turn calls - ASyncPort::sendPacket(packet) - 3-S. the ASyncPort sends the DataPacket to every subscriber (incrementing the - useCount) over the NotificationManager - 4-S. the NotificationManager delivers the DataPackets to the ASyncNetSend - 5-S. the ASyncNetSend::notify method gets called, which in turn converts - the packet to a network message - - ... network transfer ... - - 6-R. the ASyncNetReceive::receive method gets called - the method creates - a new data packet, and sends it using the NotificationManager again - 7-R. the NotificationManager delivers the DataPacket to the receiver - 8-R. eventually, the receiver confirms using "packet->processed()" - 9-R. the packet informs the ASyncNetReceive::processedPacket() which - frees the packet and tells the (remote) sender that it went all right - - ... network transfer ... - - 10-S. eventually, ASyncNetSend::processed() gets called, and confirms - the packet using "packet->processed()" - 11-S. the packet informs the ASyncPort::processedPacket() - 12-S. the packet is freed - -variant(pulling): - - works the same as in the local case by exchanging steps 1-S and 12-S - -4) ownership: - - * ASyncPort: is owned by the Object which it is a part of, if the object - dies, ASyncPort dies unconditionally - - * DataPacket: is owned by the GenericDataChannel they are propagated over, - that is, the ASyncPort normally - however if the DataPacket is still in - use (i.e. in state 5 of the local case), it will take responsibility to - free itself once all processed() calls have been collected - - * ASyncNetSend, ASyncNetReceive: own each other, so that if the sender dies, - the connection will die as well, and if the receiver dies, the same happens - -*/ - -#undef DEBUG_ASYNC_TRANSFER - -ASyncPort::ASyncPort(const std::string& name, void *ptr, long flags, - StdScheduleNode* parent) : Port(name, ptr, flags, parent), pull(false) -{ - stream = (GenericAsyncStream *)ptr; - stream->channel = this; - stream->_notifyID = notifyID = parent->object()->_mkNotifyID(); -} - -ASyncPort::~ASyncPort() -{ - /* - * tell all outstanding packets that we don't exist any longer, so that - * if they feel like they need to confirm they have been processed now, - * they don't talk to an no longer existing object about it - */ - while(!sent.empty()) - { - sent.front()->channel = 0; - sent.pop_front(); - } - - /* disconnect remote connections (if present): the following things will - * need to be ensured here, since we are being deleted: - * - * - the senders should not talk to us after our destructor - * - all of our connections need to be disconnected - * - every connection needs to be closed exactly once - * - * (closing a connection can cause reentrancy due to mcop communication) - */ - while(!netSenders.empty()) - netSenders.front()->disconnect(); - - FlowSystemReceiver receiver = netReceiver; - if(!receiver.isNull()) - receiver.disconnect(); -} - -//-------------------- GenericDataChannel interface ------------------------- - -void ASyncPort::setPull(int packets, int capacity) -{ - pullNotification.receiver = parent->object(); - pullNotification.ID = notifyID; - pullNotification.internal = 0; - pull = true; - - for(int i=0;icreatePacket(capacity); - packet->useCount = 0; - pullNotification.data = packet; - NotificationManager::the()->send(pullNotification); - } -} - -void ASyncPort::endPull() -{ - pull = false; - // TODO: maybe remove all pending pull packets here -} - -void ASyncPort::processedPacket(GenericDataPacket *packet) -{ - int count = 0; - list::iterator i = sent.begin(); - while(i != sent.end()) - { - if(*i == packet) - { - count++; - i = sent.erase(i); - } - else i++; - } - assert(count == 1); - -#ifdef DEBUG_ASYNC_TRANSFER - cout << "port::processedPacket" << endl; -#endif - assert(packet->useCount == 0); - if(pull) - { - pullNotification.data = packet; - NotificationManager::the()->send(pullNotification); - } - else - { - stream->freePacket(packet); - } -} - -void ASyncPort::sendPacket(GenericDataPacket *packet) -{ - bool sendOk = false; - -#ifdef DEBUG_ASYNC_TRANSFER - cout << "port::sendPacket" << endl; -#endif - - if(packet->size > 0) - { - vector::iterator i; - for(i=subscribers.begin(); i != subscribers.end(); i++) - { - Notification n = *i; - n.data = packet; - packet->useCount++; -#ifdef DEBUG_ASYNC_TRANSFER - cout << "sending notification " << n.ID << endl; -#endif - NotificationManager::the()->send(n); - sendOk = true; - } - } - - if(sendOk) - sent.push_back(packet); - else - stream->freePacket(packet); -} - -//----------------------- Port interface ------------------------------------ - -void ASyncPort::connect(Port *xsource) -{ - arts_debug("port(%s)::connect",_name.c_str()); - - ASyncPort *source = xsource->asyncPort(); - assert(source); - addAutoDisconnect(xsource); - - Notification n; - n.receiver = parent->object(); - n.ID = notifyID; - n.internal = 0; - source->subscribers.push_back(n); -} - -void ASyncPort::disconnect(Port *xsource) -{ - arts_debug("port::disconnect"); - - ASyncPort *source = xsource->asyncPort(); - assert(source); - removeAutoDisconnect(xsource); - - // remove our subscription from the source object - vector::iterator si; - for(si = source->subscribers.begin(); si != source->subscribers.end(); si++) - { - if(si->receiver == parent->object()) - { - source->subscribers.erase(si); - return; - } - } - - // there should have been exactly one, so this shouldn't be reached - assert(false); -} - -ASyncPort *ASyncPort::asyncPort() -{ - return this; -} - -GenericAsyncStream *ASyncPort::receiveNetCreateStream() -{ - return stream->createNewStream(); -} - -NotificationClient *ASyncPort::receiveNetObject() -{ - return parent->object(); -} - -long ASyncPort::receiveNetNotifyID() -{ - return notifyID; -} - -// Network transparency -void ASyncPort::addSendNet(ASyncNetSend *netsend) -{ - Notification n; - n.receiver = netsend; - n.ID = netsend->notifyID(); - n.internal = 0; - subscribers.push_back(n); - netSenders.push_back(netsend); -} - -void ASyncPort::removeSendNet(ASyncNetSend *netsend) -{ - arts_return_if_fail(netsend != 0); - netSenders.remove(netsend); - - vector::iterator si; - for(si = subscribers.begin(); si != subscribers.end(); si++) - { - if(si->receiver == netsend) - { - subscribers.erase(si); - return; - } - } - arts_warning("Failed to remove ASyncNetSend (%p) from ASyncPort", netsend); -} - -void ASyncPort::setNetReceiver(ASyncNetReceive *receiver) -{ - arts_return_if_fail(receiver != 0); - - FlowSystemReceiver r = FlowSystemReceiver::_from_base(receiver->_copy()); - netReceiver = r; -} - -void ASyncPort::disconnectRemote(const string& dest) -{ - list::iterator i; - - for(i = netSenders.begin(); i != netSenders.end(); i++) - { - if((*i)->dest() == dest) - { - (*i)->disconnect(); - return; - } - } - arts_warning("failed to disconnect %s in ASyncPort", dest.c_str()); -} - -ASyncNetSend::ASyncNetSend(ASyncPort *ap, const std::string& dest) : ap(ap) -{ - _dest = dest; - ap->addSendNet(this); -} - -ASyncNetSend::~ASyncNetSend() -{ - while(!pqueue.empty()) - { - pqueue.front()->processed(); - pqueue.pop(); - } - if(ap) - { - ap->removeSendNet(this); - ap = 0; - } -} - -long ASyncNetSend::notifyID() -{ - return 1; -} - -void ASyncNetSend::notify(const Notification& notification) -{ - // got a packet? - assert(notification.ID == notifyID()); - GenericDataPacket *dp = (GenericDataPacket *)notification.data; - pqueue.push(dp); - - /* - * since packets are delivered asynchronously, and since disconnection - * involves communication, it might happen that we get a packet without - * actually being connected any longer - in that case, silently forget it - */ - if(!receiver.isNull()) - { - // put it into a custom data message and send it to the receiver - Buffer *buffer = receiver._allocCustomMessage(receiveHandlerID); - dp->write(*buffer); - receiver._sendCustomMessage(buffer); - } -} - -void ASyncNetSend::processed() -{ - assert(!pqueue.empty()); - pqueue.front()->processed(); - pqueue.pop(); -} - -void ASyncNetSend::setReceiver(FlowSystemReceiver newReceiver) -{ - receiver = newReceiver; - receiveHandlerID = newReceiver.receiveHandlerID(); -} - -void ASyncNetSend::disconnect() -{ - /* since disconnection will cause destruction (most likely immediate), - * we'll reference ourselves ... */ - _copy(); - - if(!receiver.isNull()) - { - FlowSystemReceiver r = receiver; - receiver = FlowSystemReceiver::null(); - r.disconnect(); - } - if(ap) - { - ap->removeSendNet(this); - ap = 0; - } - - _release(); -} - -string ASyncNetSend::dest() -{ - return _dest; -} - -/* dispatching function for custom message */ - -static void _dispatch_ASyncNetReceive_receive(void *object, Buffer *buffer) -{ - ((ASyncNetReceive *)object)->receive(buffer); -} - -ASyncNetReceive::ASyncNetReceive(ASyncPort *port, FlowSystemSender sender) -{ - port->setNetReceiver(this); - stream = port->receiveNetCreateStream(); - stream->channel = this; - this->sender = sender; - /* stream->_notifyID = _mkNotifyID(); */ - - gotPacketNotification.ID = port->receiveNetNotifyID(); - gotPacketNotification.receiver = port->receiveNetObject(); - gotPacketNotification.internal = 0; - _receiveHandlerID = - _addCustomMessageHandler(_dispatch_ASyncNetReceive_receive,this); -} - -ASyncNetReceive::~ASyncNetReceive() -{ - /* tell outstanding packets that we don't exist any longer */ - while(!sent.empty()) - { - sent.front()->channel = 0; - sent.pop_front(); - } - delete stream; -} - -long ASyncNetReceive::receiveHandlerID() -{ - return _receiveHandlerID; -} - -void ASyncNetReceive::receive(Buffer *buffer) -{ - GenericDataPacket *dp = stream->createPacket(512); - dp->read(*buffer); - dp->useCount = 1; - gotPacketNotification.data = dp; - NotificationManager::the()->send(gotPacketNotification); - sent.push_back(dp); -} - -/* - * It will happen that this routine is called in time critical situations, - * such as: while audio calculation is running, and must be finished in - * time. The routine is mostly harmless, because sender->processed() is - * a oneway function, which just queues the buffer for sending and returns - * back, so it should return at once. - * - * However there is an exception upon first call: when sender->processed() - * is called for the first time, the method processed has still to be looked - * up. Thus, a synchronous call to _lookupMethod is made. That means, upon - * first call, the method will send out an MCOP request and block until the - * remote process tells that id. - */ -void ASyncNetReceive::processedPacket(GenericDataPacket *packet) -{ - /* - * HACK! Upon disconnect, strange things will happen. One of them is - * that we might, for the reason of not being referenced any longer, - * cease to exist without warning. Another is that our nice "sender" - * reference will get a null reference without warning, see disconnect - * code (which will cause the attached stub to also disappear). As - * those objects (especially the stub) are not prepared for not - * being there any more in the middle of whatever they do, we here - * explicitly reference us, and them, *again*, so that no evil things - * will happen. A general solution for this would be garbage collection - * in a timer, but until this is implemented (if it ever will become - * implemented), we'll live with this hack. - */ - _copy(); - sent.remove(packet); - stream->freePacket(packet); - if(!sender.isNull()) - { - FlowSystemSender xsender = sender; - xsender.processed(); - } - _release(); -} - -void ASyncNetReceive::disconnect() -{ - if(!sender.isNull()) - { - FlowSystemSender s = sender; - sender = FlowSystemSender::null(); - s.disconnect(); - } -} - -void ASyncNetReceive::sendPacket(GenericDataPacket *) -{ - assert(false); -} - -void ASyncNetReceive::setPull(int, int) -{ - assert(false); -} - -void ASyncNetReceive::endPull() -{ - assert(false); -} diff --git a/flow/asyncschedule.cpp b/flow/asyncschedule.cpp new file mode 100644 index 0000000..66ae48b --- /dev/null +++ b/flow/asyncschedule.cpp @@ -0,0 +1,553 @@ + /* + + Copyright (C) 2000,2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include +#include "asyncschedule.h" + +using namespace std; +using namespace Arts; + +#include "debug.h" +#include + +/* Since this file is a tad bit more complex, here is some basic documentation: + +1) ASyncPort: There are asynchronous ports which are parts of the standard- + flowsystem schedule nodes. Their lifetime starts whenever an asynchronous + stream gets created by the flow system, and ends when the schedule node + gets destroyed. Basically, an ASyncPort has two functions: + + * it is a "Port", which means that it gets connect(), disconnect() and + other calls from the flowsystem + + * it is a "GenericDataChannel", which means that DataPackets can interact + with it + + Although there will be ASyncPorts which only send data and ASyncPorts which + only receive data (there are none that do both), there are no distinct + classes for this. + +2) Standard case: a DataPacket that gets transported over a datachannel locally: + + 1. the user allocates himself a datapacket "packet" + 2. the user calls "packet->send()", which in turn calls + ASyncPort::sendPacket(packet) + 3. the ASyncPort sends the DataPacket to every subscriber (incrementing the + useCount) over the NotificationManager + 4. the NotificationManager delivers the DataPackets to the receiver + 5. eventually, the receiver confirms using "packet->processed()" + 6. the packet informs the ASyncPort::processedPacket() + 7. the packet is freed + +variant (pulling): + + 1. the user gets told by the ASyncPort: produce some data, here is a "packet" + 2. the user calls "packet->send()", which in turn calls + ASyncPort::sendPacket(packet) + 3. the ASyncPort sends the DataPacket to every subscriber (incrementing the + useCount) over the NotificationManager + 4. the NotificationManager delivers the DataPackets to the receiver + 5. eventually, the receiver confirms using "packet->processed()" + 6. the packet informs the ASyncPort::processedPacket() + 7. the ASyncPort restarts with 1. + +3) Remote case: the remote case follows from the local case by adding two extra +things: one object that converts packets from their packet form to a message +(ASyncNetSend), and one object that converts packets from the message form +to a packet again. Effectively, the sending of a single packet looks like +this, then: + + 1-S. the user allocates himself a datapacket "packet" + 2-S. the user calls "packet->send()", which in turn calls + ASyncPort::sendPacket(packet) + 3-S. the ASyncPort sends the DataPacket to every subscriber (incrementing the + useCount) over the NotificationManager + 4-S. the NotificationManager delivers the DataPackets to the ASyncNetSend + 5-S. the ASyncNetSend::notify method gets called, which in turn converts + the packet to a network message + + ... network transfer ... + + 6-R. the ASyncNetReceive::receive method gets called - the method creates + a new data packet, and sends it using the NotificationManager again + 7-R. the NotificationManager delivers the DataPacket to the receiver + 8-R. eventually, the receiver confirms using "packet->processed()" + 9-R. the packet informs the ASyncNetReceive::processedPacket() which + frees the packet and tells the (remote) sender that it went all right + + ... network transfer ... + + 10-S. eventually, ASyncNetSend::processed() gets called, and confirms + the packet using "packet->processed()" + 11-S. the packet informs the ASyncPort::processedPacket() + 12-S. the packet is freed + +variant(pulling): + + works the same as in the local case by exchanging steps 1-S and 12-S + +4) ownership: + + * ASyncPort: is owned by the Object which it is a part of, if the object + dies, ASyncPort dies unconditionally + + * DataPacket: is owned by the GenericDataChannel they are propagated over, + that is, the ASyncPort normally - however if the DataPacket is still in + use (i.e. in state 5 of the local case), it will take responsibility to + free itself once all processed() calls have been collected + + * ASyncNetSend, ASyncNetReceive: own each other, so that if the sender dies, + the connection will die as well, and if the receiver dies, the same happens + +*/ + +#undef DEBUG_ASYNC_TRANSFER + +ASyncPort::ASyncPort(const std::string& name, void *ptr, long flags, + StdScheduleNode* parent) : Port(name, ptr, flags, parent), pull(false) +{ + stream = (GenericAsyncStream *)ptr; + stream->channel = this; + stream->_notifyID = notifyID = parent->object()->_mkNotifyID(); +} + +ASyncPort::~ASyncPort() +{ + /* + * tell all outstanding packets that we don't exist any longer, so that + * if they feel like they need to confirm they have been processed now, + * they don't talk to an no longer existing object about it + */ + while(!sent.empty()) + { + sent.front()->channel = 0; + sent.pop_front(); + } + + /* disconnect remote connections (if present): the following things will + * need to be ensured here, since we are being deleted: + * + * - the senders should not talk to us after our destructor + * - all of our connections need to be disconnected + * - every connection needs to be closed exactly once + * + * (closing a connection can cause reentrancy due to mcop communication) + */ + while(!netSenders.empty()) + netSenders.front()->disconnect(); + + FlowSystemReceiver receiver = netReceiver; + if(!receiver.isNull()) + receiver.disconnect(); +} + +//-------------------- GenericDataChannel interface ------------------------- + +void ASyncPort::setPull(int packets, int capacity) +{ + pullNotification.receiver = parent->object(); + pullNotification.ID = notifyID; + pullNotification.internal = 0; + pull = true; + + for(int i=0;icreatePacket(capacity); + packet->useCount = 0; + pullNotification.data = packet; + NotificationManager::the()->send(pullNotification); + } +} + +void ASyncPort::endPull() +{ + pull = false; + // TODO: maybe remove all pending pull packets here +} + +void ASyncPort::processedPacket(GenericDataPacket *packet) +{ + int count = 0; + list::iterator i = sent.begin(); + while(i != sent.end()) + { + if(*i == packet) + { + count++; + i = sent.erase(i); + } + else i++; + } + assert(count == 1); + +#ifdef DEBUG_ASYNC_TRANSFER + cout << "port::processedPacket" << endl; +#endif + assert(packet->useCount == 0); + if(pull) + { + pullNotification.data = packet; + NotificationManager::the()->send(pullNotification); + } + else + { + stream->freePacket(packet); + } +} + +void ASyncPort::sendPacket(GenericDataPacket *packet) +{ + bool sendOk = false; + +#ifdef DEBUG_ASYNC_TRANSFER + cout << "port::sendPacket" << endl; +#endif + + if(packet->size > 0) + { + vector::iterator i; + for(i=subscribers.begin(); i != subscribers.end(); i++) + { + Notification n = *i; + n.data = packet; + packet->useCount++; +#ifdef DEBUG_ASYNC_TRANSFER + cout << "sending notification " << n.ID << endl; +#endif + NotificationManager::the()->send(n); + sendOk = true; + } + } + + if(sendOk) + sent.push_back(packet); + else + stream->freePacket(packet); +} + +//----------------------- Port interface ------------------------------------ + +void ASyncPort::connect(Port *xsource) +{ + arts_debug("port(%s)::connect",_name.c_str()); + + ASyncPort *source = xsource->asyncPort(); + assert(source); + addAutoDisconnect(xsource); + + Notification n; + n.receiver = parent->object(); + n.ID = notifyID; + n.internal = 0; + source->subscribers.push_back(n); +} + +void ASyncPort::disconnect(Port *xsource) +{ + arts_debug("port::disconnect"); + + ASyncPort *source = xsource->asyncPort(); + assert(source); + removeAutoDisconnect(xsource); + + // remove our subscription from the source object + vector::iterator si; + for(si = source->subscribers.begin(); si != source->subscribers.end(); si++) + { + if(si->receiver == parent->object()) + { + source->subscribers.erase(si); + return; + } + } + + // there should have been exactly one, so this shouldn't be reached + assert(false); +} + +ASyncPort *ASyncPort::asyncPort() +{ + return this; +} + +GenericAsyncStream *ASyncPort::receiveNetCreateStream() +{ + return stream->createNewStream(); +} + +NotificationClient *ASyncPort::receiveNetObject() +{ + return parent->object(); +} + +long ASyncPort::receiveNetNotifyID() +{ + return notifyID; +} + +// Network transparency +void ASyncPort::addSendNet(ASyncNetSend *netsend) +{ + Notification n; + n.receiver = netsend; + n.ID = netsend->notifyID(); + n.internal = 0; + subscribers.push_back(n); + netSenders.push_back(netsend); +} + +void ASyncPort::removeSendNet(ASyncNetSend *netsend) +{ + arts_return_if_fail(netsend != 0); + netSenders.remove(netsend); + + vector::iterator si; + for(si = subscribers.begin(); si != subscribers.end(); si++) + { + if(si->receiver == netsend) + { + subscribers.erase(si); + return; + } + } + arts_warning("Failed to remove ASyncNetSend (%p) from ASyncPort", netsend); +} + +void ASyncPort::setNetReceiver(ASyncNetReceive *receiver) +{ + arts_return_if_fail(receiver != 0); + + FlowSystemReceiver r = FlowSystemReceiver::_from_base(receiver->_copy()); + netReceiver = r; +} + +void ASyncPort::disconnectRemote(const string& dest) +{ + list::iterator i; + + for(i = netSenders.begin(); i != netSenders.end(); i++) + { + if((*i)->dest() == dest) + { + (*i)->disconnect(); + return; + } + } + arts_warning("failed to disconnect %s in ASyncPort", dest.c_str()); +} + +ASyncNetSend::ASyncNetSend(ASyncPort *ap, const std::string& dest) : ap(ap) +{ + _dest = dest; + ap->addSendNet(this); +} + +ASyncNetSend::~ASyncNetSend() +{ + while(!pqueue.empty()) + { + pqueue.front()->processed(); + pqueue.pop(); + } + if(ap) + { + ap->removeSendNet(this); + ap = 0; + } +} + +long ASyncNetSend::notifyID() +{ + return 1; +} + +void ASyncNetSend::notify(const Notification& notification) +{ + // got a packet? + assert(notification.ID == notifyID()); + GenericDataPacket *dp = (GenericDataPacket *)notification.data; + pqueue.push(dp); + + /* + * since packets are delivered asynchronously, and since disconnection + * involves communication, it might happen that we get a packet without + * actually being connected any longer - in that case, silently forget it + */ + if(!receiver.isNull()) + { + // put it into a custom data message and send it to the receiver + Buffer *buffer = receiver._allocCustomMessage(receiveHandlerID); + dp->write(*buffer); + receiver._sendCustomMessage(buffer); + } +} + +void ASyncNetSend::processed() +{ + assert(!pqueue.empty()); + pqueue.front()->processed(); + pqueue.pop(); +} + +void ASyncNetSend::setReceiver(FlowSystemReceiver newReceiver) +{ + receiver = newReceiver; + receiveHandlerID = newReceiver.receiveHandlerID(); +} + +void ASyncNetSend::disconnect() +{ + /* since disconnection will cause destruction (most likely immediate), + * we'll reference ourselves ... */ + _copy(); + + if(!receiver.isNull()) + { + FlowSystemReceiver r = receiver; + receiver = FlowSystemReceiver::null(); + r.disconnect(); + } + if(ap) + { + ap->removeSendNet(this); + ap = 0; + } + + _release(); +} + +string ASyncNetSend::dest() +{ + return _dest; +} + +/* dispatching function for custom message */ + +static void _dispatch_ASyncNetReceive_receive(void *object, Buffer *buffer) +{ + ((ASyncNetReceive *)object)->receive(buffer); +} + +ASyncNetReceive::ASyncNetReceive(ASyncPort *port, FlowSystemSender sender) +{ + port->setNetReceiver(this); + stream = port->receiveNetCreateStream(); + stream->channel = this; + this->sender = sender; + /* stream->_notifyID = _mkNotifyID(); */ + + gotPacketNotification.ID = port->receiveNetNotifyID(); + gotPacketNotification.receiver = port->receiveNetObject(); + gotPacketNotification.internal = 0; + _receiveHandlerID = + _addCustomMessageHandler(_dispatch_ASyncNetReceive_receive,this); +} + +ASyncNetReceive::~ASyncNetReceive() +{ + /* tell outstanding packets that we don't exist any longer */ + while(!sent.empty()) + { + sent.front()->channel = 0; + sent.pop_front(); + } + delete stream; +} + +long ASyncNetReceive::receiveHandlerID() +{ + return _receiveHandlerID; +} + +void ASyncNetReceive::receive(Buffer *buffer) +{ + GenericDataPacket *dp = stream->createPacket(512); + dp->read(*buffer); + dp->useCount = 1; + gotPacketNotification.data = dp; + NotificationManager::the()->send(gotPacketNotification); + sent.push_back(dp); +} + +/* + * It will happen that this routine is called in time critical situations, + * such as: while audio calculation is running, and must be finished in + * time. The routine is mostly harmless, because sender->processed() is + * a oneway function, which just queues the buffer for sending and returns + * back, so it should return at once. + * + * However there is an exception upon first call: when sender->processed() + * is called for the first time, the method processed has still to be looked + * up. Thus, a synchronous call to _lookupMethod is made. That means, upon + * first call, the method will send out an MCOP request and block until the + * remote process tells that id. + */ +void ASyncNetReceive::processedPacket(GenericDataPacket *packet) +{ + /* + * HACK! Upon disconnect, strange things will happen. One of them is + * that we might, for the reason of not being referenced any longer, + * cease to exist without warning. Another is that our nice "sender" + * reference will get a null reference without warning, see disconnect + * code (which will cause the attached stub to also disappear). As + * those objects (especially the stub) are not prepared for not + * being there any more in the middle of whatever they do, we here + * explicitly reference us, and them, *again*, so that no evil things + * will happen. A general solution for this would be garbage collection + * in a timer, but until this is implemented (if it ever will become + * implemented), we'll live with this hack. + */ + _copy(); + sent.remove(packet); + stream->freePacket(packet); + if(!sender.isNull()) + { + FlowSystemSender xsender = sender; + xsender.processed(); + } + _release(); +} + +void ASyncNetReceive::disconnect() +{ + if(!sender.isNull()) + { + FlowSystemSender s = sender; + sender = FlowSystemSender::null(); + s.disconnect(); + } +} + +void ASyncNetReceive::sendPacket(GenericDataPacket *) +{ + assert(false); +} + +void ASyncNetReceive::setPull(int, int) +{ + assert(false); +} + +void ASyncNetReceive::endPull() +{ + assert(false); +} diff --git a/flow/audioio.cc b/flow/audioio.cc deleted file mode 100644 index eafb197..0000000 --- a/flow/audioio.cc +++ /dev/null @@ -1,165 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#include "audioio.h" -#include -#include -#include -#include - -using namespace Arts; -using namespace std; - -class Arts::AudioIOPrivate { -public: - map paramMap; - map paramStrMap; -}; - -AudioIO::AudioIO() :d(new AudioIOPrivate) -{ -} - -AudioIO::~AudioIO() -{ - delete d; -} - -int& AudioIO::param(AudioParam param) -{ - /* - * returns d->paramMap[param], initializes new elements with -1 (for those - * parameters not handled explicitly by the derived AudioIO* class). - */ - - map::iterator pi = d->paramMap.find(param); - if(pi == d->paramMap.end()) - { - int& result = d->paramMap[param]; - result = -1; - return result; - } - else return pi->second; -} - -string& AudioIO::paramStr(AudioParam param) -{ - return d->paramStrMap[param]; -} - -void AudioIO::setParamStr(AudioParam p, const char *value) -{ - paramStr(p) = value; -} - -void AudioIO::setParam(AudioParam p, int& value) -{ - param(p) = value; -} - -int AudioIO::getParam(AudioParam p) -{ - return param(p); -} - -const char *AudioIO::getParamStr(AudioParam p) -{ - return paramStr(p).c_str(); -} - -/* ---- factories ---- */ - -static list *audioIOFactories = 0; - -AudioIO *AudioIO::createAudioIO(const char *name) -{ - if(audioIOFactories) - { - list::iterator i; - for(i = audioIOFactories->begin(); i != audioIOFactories->end(); i++) - { - AudioIOFactory *factory = *i; - - if(strcmp(factory->name(),name) == 0) - return factory->createAudioIO(); - } - } - return 0; -} - -int AudioIO::queryAudioIOCount() -{ - return audioIOFactories->size(); -} - -int AudioIO::queryAudioIOParam(int /*audioIO*/, AudioParam /*p*/) -{ - return 0; -} - -const char *AudioIO::queryAudioIOParamStr(int audioIO, AudioParam p) -{ - list::iterator i = audioIOFactories->begin(); - - while(audioIO && i != audioIOFactories->end()) { i++; audioIO--; } - if(i == audioIOFactories->end()) return 0; - - switch(p) - { - case name: - return (*i)->name(); - case fullName: - return (*i)->fullName(); - default: - return 0; - } -} - -void AudioIO::addFactory(AudioIOFactory *factory) -{ - if(!audioIOFactories) - audioIOFactories = new list; - - audioIOFactories->push_back(factory); -} - -void AudioIO::removeFactory(AudioIOFactory *factory) -{ - assert(audioIOFactories); - - audioIOFactories->remove(factory); - if(audioIOFactories->empty()) - { - delete audioIOFactories; - audioIOFactories = 0; - } -} - -void AudioIOFactory::startup() -{ - AudioIO::addFactory(this); -} - -void AudioIOFactory::shutdown() -{ - AudioIO::removeFactory(this); -} diff --git a/flow/audioio.cpp b/flow/audioio.cpp new file mode 100644 index 0000000..eafb197 --- /dev/null +++ b/flow/audioio.cpp @@ -0,0 +1,165 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "audioio.h" +#include +#include +#include +#include + +using namespace Arts; +using namespace std; + +class Arts::AudioIOPrivate { +public: + map paramMap; + map paramStrMap; +}; + +AudioIO::AudioIO() :d(new AudioIOPrivate) +{ +} + +AudioIO::~AudioIO() +{ + delete d; +} + +int& AudioIO::param(AudioParam param) +{ + /* + * returns d->paramMap[param], initializes new elements with -1 (for those + * parameters not handled explicitly by the derived AudioIO* class). + */ + + map::iterator pi = d->paramMap.find(param); + if(pi == d->paramMap.end()) + { + int& result = d->paramMap[param]; + result = -1; + return result; + } + else return pi->second; +} + +string& AudioIO::paramStr(AudioParam param) +{ + return d->paramStrMap[param]; +} + +void AudioIO::setParamStr(AudioParam p, const char *value) +{ + paramStr(p) = value; +} + +void AudioIO::setParam(AudioParam p, int& value) +{ + param(p) = value; +} + +int AudioIO::getParam(AudioParam p) +{ + return param(p); +} + +const char *AudioIO::getParamStr(AudioParam p) +{ + return paramStr(p).c_str(); +} + +/* ---- factories ---- */ + +static list *audioIOFactories = 0; + +AudioIO *AudioIO::createAudioIO(const char *name) +{ + if(audioIOFactories) + { + list::iterator i; + for(i = audioIOFactories->begin(); i != audioIOFactories->end(); i++) + { + AudioIOFactory *factory = *i; + + if(strcmp(factory->name(),name) == 0) + return factory->createAudioIO(); + } + } + return 0; +} + +int AudioIO::queryAudioIOCount() +{ + return audioIOFactories->size(); +} + +int AudioIO::queryAudioIOParam(int /*audioIO*/, AudioParam /*p*/) +{ + return 0; +} + +const char *AudioIO::queryAudioIOParamStr(int audioIO, AudioParam p) +{ + list::iterator i = audioIOFactories->begin(); + + while(audioIO && i != audioIOFactories->end()) { i++; audioIO--; } + if(i == audioIOFactories->end()) return 0; + + switch(p) + { + case name: + return (*i)->name(); + case fullName: + return (*i)->fullName(); + default: + return 0; + } +} + +void AudioIO::addFactory(AudioIOFactory *factory) +{ + if(!audioIOFactories) + audioIOFactories = new list; + + audioIOFactories->push_back(factory); +} + +void AudioIO::removeFactory(AudioIOFactory *factory) +{ + assert(audioIOFactories); + + audioIOFactories->remove(factory); + if(audioIOFactories->empty()) + { + delete audioIOFactories; + audioIOFactories = 0; + } +} + +void AudioIOFactory::startup() +{ + AudioIO::addFactory(this); +} + +void AudioIOFactory::shutdown() +{ + AudioIO::removeFactory(this); +} diff --git a/flow/audioioaix.cc b/flow/audioioaix.cc deleted file mode 100644 index b5c288b..0000000 --- a/flow/audioioaix.cc +++ /dev/null @@ -1,390 +0,0 @@ -/* - - Copyright (C) 2001 Carsten Griwodz - griff@ifi.uio.no - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef _AIX - -/* - * The audio header files exist even if there is not soundcard the - * the AIX machine. You won't be able to compile this code on AIX3 - * which had ACPA support, so /dev/acpa is not checked here. - * I have no idea whether the Ultimedia Audio Adapter is actually - * working or what it is right now. - * For PCI machines including PowerSeries 850, baud or paud should - * work. The DSP (MWave?) of the 850 laptops may need microcode - * download. This is not implemented. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#undef BIG_ENDIAN -#include - -#ifndef AUDIO_BIG_ENDIAN -#define AUDIO_BIG_ENDIAN BIG_ENDIAN -#endif - -#include "debug.h" -#include "audioio.h" - -namespace Arts { - -class AudioIOAIX : public AudioIO { - int openDevice(); - -protected: - int audio_fd; - -public: - AudioIOAIX(); - - void setParam(AudioParam param, int& value); - int getParam(AudioParam param); - - bool open(); - void close(); - int read(void *buffer, int size); - int write(void *buffer, int size); -}; - -REGISTER_AUDIO_IO(AudioIOAIX,"paud","Personal Audio Device"); -}; - -using namespace std; -using namespace Arts; - -int AudioIOAIX::openDevice() -{ - char devname[14]; - int fd; - for ( int dev=0; dev<4; dev++ ) - { - for ( int chan=1; chan<8; chan++ ) - { - sprintf(devname,"/dev/paud%d/%d",dev,chan); - fd = ::open (devname, O_WRONLY, 0); - if ( fd >= 0 ) - { - paramStr(deviceName) = devname; - return fd; - } - sprintf(devname,"/dev/baud%d/%d",dev,chan); - fd = ::open (devname, O_WRONLY, 0); - if ( fd >= 0 ) - { - paramStr(deviceName) = devname; - return fd; - } - } - } - return -1; -} - -AudioIOAIX::AudioIOAIX() -{ - int fd = openDevice(); - if( fd >= 0 ) - { - audio_status audioStatus; - memset( &audioStatus, 0, sizeof(audio_status) ); - ioctl(fd, AUDIO_STATUS, &audioStatus); - - audio_buffer audioBuffer; - memset( &audioBuffer, 0, sizeof(audio_buffer) ); - ioctl(fd, AUDIO_BUFFER, &audioBuffer); - - ::close( fd ); - - /* - * default parameters - */ - param(samplingRate) = audioStatus.srate; - param(fragmentSize) = audioStatus.bsize; - param(fragmentCount) = audioBuffer.write_buf_cap / audioStatus.bsize; - param(channels) = audioStatus.channels; - param(direction) = 2; - - param(format) = ( audioStatus.bits_per_sample==8 ) ? 8 - : ( ( audioStatus.flags & AUDIO_BIG_ENDIAN ) ? 17 : 16 ); - } -} - -bool AudioIOAIX::open() -{ - string& _error = paramStr(lastError); - string& _deviceName = paramStr(deviceName); - int& _channels = param(channels); - int& _fragmentSize = param(fragmentSize); - int& _fragmentCount = param(fragmentCount); - int& _samplingRate = param(samplingRate); - int& _format = param(format); - - int mode; - - switch( param(direction) ) - { - case 1 : mode = O_RDONLY | O_NDELAY; break; - case 2 : mode = O_WRONLY | O_NDELAY; break; - case 3 : - _error = "open device twice to RDWR"; - return false; - default : - _error = "invalid direction"; - return false; - } - - audio_fd = ::open(_deviceName.c_str(), mode, 0); - - if(audio_fd == -1) - { - _error = "device "; - _error += _deviceName.c_str(); - _error += " can't be opened ("; - _error += strerror(errno); - _error += ")"; - return false; - } - - if( (_channels!=1) && (_channels!=2) ) - { - _error = "internal error; set channels to 1 (mono) or 2 (stereo)"; - - close(); - return false; - } - - // int requeststereo = stereo; - - // int speed = _samplingRate; - - audio_init audioInit; - memset( &audioInit, 0, sizeof(audio_init) ); - audioInit.srate = _samplingRate; - audioInit.bits_per_sample = ((_format==8)?8:16); - audioInit.bsize = _fragmentSize; - audioInit.mode = PCM; - audioInit.channels = _channels; - audioInit.flags = 0; - audioInit.flags |= (_format==17) ? AUDIO_BIG_ENDIAN : 0; - audioInit.flags |= (_format==8) ? 0 : SIGNED; - audioInit.operation = (param(direction)==1) ? RECORD : PLAY; - - if ( ioctl(audio_fd, AUDIO_INIT, &audioInit) < 0 ) - { - _error = "AUDIO_INIT failed - "; - _error += strerror(errno); - switch ( audioInit.rc ) - { - case 1 : - _error += "Couldn't set audio format: DSP can't do play requests"; - break; - case 2 : - _error += "Couldn't set audio format: DSP can't do record requests"; - break; - case 4 : - _error += "Couldn't set audio format: request was invalid"; - break; - case 5 : - _error += "Couldn't set audio format: conflict with open's flags"; - break; - case 6 : - _error += "Couldn't set audio format: out of DSP MIPS or memory"; - break; - default : - _error += "Couldn't set audio format: not documented in sys/audio.h"; - break; - } - - close(); - return false; - } - - if (audioInit.channels != _channels) - { - _error = "audio device doesn't support number of requested channels"; - close(); - return false; - } - - switch( _format ) - { - case 8 : - if (audioInit.flags&AUDIO_BIG_ENDIAN==1) - { - _error = "setting little endian format failed"; - close(); - return false; - } - if (audioInit.flags&SIGNED==1) - { - _error = "setting unsigned format failed"; - close(); - return false; - } - break; - case 16 : - if (audioInit.flags&AUDIO_BIG_ENDIAN==1) - { - _error = "setting little endian format failed"; - close(); - return false; - } - if (audioInit.flags&SIGNED==0) - { - _error = "setting signed format failed"; - close(); - return false; - } - break; - case 17 : - if (audioInit.flags&AUDIO_BIG_ENDIAN==0) - { - _error = "setting big endian format failed"; - close(); - return false; - } - if (audioInit.flags&SIGNED==0) - { - _error = "setting signed format failed"; - close(); - return false; - } - break; - default : - break; - } - - /* - * Some soundcards seem to be able to only supply "nearly" the requested - * sampling rate, especially PAS 16 cards seem to quite radical supplying - * something different than the requested sampling rate ;) - * - * So we have a quite large tolerance here (when requesting 44100 Hz, it - * will accept anything between 38690 Hz and 49510 Hz). Most parts of the - * aRts code will do resampling where appropriate, so it shouldn't affect - * sound quality. - */ - int tolerance = _samplingRate/10+1000; - - if (abs(audioInit.srate - _samplingRate) > tolerance) - { - _error = "can't set requested samplingrate"; - - char details[80]; - sprintf(details," (requested rate %d, got rate %ld)", - _samplingRate, audioInit.srate); - _error += details; - - close(); - return false; - } - _samplingRate = audioInit.srate; - - _fragmentSize = audioInit.bsize; - _fragmentCount = audioInit.bsize / audioInit.bits_per_sample; - - audio_buffer buffer_info; - ioctl(audio_fd, AUDIO_BUFFER, &buffer_info); - _fragmentCount = buffer_info.write_buf_cap / audioInit.bsize; - - - artsdebug("buffering: %d fragments with %d bytes " - "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, - (float)(_fragmentSize*_fragmentCount) / - (float)(2.0 * _samplingRate * _channels)*1000.0); - - return true; -} - -void AudioIOAIX::close() -{ - ::close(audio_fd); -} - -void AudioIOAIX::setParam(AudioParam p, int& value) -{ - param(p) = value; -} - -int AudioIOAIX::getParam(AudioParam p) -{ - audio_buffer info; - switch(p) - { - case canRead: - ioctl(audio_fd, AUDIO_BUFFER, &info); - return (info.read_buf_cap - info.read_buf_size); - break; - - case canWrite: - ioctl(audio_fd, AUDIO_BUFFER, &info); - return (info.write_buf_cap - info.write_buf_size); - break; - - case selectReadFD: - return (param(direction) & directionRead)?audio_fd:-1; - break; - - case selectWriteFD: - return (param(direction) & directionWrite)?audio_fd:-1; - break; - - case autoDetect: - /* You may prefer OSS if it works, e.g. on 43P 240 - * or you may prefer UMS, if anyone bothers to write - * a module for it. - */ - return 2; - break; - - default: - return param(p); - break; - } -} - -int AudioIOAIX::read(void *buffer, int size) -{ - arts_assert(audio_fd != 0); - return ::read(audio_fd,buffer,size); -} - -int AudioIOAIX::write(void *buffer, int size) -{ - arts_assert(audio_fd != 0); - return ::write(audio_fd,buffer,size); -} - -#endif - diff --git a/flow/audioioaix.cpp b/flow/audioioaix.cpp new file mode 100644 index 0000000..b5c288b --- /dev/null +++ b/flow/audioioaix.cpp @@ -0,0 +1,390 @@ +/* + + Copyright (C) 2001 Carsten Griwodz + griff@ifi.uio.no + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef _AIX + +/* + * The audio header files exist even if there is not soundcard the + * the AIX machine. You won't be able to compile this code on AIX3 + * which had ACPA support, so /dev/acpa is not checked here. + * I have no idea whether the Ultimedia Audio Adapter is actually + * working or what it is right now. + * For PCI machines including PowerSeries 850, baud or paud should + * work. The DSP (MWave?) of the 850 laptops may need microcode + * download. This is not implemented. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef BIG_ENDIAN +#include + +#ifndef AUDIO_BIG_ENDIAN +#define AUDIO_BIG_ENDIAN BIG_ENDIAN +#endif + +#include "debug.h" +#include "audioio.h" + +namespace Arts { + +class AudioIOAIX : public AudioIO { + int openDevice(); + +protected: + int audio_fd; + +public: + AudioIOAIX(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOAIX,"paud","Personal Audio Device"); +}; + +using namespace std; +using namespace Arts; + +int AudioIOAIX::openDevice() +{ + char devname[14]; + int fd; + for ( int dev=0; dev<4; dev++ ) + { + for ( int chan=1; chan<8; chan++ ) + { + sprintf(devname,"/dev/paud%d/%d",dev,chan); + fd = ::open (devname, O_WRONLY, 0); + if ( fd >= 0 ) + { + paramStr(deviceName) = devname; + return fd; + } + sprintf(devname,"/dev/baud%d/%d",dev,chan); + fd = ::open (devname, O_WRONLY, 0); + if ( fd >= 0 ) + { + paramStr(deviceName) = devname; + return fd; + } + } + } + return -1; +} + +AudioIOAIX::AudioIOAIX() +{ + int fd = openDevice(); + if( fd >= 0 ) + { + audio_status audioStatus; + memset( &audioStatus, 0, sizeof(audio_status) ); + ioctl(fd, AUDIO_STATUS, &audioStatus); + + audio_buffer audioBuffer; + memset( &audioBuffer, 0, sizeof(audio_buffer) ); + ioctl(fd, AUDIO_BUFFER, &audioBuffer); + + ::close( fd ); + + /* + * default parameters + */ + param(samplingRate) = audioStatus.srate; + param(fragmentSize) = audioStatus.bsize; + param(fragmentCount) = audioBuffer.write_buf_cap / audioStatus.bsize; + param(channels) = audioStatus.channels; + param(direction) = 2; + + param(format) = ( audioStatus.bits_per_sample==8 ) ? 8 + : ( ( audioStatus.flags & AUDIO_BIG_ENDIAN ) ? 17 : 16 ); + } +} + +bool AudioIOAIX::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + + int mode; + + switch( param(direction) ) + { + case 1 : mode = O_RDONLY | O_NDELAY; break; + case 2 : mode = O_WRONLY | O_NDELAY; break; + case 3 : + _error = "open device twice to RDWR"; + return false; + default : + _error = "invalid direction"; + return false; + } + + audio_fd = ::open(_deviceName.c_str(), mode, 0); + + if(audio_fd == -1) + { + _error = "device "; + _error += _deviceName.c_str(); + _error += " can't be opened ("; + _error += strerror(errno); + _error += ")"; + return false; + } + + if( (_channels!=1) && (_channels!=2) ) + { + _error = "internal error; set channels to 1 (mono) or 2 (stereo)"; + + close(); + return false; + } + + // int requeststereo = stereo; + + // int speed = _samplingRate; + + audio_init audioInit; + memset( &audioInit, 0, sizeof(audio_init) ); + audioInit.srate = _samplingRate; + audioInit.bits_per_sample = ((_format==8)?8:16); + audioInit.bsize = _fragmentSize; + audioInit.mode = PCM; + audioInit.channels = _channels; + audioInit.flags = 0; + audioInit.flags |= (_format==17) ? AUDIO_BIG_ENDIAN : 0; + audioInit.flags |= (_format==8) ? 0 : SIGNED; + audioInit.operation = (param(direction)==1) ? RECORD : PLAY; + + if ( ioctl(audio_fd, AUDIO_INIT, &audioInit) < 0 ) + { + _error = "AUDIO_INIT failed - "; + _error += strerror(errno); + switch ( audioInit.rc ) + { + case 1 : + _error += "Couldn't set audio format: DSP can't do play requests"; + break; + case 2 : + _error += "Couldn't set audio format: DSP can't do record requests"; + break; + case 4 : + _error += "Couldn't set audio format: request was invalid"; + break; + case 5 : + _error += "Couldn't set audio format: conflict with open's flags"; + break; + case 6 : + _error += "Couldn't set audio format: out of DSP MIPS or memory"; + break; + default : + _error += "Couldn't set audio format: not documented in sys/audio.h"; + break; + } + + close(); + return false; + } + + if (audioInit.channels != _channels) + { + _error = "audio device doesn't support number of requested channels"; + close(); + return false; + } + + switch( _format ) + { + case 8 : + if (audioInit.flags&AUDIO_BIG_ENDIAN==1) + { + _error = "setting little endian format failed"; + close(); + return false; + } + if (audioInit.flags&SIGNED==1) + { + _error = "setting unsigned format failed"; + close(); + return false; + } + break; + case 16 : + if (audioInit.flags&AUDIO_BIG_ENDIAN==1) + { + _error = "setting little endian format failed"; + close(); + return false; + } + if (audioInit.flags&SIGNED==0) + { + _error = "setting signed format failed"; + close(); + return false; + } + break; + case 17 : + if (audioInit.flags&AUDIO_BIG_ENDIAN==0) + { + _error = "setting big endian format failed"; + close(); + return false; + } + if (audioInit.flags&SIGNED==0) + { + _error = "setting signed format failed"; + close(); + return false; + } + break; + default : + break; + } + + /* + * Some soundcards seem to be able to only supply "nearly" the requested + * sampling rate, especially PAS 16 cards seem to quite radical supplying + * something different than the requested sampling rate ;) + * + * So we have a quite large tolerance here (when requesting 44100 Hz, it + * will accept anything between 38690 Hz and 49510 Hz). Most parts of the + * aRts code will do resampling where appropriate, so it shouldn't affect + * sound quality. + */ + int tolerance = _samplingRate/10+1000; + + if (abs(audioInit.srate - _samplingRate) > tolerance) + { + _error = "can't set requested samplingrate"; + + char details[80]; + sprintf(details," (requested rate %d, got rate %ld)", + _samplingRate, audioInit.srate); + _error += details; + + close(); + return false; + } + _samplingRate = audioInit.srate; + + _fragmentSize = audioInit.bsize; + _fragmentCount = audioInit.bsize / audioInit.bits_per_sample; + + audio_buffer buffer_info; + ioctl(audio_fd, AUDIO_BUFFER, &buffer_info); + _fragmentCount = buffer_info.write_buf_cap / audioInit.bsize; + + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + return true; +} + +void AudioIOAIX::close() +{ + ::close(audio_fd); +} + +void AudioIOAIX::setParam(AudioParam p, int& value) +{ + param(p) = value; +} + +int AudioIOAIX::getParam(AudioParam p) +{ + audio_buffer info; + switch(p) + { + case canRead: + ioctl(audio_fd, AUDIO_BUFFER, &info); + return (info.read_buf_cap - info.read_buf_size); + break; + + case canWrite: + ioctl(audio_fd, AUDIO_BUFFER, &info); + return (info.write_buf_cap - info.write_buf_size); + break; + + case selectReadFD: + return (param(direction) & directionRead)?audio_fd:-1; + break; + + case selectWriteFD: + return (param(direction) & directionWrite)?audio_fd:-1; + break; + + case autoDetect: + /* You may prefer OSS if it works, e.g. on 43P 240 + * or you may prefer UMS, if anyone bothers to write + * a module for it. + */ + return 2; + break; + + default: + return param(p); + break; + } +} + +int AudioIOAIX::read(void *buffer, int size) +{ + arts_assert(audio_fd != 0); + return ::read(audio_fd,buffer,size); +} + +int AudioIOAIX::write(void *buffer, int size) +{ + arts_assert(audio_fd != 0); + return ::write(audio_fd,buffer,size); +} + +#endif + diff --git a/flow/audioioalsa.cc b/flow/audioioalsa.cc deleted file mode 100644 index 5b8d485..0000000 --- a/flow/audioioalsa.cc +++ /dev/null @@ -1,561 +0,0 @@ - /* - - Copyright (C) 2000,2001 Jozef Kosoru - jozef.kosoru@pobox.sk - (C) 2000,2001 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/** - * only compile 'alsa' AudioIO class if configure thinks it is a good idea - */ -#ifdef HAVE_LIBASOUND - -#ifdef HAVE_ALSA_ASOUNDLIB_H -#include -#elif defined(HAVE_SYS_ASOUNDLIB_H) -#include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_SYS_SELECT_H -#include // Needed on some systems. -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "debug.h" -#include "audioio.h" - -namespace Arts { - -class AudioIOALSA : public AudioIO { -protected: - int audio_read_fd; - int audio_write_fd; - int requestedFragmentSize; - int requestedFragmentCount; - - enum BufferMode{block, stream}; - int m_card; - int m_device; - int m_format; - BufferMode m_bufferMode; - - snd_pcm_t *m_pcm_handle; - snd_pcm_channel_info_t m_cinfo; - snd_pcm_format_t m_cformat; - snd_pcm_channel_params_t m_params; - snd_pcm_channel_setup_t m_setup; - - int setPcmParams(const int channel); - void checkCapabilities(); - -public: - AudioIOALSA(); - - void setParam(AudioParam param, int& value); - int getParam(AudioParam param); - - bool open(); - void close(); - int read(void *buffer, int size); - int write(void *buffer, int size); -}; - -REGISTER_AUDIO_IO(AudioIOALSA,"alsa","Advanced Linux Sound Architecture"); -}; - -using namespace std; -using namespace Arts; - -AudioIOALSA::AudioIOALSA() -{ - param(samplingRate) = 44100; - paramStr(deviceName) = "/dev/dsp"; //!! alsa doesn't need this - requestedFragmentSize = param(fragmentSize) = 1024; - requestedFragmentCount = param(fragmentCount) = 7; - param(channels) = 2; - param(direction) = directionWrite; - - /* - * default parameters - */ - m_card = snd_defaults_pcm_card(); //!! need interface !! - m_device = snd_defaults_pcm_device(); //!! -#ifdef WORDS_BIGENDIAN - m_format = SND_PCM_SFMT_S16_BE; -#else - m_format = SND_PCM_SFMT_S16_LE; -#endif - m_bufferMode = block; //block/stream (stream mode doesn't work yet) - - if(m_card >= 0) { - char* cardname = 0; - - if(snd_card_get_name(m_card, &cardname) == 0 && cardname != 0) - { - //!! thats not what devicename is intended to do - //!! devicename is an input information into - //!! the "driver", to select which card to use - //!! not an output information - paramStr(deviceName) = cardname; - free(cardname); - } - } -} - -bool AudioIOALSA::open() -{ - string& _error = paramStr(lastError); - string& _deviceName = paramStr(deviceName); - int& _channels = param(channels); - int& _fragmentSize = param(fragmentSize); - int& _fragmentCount = param(fragmentCount); - int& _samplingRate = param(samplingRate); - int& _direction = param(direction); - int& _format = param(format); - - /* - * initialize format - TODO: implement fallback (i.e. if no format given, - * it should try 16bit first, then fall back to 8bit) - */ - switch(_format) - { - default: _format = 16; - - case 16: // 16bit, signed little endian - m_format = SND_PCM_SFMT_S16_LE; - break; - - case 17: // 16bit, signed big endian - m_format = SND_PCM_SFMT_S16_BE; - break; - - case 8: // 8bit, unsigned - m_format = SND_PCM_SFMT_U8; - break; - } - - /* open pcm device */ - int mode = SND_PCM_OPEN_NONBLOCK; - - if(_direction == directionReadWrite) - mode |= SND_PCM_OPEN_DUPLEX; - else if(_direction == directionWrite) - mode |= SND_PCM_OPEN_PLAYBACK; - else - { - _error = "invalid direction"; - return false; - } - - int err; - if((err = snd_pcm_open(&m_pcm_handle, m_card, m_device, mode)) < 0) { - _error = "device: "; - _error += _deviceName.c_str(); - _error += " can't be opened ("; - _error += snd_strerror(err); - _error += ")"; - return false; - } - else { - artsdebug("ALSA driver: %s", _deviceName.c_str()); - } - - snd_pcm_nonblock_mode(m_pcm_handle, 0); - - /* flush buffers */ - (void)snd_pcm_capture_flush(m_pcm_handle); - if(_direction & directionRead) - (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE); - if(_direction & directionWrite) - (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK); - - /* check device capabilities */ - checkCapabilities(); - - /* set the fragment settings to what the user requested */ - _fragmentSize = requestedFragmentSize; - _fragmentCount = requestedFragmentCount; - - /* set PCM communication parameters */ - if((_direction & directionRead) && setPcmParams(SND_PCM_CHANNEL_CAPTURE)) - return false; - if((_direction & directionWrite) && setPcmParams(SND_PCM_CHANNEL_PLAYBACK)) - return false; - - /* prepare channel */ - if((_direction & directionRead) && - snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE) < 0) - { - _error = "Unable to prepare capture channel!"; - return false; - } - if((_direction & directionWrite) && - snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK) < 0) - { - _error = "Unable to prepare playback channel!"; - return false; - } - - /* obtain current PCM setup (may differ from requested one) */ - (void)memset(&m_setup, 0, sizeof(m_setup)); - - m_setup.channel = SND_PCM_CHANNEL_PLAYBACK; - if(snd_pcm_channel_setup(m_pcm_handle, &m_setup) < 0) { - _error = "Unable to obtain channel setup!"; - return false; - } - - /* check samplerate */ - const int tolerance = _samplingRate/10+1000; - if(abs(m_setup.format.rate-_samplingRate) > tolerance) - { - _error = "Can't set requested sampling rate!"; - char details[80]; - sprintf(details," (requested rate %d, got rate %d)", - _samplingRate, m_setup.format.rate); - _error += details; - return false; - } - _samplingRate = m_setup.format.rate; - - /* check format */ - if(m_setup.format.format != m_format) { - _error = "Can't set requested format:"; - _error += snd_pcm_get_format_name(m_format); - return false; - } - - /* check voices */ - if(m_setup.format.voices != _channels) { - _error = "Audio device doesn't support number of requested channels!"; - return false; - } - - /* update fragment settings with what we got */ - switch(m_bufferMode) { - case block: - _fragmentSize = m_setup.buf.block.frag_size; - _fragmentCount = m_setup.buf.block.frags_max-1; - break; - case stream: - _fragmentSize = m_setup.buf.stream.queue_size; - _fragmentCount = 1; - break; - } - - artsdebug("buffering: %d fragments with %d bytes " - "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, - (float)(_fragmentSize*_fragmentCount) / - (float)(2.0 * _samplingRate * _channels)*1000.0); - - /* obtain PCM file descriptor(s) */ - audio_read_fd = audio_write_fd = -1; - - if(_direction & directionRead) - audio_read_fd = snd_pcm_file_descriptor(m_pcm_handle, - SND_PCM_CHANNEL_CAPTURE); - if(_direction & directionWrite) - audio_write_fd = snd_pcm_file_descriptor(m_pcm_handle, - SND_PCM_CHANNEL_PLAYBACK); - - /* start recording */ - if((_direction & directionRead) && snd_pcm_capture_go(m_pcm_handle)) { - _error = "Can't start recording!"; - return false; - } - - return true; -} - -void AudioIOALSA::close() -{ - int& _direction = param(direction); - if(_direction & directionRead) - (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE); - if(_direction & directionWrite) - (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK); - (void)snd_pcm_close(m_pcm_handle); -} - -void AudioIOALSA::setParam(AudioParam p, int& value) -{ - switch(p) - { - case fragmentSize: - param(p) = requestedFragmentSize = value; - break; - case fragmentCount: - param(p) = requestedFragmentCount = value; - break; - default: - param(p) = value; - break; - } -} - -int AudioIOALSA::getParam(AudioParam p) -{ - snd_pcm_channel_status_t status; - (void)memset(&status, 0, sizeof(status)); - - switch(p) - { - case canRead: - status.channel = SND_PCM_CHANNEL_CAPTURE; - if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { - arts_warning("Capture channel status error!"); - return -1; - } - return status.free; - break; - - case canWrite: - status.channel = SND_PCM_CHANNEL_PLAYBACK; - if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { - arts_warning("Playback channel status error!"); - return -1; - } - return status.free; - break; - - case selectReadFD: - return audio_read_fd; - break; - - case selectWriteFD: - return audio_write_fd; - break; - - case autoDetect: - /* - * that the ALSA driver could be compiled doesn't say anything - * about whether it will work (the user might be using an OSS - * kernel driver) so we'll use a value less than the OSS one - * here, because OSS will most certainly work (ALSA's OSS emu) - */ - return 5; - break; - - default: - return param(p); - break; - } -} - -int AudioIOALSA::read(void *buffer, int size) -{ - int length; - do { - length = snd_pcm_read(m_pcm_handle, buffer, size); - } while (length == -EINTR); - if(length == -EPIPE) { - snd_pcm_channel_status_t status; - (void)memset(&status, 0, sizeof(status)); - status.channel = SND_PCM_CHANNEL_CAPTURE; - if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { - arts_info("Capture channel status error!"); - return -1; - } - else if(status.status == SND_PCM_STATUS_RUNNING) { - length = 0; - } - else if(status.status == SND_PCM_STATUS_OVERRUN) { - artsdebug("Overrun at position: %d" ,status.scount); - if(snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE)<0) - { - arts_info("Overrun: capture prepare error!"); - return -1; - } - length = 0; - } - else { - arts_info("Unknown capture error!"); - return -1; - } - } - else if(length < 0) { - arts_info("Capture error: %s", snd_strerror(length)); - return -1; - } - return length; -} - -int AudioIOALSA::write(void *buffer, int size) -{ - int length; - while((length = snd_pcm_write(m_pcm_handle, buffer, size)) != size) { - if (length == -EINTR) - continue; // Try again - snd_pcm_channel_status_t status; - (void)memset(&status, 0, sizeof(status)); - status.channel = SND_PCM_CHANNEL_PLAYBACK; - - if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { - arts_warning("Playback channel status error!"); - return -1; - } - else if(status.status == SND_PCM_STATUS_UNDERRUN) { - artsdebug("Underrun at position: %d", status.scount); - if(snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK) - < 0) { - arts_warning("Underrun: playback prepare error!"); - return -1; - } - } - else { - arts_warning("Unknown playback error!"); - return -1; - } - } - return size; -} - -int AudioIOALSA::setPcmParams(const int channel) -{ - int &_samplingRate = param(samplingRate); - int &_channels = param(channels); - int &_fragmentSize = param(fragmentSize); - int &_fragmentCount = param(fragmentCount); - - (void)memset(&m_cformat, 0, sizeof(m_cformat)); - m_cformat.interleave = 1; - m_cformat.format = m_format; - m_cformat.rate = _samplingRate; - m_cformat.voices = _channels; - - (void)memset(&m_params, 0, sizeof(m_params)); - switch(m_bufferMode){ - case stream: - m_params.mode=SND_PCM_MODE_STREAM; - break; - case block: - m_params.mode=SND_PCM_MODE_BLOCK; - break; - } - m_params.channel=channel; - (void)memcpy(&m_params.format, &m_cformat, sizeof(m_cformat)); - if(channel==SND_PCM_CHANNEL_CAPTURE){ - m_params.start_mode=SND_PCM_START_GO; - m_params.stop_mode=SND_PCM_STOP_ROLLOVER; - } - else{ //SND_PCM_CHANNEL_PLAYBACK - m_params.start_mode= (m_bufferMode==block) ? SND_PCM_START_FULL : SND_PCM_START_DATA; - m_params.stop_mode=SND_PCM_STOP_ROLLOVER; // SND_PCM_STOP_STOP - //use this ^^^ if you want to track underruns - } - - switch(m_bufferMode){ - case stream: - m_params.buf.stream.queue_size=1024*1024; //_fragmentSize*_fragmentCount; - m_params.buf.stream.fill=SND_PCM_FILL_SILENCE_WHOLE; - m_params.buf.stream.max_fill=1024; - break; - case block: - m_params.buf.block.frag_size=_fragmentSize; - if(channel==SND_PCM_CHANNEL_CAPTURE){ - m_params.buf.block.frags_max=1; - m_params.buf.block.frags_min=1; - } - else{ //SND_PCM_CHANNEL_PLAYBACK - m_params.buf.block.frags_max=_fragmentCount+1; - m_params.buf.block.frags_min=1; - } - } - if(snd_pcm_channel_params(m_pcm_handle, &m_params)<0){ - paramStr(lastError) = "Unable to set channel params!"; - return 1; - } - else { - return 0; - } -} - -void AudioIOALSA::checkCapabilities() -{ - snd_pcm_info_t info; - (void)memset(&info, 0, sizeof(info)); - if(!snd_pcm_info(m_pcm_handle, &info)) { - string flags = ""; - if(info.flags & SND_PCM_INFO_PLAYBACK) flags += "playback "; - if(info.flags & SND_PCM_INFO_CAPTURE) flags += "capture "; - if(info.flags & SND_PCM_INFO_DUPLEX) flags += "duplex "; - if(info.flags & SND_PCM_INFO_DUPLEX_RATE) flags += "duplex_rate "; - artsdebug(" type:%d id:%s\n" - " flags:%s\n" - " playback_subdevices:%d capture_subdevices:%d", - info.type, info.id, - flags.c_str(), - info.playback+1, info.capture+1); - } - else { - arts_warning("Can't get device info!"); //not fatal error - } - - (void)memset(&m_cinfo, 0, sizeof(m_cinfo)); - m_cinfo.channel = SND_PCM_CHANNEL_PLAYBACK; - if(!snd_pcm_channel_info(m_pcm_handle, &m_cinfo)) { - string flags = ""; - if(m_cinfo.flags & SND_PCM_CHNINFO_MMAP) flags += "mmap "; - if(m_cinfo.flags & SND_PCM_CHNINFO_STREAM) flags += "stream "; - if(m_cinfo.flags & SND_PCM_CHNINFO_BLOCK) flags += "block "; - if(m_cinfo.flags & SND_PCM_CHNINFO_BATCH) flags += "batch "; - if(m_cinfo.flags & SND_PCM_CHNINFO_INTERLEAVE) flags += "interleave "; - if(m_cinfo.flags & SND_PCM_CHNINFO_NONINTERLEAVE) flags += "noninterleave "; - if(m_cinfo.flags & SND_PCM_CHNINFO_BLOCK_TRANSFER) flags += "block_transfer "; - if(m_cinfo.flags & SND_PCM_CHNINFO_OVERRANGE) flags += "overrange "; - if(m_cinfo.flags & SND_PCM_CHNINFO_MMAP_VALID) flags += "mmap_valid "; - if(m_cinfo.flags & SND_PCM_CHNINFO_PAUSE) flags += "pause "; - - artsdebug(" subdevice:%d\n" - " flags:%s\n" - " min_rate:%d max_rate:%d\n" - " buffer_size:%d min_fragment_size:%d max_fragment_size:%d\n" - " fragment_align:%d fifo_size:%d transfer_block_size:%d\n" - " mmap_size:%d", - m_cinfo.subdevice, - flags.c_str(), - m_cinfo.min_rate, m_cinfo.max_rate, - m_cinfo.buffer_size, m_cinfo.min_fragment_size, m_cinfo.max_fragment_size, - m_cinfo.fragment_align, m_cinfo.fifo_size, m_cinfo.transfer_block_size, - m_cinfo.mmap_size); - } - else { - arts_warning("Can't get channel info!"); //not fatal error - } -} - -#endif /* HAVE_LIBASOUND */ diff --git a/flow/audioioalsa.cpp b/flow/audioioalsa.cpp new file mode 100644 index 0000000..5b8d485 --- /dev/null +++ b/flow/audioioalsa.cpp @@ -0,0 +1,561 @@ + /* + + Copyright (C) 2000,2001 Jozef Kosoru + jozef.kosoru@pobox.sk + (C) 2000,2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile 'alsa' AudioIO class if configure thinks it is a good idea + */ +#ifdef HAVE_LIBASOUND + +#ifdef HAVE_ALSA_ASOUNDLIB_H +#include +#elif defined(HAVE_SYS_ASOUNDLIB_H) +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_SYS_SELECT_H +#include // Needed on some systems. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "audioio.h" + +namespace Arts { + +class AudioIOALSA : public AudioIO { +protected: + int audio_read_fd; + int audio_write_fd; + int requestedFragmentSize; + int requestedFragmentCount; + + enum BufferMode{block, stream}; + int m_card; + int m_device; + int m_format; + BufferMode m_bufferMode; + + snd_pcm_t *m_pcm_handle; + snd_pcm_channel_info_t m_cinfo; + snd_pcm_format_t m_cformat; + snd_pcm_channel_params_t m_params; + snd_pcm_channel_setup_t m_setup; + + int setPcmParams(const int channel); + void checkCapabilities(); + +public: + AudioIOALSA(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOALSA,"alsa","Advanced Linux Sound Architecture"); +}; + +using namespace std; +using namespace Arts; + +AudioIOALSA::AudioIOALSA() +{ + param(samplingRate) = 44100; + paramStr(deviceName) = "/dev/dsp"; //!! alsa doesn't need this + requestedFragmentSize = param(fragmentSize) = 1024; + requestedFragmentCount = param(fragmentCount) = 7; + param(channels) = 2; + param(direction) = directionWrite; + + /* + * default parameters + */ + m_card = snd_defaults_pcm_card(); //!! need interface !! + m_device = snd_defaults_pcm_device(); //!! +#ifdef WORDS_BIGENDIAN + m_format = SND_PCM_SFMT_S16_BE; +#else + m_format = SND_PCM_SFMT_S16_LE; +#endif + m_bufferMode = block; //block/stream (stream mode doesn't work yet) + + if(m_card >= 0) { + char* cardname = 0; + + if(snd_card_get_name(m_card, &cardname) == 0 && cardname != 0) + { + //!! thats not what devicename is intended to do + //!! devicename is an input information into + //!! the "driver", to select which card to use + //!! not an output information + paramStr(deviceName) = cardname; + free(cardname); + } + } +} + +bool AudioIOALSA::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _direction = param(direction); + int& _format = param(format); + + /* + * initialize format - TODO: implement fallback (i.e. if no format given, + * it should try 16bit first, then fall back to 8bit) + */ + switch(_format) + { + default: _format = 16; + + case 16: // 16bit, signed little endian + m_format = SND_PCM_SFMT_S16_LE; + break; + + case 17: // 16bit, signed big endian + m_format = SND_PCM_SFMT_S16_BE; + break; + + case 8: // 8bit, unsigned + m_format = SND_PCM_SFMT_U8; + break; + } + + /* open pcm device */ + int mode = SND_PCM_OPEN_NONBLOCK; + + if(_direction == directionReadWrite) + mode |= SND_PCM_OPEN_DUPLEX; + else if(_direction == directionWrite) + mode |= SND_PCM_OPEN_PLAYBACK; + else + { + _error = "invalid direction"; + return false; + } + + int err; + if((err = snd_pcm_open(&m_pcm_handle, m_card, m_device, mode)) < 0) { + _error = "device: "; + _error += _deviceName.c_str(); + _error += " can't be opened ("; + _error += snd_strerror(err); + _error += ")"; + return false; + } + else { + artsdebug("ALSA driver: %s", _deviceName.c_str()); + } + + snd_pcm_nonblock_mode(m_pcm_handle, 0); + + /* flush buffers */ + (void)snd_pcm_capture_flush(m_pcm_handle); + if(_direction & directionRead) + (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE); + if(_direction & directionWrite) + (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + + /* check device capabilities */ + checkCapabilities(); + + /* set the fragment settings to what the user requested */ + _fragmentSize = requestedFragmentSize; + _fragmentCount = requestedFragmentCount; + + /* set PCM communication parameters */ + if((_direction & directionRead) && setPcmParams(SND_PCM_CHANNEL_CAPTURE)) + return false; + if((_direction & directionWrite) && setPcmParams(SND_PCM_CHANNEL_PLAYBACK)) + return false; + + /* prepare channel */ + if((_direction & directionRead) && + snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE) < 0) + { + _error = "Unable to prepare capture channel!"; + return false; + } + if((_direction & directionWrite) && + snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK) < 0) + { + _error = "Unable to prepare playback channel!"; + return false; + } + + /* obtain current PCM setup (may differ from requested one) */ + (void)memset(&m_setup, 0, sizeof(m_setup)); + + m_setup.channel = SND_PCM_CHANNEL_PLAYBACK; + if(snd_pcm_channel_setup(m_pcm_handle, &m_setup) < 0) { + _error = "Unable to obtain channel setup!"; + return false; + } + + /* check samplerate */ + const int tolerance = _samplingRate/10+1000; + if(abs(m_setup.format.rate-_samplingRate) > tolerance) + { + _error = "Can't set requested sampling rate!"; + char details[80]; + sprintf(details," (requested rate %d, got rate %d)", + _samplingRate, m_setup.format.rate); + _error += details; + return false; + } + _samplingRate = m_setup.format.rate; + + /* check format */ + if(m_setup.format.format != m_format) { + _error = "Can't set requested format:"; + _error += snd_pcm_get_format_name(m_format); + return false; + } + + /* check voices */ + if(m_setup.format.voices != _channels) { + _error = "Audio device doesn't support number of requested channels!"; + return false; + } + + /* update fragment settings with what we got */ + switch(m_bufferMode) { + case block: + _fragmentSize = m_setup.buf.block.frag_size; + _fragmentCount = m_setup.buf.block.frags_max-1; + break; + case stream: + _fragmentSize = m_setup.buf.stream.queue_size; + _fragmentCount = 1; + break; + } + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + /* obtain PCM file descriptor(s) */ + audio_read_fd = audio_write_fd = -1; + + if(_direction & directionRead) + audio_read_fd = snd_pcm_file_descriptor(m_pcm_handle, + SND_PCM_CHANNEL_CAPTURE); + if(_direction & directionWrite) + audio_write_fd = snd_pcm_file_descriptor(m_pcm_handle, + SND_PCM_CHANNEL_PLAYBACK); + + /* start recording */ + if((_direction & directionRead) && snd_pcm_capture_go(m_pcm_handle)) { + _error = "Can't start recording!"; + return false; + } + + return true; +} + +void AudioIOALSA::close() +{ + int& _direction = param(direction); + if(_direction & directionRead) + (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE); + if(_direction & directionWrite) + (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + (void)snd_pcm_close(m_pcm_handle); +} + +void AudioIOALSA::setParam(AudioParam p, int& value) +{ + switch(p) + { + case fragmentSize: + param(p) = requestedFragmentSize = value; + break; + case fragmentCount: + param(p) = requestedFragmentCount = value; + break; + default: + param(p) = value; + break; + } +} + +int AudioIOALSA::getParam(AudioParam p) +{ + snd_pcm_channel_status_t status; + (void)memset(&status, 0, sizeof(status)); + + switch(p) + { + case canRead: + status.channel = SND_PCM_CHANNEL_CAPTURE; + if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { + arts_warning("Capture channel status error!"); + return -1; + } + return status.free; + break; + + case canWrite: + status.channel = SND_PCM_CHANNEL_PLAYBACK; + if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { + arts_warning("Playback channel status error!"); + return -1; + } + return status.free; + break; + + case selectReadFD: + return audio_read_fd; + break; + + case selectWriteFD: + return audio_write_fd; + break; + + case autoDetect: + /* + * that the ALSA driver could be compiled doesn't say anything + * about whether it will work (the user might be using an OSS + * kernel driver) so we'll use a value less than the OSS one + * here, because OSS will most certainly work (ALSA's OSS emu) + */ + return 5; + break; + + default: + return param(p); + break; + } +} + +int AudioIOALSA::read(void *buffer, int size) +{ + int length; + do { + length = snd_pcm_read(m_pcm_handle, buffer, size); + } while (length == -EINTR); + if(length == -EPIPE) { + snd_pcm_channel_status_t status; + (void)memset(&status, 0, sizeof(status)); + status.channel = SND_PCM_CHANNEL_CAPTURE; + if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { + arts_info("Capture channel status error!"); + return -1; + } + else if(status.status == SND_PCM_STATUS_RUNNING) { + length = 0; + } + else if(status.status == SND_PCM_STATUS_OVERRUN) { + artsdebug("Overrun at position: %d" ,status.scount); + if(snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE)<0) + { + arts_info("Overrun: capture prepare error!"); + return -1; + } + length = 0; + } + else { + arts_info("Unknown capture error!"); + return -1; + } + } + else if(length < 0) { + arts_info("Capture error: %s", snd_strerror(length)); + return -1; + } + return length; +} + +int AudioIOALSA::write(void *buffer, int size) +{ + int length; + while((length = snd_pcm_write(m_pcm_handle, buffer, size)) != size) { + if (length == -EINTR) + continue; // Try again + snd_pcm_channel_status_t status; + (void)memset(&status, 0, sizeof(status)); + status.channel = SND_PCM_CHANNEL_PLAYBACK; + + if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { + arts_warning("Playback channel status error!"); + return -1; + } + else if(status.status == SND_PCM_STATUS_UNDERRUN) { + artsdebug("Underrun at position: %d", status.scount); + if(snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK) + < 0) { + arts_warning("Underrun: playback prepare error!"); + return -1; + } + } + else { + arts_warning("Unknown playback error!"); + return -1; + } + } + return size; +} + +int AudioIOALSA::setPcmParams(const int channel) +{ + int &_samplingRate = param(samplingRate); + int &_channels = param(channels); + int &_fragmentSize = param(fragmentSize); + int &_fragmentCount = param(fragmentCount); + + (void)memset(&m_cformat, 0, sizeof(m_cformat)); + m_cformat.interleave = 1; + m_cformat.format = m_format; + m_cformat.rate = _samplingRate; + m_cformat.voices = _channels; + + (void)memset(&m_params, 0, sizeof(m_params)); + switch(m_bufferMode){ + case stream: + m_params.mode=SND_PCM_MODE_STREAM; + break; + case block: + m_params.mode=SND_PCM_MODE_BLOCK; + break; + } + m_params.channel=channel; + (void)memcpy(&m_params.format, &m_cformat, sizeof(m_cformat)); + if(channel==SND_PCM_CHANNEL_CAPTURE){ + m_params.start_mode=SND_PCM_START_GO; + m_params.stop_mode=SND_PCM_STOP_ROLLOVER; + } + else{ //SND_PCM_CHANNEL_PLAYBACK + m_params.start_mode= (m_bufferMode==block) ? SND_PCM_START_FULL : SND_PCM_START_DATA; + m_params.stop_mode=SND_PCM_STOP_ROLLOVER; // SND_PCM_STOP_STOP + //use this ^^^ if you want to track underruns + } + + switch(m_bufferMode){ + case stream: + m_params.buf.stream.queue_size=1024*1024; //_fragmentSize*_fragmentCount; + m_params.buf.stream.fill=SND_PCM_FILL_SILENCE_WHOLE; + m_params.buf.stream.max_fill=1024; + break; + case block: + m_params.buf.block.frag_size=_fragmentSize; + if(channel==SND_PCM_CHANNEL_CAPTURE){ + m_params.buf.block.frags_max=1; + m_params.buf.block.frags_min=1; + } + else{ //SND_PCM_CHANNEL_PLAYBACK + m_params.buf.block.frags_max=_fragmentCount+1; + m_params.buf.block.frags_min=1; + } + } + if(snd_pcm_channel_params(m_pcm_handle, &m_params)<0){ + paramStr(lastError) = "Unable to set channel params!"; + return 1; + } + else { + return 0; + } +} + +void AudioIOALSA::checkCapabilities() +{ + snd_pcm_info_t info; + (void)memset(&info, 0, sizeof(info)); + if(!snd_pcm_info(m_pcm_handle, &info)) { + string flags = ""; + if(info.flags & SND_PCM_INFO_PLAYBACK) flags += "playback "; + if(info.flags & SND_PCM_INFO_CAPTURE) flags += "capture "; + if(info.flags & SND_PCM_INFO_DUPLEX) flags += "duplex "; + if(info.flags & SND_PCM_INFO_DUPLEX_RATE) flags += "duplex_rate "; + artsdebug(" type:%d id:%s\n" + " flags:%s\n" + " playback_subdevices:%d capture_subdevices:%d", + info.type, info.id, + flags.c_str(), + info.playback+1, info.capture+1); + } + else { + arts_warning("Can't get device info!"); //not fatal error + } + + (void)memset(&m_cinfo, 0, sizeof(m_cinfo)); + m_cinfo.channel = SND_PCM_CHANNEL_PLAYBACK; + if(!snd_pcm_channel_info(m_pcm_handle, &m_cinfo)) { + string flags = ""; + if(m_cinfo.flags & SND_PCM_CHNINFO_MMAP) flags += "mmap "; + if(m_cinfo.flags & SND_PCM_CHNINFO_STREAM) flags += "stream "; + if(m_cinfo.flags & SND_PCM_CHNINFO_BLOCK) flags += "block "; + if(m_cinfo.flags & SND_PCM_CHNINFO_BATCH) flags += "batch "; + if(m_cinfo.flags & SND_PCM_CHNINFO_INTERLEAVE) flags += "interleave "; + if(m_cinfo.flags & SND_PCM_CHNINFO_NONINTERLEAVE) flags += "noninterleave "; + if(m_cinfo.flags & SND_PCM_CHNINFO_BLOCK_TRANSFER) flags += "block_transfer "; + if(m_cinfo.flags & SND_PCM_CHNINFO_OVERRANGE) flags += "overrange "; + if(m_cinfo.flags & SND_PCM_CHNINFO_MMAP_VALID) flags += "mmap_valid "; + if(m_cinfo.flags & SND_PCM_CHNINFO_PAUSE) flags += "pause "; + + artsdebug(" subdevice:%d\n" + " flags:%s\n" + " min_rate:%d max_rate:%d\n" + " buffer_size:%d min_fragment_size:%d max_fragment_size:%d\n" + " fragment_align:%d fifo_size:%d transfer_block_size:%d\n" + " mmap_size:%d", + m_cinfo.subdevice, + flags.c_str(), + m_cinfo.min_rate, m_cinfo.max_rate, + m_cinfo.buffer_size, m_cinfo.min_fragment_size, m_cinfo.max_fragment_size, + m_cinfo.fragment_align, m_cinfo.fifo_size, m_cinfo.transfer_block_size, + m_cinfo.mmap_size); + } + else { + arts_warning("Can't get channel info!"); //not fatal error + } +} + +#endif /* HAVE_LIBASOUND */ diff --git a/flow/audioioalsa9.cc b/flow/audioioalsa9.cc deleted file mode 100644 index 94c72ef..0000000 --- a/flow/audioioalsa9.cc +++ /dev/null @@ -1,590 +0,0 @@ - /* - - Copyright (C) 2001 Takashi Iwai - Copyright (C) 2004 Allan Sandfeld Jensen - - based on audioalsa.cc: - Copyright (C) 2000,2001 Jozef Kosoru - jozef.kosoru@pobox.sk - (C) 2000,2001 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/** - * only compile 'alsa' AudioIO class if configure thinks it is a good idea - */ -#ifdef HAVE_LIBASOUND2 - -#ifdef HAVE_ALSA_ASOUNDLIB_H -#include -#elif defined(HAVE_SYS_ASOUNDLIB_H) -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "debug.h" -#include "audioio.h" -#include "audiosubsys.h" -#include "dispatcher.h" -#include "iomanager.h" - -namespace Arts { - -class AudioIOALSA : public AudioIO, public IONotify { -protected: - // List of file descriptors - struct poll_descriptors { - poll_descriptors() : nfds(0), pfds(0) {}; - int nfds; - struct pollfd *pfds; - } audio_write_pds, audio_read_pds; - - snd_pcm_t *m_pcm_playback; - snd_pcm_t *m_pcm_capture; - snd_pcm_format_t m_format; - int m_period_size, m_periods; - - void startIO(); - int setPcmParams(snd_pcm_t *pcm); - static int poll2iomanager(int pollTypes); - static int iomanager2poll(int ioTypes); - void getDescriptors(snd_pcm_t *pcm, poll_descriptors *pds); - void watchDescriptors(poll_descriptors *pds); - - void notifyIO(int fd, int types); - - int xrun(snd_pcm_t *pcm); -#ifdef HAVE_SND_PCM_RESUME - int resume(snd_pcm_t *pcm); -#endif - -public: - AudioIOALSA(); - - void setParam(AudioParam param, int& value); - int getParam(AudioParam param); - - bool open(); - void close(); - int read(void *buffer, int size); - int write(void *buffer, int size); -}; - -REGISTER_AUDIO_IO(AudioIOALSA,"alsa","Advanced Linux Sound Architecture"); -} - -using namespace std; -using namespace Arts; - -AudioIOALSA::AudioIOALSA() -{ - param(samplingRate) = 44100; - paramStr(deviceName) = "default"; // ALSA pcm device name - not file name - param(fragmentSize) = 1024; - param(fragmentCount) = 7; - param(channels) = 2; - param(direction) = directionWrite; - param(format) = 16; - /* - * default parameters - */ - m_format = SND_PCM_FORMAT_S16_LE; - m_pcm_playback = NULL; - m_pcm_capture = NULL; -} - -bool AudioIOALSA::open() -{ - string& _error = paramStr(lastError); - string& _deviceName = paramStr(deviceName); - int& _channels = param(channels); - int& _fragmentSize = param(fragmentSize); - int& _fragmentCount = param(fragmentCount); - int& _samplingRate = param(samplingRate); - int& _direction = param(direction); - int& _format = param(format); - - m_pcm_playback = NULL; - m_pcm_capture = NULL; - - /* initialize format */ - switch(_format) { - case 16: // 16bit, signed little endian - m_format = SND_PCM_FORMAT_S16_LE; - break; - case 17: // 16bit, signed big endian - m_format = SND_PCM_FORMAT_S16_BE; - break; - case 8: // 8bit, unsigned - m_format = SND_PCM_FORMAT_U8; - break; - default: // test later - m_format = SND_PCM_FORMAT_UNKNOWN; - break; - } - - /* open pcm device */ - int err; - if (_direction & directionWrite) { - if ((err = snd_pcm_open(&m_pcm_playback, _deviceName.c_str(), - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { - _error = "device: "; - _error += _deviceName.c_str(); - _error += " can't be opened for playback ("; - _error += snd_strerror(err); - _error += ")"; - return false; - } - snd_pcm_nonblock(m_pcm_playback, 0); - } - if (_direction & directionRead) { - if ((err = snd_pcm_open(&m_pcm_capture, _deviceName.c_str(), - SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - _error = "device: "; - _error += _deviceName.c_str(); - _error += " can't be opened for capture ("; - _error += snd_strerror(err); - _error += ")"; - snd_pcm_close(m_pcm_playback); - return false; - } - snd_pcm_nonblock(m_pcm_capture, 0); - } - - artsdebug("ALSA driver: %s", _deviceName.c_str()); - - /* check device capabilities */ - // checkCapabilities(); - - /* set PCM communication parameters */ - if (((_direction & directionWrite) && setPcmParams(m_pcm_playback)) || - ((_direction & directionRead) && setPcmParams(m_pcm_capture))) { - snd_pcm_close(m_pcm_playback); - snd_pcm_close(m_pcm_capture); - return false; - } - - artsdebug("buffering: %d fragments with %d bytes " - "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, - (float)(_fragmentSize*_fragmentCount) / - (float)(2.0 * _samplingRate * _channels)*1000.0); - - - startIO(); - /* restore the format value */ - switch (m_format) { - case SND_PCM_FORMAT_S16_LE: - _format = 16; - break; - case SND_PCM_FORMAT_S16_BE: - _format = 17; - break; - case SND_PCM_FORMAT_U8: - _format = 8; - break; - default: - _error = "Unknown PCM format"; - return false; - } - - /* start recording */ - if (_direction & directionRead) - snd_pcm_start(m_pcm_capture); - - return true; -} - -void AudioIOALSA::close() -{ - arts_debug("Closing ALSA-driver"); - int& _direction = param(direction); - if ((_direction & directionRead) && m_pcm_capture) { - (void)snd_pcm_drop(m_pcm_capture); - (void)snd_pcm_close(m_pcm_capture); - m_pcm_capture = NULL; - } - if ((_direction & directionWrite) && m_pcm_playback) { - (void)snd_pcm_drop(m_pcm_playback); - (void)snd_pcm_close(m_pcm_playback); - m_pcm_playback = NULL; - } - Dispatcher::the()->ioManager()->remove(this, IOType::all); - - delete[] audio_read_pds.pfds; - delete[] audio_write_pds.pfds; - audio_read_pds.pfds = NULL; audio_write_pds.pfds = NULL; - audio_read_pds.nfds = 0; audio_write_pds.nfds = 0; -} - -void AudioIOALSA::setParam(AudioParam p, int& value) -{ - param(p) = value; - if (m_pcm_playback != NULL) { - setPcmParams(m_pcm_playback); - } - if (m_pcm_capture != NULL) { - setPcmParams(m_pcm_capture); - } -} - -int AudioIOALSA::getParam(AudioParam p) -{ - snd_pcm_sframes_t avail; - switch(p) { - - case canRead: - if (! m_pcm_capture) return -1; - while ((avail = snd_pcm_avail_update(m_pcm_capture)) < 0) { - if (avail == -EPIPE) - avail = xrun(m_pcm_capture); -#ifdef HAVE_SND_PCM_RESUME - else if (avail == -ESTRPIPE) - avail = resume(m_pcm_capture); -#endif - if (avail < 0) { - arts_info("Capture error: %s", snd_strerror(avail)); - return -1; - } - } - return snd_pcm_frames_to_bytes(m_pcm_capture, avail); - - case canWrite: - if (! m_pcm_playback) return -1; - while ((avail = snd_pcm_avail_update(m_pcm_playback)) < 0) { - if (avail == -EPIPE) - avail = xrun(m_pcm_playback); -#ifdef HAVE_SND_PCM_RESUME - else if (avail == -ESTRPIPE) - avail = resume(m_pcm_playback); -#endif - if (avail < 0) { - arts_info("Playback error: %s", snd_strerror(avail)); - return -1; - } - } - return snd_pcm_frames_to_bytes(m_pcm_playback, avail); - - case selectReadFD: - return -1; - - case selectWriteFD: - return -1; - - case autoDetect: - { - /* - * that the ALSA driver could be compiled doesn't say anything - * about whether it will work (the user might be using an OSS - * kernel driver). - * If we can open the device, it'll work - and we'll have to use - * a higher number than OSS to avoid buggy OSS emulation being used. - */ - int card = -1; - if (snd_card_next(&card) < 0 || card < 0) { - // No ALSA drivers in use... - return 0; - } - return 15; - } - - default: - return param(p); - } -} - -void AudioIOALSA::startIO() -{ - /* get & watch PCM file descriptor(s) */ - if (m_pcm_playback) { - getDescriptors(m_pcm_playback, &audio_write_pds); - watchDescriptors(&audio_write_pds); - } - if (m_pcm_capture) { - getDescriptors(m_pcm_capture, &audio_read_pds); - watchDescriptors(&audio_read_pds); - } - -} - -int AudioIOALSA::poll2iomanager(int pollTypes) -{ - int types = 0; - - if(pollTypes & POLLIN) - types |= IOType::read; - if(pollTypes & POLLOUT) - types |= IOType::write; - if(pollTypes & POLLERR) - types |= IOType::except; - - return types; -} - -int AudioIOALSA::iomanager2poll(int ioTypes) -{ - int types = 0; - - if(ioTypes & IOType::read) - types |= POLLIN; - if(ioTypes & IOType::write) - types |= POLLOUT; - if(ioTypes & IOType::except) - types |= POLLERR; - - return types; -} - -void AudioIOALSA::getDescriptors(snd_pcm_t *pcm, poll_descriptors *pds) -{ - pds->nfds = snd_pcm_poll_descriptors_count(pcm); - pds->pfds = new struct pollfd[pds->nfds]; - - if (snd_pcm_poll_descriptors(pcm, pds->pfds, pds->nfds) != pds->nfds) { - arts_info("Cannot get poll descriptor(s)\n"); - } - -} - -void AudioIOALSA::watchDescriptors(poll_descriptors *pds) -{ - for(int i=0; infds; i++) { - // Check in which direction this handle is supposed to be watched - int types = poll2iomanager(pds->pfds[i].events); - Dispatcher::the()->ioManager()->watchFD(pds->pfds[i].fd, types, this); - } -} - -int AudioIOALSA::xrun(snd_pcm_t *pcm) -{ - int err; - artsdebug("xrun!!\n"); - if ((err = snd_pcm_prepare(pcm)) < 0) - return err; - if (pcm == m_pcm_capture) - snd_pcm_start(pcm); // ignore error here.. - return 0; -} - -#ifdef HAVE_SND_PCM_RESUME -int AudioIOALSA::resume(snd_pcm_t *pcm) -{ - int err; - artsdebug("resume!\n"); - while ((err = snd_pcm_resume(pcm)) == -EAGAIN) - sleep(1); /* wait until suspend flag is not released */ - if (err < 0) { - if ((err = snd_pcm_prepare(pcm)) < 0) - return err; - if (pcm == m_pcm_capture) - snd_pcm_start(pcm); // ignore error here.. - } - return 0; -} -#endif - -int AudioIOALSA::read(void *buffer, int size) -{ - int frames = snd_pcm_bytes_to_frames(m_pcm_capture, size); - int length; - while ((length = snd_pcm_readi(m_pcm_capture, buffer, frames)) < 0) { - if (length == -EINTR) - continue; // Try again - else if (length == -EPIPE) - length = xrun(m_pcm_capture); -#ifdef HAVE_SND_PCM_RESUME - else if (length == -ESTRPIPE) - length = resume(m_pcm_capture); -#endif - if (length < 0) { - arts_info("Capture error: %s", snd_strerror(length)); - return -1; - } - } - return snd_pcm_frames_to_bytes(m_pcm_capture, length); -} - -int AudioIOALSA::write(void *buffer, int size) -{ - int frames = snd_pcm_bytes_to_frames(m_pcm_playback, size); - int length; - while ((length = snd_pcm_writei(m_pcm_playback, buffer, frames)) < 0) { - if (length == -EINTR) - continue; // Try again - else if (length == -EPIPE) - length = xrun(m_pcm_playback); -#ifdef HAVE_SND_PCM_RESUME - else if (length == -ESTRPIPE) - length = resume(m_pcm_playback); -#endif - if (length < 0) { - arts_info("Playback error: %s", snd_strerror(length)); - return -1; - } - } - - // Start the sink if it needs it - if (snd_pcm_state( m_pcm_playback ) == SND_PCM_STATE_PREPARED) - snd_pcm_start(m_pcm_playback); - - if (length == frames) // Sometimes the fragments are "odd" in alsa - return size; - else - return snd_pcm_frames_to_bytes(m_pcm_playback, length); -} - -void AudioIOALSA::notifyIO(int fd, int type) -{ - int todo = 0; - - // Translate from iomanager-types to poll-types, - // inorder to fake a snd_pcm_poll_descriptors_revents call. - if(m_pcm_playback) { - for(int i=0; i < audio_write_pds.nfds; i++) { - if(fd == audio_write_pds.pfds[i].fd) { - audio_write_pds.pfds[i].revents = iomanager2poll(type); - todo |= AudioSubSystem::ioWrite; - } - } - if (todo & AudioSubSystem::ioWrite) { - unsigned short revents; - snd_pcm_poll_descriptors_revents(m_pcm_playback, - audio_write_pds.pfds, - audio_write_pds.nfds, - &revents); - if (! (revents & POLLOUT)) todo &= ~AudioSubSystem::ioWrite; - } - } - if(m_pcm_capture) { - for(int i=0; i < audio_read_pds.nfds; i++) { - if(fd == audio_read_pds.pfds[i].fd) { - audio_read_pds.pfds[i].revents = iomanager2poll(type); - todo |= AudioSubSystem::ioRead; - } - } - if (todo & AudioSubSystem::ioRead) { - unsigned short revents; - snd_pcm_poll_descriptors_revents(m_pcm_capture, - audio_read_pds.pfds, - audio_read_pds.nfds, - &revents); - if (! (revents & POLLIN)) todo &= ~AudioSubSystem::ioRead; - } - } - - if (type & IOType::except) todo |= AudioSubSystem::ioExcept; - - if (todo != 0) AudioSubSystem::the()->handleIO(todo); -} - -int AudioIOALSA::setPcmParams(snd_pcm_t *pcm) -{ - int &_samplingRate = param(samplingRate); - int &_channels = param(channels); - int &_fragmentSize = param(fragmentSize); - int &_fragmentCount = param(fragmentCount); - string& _error = paramStr(lastError); - - snd_pcm_hw_params_t *hw; - snd_pcm_hw_params_alloca(&hw); - snd_pcm_hw_params_any(pcm, hw); - - if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { - _error = "Unable to set interleaved!"; - return 1; - } - if (m_format == SND_PCM_FORMAT_UNKNOWN) { - // test the available formats - // try 16bit first, then fall back to 8bit - if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_S16_LE)) - m_format = SND_PCM_FORMAT_S16_LE; - else if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_S16_BE)) - m_format = SND_PCM_FORMAT_S16_BE; - else if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_U8)) - m_format = SND_PCM_FORMAT_U8; - else - m_format = SND_PCM_FORMAT_UNKNOWN; - } - if (snd_pcm_hw_params_set_format(pcm, hw, m_format) < 0) { - _error = "Unable to set format!"; - return 1; - } - - unsigned int rate = snd_pcm_hw_params_set_rate_near(pcm, hw, _samplingRate, 0); - const unsigned int tolerance = _samplingRate/10+1000; - if (abs((int)rate - (int)_samplingRate) > (int)tolerance) { - _error = "Can't set requested sampling rate!"; - char details[80]; - sprintf(details," (requested rate %d, got rate %d)", - _samplingRate, rate); - _error += details; - return 1; - } - _samplingRate = rate; - - if (snd_pcm_hw_params_set_channels(pcm, hw, _channels) < 0) { - _error = "Unable to set channels!"; - return 1; - } - - m_period_size = _fragmentSize; - if (m_format != SND_PCM_FORMAT_U8) - m_period_size <<= 1; - if (_channels > 1) - m_period_size /= _channels; - if ((m_period_size = snd_pcm_hw_params_set_period_size_near(pcm, hw, m_period_size, 0)) < 0) { - _error = "Unable to set period size!"; - return 1; - } - m_periods = _fragmentCount; - if ((m_periods = snd_pcm_hw_params_set_periods_near(pcm, hw, m_periods, 0)) < 0) { - _error = "Unable to set periods!"; - return 1; - } - - if (snd_pcm_hw_params(pcm, hw) < 0) { - _error = "Unable to set hw params!"; - return 1; - } - - _fragmentSize = m_period_size; - _fragmentCount = m_periods; - if (m_format != SND_PCM_FORMAT_U8) - _fragmentSize >>= 1; - if (_channels > 1) - _fragmentSize *= _channels; - - return 0; // ok, we're ready.. -} - -#endif /* HAVE_LIBASOUND2 */ diff --git a/flow/audioioalsa9.cpp b/flow/audioioalsa9.cpp new file mode 100644 index 0000000..1c8b3a5 --- /dev/null +++ b/flow/audioioalsa9.cpp @@ -0,0 +1,590 @@ + /* + + Copyright (C) 2001 Takashi Iwai + Copyright (C) 2004 Allan Sandfeld Jensen + + based on audioalsa.cpp: + Copyright (C) 2000,2001 Jozef Kosoru + jozef.kosoru@pobox.sk + (C) 2000,2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile 'alsa' AudioIO class if configure thinks it is a good idea + */ +#ifdef HAVE_LIBASOUND2 + +#ifdef HAVE_ALSA_ASOUNDLIB_H +#include +#elif defined(HAVE_SYS_ASOUNDLIB_H) +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "audioio.h" +#include "audiosubsys.h" +#include "dispatcher.h" +#include "iomanager.h" + +namespace Arts { + +class AudioIOALSA : public AudioIO, public IONotify { +protected: + // List of file descriptors + struct poll_descriptors { + poll_descriptors() : nfds(0), pfds(0) {}; + int nfds; + struct pollfd *pfds; + } audio_write_pds, audio_read_pds; + + snd_pcm_t *m_pcm_playback; + snd_pcm_t *m_pcm_capture; + snd_pcm_format_t m_format; + int m_period_size, m_periods; + + void startIO(); + int setPcmParams(snd_pcm_t *pcm); + static int poll2iomanager(int pollTypes); + static int iomanager2poll(int ioTypes); + void getDescriptors(snd_pcm_t *pcm, poll_descriptors *pds); + void watchDescriptors(poll_descriptors *pds); + + void notifyIO(int fd, int types); + + int xrun(snd_pcm_t *pcm); +#ifdef HAVE_SND_PCM_RESUME + int resume(snd_pcm_t *pcm); +#endif + +public: + AudioIOALSA(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOALSA,"alsa","Advanced Linux Sound Architecture"); +} + +using namespace std; +using namespace Arts; + +AudioIOALSA::AudioIOALSA() +{ + param(samplingRate) = 44100; + paramStr(deviceName) = "default"; // ALSA pcm device name - not file name + param(fragmentSize) = 1024; + param(fragmentCount) = 7; + param(channels) = 2; + param(direction) = directionWrite; + param(format) = 16; + /* + * default parameters + */ + m_format = SND_PCM_FORMAT_S16_LE; + m_pcm_playback = NULL; + m_pcm_capture = NULL; +} + +bool AudioIOALSA::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _direction = param(direction); + int& _format = param(format); + + m_pcm_playback = NULL; + m_pcm_capture = NULL; + + /* initialize format */ + switch(_format) { + case 16: // 16bit, signed little endian + m_format = SND_PCM_FORMAT_S16_LE; + break; + case 17: // 16bit, signed big endian + m_format = SND_PCM_FORMAT_S16_BE; + break; + case 8: // 8bit, unsigned + m_format = SND_PCM_FORMAT_U8; + break; + default: // test later + m_format = SND_PCM_FORMAT_UNKNOWN; + break; + } + + /* open pcm device */ + int err; + if (_direction & directionWrite) { + if ((err = snd_pcm_open(&m_pcm_playback, _deviceName.c_str(), + SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { + _error = "device: "; + _error += _deviceName.c_str(); + _error += " can't be opened for playback ("; + _error += snd_strerror(err); + _error += ")"; + return false; + } + snd_pcm_nonblock(m_pcm_playback, 0); + } + if (_direction & directionRead) { + if ((err = snd_pcm_open(&m_pcm_capture, _deviceName.c_str(), + SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + _error = "device: "; + _error += _deviceName.c_str(); + _error += " can't be opened for capture ("; + _error += snd_strerror(err); + _error += ")"; + snd_pcm_close(m_pcm_playback); + return false; + } + snd_pcm_nonblock(m_pcm_capture, 0); + } + + artsdebug("ALSA driver: %s", _deviceName.c_str()); + + /* check device capabilities */ + // checkCapabilities(); + + /* set PCM communication parameters */ + if (((_direction & directionWrite) && setPcmParams(m_pcm_playback)) || + ((_direction & directionRead) && setPcmParams(m_pcm_capture))) { + snd_pcm_close(m_pcm_playback); + snd_pcm_close(m_pcm_capture); + return false; + } + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + + startIO(); + /* restore the format value */ + switch (m_format) { + case SND_PCM_FORMAT_S16_LE: + _format = 16; + break; + case SND_PCM_FORMAT_S16_BE: + _format = 17; + break; + case SND_PCM_FORMAT_U8: + _format = 8; + break; + default: + _error = "Unknown PCM format"; + return false; + } + + /* start recording */ + if (_direction & directionRead) + snd_pcm_start(m_pcm_capture); + + return true; +} + +void AudioIOALSA::close() +{ + arts_debug("Closing ALSA-driver"); + int& _direction = param(direction); + if ((_direction & directionRead) && m_pcm_capture) { + (void)snd_pcm_drop(m_pcm_capture); + (void)snd_pcm_close(m_pcm_capture); + m_pcm_capture = NULL; + } + if ((_direction & directionWrite) && m_pcm_playback) { + (void)snd_pcm_drop(m_pcm_playback); + (void)snd_pcm_close(m_pcm_playback); + m_pcm_playback = NULL; + } + Dispatcher::the()->ioManager()->remove(this, IOType::all); + + delete[] audio_read_pds.pfds; + delete[] audio_write_pds.pfds; + audio_read_pds.pfds = NULL; audio_write_pds.pfds = NULL; + audio_read_pds.nfds = 0; audio_write_pds.nfds = 0; +} + +void AudioIOALSA::setParam(AudioParam p, int& value) +{ + param(p) = value; + if (m_pcm_playback != NULL) { + setPcmParams(m_pcm_playback); + } + if (m_pcm_capture != NULL) { + setPcmParams(m_pcm_capture); + } +} + +int AudioIOALSA::getParam(AudioParam p) +{ + snd_pcm_sframes_t avail; + switch(p) { + + case canRead: + if (! m_pcm_capture) return -1; + while ((avail = snd_pcm_avail_update(m_pcm_capture)) < 0) { + if (avail == -EPIPE) + avail = xrun(m_pcm_capture); +#ifdef HAVE_SND_PCM_RESUME + else if (avail == -ESTRPIPE) + avail = resume(m_pcm_capture); +#endif + if (avail < 0) { + arts_info("Capture error: %s", snd_strerror(avail)); + return -1; + } + } + return snd_pcm_frames_to_bytes(m_pcm_capture, avail); + + case canWrite: + if (! m_pcm_playback) return -1; + while ((avail = snd_pcm_avail_update(m_pcm_playback)) < 0) { + if (avail == -EPIPE) + avail = xrun(m_pcm_playback); +#ifdef HAVE_SND_PCM_RESUME + else if (avail == -ESTRPIPE) + avail = resume(m_pcm_playback); +#endif + if (avail < 0) { + arts_info("Playback error: %s", snd_strerror(avail)); + return -1; + } + } + return snd_pcm_frames_to_bytes(m_pcm_playback, avail); + + case selectReadFD: + return -1; + + case selectWriteFD: + return -1; + + case autoDetect: + { + /* + * that the ALSA driver could be compiled doesn't say anything + * about whether it will work (the user might be using an OSS + * kernel driver). + * If we can open the device, it'll work - and we'll have to use + * a higher number than OSS to avoid buggy OSS emulation being used. + */ + int card = -1; + if (snd_card_next(&card) < 0 || card < 0) { + // No ALSA drivers in use... + return 0; + } + return 15; + } + + default: + return param(p); + } +} + +void AudioIOALSA::startIO() +{ + /* get & watch PCM file descriptor(s) */ + if (m_pcm_playback) { + getDescriptors(m_pcm_playback, &audio_write_pds); + watchDescriptors(&audio_write_pds); + } + if (m_pcm_capture) { + getDescriptors(m_pcm_capture, &audio_read_pds); + watchDescriptors(&audio_read_pds); + } + +} + +int AudioIOALSA::poll2iomanager(int pollTypes) +{ + int types = 0; + + if(pollTypes & POLLIN) + types |= IOType::read; + if(pollTypes & POLLOUT) + types |= IOType::write; + if(pollTypes & POLLERR) + types |= IOType::except; + + return types; +} + +int AudioIOALSA::iomanager2poll(int ioTypes) +{ + int types = 0; + + if(ioTypes & IOType::read) + types |= POLLIN; + if(ioTypes & IOType::write) + types |= POLLOUT; + if(ioTypes & IOType::except) + types |= POLLERR; + + return types; +} + +void AudioIOALSA::getDescriptors(snd_pcm_t *pcm, poll_descriptors *pds) +{ + pds->nfds = snd_pcm_poll_descriptors_count(pcm); + pds->pfds = new struct pollfd[pds->nfds]; + + if (snd_pcm_poll_descriptors(pcm, pds->pfds, pds->nfds) != pds->nfds) { + arts_info("Cannot get poll descriptor(s)\n"); + } + +} + +void AudioIOALSA::watchDescriptors(poll_descriptors *pds) +{ + for(int i=0; infds; i++) { + // Check in which direction this handle is supposed to be watched + int types = poll2iomanager(pds->pfds[i].events); + Dispatcher::the()->ioManager()->watchFD(pds->pfds[i].fd, types, this); + } +} + +int AudioIOALSA::xrun(snd_pcm_t *pcm) +{ + int err; + artsdebug("xrun!!\n"); + if ((err = snd_pcm_prepare(pcm)) < 0) + return err; + if (pcm == m_pcm_capture) + snd_pcm_start(pcm); // ignore error here.. + return 0; +} + +#ifdef HAVE_SND_PCM_RESUME +int AudioIOALSA::resume(snd_pcm_t *pcm) +{ + int err; + artsdebug("resume!\n"); + while ((err = snd_pcm_resume(pcm)) == -EAGAIN) + sleep(1); /* wait until suspend flag is not released */ + if (err < 0) { + if ((err = snd_pcm_prepare(pcm)) < 0) + return err; + if (pcm == m_pcm_capture) + snd_pcm_start(pcm); // ignore error here.. + } + return 0; +} +#endif + +int AudioIOALSA::read(void *buffer, int size) +{ + int frames = snd_pcm_bytes_to_frames(m_pcm_capture, size); + int length; + while ((length = snd_pcm_readi(m_pcm_capture, buffer, frames)) < 0) { + if (length == -EINTR) + continue; // Try again + else if (length == -EPIPE) + length = xrun(m_pcm_capture); +#ifdef HAVE_SND_PCM_RESUME + else if (length == -ESTRPIPE) + length = resume(m_pcm_capture); +#endif + if (length < 0) { + arts_info("Capture error: %s", snd_strerror(length)); + return -1; + } + } + return snd_pcm_frames_to_bytes(m_pcm_capture, length); +} + +int AudioIOALSA::write(void *buffer, int size) +{ + int frames = snd_pcm_bytes_to_frames(m_pcm_playback, size); + int length; + while ((length = snd_pcm_writei(m_pcm_playback, buffer, frames)) < 0) { + if (length == -EINTR) + continue; // Try again + else if (length == -EPIPE) + length = xrun(m_pcm_playback); +#ifdef HAVE_SND_PCM_RESUME + else if (length == -ESTRPIPE) + length = resume(m_pcm_playback); +#endif + if (length < 0) { + arts_info("Playback error: %s", snd_strerror(length)); + return -1; + } + } + + // Start the sink if it needs it + if (snd_pcm_state( m_pcm_playback ) == SND_PCM_STATE_PREPARED) + snd_pcm_start(m_pcm_playback); + + if (length == frames) // Sometimes the fragments are "odd" in alsa + return size; + else + return snd_pcm_frames_to_bytes(m_pcm_playback, length); +} + +void AudioIOALSA::notifyIO(int fd, int type) +{ + int todo = 0; + + // Translate from iomanager-types to poll-types, + // inorder to fake a snd_pcm_poll_descriptors_revents call. + if(m_pcm_playback) { + for(int i=0; i < audio_write_pds.nfds; i++) { + if(fd == audio_write_pds.pfds[i].fd) { + audio_write_pds.pfds[i].revents = iomanager2poll(type); + todo |= AudioSubSystem::ioWrite; + } + } + if (todo & AudioSubSystem::ioWrite) { + unsigned short revents; + snd_pcm_poll_descriptors_revents(m_pcm_playback, + audio_write_pds.pfds, + audio_write_pds.nfds, + &revents); + if (! (revents & POLLOUT)) todo &= ~AudioSubSystem::ioWrite; + } + } + if(m_pcm_capture) { + for(int i=0; i < audio_read_pds.nfds; i++) { + if(fd == audio_read_pds.pfds[i].fd) { + audio_read_pds.pfds[i].revents = iomanager2poll(type); + todo |= AudioSubSystem::ioRead; + } + } + if (todo & AudioSubSystem::ioRead) { + unsigned short revents; + snd_pcm_poll_descriptors_revents(m_pcm_capture, + audio_read_pds.pfds, + audio_read_pds.nfds, + &revents); + if (! (revents & POLLIN)) todo &= ~AudioSubSystem::ioRead; + } + } + + if (type & IOType::except) todo |= AudioSubSystem::ioExcept; + + if (todo != 0) AudioSubSystem::the()->handleIO(todo); +} + +int AudioIOALSA::setPcmParams(snd_pcm_t *pcm) +{ + int &_samplingRate = param(samplingRate); + int &_channels = param(channels); + int &_fragmentSize = param(fragmentSize); + int &_fragmentCount = param(fragmentCount); + string& _error = paramStr(lastError); + + snd_pcm_hw_params_t *hw; + snd_pcm_hw_params_alloca(&hw); + snd_pcm_hw_params_any(pcm, hw); + + if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { + _error = "Unable to set interleaved!"; + return 1; + } + if (m_format == SND_PCM_FORMAT_UNKNOWN) { + // test the available formats + // try 16bit first, then fall back to 8bit + if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_S16_LE)) + m_format = SND_PCM_FORMAT_S16_LE; + else if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_S16_BE)) + m_format = SND_PCM_FORMAT_S16_BE; + else if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_U8)) + m_format = SND_PCM_FORMAT_U8; + else + m_format = SND_PCM_FORMAT_UNKNOWN; + } + if (snd_pcm_hw_params_set_format(pcm, hw, m_format) < 0) { + _error = "Unable to set format!"; + return 1; + } + + unsigned int rate = snd_pcm_hw_params_set_rate_near(pcm, hw, _samplingRate, 0); + const unsigned int tolerance = _samplingRate/10+1000; + if (abs((int)rate - (int)_samplingRate) > (int)tolerance) { + _error = "Can't set requested sampling rate!"; + char details[80]; + sprintf(details," (requested rate %d, got rate %d)", + _samplingRate, rate); + _error += details; + return 1; + } + _samplingRate = rate; + + if (snd_pcm_hw_params_set_channels(pcm, hw, _channels) < 0) { + _error = "Unable to set channels!"; + return 1; + } + + m_period_size = _fragmentSize; + if (m_format != SND_PCM_FORMAT_U8) + m_period_size <<= 1; + if (_channels > 1) + m_period_size /= _channels; + if ((m_period_size = snd_pcm_hw_params_set_period_size_near(pcm, hw, m_period_size, 0)) < 0) { + _error = "Unable to set period size!"; + return 1; + } + m_periods = _fragmentCount; + if ((m_periods = snd_pcm_hw_params_set_periods_near(pcm, hw, m_periods, 0)) < 0) { + _error = "Unable to set periods!"; + return 1; + } + + if (snd_pcm_hw_params(pcm, hw) < 0) { + _error = "Unable to set hw params!"; + return 1; + } + + _fragmentSize = m_period_size; + _fragmentCount = m_periods; + if (m_format != SND_PCM_FORMAT_U8) + _fragmentSize >>= 1; + if (_channels > 1) + _fragmentSize *= _channels; + + return 0; // ok, we're ready.. +} + +#endif /* HAVE_LIBASOUND2 */ diff --git a/flow/audioiocsl.cc b/flow/audioiocsl.cc deleted file mode 100644 index 7f3d5dd..0000000 --- a/flow/audioiocsl.cc +++ /dev/null @@ -1,640 +0,0 @@ - /* - - Copyright (C) 2000-2002 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/** - * only compile 'csl' AudioIO class if libcsl is present - */ -#ifdef HAVE_LIBCSL -#include - -/* g_newa */ -#include - -#include - -#include "audioio.h" -#include "audiosubsys.h" -#include "debug.h" -#include "dispatcher.h" -#include "iomanager.h" - -namespace Arts { - -class AudioIOCSL : public AudioIO, - public IONotify -{ -protected: - CslPcmStream *inputStream, *outputStream; - CslDriver *cslDriver; - int requestedFragmentSize; - int requestedFragmentCount; - const char *cslDriverName; - - std::vector cslFds, cslOldFds; - int csl2iomanager(int cslTypes); - void updateFds(); - - void notifyIO(int fd, int types); - static void handleRead(void *user_data, CslPcmStream *stream); - static void handleWrite(void *user_data, CslPcmStream *stream); - -public: - AudioIOCSL(const char *driverName = 0); - - void setParam(AudioParam param, int& value); - int getParam(AudioParam param); - - bool open(); - void close(); - int read(void *buffer, int size); - int write(void *buffer, int size); -}; - -REGISTER_AUDIO_IO(AudioIOCSL,"csl","Common Sound Layer"); - -class AudioIOCSLFactory : public AudioIOFactory { -protected: - const char *driverName; - std::string _name; - std::string _fullName; - -public: - AudioIOCSLFactory(const char *driverName) - : driverName(driverName) - { - _name = "csl-"; - _name += driverName; - - _fullName = "Common Sound Layer ("; - _fullName += driverName; - _fullName += ")"; - } - virtual ~AudioIOCSLFactory() - { - } - AudioIO *createAudioIO() { return new AudioIOCSL(driverName); } - virtual const char *name() { return _name.c_str(); } - virtual const char *fullName() { return _fullName.c_str(); } -}; - -static class AudioIOCSLInit { -protected: - std::list factories; - -public: - AudioIOCSLInit() - { - unsigned int i,n; - const char **drivers = csl_list_drivers(&n); - - for(i = 0; i < n; i++) - factories.push_back(new AudioIOCSLFactory(drivers[i])); - } - ~AudioIOCSLInit() - { - std::list::iterator i; - for(i = factories.begin(); i != factories.end(); i++) - delete (*i); - - factories.clear(); - } -} aci; - -}; - -using namespace std; -using namespace Arts; - -AudioIOCSL::AudioIOCSL(const char *driverName) - : cslDriverName(driverName) -{ - /* - * default parameters - */ - param(samplingRate) = 44100; - paramStr(deviceName) = "todo"; - requestedFragmentSize = param(fragmentSize) = 1024; - requestedFragmentCount = param(fragmentCount) = 7; - param(channels) = 2; - param(direction) = 2; - -#ifdef WORDS_BIGENDIAN - param(format) = 17; -#else - param(format) = 16; -#endif -} - -bool AudioIOCSL::open() -{ - string& errorMsg = paramStr(lastError); - string& _deviceName = paramStr(deviceName); - int& _channels = param(channels); - int& _fragmentSize = param(fragmentSize); - int& _fragmentCount = param(fragmentCount); - int& _samplingRate = param(samplingRate); - int& _format = param(format); - int fmt = 0; - char *env = 0; - - if(cslDriverName && strcmp(cslDriverName, "arts") == 0) - env = arts_strdup_printf("ARTS_SERVER=%s",_deviceName.c_str()); - - if(env) - { - putenv(env); - arts_debug("AudioIOCsl: set %s\n",env); - } - - CslErrorType error; - error = csl_driver_init(cslDriverName, &cslDriver); /* choose backend */ - - if(env) - { - putenv("ARTS_SERVER"); - free(env); - } - - if (error) - { - errorMsg = "unable to initialize CSL driver: "; - errorMsg += csl_strerror(error); - return false; - } - - if(_format == 8) - fmt = CSL_PCM_FORMAT_U8; - else if(_format == 16) - fmt = CSL_PCM_FORMAT_S16_LE; - else if(_format == 17) - fmt = CSL_PCM_FORMAT_S16_BE; - - inputStream = outputStream = 0; - if(param(direction) & directionRead) - { - /* open PCM output stream */ - error = csl_pcm_open_output(cslDriver, - "artsd output", - _samplingRate, - _channels, - fmt, &inputStream); - if (error) - { - errorMsg = "failed to open CSL input stream: "; - errorMsg += csl_strerror(error); - return false; - } - csl_pcm_set_callback(inputStream, handleRead, 0, 0); - } - if(param(direction) & directionWrite) - { - /* open PCM output stream */ - error = csl_pcm_open_output(cslDriver, - "artsd output", - _samplingRate, - _channels, - fmt, &outputStream); - if (error) - { - close(); - - errorMsg = "failed to open CSL output stream: "; - errorMsg += csl_strerror(error); - return false; - } - csl_pcm_set_callback(outputStream, handleWrite, 0, 0); - } -#if 0 - if (_format && (ossBits(gotFormat) != ossBits(requestedFormat))) - { - char details[80]; - sprintf(details," (_format = %d, asked driver to give %d, got %d)", - _format, requestedFormat, gotFormat); - - _error = "Can't set playback format"; - _error += details; - - close(); - return false; - } - - if(gotFormat == AFMT_U8) - _format = 8; - else if(gotFormat == AFMT_S16_LE) - _format = 16; - else if(gotFormat == AFMT_S16_BE) - _format = 17; - else - { - char details[80]; - sprintf(details," (_format = %d, asked driver to give %d, got %d)", - _format, requestedFormat, gotFormat); - - _error = "unknown format given by driver"; - _error += details; - - close(); - return false; - } - - - int stereo=-1; /* 0=mono, 1=stereo */ - - if(_channels == 1) - { - stereo = 0; - } - if(_channels == 2) - { - stereo = 1; - } - - if(stereo == -1) - { - _error = "internal error; set channels to 1 (mono) or 2 (stereo)"; - - close(); - return false; - } - - int requeststereo = stereo; - - if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1) - { - _error = "SNDCTL_DSP_STEREO failed - "; - _error += strerror(errno); - - close(); - return false; - } - - if (requeststereo != stereo) - { - _error = "audio device doesn't support number of requested channels"; - - close(); - return false; - } - - int speed = _samplingRate; - - if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) - { - _error = "SNDCTL_DSP_SPEED failed - "; - _error += strerror(errno); - - close(); - return false; - } - - /* - * Some soundcards seem to be able to only supply "nearly" the requested - * sampling rate, especially PAS 16 cards seem to quite radical supplying - * something different than the requested sampling rate ;) - * - * So we have a quite large tolerance here (when requesting 44100 Hz, it - * will accept anything between 38690 Hz and 49510 Hz). Most parts of the - * aRts code will do resampling where appropriate, so it shouldn't affect - * sound quality. - */ - int tolerance = _samplingRate/10+1000; - - if (abs(speed-_samplingRate) > tolerance) - { - _error = "can't set requested samplingrate"; - - char details[80]; - sprintf(details," (requested rate %d, got rate %d)", - _samplingRate, speed); - _error += details; - - close(); - return false; - } - _samplingRate = speed; - - /* - * set the fragment settings to what the user requested - */ - - _fragmentSize = requestedFragmentSize; - _fragmentCount = requestedFragmentCount; - - /* - * lower 16 bits are the fragment size (as 2^S) - * higher 16 bits are the number of fragments - */ - int frag_arg = 0; - - int size = _fragmentSize; - while(size > 1) { size /= 2; frag_arg++; } - frag_arg += (_fragmentCount << 16); - if(ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_arg) == -1) - { - char buffer[1024]; - _error = "can't set requested fragments settings"; - sprintf(buffer,"size%d:count%d\n",_fragmentSize,_fragmentCount); - close(); - return false; - } - - /* - * now see what we really got as cards aren't required to supply what - * we asked for - */ - audio_buf_info info; - if(ioctl(audio_fd,SNDCTL_DSP_GETOSPACE, &info) == -1) - { - _error = "can't retrieve fragment settings"; - close(); - return false; - } - - // update fragment settings with what we got - _fragmentSize = info.fragsize; - _fragmentCount = info.fragstotal; - - artsdebug("buffering: %d fragments with %d bytes " - "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, - (float)(_fragmentSize*_fragmentCount) / - (float)(2.0 * _samplingRate * _channels)*1000.0); - - /* - * Workaround for broken kernel drivers: usually filling up the audio - * buffer is _only_ required if _fullDuplex is true. However, there - * are kernel drivers around (especially everything related to ES1370/1371) - * which will not trigger select()ing the file descriptor unless we have - * written something first. - */ - char *zbuffer = (char *)calloc(sizeof(char), _fragmentSize); - if(_format == 8) - for(int zpos = 0; zpos < _fragmentSize; zpos++) - zbuffer[zpos] |= 0x80; - - for(int fill = 0; fill < _fragmentCount; fill++) - { - int len = ::write(audio_fd,zbuffer,_fragmentSize); - if(len != _fragmentSize) - { - arts_debug("AudioIOCSL: failed prefilling audio buffer (might cause synchronization problems in conjunction with full duplex)"); - fill = _fragmentCount+1; - } - } - free(zbuffer); - - /* - * Triggering - the original aRts code did this for full duplex: - * - * - stop audio i/o using SETTRIGGER(~(PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT)) - * - fill buffer (see zbuffer code two lines above) - * - start audio i/o using SETTRIGGER(PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT) - * - * this should guarantee synchronous start of input/output. Today, it - * seems there are too many broken drivers around for this. - */ - - if(device_caps & DSP_CAP_TRIGGER) - { - int enable_bits = 0; - - if(param(direction) & 1) enable_bits |= PCM_ENABLE_INPUT; - if(param(direction) & 2) enable_bits |= PCM_ENABLE_OUTPUT; - - if(ioctl(audio_fd,SNDCTL_DSP_SETTRIGGER, &enable_bits) == -1) - { - _error = "can't start sound i/o"; - - close(); - return false; - } - } -#endif - updateFds(); - return true; -} - -void AudioIOCSL::close() -{ - if(inputStream) - { - csl_pcm_close(inputStream); - inputStream = 0; - } - if(outputStream) - { - csl_pcm_close(outputStream); - outputStream = 0; - } - updateFds(); -} - -void AudioIOCSL::setParam(AudioParam p, int& value) -{ - switch(p) - { - case fragmentSize: - param(p) = requestedFragmentSize = value; - break; - case fragmentCount: - param(p) = requestedFragmentCount = value; - break; - default: - param(p) = value; - break; - } -} - -int AudioIOCSL::getParam(AudioParam p) -{ - CslErrorType error; - CslPcmStatus status; - - switch(p) - { - case canRead: - error = csl_pcm_get_status (inputStream, &status); - if (error) /* FIXME */ - arts_fatal("unable to obtain csl stream status: %s", - csl_strerror (error)); - - updateFds(); - return status.n_bytes_available; - break; - - case canWrite: - error = csl_pcm_get_status(outputStream, &status); - if (error) /* FIXME */ - arts_fatal("unable to obtain csl stream status: %s", - csl_strerror (error)); - - updateFds(); - return status.n_bytes_available; - break; - - case autoDetect: - /* CSL is pretty experimental currently */ - return 1; - break; - - default: - return param(p); - break; - } -} - -int AudioIOCSL::read(void *buffer, int size) -{ - arts_assert(inputStream != 0); - - int result = csl_pcm_read(inputStream, size, buffer); - updateFds(); - - return result; -} - -void AudioIOCSL::handleRead(void *, CslPcmStream *) -{ - AudioSubSystem::the()->handleIO(AudioSubSystem::ioRead); -} - -int AudioIOCSL::write(void *buffer, int size) -{ - arts_assert(outputStream != 0); - - int result = csl_pcm_write(outputStream, size, buffer); - updateFds(); - - return result; -} - -void AudioIOCSL::handleWrite(void *, CslPcmStream *) -{ - AudioSubSystem::the()->handleIO(AudioSubSystem::ioWrite); -} - -/* mainloop integration: make CSL callbacks work inside the aRts mainloop */ - -int AudioIOCSL::csl2iomanager(int cslTypes) -{ - /* FIXME: doublecheck this list */ - int types = 0; - - if(cslTypes & CSL_POLLIN) - types |= IOType::read; - if(cslTypes & CSL_POLLOUT) - types |= IOType::write; - if(cslTypes & CSL_POLLERR) - types |= IOType::except; - - return types; -} - -void AudioIOCSL::updateFds() -{ - unsigned int n_fds = csl_poll_count_fds(cslDriver); - CslPollFD *newFds = g_newa(CslPollFD, n_fds); - - unsigned int have_fds = csl_poll_get_fds(cslDriver, n_fds, newFds); - arts_assert(have_fds == n_fds); - - cslFds.clear(); - - unsigned int i; - for(i = 0; i < have_fds; i++) - cslFds.push_back(newFds[i]); - - /* FIXME: if csl provided a flag for this, we could save some work here */ - bool fdsChanged; - if(cslFds.size() == cslOldFds.size()) - { - fdsChanged = false; - for(i = 0; i < have_fds; i++) - { - if(cslFds[i].events != cslOldFds[i].events) - fdsChanged = true; - if(cslFds[i].fd != cslOldFds[i].fd) - fdsChanged = true; - } - } - else - { - fdsChanged = true; - } - if(!fdsChanged) - return; - - vector::iterator ci; - - /* remove old watches */ - /* - * UGLY! due to broken API, we can only remove all watches here, and not - * do anything selectively - its not a problem for the code here, but it - * might be a problem elsewhere. Unfortunately, it can't be fixed without - * breaking BC. - */ - Dispatcher::the()->ioManager()->remove(this, IOType::all); - arts_debug("AudioIOCSL::updateFds(): removing watches"); - - /* add new watches */ - for(ci = cslFds.begin(); ci < cslFds.end(); ci++) - { - int types = csl2iomanager(ci->events); - if(types) - { - Dispatcher::the()->ioManager()->watchFD(ci->fd, types, this); - arts_debug("AudioIOCSL::updateFds(): adding watch on %d", ci->fd); - } - } - - cslOldFds = cslFds; -} - -void AudioIOCSL::notifyIO(int fd, int type) -{ - vector::iterator fi; - - for(fi = cslFds.begin(); fi != cslFds.end(); fi++) - { - if(fi->fd == fd) - { - int ftype = csl2iomanager(fi->events); - fi->revents = 0; - - if(type & ftype & IOType::read) - fi->revents |= CSL_POLLIN; - if(type & ftype & IOType::write) - fi->revents |= CSL_POLLOUT; - if(type & ftype & IOType::except) - fi->revents |= CSL_POLLERR; - - if(fi->revents) - csl_poll_handle_fds(cslDriver, 1, &(*fi)); - } - } - updateFds(); -} - -#endif diff --git a/flow/audioiocsl.cpp b/flow/audioiocsl.cpp new file mode 100644 index 0000000..7f3d5dd --- /dev/null +++ b/flow/audioiocsl.cpp @@ -0,0 +1,640 @@ + /* + + Copyright (C) 2000-2002 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile 'csl' AudioIO class if libcsl is present + */ +#ifdef HAVE_LIBCSL +#include + +/* g_newa */ +#include + +#include + +#include "audioio.h" +#include "audiosubsys.h" +#include "debug.h" +#include "dispatcher.h" +#include "iomanager.h" + +namespace Arts { + +class AudioIOCSL : public AudioIO, + public IONotify +{ +protected: + CslPcmStream *inputStream, *outputStream; + CslDriver *cslDriver; + int requestedFragmentSize; + int requestedFragmentCount; + const char *cslDriverName; + + std::vector cslFds, cslOldFds; + int csl2iomanager(int cslTypes); + void updateFds(); + + void notifyIO(int fd, int types); + static void handleRead(void *user_data, CslPcmStream *stream); + static void handleWrite(void *user_data, CslPcmStream *stream); + +public: + AudioIOCSL(const char *driverName = 0); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOCSL,"csl","Common Sound Layer"); + +class AudioIOCSLFactory : public AudioIOFactory { +protected: + const char *driverName; + std::string _name; + std::string _fullName; + +public: + AudioIOCSLFactory(const char *driverName) + : driverName(driverName) + { + _name = "csl-"; + _name += driverName; + + _fullName = "Common Sound Layer ("; + _fullName += driverName; + _fullName += ")"; + } + virtual ~AudioIOCSLFactory() + { + } + AudioIO *createAudioIO() { return new AudioIOCSL(driverName); } + virtual const char *name() { return _name.c_str(); } + virtual const char *fullName() { return _fullName.c_str(); } +}; + +static class AudioIOCSLInit { +protected: + std::list factories; + +public: + AudioIOCSLInit() + { + unsigned int i,n; + const char **drivers = csl_list_drivers(&n); + + for(i = 0; i < n; i++) + factories.push_back(new AudioIOCSLFactory(drivers[i])); + } + ~AudioIOCSLInit() + { + std::list::iterator i; + for(i = factories.begin(); i != factories.end(); i++) + delete (*i); + + factories.clear(); + } +} aci; + +}; + +using namespace std; +using namespace Arts; + +AudioIOCSL::AudioIOCSL(const char *driverName) + : cslDriverName(driverName) +{ + /* + * default parameters + */ + param(samplingRate) = 44100; + paramStr(deviceName) = "todo"; + requestedFragmentSize = param(fragmentSize) = 1024; + requestedFragmentCount = param(fragmentCount) = 7; + param(channels) = 2; + param(direction) = 2; + +#ifdef WORDS_BIGENDIAN + param(format) = 17; +#else + param(format) = 16; +#endif +} + +bool AudioIOCSL::open() +{ + string& errorMsg = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + int fmt = 0; + char *env = 0; + + if(cslDriverName && strcmp(cslDriverName, "arts") == 0) + env = arts_strdup_printf("ARTS_SERVER=%s",_deviceName.c_str()); + + if(env) + { + putenv(env); + arts_debug("AudioIOCsl: set %s\n",env); + } + + CslErrorType error; + error = csl_driver_init(cslDriverName, &cslDriver); /* choose backend */ + + if(env) + { + putenv("ARTS_SERVER"); + free(env); + } + + if (error) + { + errorMsg = "unable to initialize CSL driver: "; + errorMsg += csl_strerror(error); + return false; + } + + if(_format == 8) + fmt = CSL_PCM_FORMAT_U8; + else if(_format == 16) + fmt = CSL_PCM_FORMAT_S16_LE; + else if(_format == 17) + fmt = CSL_PCM_FORMAT_S16_BE; + + inputStream = outputStream = 0; + if(param(direction) & directionRead) + { + /* open PCM output stream */ + error = csl_pcm_open_output(cslDriver, + "artsd output", + _samplingRate, + _channels, + fmt, &inputStream); + if (error) + { + errorMsg = "failed to open CSL input stream: "; + errorMsg += csl_strerror(error); + return false; + } + csl_pcm_set_callback(inputStream, handleRead, 0, 0); + } + if(param(direction) & directionWrite) + { + /* open PCM output stream */ + error = csl_pcm_open_output(cslDriver, + "artsd output", + _samplingRate, + _channels, + fmt, &outputStream); + if (error) + { + close(); + + errorMsg = "failed to open CSL output stream: "; + errorMsg += csl_strerror(error); + return false; + } + csl_pcm_set_callback(outputStream, handleWrite, 0, 0); + } +#if 0 + if (_format && (ossBits(gotFormat) != ossBits(requestedFormat))) + { + char details[80]; + sprintf(details," (_format = %d, asked driver to give %d, got %d)", + _format, requestedFormat, gotFormat); + + _error = "Can't set playback format"; + _error += details; + + close(); + return false; + } + + if(gotFormat == AFMT_U8) + _format = 8; + else if(gotFormat == AFMT_S16_LE) + _format = 16; + else if(gotFormat == AFMT_S16_BE) + _format = 17; + else + { + char details[80]; + sprintf(details," (_format = %d, asked driver to give %d, got %d)", + _format, requestedFormat, gotFormat); + + _error = "unknown format given by driver"; + _error += details; + + close(); + return false; + } + + + int stereo=-1; /* 0=mono, 1=stereo */ + + if(_channels == 1) + { + stereo = 0; + } + if(_channels == 2) + { + stereo = 1; + } + + if(stereo == -1) + { + _error = "internal error; set channels to 1 (mono) or 2 (stereo)"; + + close(); + return false; + } + + int requeststereo = stereo; + + if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1) + { + _error = "SNDCTL_DSP_STEREO failed - "; + _error += strerror(errno); + + close(); + return false; + } + + if (requeststereo != stereo) + { + _error = "audio device doesn't support number of requested channels"; + + close(); + return false; + } + + int speed = _samplingRate; + + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) + { + _error = "SNDCTL_DSP_SPEED failed - "; + _error += strerror(errno); + + close(); + return false; + } + + /* + * Some soundcards seem to be able to only supply "nearly" the requested + * sampling rate, especially PAS 16 cards seem to quite radical supplying + * something different than the requested sampling rate ;) + * + * So we have a quite large tolerance here (when requesting 44100 Hz, it + * will accept anything between 38690 Hz and 49510 Hz). Most parts of the + * aRts code will do resampling where appropriate, so it shouldn't affect + * sound quality. + */ + int tolerance = _samplingRate/10+1000; + + if (abs(speed-_samplingRate) > tolerance) + { + _error = "can't set requested samplingrate"; + + char details[80]; + sprintf(details," (requested rate %d, got rate %d)", + _samplingRate, speed); + _error += details; + + close(); + return false; + } + _samplingRate = speed; + + /* + * set the fragment settings to what the user requested + */ + + _fragmentSize = requestedFragmentSize; + _fragmentCount = requestedFragmentCount; + + /* + * lower 16 bits are the fragment size (as 2^S) + * higher 16 bits are the number of fragments + */ + int frag_arg = 0; + + int size = _fragmentSize; + while(size > 1) { size /= 2; frag_arg++; } + frag_arg += (_fragmentCount << 16); + if(ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_arg) == -1) + { + char buffer[1024]; + _error = "can't set requested fragments settings"; + sprintf(buffer,"size%d:count%d\n",_fragmentSize,_fragmentCount); + close(); + return false; + } + + /* + * now see what we really got as cards aren't required to supply what + * we asked for + */ + audio_buf_info info; + if(ioctl(audio_fd,SNDCTL_DSP_GETOSPACE, &info) == -1) + { + _error = "can't retrieve fragment settings"; + close(); + return false; + } + + // update fragment settings with what we got + _fragmentSize = info.fragsize; + _fragmentCount = info.fragstotal; + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + /* + * Workaround for broken kernel drivers: usually filling up the audio + * buffer is _only_ required if _fullDuplex is true. However, there + * are kernel drivers around (especially everything related to ES1370/1371) + * which will not trigger select()ing the file descriptor unless we have + * written something first. + */ + char *zbuffer = (char *)calloc(sizeof(char), _fragmentSize); + if(_format == 8) + for(int zpos = 0; zpos < _fragmentSize; zpos++) + zbuffer[zpos] |= 0x80; + + for(int fill = 0; fill < _fragmentCount; fill++) + { + int len = ::write(audio_fd,zbuffer,_fragmentSize); + if(len != _fragmentSize) + { + arts_debug("AudioIOCSL: failed prefilling audio buffer (might cause synchronization problems in conjunction with full duplex)"); + fill = _fragmentCount+1; + } + } + free(zbuffer); + + /* + * Triggering - the original aRts code did this for full duplex: + * + * - stop audio i/o using SETTRIGGER(~(PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT)) + * - fill buffer (see zbuffer code two lines above) + * - start audio i/o using SETTRIGGER(PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT) + * + * this should guarantee synchronous start of input/output. Today, it + * seems there are too many broken drivers around for this. + */ + + if(device_caps & DSP_CAP_TRIGGER) + { + int enable_bits = 0; + + if(param(direction) & 1) enable_bits |= PCM_ENABLE_INPUT; + if(param(direction) & 2) enable_bits |= PCM_ENABLE_OUTPUT; + + if(ioctl(audio_fd,SNDCTL_DSP_SETTRIGGER, &enable_bits) == -1) + { + _error = "can't start sound i/o"; + + close(); + return false; + } + } +#endif + updateFds(); + return true; +} + +void AudioIOCSL::close() +{ + if(inputStream) + { + csl_pcm_close(inputStream); + inputStream = 0; + } + if(outputStream) + { + csl_pcm_close(outputStream); + outputStream = 0; + } + updateFds(); +} + +void AudioIOCSL::setParam(AudioParam p, int& value) +{ + switch(p) + { + case fragmentSize: + param(p) = requestedFragmentSize = value; + break; + case fragmentCount: + param(p) = requestedFragmentCount = value; + break; + default: + param(p) = value; + break; + } +} + +int AudioIOCSL::getParam(AudioParam p) +{ + CslErrorType error; + CslPcmStatus status; + + switch(p) + { + case canRead: + error = csl_pcm_get_status (inputStream, &status); + if (error) /* FIXME */ + arts_fatal("unable to obtain csl stream status: %s", + csl_strerror (error)); + + updateFds(); + return status.n_bytes_available; + break; + + case canWrite: + error = csl_pcm_get_status(outputStream, &status); + if (error) /* FIXME */ + arts_fatal("unable to obtain csl stream status: %s", + csl_strerror (error)); + + updateFds(); + return status.n_bytes_available; + break; + + case autoDetect: + /* CSL is pretty experimental currently */ + return 1; + break; + + default: + return param(p); + break; + } +} + +int AudioIOCSL::read(void *buffer, int size) +{ + arts_assert(inputStream != 0); + + int result = csl_pcm_read(inputStream, size, buffer); + updateFds(); + + return result; +} + +void AudioIOCSL::handleRead(void *, CslPcmStream *) +{ + AudioSubSystem::the()->handleIO(AudioSubSystem::ioRead); +} + +int AudioIOCSL::write(void *buffer, int size) +{ + arts_assert(outputStream != 0); + + int result = csl_pcm_write(outputStream, size, buffer); + updateFds(); + + return result; +} + +void AudioIOCSL::handleWrite(void *, CslPcmStream *) +{ + AudioSubSystem::the()->handleIO(AudioSubSystem::ioWrite); +} + +/* mainloop integration: make CSL callbacks work inside the aRts mainloop */ + +int AudioIOCSL::csl2iomanager(int cslTypes) +{ + /* FIXME: doublecheck this list */ + int types = 0; + + if(cslTypes & CSL_POLLIN) + types |= IOType::read; + if(cslTypes & CSL_POLLOUT) + types |= IOType::write; + if(cslTypes & CSL_POLLERR) + types |= IOType::except; + + return types; +} + +void AudioIOCSL::updateFds() +{ + unsigned int n_fds = csl_poll_count_fds(cslDriver); + CslPollFD *newFds = g_newa(CslPollFD, n_fds); + + unsigned int have_fds = csl_poll_get_fds(cslDriver, n_fds, newFds); + arts_assert(have_fds == n_fds); + + cslFds.clear(); + + unsigned int i; + for(i = 0; i < have_fds; i++) + cslFds.push_back(newFds[i]); + + /* FIXME: if csl provided a flag for this, we could save some work here */ + bool fdsChanged; + if(cslFds.size() == cslOldFds.size()) + { + fdsChanged = false; + for(i = 0; i < have_fds; i++) + { + if(cslFds[i].events != cslOldFds[i].events) + fdsChanged = true; + if(cslFds[i].fd != cslOldFds[i].fd) + fdsChanged = true; + } + } + else + { + fdsChanged = true; + } + if(!fdsChanged) + return; + + vector::iterator ci; + + /* remove old watches */ + /* + * UGLY! due to broken API, we can only remove all watches here, and not + * do anything selectively - its not a problem for the code here, but it + * might be a problem elsewhere. Unfortunately, it can't be fixed without + * breaking BC. + */ + Dispatcher::the()->ioManager()->remove(this, IOType::all); + arts_debug("AudioIOCSL::updateFds(): removing watches"); + + /* add new watches */ + for(ci = cslFds.begin(); ci < cslFds.end(); ci++) + { + int types = csl2iomanager(ci->events); + if(types) + { + Dispatcher::the()->ioManager()->watchFD(ci->fd, types, this); + arts_debug("AudioIOCSL::updateFds(): adding watch on %d", ci->fd); + } + } + + cslOldFds = cslFds; +} + +void AudioIOCSL::notifyIO(int fd, int type) +{ + vector::iterator fi; + + for(fi = cslFds.begin(); fi != cslFds.end(); fi++) + { + if(fi->fd == fd) + { + int ftype = csl2iomanager(fi->events); + fi->revents = 0; + + if(type & ftype & IOType::read) + fi->revents |= CSL_POLLIN; + if(type & ftype & IOType::write) + fi->revents |= CSL_POLLOUT; + if(type & ftype & IOType::except) + fi->revents |= CSL_POLLERR; + + if(fi->revents) + csl_poll_handle_fds(cslDriver, 1, &(*fi)); + } + } + updateFds(); +} + +#endif diff --git a/flow/audioioesd.cc b/flow/audioioesd.cc deleted file mode 100644 index 90b074d..0000000 --- a/flow/audioioesd.cc +++ /dev/null @@ -1,227 +0,0 @@ - /* - - Copyright (C) 2001 Jochen Hoenicke - jochen@gnu.org - - Copyright (C) 2003 Ian Chiew - ian@snork.net - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/** - * only compile esound AudioIO class if libesd was detected during - * configure - */ -#ifdef HAVE_LIBESD - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "audioio.h" -#include "audiosubsys.h" -#include "iomanager.h" -#include "dispatcher.h" - -#include - -#ifdef __BIG_ENDIAN__ -#define _format_bits 17 -#else -#define _format_bits 16 -#endif - -namespace Arts { - -class AudioIOESD : public AudioIO, public IONotify { -protected: - int server_fd, read_fd, write_fd; - -public: - AudioIOESD(); - - void setParam(AudioParam param, int& value); - int getParam(AudioParam param); - void notifyIO(int fd, int type); - - bool open(); - void close(); - void run(); - int read(void *buffer, int size); - int write(void *buffer, int size); -}; - -REGISTER_AUDIO_IO(AudioIOESD,"esd","Enlightened Sound Daemon"); -} - -using namespace std; -using namespace Arts; - -AudioIOESD::AudioIOESD() -{ - /* - * default parameters - */ - param(samplingRate) = 44100; - paramStr(deviceName) = "null"; - param(fragmentSize) = 1024; - param(fragmentCount) = 7; - param(format) = _format_bits; - param(channels) = 2; - param(direction) = 2; - - server_fd = -1; - read_fd = -1; - write_fd = -1; -} - -bool AudioIOESD::open() -{ - int& _channels = param(channels); - int& _direction = param(direction); - int& _samplingRate = param(samplingRate); - int& _format = param(format); - string& _error = paramStr(lastError); - - if ((server_fd = esd_open_sound(NULL)) == -1) - { - _error = "Couldn't connect to server"; - return false; - } - - esd_server_info_t *server_info = esd_get_server_info(server_fd); - - if (server_info == NULL) - { - _error = "Unable to query EsounD server"; - return false; - } - - esd_format_t server_format = server_info->format; - - _samplingRate = server_info->rate; - _channels = (server_format & ESD_STEREO) ? 2 : 1; - _format = (server_format & ESD_BITS16) ? _format_bits : 8; - - esd_free_server_info(server_info); - - if (_direction & directionRead) - { - read_fd = esd_record_stream(server_format, _samplingRate, - NULL, "aRts"); - if (read_fd == -1) - { - _error = "Couldn't create read uflow"; - return false; - } - } - - if (_direction & directionWrite) - { - write_fd = esd_play_stream(server_format, _samplingRate, - NULL, "aRts"); - if (write_fd == -1) - { - _error = "Couldn't create write flow"; - return false; - } - } - - return true; -} - -void AudioIOESD::notifyIO(int, int) -{ -} - -void AudioIOESD::close() -{ - if (write_fd != -1) - esd_close(write_fd); - - if (read_fd != -1) - esd_close(read_fd); - - if (server_fd != -1) - esd_close(server_fd); -} - -void AudioIOESD::setParam(AudioParam p, int& value) -{ - switch(p) - { - case channels: - case format: - case direction: - case samplingRate: - param(p) = value; - close(); - open(); - return; - - default: - param(p) = value; - return; - } -} - -int AudioIOESD::getParam(AudioParam p) -{ - switch(p) - { - case selectReadFD: - return read_fd; - - case selectWriteFD: - return write_fd; - - case canRead: - return param(fragmentSize); - - case canWrite: - return param(fragmentSize); - - default: - return param(p); - } -} - -int AudioIOESD::read(void *buffer, int size) -{ - return ::read(read_fd, buffer, size); -} - -int AudioIOESD::write(void *buffer, int size) -{ - return ::write(write_fd, buffer, size); -} - -#endif diff --git a/flow/audioioesd.cpp b/flow/audioioesd.cpp new file mode 100644 index 0000000..90b074d --- /dev/null +++ b/flow/audioioesd.cpp @@ -0,0 +1,227 @@ + /* + + Copyright (C) 2001 Jochen Hoenicke + jochen@gnu.org + + Copyright (C) 2003 Ian Chiew + ian@snork.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile esound AudioIO class if libesd was detected during + * configure + */ +#ifdef HAVE_LIBESD + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "audioio.h" +#include "audiosubsys.h" +#include "iomanager.h" +#include "dispatcher.h" + +#include + +#ifdef __BIG_ENDIAN__ +#define _format_bits 17 +#else +#define _format_bits 16 +#endif + +namespace Arts { + +class AudioIOESD : public AudioIO, public IONotify { +protected: + int server_fd, read_fd, write_fd; + +public: + AudioIOESD(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + void notifyIO(int fd, int type); + + bool open(); + void close(); + void run(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOESD,"esd","Enlightened Sound Daemon"); +} + +using namespace std; +using namespace Arts; + +AudioIOESD::AudioIOESD() +{ + /* + * default parameters + */ + param(samplingRate) = 44100; + paramStr(deviceName) = "null"; + param(fragmentSize) = 1024; + param(fragmentCount) = 7; + param(format) = _format_bits; + param(channels) = 2; + param(direction) = 2; + + server_fd = -1; + read_fd = -1; + write_fd = -1; +} + +bool AudioIOESD::open() +{ + int& _channels = param(channels); + int& _direction = param(direction); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + string& _error = paramStr(lastError); + + if ((server_fd = esd_open_sound(NULL)) == -1) + { + _error = "Couldn't connect to server"; + return false; + } + + esd_server_info_t *server_info = esd_get_server_info(server_fd); + + if (server_info == NULL) + { + _error = "Unable to query EsounD server"; + return false; + } + + esd_format_t server_format = server_info->format; + + _samplingRate = server_info->rate; + _channels = (server_format & ESD_STEREO) ? 2 : 1; + _format = (server_format & ESD_BITS16) ? _format_bits : 8; + + esd_free_server_info(server_info); + + if (_direction & directionRead) + { + read_fd = esd_record_stream(server_format, _samplingRate, + NULL, "aRts"); + if (read_fd == -1) + { + _error = "Couldn't create read uflow"; + return false; + } + } + + if (_direction & directionWrite) + { + write_fd = esd_play_stream(server_format, _samplingRate, + NULL, "aRts"); + if (write_fd == -1) + { + _error = "Couldn't create write flow"; + return false; + } + } + + return true; +} + +void AudioIOESD::notifyIO(int, int) +{ +} + +void AudioIOESD::close() +{ + if (write_fd != -1) + esd_close(write_fd); + + if (read_fd != -1) + esd_close(read_fd); + + if (server_fd != -1) + esd_close(server_fd); +} + +void AudioIOESD::setParam(AudioParam p, int& value) +{ + switch(p) + { + case channels: + case format: + case direction: + case samplingRate: + param(p) = value; + close(); + open(); + return; + + default: + param(p) = value; + return; + } +} + +int AudioIOESD::getParam(AudioParam p) +{ + switch(p) + { + case selectReadFD: + return read_fd; + + case selectWriteFD: + return write_fd; + + case canRead: + return param(fragmentSize); + + case canWrite: + return param(fragmentSize); + + default: + return param(p); + } +} + +int AudioIOESD::read(void *buffer, int size) +{ + return ::read(read_fd, buffer, size); +} + +int AudioIOESD::write(void *buffer, int size) +{ + return ::write(write_fd, buffer, size); +} + +#endif diff --git a/flow/audioiojack.cc b/flow/audioiojack.cc deleted file mode 100644 index ca8110a..0000000 --- a/flow/audioiojack.cc +++ /dev/null @@ -1,345 +0,0 @@ -/* - Copyright (C) 2004 Matthias Kretz - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_LIBJACK - -#include -#include - -#include "debug.h" -#include "audioio.h" -#include "audiosubsys.h" -#include "iomanager.h" -#include "dispatcher.h" - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#undef DEBUG_WAVEFORM -#ifdef DEBUG_WAVEFORM -#include -#endif - -#include -#include - -namespace Arts { - -class AudioIOJack : public AudioIO, public TimeNotify { -private: -#ifdef DEBUG_WAVEFORM - std::ofstream plotfile; -#endif - char * processBuffer; - size_t buffersize; - -protected: - jack_client_t *jack; - jack_port_t *outleft, *outright; - jack_port_t *inleft, *inright; - jack_ringbuffer_t *olb, *orb, *ilb, *irb; - -public: - AudioIOJack(); - - void notifyTime(); - - void setParam( AudioParam p, int & val ); - int getParam(AudioParam param); - - static int jackCallback( jack_nframes_t, void * ); - - bool open(); - void close(); - int read(void *buffer, int size); - int write(void *buffer, int size); -}; - -REGISTER_AUDIO_IO(AudioIOJack,"jack","Jack Audio Connection Kit"); -} - -using namespace std; -using namespace Arts; - -AudioIOJack::AudioIOJack() - : -#ifdef DEBUG_WAVEFORM - plotfile( "/dev/shm/audioiojack.plot" ), -#endif - jack( 0 ) - , outleft( 0 ) - , outright( 0 ) - , inleft( 0 ) - , inright( 0 ) -{ - /* - * default parameters - */ - param( samplingRate ) = 44100; - paramStr( deviceName ) = "jack"; - param( fragmentSize ) = 512; - param( fragmentCount ) = 2; - param( channels ) = 2; - param( direction ) = 2; - param( format ) = 32; -} - -bool AudioIOJack::open() -{ - string& _error = paramStr( lastError ); - jack = jack_client_new( "artsd" ); - if( jack == 0 ) - { - _error = "Couldn't connect to jackd"; - return false; - } - - int& _sampleRate = param(samplingRate); - _sampleRate = jack_get_sample_rate( jack ); - int& _fragmentSize = param(fragmentSize); - int& _fragmentCount = param(fragmentCount); - - /* - * don't allow unreasonable large fragmentSize/Count combinations, - * because "real" hardware also doesn't - */ - - if(_fragmentSize > 1024*8) _fragmentSize = 1024*8; - - while(_fragmentSize * _fragmentCount > 1024*128) - _fragmentCount--; - - jack_set_process_callback( jack, Arts::AudioIOJack::jackCallback, this ); - - if( param( direction ) & directionWrite ) - { - outleft = jack_port_register( jack, "out_1", - JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); - outright = jack_port_register( jack, "out_2", - JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); - olb = jack_ringbuffer_create( - sizeof( jack_default_audio_sample_t ) * - _fragmentSize * _fragmentCount ); - orb = jack_ringbuffer_create( - sizeof( jack_default_audio_sample_t ) * - _fragmentSize * _fragmentCount ); - } - if( param( direction ) & directionRead ) - { - inleft = jack_port_register( jack, "in_1", - JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); - inright = jack_port_register( jack, "in_2", - JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); - ilb = jack_ringbuffer_create( - sizeof( jack_default_audio_sample_t ) * - 1024 * 64 ); - irb = jack_ringbuffer_create( - sizeof( jack_default_audio_sample_t ) * - 1024 * 64 ); - } - - if( jack_activate( jack ) ) - { - _error = "Activating as jack client failed."; - return false; - } - - const char **ports; - if( param( direction ) & directionRead ) - { - ports = jack_get_ports( jack, 0, 0, JackPortIsPhysical - | JackPortIsOutput ); - if( ports == 0 ) - { - arts_warning( "Cannot find any capture ports to" - " connect to. You need to manually connect" - " the capture ports in jack" ); - } - else - { - if( ports[ 0 ] != 0 ) - jack_connect( jack, ports[ 0 ], - jack_port_name( inleft ) ); - if( ports[ 1 ] != 0 ) - jack_connect( jack, ports[ 1 ], - jack_port_name( inright ) ); - free( ports ); - } - } - if( param( direction ) & directionWrite ) - { - ports = jack_get_ports( jack, 0, 0, JackPortIsPhysical - | JackPortIsInput ); - if( ports == 0 ) - { - arts_warning( "Cannot find any playback ports to" - " connect to. You need to manually connect" - " the playback ports in jack" ); - } - else - { - if( ports[ 0 ] != 0 ) - jack_connect( jack, jack_port_name( outleft ), - ports[ 0 ] ); - if( ports[ 1 ] != 0 ) - jack_connect( jack, jack_port_name( outright ), - ports[ 1 ] ); - free( ports ); - } - } - - // Install the timer - Dispatcher::the()->ioManager()->addTimer(10, this); - - return true; -} - -void AudioIOJack::close() -{ - jack_client_close( jack ); - Dispatcher::the()->ioManager()->removeTimer(this); -} - -int AudioIOJack::jackCallback( jack_nframes_t nframes, void * args ) -{ - AudioIOJack * that = static_cast( args ); - - that->buffersize = nframes * sizeof( jack_default_audio_sample_t ); - if( that->outleft ) - { - if( jack_ringbuffer_read_space( that->olb ) < that->buffersize ) - { - that->processBuffer = static_cast( - jack_port_get_buffer( that->outleft, nframes ) ); - memset( that->processBuffer, 0, that->buffersize ); - that->processBuffer = static_cast( - jack_port_get_buffer( that->outright, nframes ) ); - memset( that->processBuffer, 0, that->buffersize ); - } - else - { - that->processBuffer = static_cast( - jack_port_get_buffer( that->outleft, nframes ) ); - jack_ringbuffer_read( that->olb, that->processBuffer, that->buffersize ); - that->processBuffer = static_cast( - jack_port_get_buffer( that->outright, nframes ) ); - jack_ringbuffer_read( that->orb, that->processBuffer, that->buffersize ); - } - } - if( that->inleft ) - { - that->processBuffer = static_cast( - jack_port_get_buffer( that->inleft, nframes ) ); - jack_ringbuffer_write( that->ilb, that->processBuffer, that->buffersize ); - that->processBuffer = static_cast( - jack_port_get_buffer( that->inright, nframes ) ); - jack_ringbuffer_write( that->irb, that->processBuffer, that->buffersize ); - } - return 0; -} - -void AudioIOJack::setParam( AudioParam p, int& val ) -{ - // don't change the format - jack only supports 32 bit float - if( p == format ) - return; - AudioIO::setParam( p, val ); -} - -int AudioIOJack::getParam(AudioParam p) -{ - switch(p) - { - case canRead: - return MIN( jack_ringbuffer_read_space( ilb ), jack_ringbuffer_read_space( irb ) ) * param( channels ); - case canWrite: - return MIN( jack_ringbuffer_write_space( olb ), jack_ringbuffer_write_space( orb ) ) * param( channels ); - default: - return AudioIO::getParam( p ); - } -} - -int AudioIOJack::read(void *buffer, int size) -{ - float * floatbuffer = static_cast( buffer ); - if( param( channels ) == 2 ) - { - float * end = ( float * )( static_cast( buffer ) + size ); - while( floatbuffer < end ) - { - jack_ringbuffer_read( ilb, ( char* )( floatbuffer++ ), sizeof( float ) ); -#ifdef DEBUG_WAVEFORM - plotfile << *( floatbuffer - 1 ) << "\n"; -#endif - jack_ringbuffer_read( irb, ( char* )( floatbuffer++ ), sizeof( float ) ); - } - } - else if( param( channels ) == 1 ) - { - jack_ringbuffer_read( ilb, ( char* )( floatbuffer ), size ); - } - return size; -} - -int AudioIOJack::write(void *buffer, int size) -{ - float * floatbuffer = static_cast( buffer ); - if( param( channels ) == 2 ) - { - float * end = ( float * )( static_cast( buffer ) + size ); - while( floatbuffer < end ) - { - jack_ringbuffer_write( olb, ( char* )( floatbuffer++ ), sizeof( float ) ); - jack_ringbuffer_write( orb, ( char* )( floatbuffer++ ), sizeof( float ) ); - } - } - else if( param( channels ) == 1 ) - { - jack_ringbuffer_write( olb, ( char* )( floatbuffer ), size ); - } - return size; -} - -void AudioIOJack::notifyTime() -{ - int& _direction = param(direction); - int& _fragmentSize = param(fragmentSize); - - for( ;; ) - { - int todo = 0; - if( ( _direction & directionRead ) && ( getParam( canRead ) >= _fragmentSize ) ) - todo |= AudioSubSystem::ioRead; - - if( ( _direction & directionWrite ) && ( getParam( canWrite ) >= _fragmentSize ) ) - todo |= AudioSubSystem::ioWrite; - - if( ! todo ) - return; - - AudioSubSystem::the()->handleIO( todo ); - } -} - -#endif diff --git a/flow/audioiojack.cpp b/flow/audioiojack.cpp new file mode 100644 index 0000000..ca8110a --- /dev/null +++ b/flow/audioiojack.cpp @@ -0,0 +1,345 @@ +/* + Copyright (C) 2004 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LIBJACK + +#include +#include + +#include "debug.h" +#include "audioio.h" +#include "audiosubsys.h" +#include "iomanager.h" +#include "dispatcher.h" + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#undef DEBUG_WAVEFORM +#ifdef DEBUG_WAVEFORM +#include +#endif + +#include +#include + +namespace Arts { + +class AudioIOJack : public AudioIO, public TimeNotify { +private: +#ifdef DEBUG_WAVEFORM + std::ofstream plotfile; +#endif + char * processBuffer; + size_t buffersize; + +protected: + jack_client_t *jack; + jack_port_t *outleft, *outright; + jack_port_t *inleft, *inright; + jack_ringbuffer_t *olb, *orb, *ilb, *irb; + +public: + AudioIOJack(); + + void notifyTime(); + + void setParam( AudioParam p, int & val ); + int getParam(AudioParam param); + + static int jackCallback( jack_nframes_t, void * ); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOJack,"jack","Jack Audio Connection Kit"); +} + +using namespace std; +using namespace Arts; + +AudioIOJack::AudioIOJack() + : +#ifdef DEBUG_WAVEFORM + plotfile( "/dev/shm/audioiojack.plot" ), +#endif + jack( 0 ) + , outleft( 0 ) + , outright( 0 ) + , inleft( 0 ) + , inright( 0 ) +{ + /* + * default parameters + */ + param( samplingRate ) = 44100; + paramStr( deviceName ) = "jack"; + param( fragmentSize ) = 512; + param( fragmentCount ) = 2; + param( channels ) = 2; + param( direction ) = 2; + param( format ) = 32; +} + +bool AudioIOJack::open() +{ + string& _error = paramStr( lastError ); + jack = jack_client_new( "artsd" ); + if( jack == 0 ) + { + _error = "Couldn't connect to jackd"; + return false; + } + + int& _sampleRate = param(samplingRate); + _sampleRate = jack_get_sample_rate( jack ); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + + /* + * don't allow unreasonable large fragmentSize/Count combinations, + * because "real" hardware also doesn't + */ + + if(_fragmentSize > 1024*8) _fragmentSize = 1024*8; + + while(_fragmentSize * _fragmentCount > 1024*128) + _fragmentCount--; + + jack_set_process_callback( jack, Arts::AudioIOJack::jackCallback, this ); + + if( param( direction ) & directionWrite ) + { + outleft = jack_port_register( jack, "out_1", + JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); + outright = jack_port_register( jack, "out_2", + JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); + olb = jack_ringbuffer_create( + sizeof( jack_default_audio_sample_t ) * + _fragmentSize * _fragmentCount ); + orb = jack_ringbuffer_create( + sizeof( jack_default_audio_sample_t ) * + _fragmentSize * _fragmentCount ); + } + if( param( direction ) & directionRead ) + { + inleft = jack_port_register( jack, "in_1", + JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); + inright = jack_port_register( jack, "in_2", + JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); + ilb = jack_ringbuffer_create( + sizeof( jack_default_audio_sample_t ) * + 1024 * 64 ); + irb = jack_ringbuffer_create( + sizeof( jack_default_audio_sample_t ) * + 1024 * 64 ); + } + + if( jack_activate( jack ) ) + { + _error = "Activating as jack client failed."; + return false; + } + + const char **ports; + if( param( direction ) & directionRead ) + { + ports = jack_get_ports( jack, 0, 0, JackPortIsPhysical + | JackPortIsOutput ); + if( ports == 0 ) + { + arts_warning( "Cannot find any capture ports to" + " connect to. You need to manually connect" + " the capture ports in jack" ); + } + else + { + if( ports[ 0 ] != 0 ) + jack_connect( jack, ports[ 0 ], + jack_port_name( inleft ) ); + if( ports[ 1 ] != 0 ) + jack_connect( jack, ports[ 1 ], + jack_port_name( inright ) ); + free( ports ); + } + } + if( param( direction ) & directionWrite ) + { + ports = jack_get_ports( jack, 0, 0, JackPortIsPhysical + | JackPortIsInput ); + if( ports == 0 ) + { + arts_warning( "Cannot find any playback ports to" + " connect to. You need to manually connect" + " the playback ports in jack" ); + } + else + { + if( ports[ 0 ] != 0 ) + jack_connect( jack, jack_port_name( outleft ), + ports[ 0 ] ); + if( ports[ 1 ] != 0 ) + jack_connect( jack, jack_port_name( outright ), + ports[ 1 ] ); + free( ports ); + } + } + + // Install the timer + Dispatcher::the()->ioManager()->addTimer(10, this); + + return true; +} + +void AudioIOJack::close() +{ + jack_client_close( jack ); + Dispatcher::the()->ioManager()->removeTimer(this); +} + +int AudioIOJack::jackCallback( jack_nframes_t nframes, void * args ) +{ + AudioIOJack * that = static_cast( args ); + + that->buffersize = nframes * sizeof( jack_default_audio_sample_t ); + if( that->outleft ) + { + if( jack_ringbuffer_read_space( that->olb ) < that->buffersize ) + { + that->processBuffer = static_cast( + jack_port_get_buffer( that->outleft, nframes ) ); + memset( that->processBuffer, 0, that->buffersize ); + that->processBuffer = static_cast( + jack_port_get_buffer( that->outright, nframes ) ); + memset( that->processBuffer, 0, that->buffersize ); + } + else + { + that->processBuffer = static_cast( + jack_port_get_buffer( that->outleft, nframes ) ); + jack_ringbuffer_read( that->olb, that->processBuffer, that->buffersize ); + that->processBuffer = static_cast( + jack_port_get_buffer( that->outright, nframes ) ); + jack_ringbuffer_read( that->orb, that->processBuffer, that->buffersize ); + } + } + if( that->inleft ) + { + that->processBuffer = static_cast( + jack_port_get_buffer( that->inleft, nframes ) ); + jack_ringbuffer_write( that->ilb, that->processBuffer, that->buffersize ); + that->processBuffer = static_cast( + jack_port_get_buffer( that->inright, nframes ) ); + jack_ringbuffer_write( that->irb, that->processBuffer, that->buffersize ); + } + return 0; +} + +void AudioIOJack::setParam( AudioParam p, int& val ) +{ + // don't change the format - jack only supports 32 bit float + if( p == format ) + return; + AudioIO::setParam( p, val ); +} + +int AudioIOJack::getParam(AudioParam p) +{ + switch(p) + { + case canRead: + return MIN( jack_ringbuffer_read_space( ilb ), jack_ringbuffer_read_space( irb ) ) * param( channels ); + case canWrite: + return MIN( jack_ringbuffer_write_space( olb ), jack_ringbuffer_write_space( orb ) ) * param( channels ); + default: + return AudioIO::getParam( p ); + } +} + +int AudioIOJack::read(void *buffer, int size) +{ + float * floatbuffer = static_cast( buffer ); + if( param( channels ) == 2 ) + { + float * end = ( float * )( static_cast( buffer ) + size ); + while( floatbuffer < end ) + { + jack_ringbuffer_read( ilb, ( char* )( floatbuffer++ ), sizeof( float ) ); +#ifdef DEBUG_WAVEFORM + plotfile << *( floatbuffer - 1 ) << "\n"; +#endif + jack_ringbuffer_read( irb, ( char* )( floatbuffer++ ), sizeof( float ) ); + } + } + else if( param( channels ) == 1 ) + { + jack_ringbuffer_read( ilb, ( char* )( floatbuffer ), size ); + } + return size; +} + +int AudioIOJack::write(void *buffer, int size) +{ + float * floatbuffer = static_cast( buffer ); + if( param( channels ) == 2 ) + { + float * end = ( float * )( static_cast( buffer ) + size ); + while( floatbuffer < end ) + { + jack_ringbuffer_write( olb, ( char* )( floatbuffer++ ), sizeof( float ) ); + jack_ringbuffer_write( orb, ( char* )( floatbuffer++ ), sizeof( float ) ); + } + } + else if( param( channels ) == 1 ) + { + jack_ringbuffer_write( olb, ( char* )( floatbuffer ), size ); + } + return size; +} + +void AudioIOJack::notifyTime() +{ + int& _direction = param(direction); + int& _fragmentSize = param(fragmentSize); + + for( ;; ) + { + int todo = 0; + if( ( _direction & directionRead ) && ( getParam( canRead ) >= _fragmentSize ) ) + todo |= AudioSubSystem::ioRead; + + if( ( _direction & directionWrite ) && ( getParam( canWrite ) >= _fragmentSize ) ) + todo |= AudioSubSystem::ioWrite; + + if( ! todo ) + return; + + AudioSubSystem::the()->handleIO( todo ); + } +} + +#endif diff --git a/flow/audioiolibaudioio.cc b/flow/audioiolibaudioio.cc deleted file mode 100644 index c3a887b..0000000 --- a/flow/audioiolibaudioio.cc +++ /dev/null @@ -1,236 +0,0 @@ - /* - - Copyright (C) 2001 Robert Lunnon - bob@yarrabee.net.au - Copyright (C) 2001 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/** - * only compile 'LibAudioIO' AudioIO class if libaudio was detected during - * configure - */ -#ifdef HAVE_LIBAUDIOIO - -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SELECT_H -#include // Needed on some systems. -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "debug.h" -#include "audioio.h" - -namespace Arts { - -class AudioIOLibAudioIO : public AudioIO { -protected: - int audio_fd; - int requestedFragmentSize; - int requestedFragmentCount; - SampleSpec_t spec; - -public: - AudioIOLibAudioIO(); - - void setParam(AudioParam param, int& value); - int getParam(AudioParam param); - - bool open(); - void close(); - int read(void *buffer, int size); - int write(void *buffer, int size); -}; - -REGISTER_AUDIO_IO(AudioIOLibAudioIO,"libaudioio"," Portable Audio Library"); -}; - -using namespace std; -using namespace Arts; - -AudioIOLibAudioIO::AudioIOLibAudioIO() -{ - /* - * default parameters - */ - param(samplingRate) = spec.rate=44100; - paramStr(deviceName) = "/dev/Audio"; - requestedFragmentSize = param(fragmentSize) = 4096; - requestedFragmentCount =spec.max_blocks= param(fragmentCount) = 7; - param(channels) = spec.channels=2; - param(direction) = 2; -} - -bool AudioIOLibAudioIO::open() -{ - string& _error = paramStr(lastError); - string& _deviceName = paramStr(deviceName); - int& _channels = param(channels); - int& _fragmentSize = param(fragmentSize); - int& _fragmentCount = param(fragmentCount); - int& _samplingRate = param(samplingRate); - int& _format = param(format); - - int mode; - spec.channels=_channels; - spec.max_blocks= param(fragmentCount); - spec.rate= _samplingRate; - spec.encoding= ENCODE_PCM; - spec.precision=16 ; - spec.endian=ENDIAN_NATURAL; - spec.disable_threads=1; - - if(param(direction) == 3) - mode = O_RDWR|O_NDELAY; - else if(param(direction) == 2) - mode = O_WRONLY|O_NDELAY; - else - { - _error = "invalid direction"; - return false; - } - - audio_fd = ::AudioIOOpenX( mode, &spec,&spec ); - if(audio_fd == -1) - { - _error = "device "; - _error += _deviceName.c_str(); - _error += " can't be opened ("; - _error += strerror(errno); - _error += ")"; - return false; - } - - - /* - * since we use spec.endian=ENDIAN_NATURAL we'll have little endian audio - * on little endian machines and big endian audio on big endian machines: - */ -#ifdef WORDS_BIGENDIAN - _format = 17; -#else - _format = 16; -#endif - - spec.channels=_channels; - - spec.rate = _samplingRate; - - - _fragmentSize = requestedFragmentSize; - spec.max_blocks=_fragmentCount = requestedFragmentCount; - - - artsdebug("buffering: %d fragments with %d bytes " - "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, - (float)(_fragmentSize*_fragmentCount) / - (float)(2.0 * _samplingRate * _channels)*1000.0); - - return(true); -} - -void AudioIOLibAudioIO::close() -{ - ::AudioIOClose(); -} - -void AudioIOLibAudioIO::setParam(AudioParam p, int& value) -{ - switch(p) - { - case fragmentSize: - param(p) = requestedFragmentSize = value; - break; - case fragmentCount: - param(p) = requestedFragmentCount = value; - break; - default: - param(p) = value; - break; - } -} - -int AudioIOLibAudioIO::getParam(AudioParam p) -{ - switch(p) - { - case canRead: - return AudioIOCheckRead(); - break; - - case canWrite: - return (AudioIOCheckWriteReady()) ? (16*1024) : 0; - // Assume if writable can write 16K - // Arts Really doesn't care - break; - - case selectReadFD: - return (param(direction) & directionRead)?audio_fd:-1; - break; - - case selectWriteFD: - return (param(direction) & directionWrite)?audio_fd:-1; - break; - - case autoDetect: - /* - * if there is a "native" aRts driver, we'll rather use this - * than the generic libaudioio one, because the native one - * is likely to be better optimized to the needs of aRts than - * a generic driver, so keep the value small - */ - return 3; - break; - - default: - return param(p); - break; - } -} - -int AudioIOLibAudioIO::read(void *buffer, int size) -{ - arts_assert(audio_fd != 0); - return ::AudioIORead(buffer,size); -} - -int AudioIOLibAudioIO::write(void *buffer, int size) -{ - arts_assert(audio_fd != 0); - return ::AudioIOWrite(buffer,size); -} - -#endif diff --git a/flow/audioiolibaudioio.cpp b/flow/audioiolibaudioio.cpp new file mode 100644 index 0000000..c3a887b --- /dev/null +++ b/flow/audioiolibaudioio.cpp @@ -0,0 +1,236 @@ + /* + + Copyright (C) 2001 Robert Lunnon + bob@yarrabee.net.au + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/** + * only compile 'LibAudioIO' AudioIO class if libaudio was detected during + * configure + */ +#ifdef HAVE_LIBAUDIOIO + +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SELECT_H +#include // Needed on some systems. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "audioio.h" + +namespace Arts { + +class AudioIOLibAudioIO : public AudioIO { +protected: + int audio_fd; + int requestedFragmentSize; + int requestedFragmentCount; + SampleSpec_t spec; + +public: + AudioIOLibAudioIO(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); +}; + +REGISTER_AUDIO_IO(AudioIOLibAudioIO,"libaudioio"," Portable Audio Library"); +}; + +using namespace std; +using namespace Arts; + +AudioIOLibAudioIO::AudioIOLibAudioIO() +{ + /* + * default parameters + */ + param(samplingRate) = spec.rate=44100; + paramStr(deviceName) = "/dev/Audio"; + requestedFragmentSize = param(fragmentSize) = 4096; + requestedFragmentCount =spec.max_blocks= param(fragmentCount) = 7; + param(channels) = spec.channels=2; + param(direction) = 2; +} + +bool AudioIOLibAudioIO::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + + int mode; + spec.channels=_channels; + spec.max_blocks= param(fragmentCount); + spec.rate= _samplingRate; + spec.encoding= ENCODE_PCM; + spec.precision=16 ; + spec.endian=ENDIAN_NATURAL; + spec.disable_threads=1; + + if(param(direction) == 3) + mode = O_RDWR|O_NDELAY; + else if(param(direction) == 2) + mode = O_WRONLY|O_NDELAY; + else + { + _error = "invalid direction"; + return false; + } + + audio_fd = ::AudioIOOpenX( mode, &spec,&spec ); + if(audio_fd == -1) + { + _error = "device "; + _error += _deviceName.c_str(); + _error += " can't be opened ("; + _error += strerror(errno); + _error += ")"; + return false; + } + + + /* + * since we use spec.endian=ENDIAN_NATURAL we'll have little endian audio + * on little endian machines and big endian audio on big endian machines: + */ +#ifdef WORDS_BIGENDIAN + _format = 17; +#else + _format = 16; +#endif + + spec.channels=_channels; + + spec.rate = _samplingRate; + + + _fragmentSize = requestedFragmentSize; + spec.max_blocks=_fragmentCount = requestedFragmentCount; + + + artsdebug("buffering: %d fragments with %d bytes " + "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, + (float)(_fragmentSize*_fragmentCount) / + (float)(2.0 * _samplingRate * _channels)*1000.0); + + return(true); +} + +void AudioIOLibAudioIO::close() +{ + ::AudioIOClose(); +} + +void AudioIOLibAudioIO::setParam(AudioParam p, int& value) +{ + switch(p) + { + case fragmentSize: + param(p) = requestedFragmentSize = value; + break; + case fragmentCount: + param(p) = requestedFragmentCount = value; + break; + default: + param(p) = value; + break; + } +} + +int AudioIOLibAudioIO::getParam(AudioParam p) +{ + switch(p) + { + case canRead: + return AudioIOCheckRead(); + break; + + case canWrite: + return (AudioIOCheckWriteReady()) ? (16*1024) : 0; + // Assume if writable can write 16K + // Arts Really doesn't care + break; + + case selectReadFD: + return (param(direction) & directionRead)?audio_fd:-1; + break; + + case selectWriteFD: + return (param(direction) & directionWrite)?audio_fd:-1; + break; + + case autoDetect: + /* + * if there is a "native" aRts driver, we'll rather use this + * than the generic libaudioio one, because the native one + * is likely to be better optimized to the needs of aRts than + * a generic driver, so keep the value small + */ + return 3; + break; + + default: + return param(p); + break; + } +} + +int AudioIOLibAudioIO::read(void *buffer, int size) +{ + arts_assert(audio_fd != 0); + return ::AudioIORead(buffer,size); +} + +int AudioIOLibAudioIO::write(void *buffer, int size) +{ + arts_assert(audio_fd != 0); + return ::AudioIOWrite(buffer,size); +} + +#endif diff --git a/flow/audioiomas.cc b/flow/audioiomas.cc deleted file mode 100644 index cfebb65..0000000 --- a/flow/audioiomas.cc +++ /dev/null @@ -1,619 +0,0 @@ - /* - - Copyright (C) 2001-2003 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/* - * Only compile this AudioIO class if we have MAS - */ -#ifdef HAVE_LIBMAS - -extern "C" { -#include -#include -#include -} - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "debug.h" -#include "audioio.h" -#include "audiosubsys.h" -#include "iomanager.h" -#include "dispatcher.h" - -namespace Arts { - - class AudioIOMAS : public AudioIO, public TimeNotify { - protected: - mas_channel_t audio_channel; - mas_port_t mix_sink; - mas_port_t srate_source, srate_sink; - mas_port_t audio_source, audio_sink; - mas_port_t endian_sink, endian_source; - mas_port_t sbuf_source, sbuf_sink; - mas_port_t squant_sink, squant_source; - mas_port_t open_source; /* (!) */ - mas_device_t endian; - mas_device_t srate; - mas_device_t squant; - mas_device_t sbuf; - mas_data *data; - mas_package package; - int32 mas_error; - - std::list allocated_channels; - std::list allocated_ports; - std::list allocated_devices; - - double lastUpdate, bytesPerSec; - int readBufferAvailable; - int writeBufferAvailable; - - double currentTime(); - void updateBufferSizes(); - -#ifdef WORDS_BIGENDIAN - static const int defaultFormat = 17; -#else - static const int defaultFormat = 16; -#endif - bool close_with_error(const std::string& text); - public: - AudioIOMAS(); - - // Timer callback - void notifyTime(); - - void setParam(AudioParam param, int& value); - int getParam(AudioParam param); - - bool open(); - void close(); - int read(void *buffer, int size); - int write(void *buffer, int size); - }; - - REGISTER_AUDIO_IO(AudioIOMAS,"mas","MAS Audio Input/Output"); - -}; - -using namespace std; -using namespace Arts; - -AudioIOMAS::AudioIOMAS() -{ - /* - * default parameters - */ - param(samplingRate) = 44100; - paramStr(deviceName) = ""; // TODO - param(fragmentSize) = 4096; - param(fragmentCount) = 7; - param(channels) = 2; - param(direction) = 2; - param(format) = defaultFormat; -} - -namespace { - int masInitCount = 0; -} - -// Opens the audio device -bool AudioIOMAS::open() -{ - string& _error = paramStr(lastError); - string& _deviceName = paramStr(deviceName); - int& _channels = param(channels); - int& _fragmentSize = param(fragmentSize); - int& _fragmentCount = param(fragmentCount); - int& _samplingRate = param(samplingRate); - int& _format = param(format); - - /* FIXME: do we need to free what we allocate with mas_init() in close() */ - if (!masInitCount) - { - mas_error = mas_init(); - - if (mas_error < 0) - return close_with_error("error connecting to MAS server"); - } - masInitCount++; - - if (param(direction) != 2) - { - _error = "unsupported direction (currently no full duplex support)"; - return false; - } - - /* - * data path - * - * audio_sink - * audio_channel: data_channel ("artsd") - * audio_source - * | - * V - * endian_sink - * endian: instantiate_device ("endian") - * open_source = endian_source - * | - * V - * [squant_sink] - * [squant] - * [squant_source] - * | - * V - * [srate_sink] - * [srate] - * [srate_source] - * | - * V - * sbuf_sink - * sbuf - * sbuf_source - * | - * V - * mix_sink: port ("default_mix_sink") - */ - - // audio_channel, source & sink - mas_error = mas_make_data_channel("artsd", &audio_channel, &audio_source, &audio_sink); - if (mas_error < 0) - return close_with_error("error initializing MAS data channel"); - - allocated_channels.push_back(audio_channel); - allocated_ports.push_back(audio_source); - allocated_ports.push_back(audio_sink); - - // endian, source & sink - mas_error = mas_asm_instantiate_device( "endian", 0, 0, &endian ); - if ( mas_error < 0 ) - return close_with_error("error initantiating MAS endian device"); - - allocated_devices.push_back(endian); - - mas_error = mas_asm_get_port_by_name( endian, "sink", &endian_sink ); - if ( mas_error < 0 ) - return close_with_error("error getting MAS endian device sink port"); - - allocated_ports.push_back(endian_sink); - - mas_error = mas_asm_get_port_by_name( endian, "source", &endian_source ); - if ( mas_error < 0 ) - return close_with_error("error getting MAS endian device source port"); - - allocated_ports.push_back(endian_source); - - char ratestring[16], resolutionstring[16]; - sprintf (ratestring, "%u", _samplingRate); - sprintf (resolutionstring, "%u", _format); - - mas_data_characteristic* dc; - - dc = (mas_data_characteristic *)MAS_NEW( dc ); - masc_setup_dc( dc, 6 ); - masc_append_dc_key_value( dc, "format", (_format==8) ? "ulinear":"linear" ); - - masc_append_dc_key_value( dc, "resolution", resolutionstring ); - masc_append_dc_key_value( dc, "sampling rate", ratestring ); - masc_append_dc_key_value( dc, "channels", "2" ); - masc_append_dc_key_value( dc, "endian", "little" ); - - mas_error = mas_asm_connect_source_sink( audio_source, endian_sink, dc ); - if ( mas_error < 0 ) - return close_with_error("error connecting MAS net audio source to endian sink"); - - /* The next device is 'if needed' only. After the following if() - statement, open_source will contain the current unconnected - source in the path (will be either endian_source or - squant_source in this case) - */ - open_source = endian_source; - - if ( _format != 16 ) - { - arts_debug("MAS output: Sample resolution is not 16 bit/sample, instantiating squant device."); - - // squant, source & sink - mas_error = mas_asm_instantiate_device( "squant", 0, 0, &squant ); - if ( mas_error < 0 ) - return close_with_error("error creating MAS squant device"); - - allocated_devices.push_back(squant); - - mas_error = mas_asm_get_port_by_name( squant, "sink", &squant_sink ); - if ( mas_error < 0 ) - return close_with_error("error getting MAS squant device sink port"); - - allocated_ports.push_back(squant_sink); - - mas_error = mas_asm_get_port_by_name( squant, "source", &squant_source ); - if ( mas_error < 0 ) - return close_with_error("error getting MAS squant device source port"); - - allocated_ports.push_back(squant_source); - - arts_debug( "MAS output: Connecting endian -> squant."); - - masc_strike_dc( dc ); - masc_setup_dc( dc, 6 ); - masc_append_dc_key_value( dc,"format",(_format==8) ? "ulinear":"linear" ); - masc_append_dc_key_value( dc, "resolution", resolutionstring ); - masc_append_dc_key_value( dc, "sampling rate", ratestring ); - masc_append_dc_key_value( dc, "channels", "2" ); - masc_append_dc_key_value( dc, "endian", "host" ); - - mas_error = mas_asm_connect_source_sink( endian_source, squant_sink, dc ); - if ( mas_error < 0 ) - return close_with_error("error connecting MAS endian output to squant device"); - - /* sneaky: the squant device is optional -> pretend it isn't there */ - open_source = squant_source; - } - - - /* Another 'if necessary' device, as above */ - if ( _samplingRate != 44100 ) - { - arts_debug ("MAS output: Sample rate is not 44100, instantiating srate device."); - - // srate, source & sink - mas_error = mas_asm_instantiate_device( "srate", 0, 0, &srate ); - if ( mas_error < 0 ) - return close_with_error("error initantiating MAS srate device"); - - allocated_devices.push_back(srate); - - mas_error = mas_asm_get_port_by_name( srate, "sink", &srate_sink ); - if ( mas_error < 0 ) - return close_with_error("error getting MAS srate sink port"); - - allocated_ports.push_back(srate_sink); - - mas_error = mas_asm_get_port_by_name( srate, "source", &srate_source ); - if ( mas_error < 0 ) - return close_with_error("error getting MAS srate source port"); - - allocated_ports.push_back(srate_source); - - arts_debug( "MAS output: Connecting to srate."); - - masc_strike_dc( dc ); - masc_setup_dc( dc, 6 ); - masc_append_dc_key_value( dc, "format", "linear" ); - masc_append_dc_key_value( dc, "resolution", "16" ); - masc_append_dc_key_value( dc, "sampling rate", ratestring ); - masc_append_dc_key_value( dc, "channels", "2" ); - masc_append_dc_key_value( dc, "endian", "host" ); - - mas_error = mas_asm_connect_source_sink( open_source, srate_sink, dc ); - if ( mas_error < 0 ) - return close_with_error("error connecting to MAS srate device"); - - open_source = srate_source; - } - - // sbuf, source & sink - mas_error = mas_asm_instantiate_device( "sbuf", 0, 0, &sbuf ); - if ( mas_error < 0 ) - return close_with_error("error initantiating MAS sbuf device"); - - allocated_devices.push_back(sbuf); - - mas_error = mas_asm_get_port_by_name( sbuf, "sink", &sbuf_sink ); - if ( mas_error < 0 ) - return close_with_error("error getting MAS sbuf device sink port"); - - allocated_ports.push_back(sbuf_sink); - - mas_error = mas_asm_get_port_by_name( sbuf, "source", &sbuf_source ); - if ( mas_error < 0 ) - return close_with_error("error getting MAS sbuf device source port"); - - allocated_ports.push_back(sbuf_source); - - masc_strike_dc( dc ); - masc_setup_dc( dc, 6 ); - - masc_append_dc_key_value( dc, "format", "linear" ); - masc_append_dc_key_value( dc, "resolution", "16" ); - masc_append_dc_key_value( dc, "sampling rate", "44100" ); - masc_append_dc_key_value( dc, "channels", "2" ); - masc_append_dc_key_value( dc, "endian", "host" ); - - arts_debug("MAS output: Connecting to sbuf."); - - mas_error = mas_asm_connect_source_sink( open_source, sbuf_sink, dc ); - if ( mas_error < 0 ) - return close_with_error("error connecting to MAS mixer device"); - - /* configure sbuf */ - - float BUFTIME_MS = _fragmentSize * _fragmentCount; - BUFTIME_MS *= 1000.0; - BUFTIME_MS /= (float)_channels; - if (_format > 8) - BUFTIME_MS /= 2.0; - BUFTIME_MS /= (float)_samplingRate; - - arts_debug("MAS output: BUFTIME_MS = %f", BUFTIME_MS); - - masc_setup_package( &package, NULL, 0, 0 ); - masc_pushk_uint32( &package, "buftime_ms", (uint32) BUFTIME_MS ); - masc_finalize_package( &package ); - mas_set( sbuf, "buftime_ms", &package ); - masc_strike_package( &package ); - - masc_setup_package( &package, NULL, 0, 0 ); - masc_pushk_int32( &package, "mc_clkid", 9 ); - masc_finalize_package( &package ); - mas_set( sbuf, "mc_clkid", &package ); - masc_strike_package( &package ); - - mas_source_play( sbuf ); - - // mix_sink - mas_error = mas_asm_get_port_by_name( 0, "default_mix_sink", &mix_sink ); - if (mas_error < 0) - return close_with_error("error finding MAS default sink"); - - allocated_ports.push_back(mix_sink); - - arts_debug("MAS output: Connecting sbuf to mix_sink."); - - mas_error = mas_asm_connect_source_sink( sbuf_source, mix_sink, dc ); - if ( mas_error < 0 ) - return close_with_error("error connecting to MAS mixer device"); - - data = (mas_data *)MAS_NEW( data ); - masc_setup_data( data, _fragmentSize ); /* we can reuse this */ - data->length = _fragmentSize; - data->allocated_length = data->length; - data->header.type = 10; - - arts_debug("MAS output: playing."); - - // Install the timer - Dispatcher::the()->ioManager()->addTimer(10, this); - - bytesPerSec = _channels * _samplingRate; - if (_format > 8) - bytesPerSec *= 2; - - lastUpdate = 0; - - return true; -} - -double AudioIOMAS::currentTime() -{ - timeval tv; - gettimeofday(&tv,0); - - return (double)tv.tv_sec + (double)tv.tv_usec/1000000.0; -} - -bool AudioIOMAS::close_with_error(const string& text) -{ - string& error = paramStr(lastError); - error = text; - error += masc_strmerror (mas_error); - return false; -} - -void AudioIOMAS::close() -{ - list::iterator pi; - for (pi = allocated_ports.begin(); pi != allocated_ports.end(); pi++) - mas_free_port (*pi); - allocated_ports.clear(); - - list::iterator ci; - for (ci = allocated_channels.begin(); ci != allocated_channels.end(); ci++) - mas_free_channel (*ci); - allocated_channels.clear(); - - list::iterator di; - for (di = allocated_devices.begin(); di != allocated_devices.end(); di++) - { - mas_device_t device = *di; - mas_error = mas_asm_terminate_device_instance(device, 0); - if (mas_error < 0) - arts_warning ("MAS output: error while closing device: %s", masc_strmerror(mas_error)); - - mas_free_device(device); - } - allocated_devices.clear(); - - Dispatcher::the()->ioManager()->removeTimer(this); -} - -void AudioIOMAS::updateBufferSizes() -{ - double time = currentTime(); - double waterMark = param(fragmentSize); - waterMark *= 1.3; - - if ((time - lastUpdate) * bytesPerSec < waterMark) - return; - - lastUpdate = time; - - uint32 inbuf_ms; - int32 mas_error; - - mas_error = mas_get( sbuf, "inbuf_ms", 0 , &package ); - if ( mas_error < 0 ) - arts_fatal ("MAS output: error getting size of buffer: %s", masc_strmerror(mas_error)); - - masc_pull_uint32( &package, &inbuf_ms ); - masc_strike_package( &package ); - - //arts_debug(" inbuf_ms = %u", inbuf_ms); - - float bytes = inbuf_ms; - bytes /= 1000.0; - bytes *= param(samplingRate); - bytes *= param(channels); - if(param(format) > 8) - bytes *= 2; - - int bytesFree = param(fragmentSize) * param(fragmentCount) - (int)bytes; - - if (bytesFree < param(fragmentSize)) - bytesFree = 0; - - writeBufferAvailable = bytesFree; - - arts_debug ("MAS output buffer: %6d / %6d bytes used => %6d bytes free", - (int)bytes, param(fragmentSize) * param(fragmentCount), writeBufferAvailable); -} - -// This is called on each timer tick -void AudioIOMAS::notifyTime() -{ - updateBufferSizes(); - - int& _direction = param(direction); - int& _fragmentSize = param(fragmentSize); - - for (;;) { - int todo = 0; - - if ((_direction & directionRead) && (getParam(canRead) >= _fragmentSize)) - todo |= AudioSubSystem::ioRead; - - if ((_direction & directionWrite) && (getParam(canWrite) >= _fragmentSize)) - todo |= AudioSubSystem::ioWrite; - - if (!todo) - return; - - AudioSubSystem::the()->handleIO(todo); - } -} - -void AudioIOMAS::setParam(AudioParam p, int& value) -{ - switch(p) { -#if 0 - case fragmentSize: - param(p) = requestedFragmentSize = value; - break; - case fragmentCount: - param(p) = requestedFragmentCount = value; - break; -#endif - default: - param(p) = value; - break; - } -} - -int AudioIOMAS::getParam(AudioParam p) -{ - int bytes; - int count; - - switch(p) - { -#if 0 - case canRead: - if (ioctl(audio_fd, AUDIO_GETINFO, &auinfo) < 0) - return (0); - bytes = (auinfo.record.samples * bytesPerSample) - bytesRead; - if (bytes < 0) { - printf("Error: bytes %d < 0, samples=%u, bytesRead=%u\n", - bytes, auinfo.record.samples, bytesRead); - bytes = 0; - } - return bytes; - - case canWrite: - if (ioctl(audio_fd, AUDIO_GETINFO, &auinfo) < 0) - return (0); - count = SUN_MAX_BUFFER_SIZE - - (bytesWritten - (auinfo.play.samples * bytesPerSample)); - return count; -#endif - case canWrite: - return writeBufferAvailable; - - case autoDetect: - /* - * Fairly small priority, for we haven't tested this a lot - */ - return 3; - - default: - return param(p); - } -} - -int AudioIOMAS::read(void *buffer, int size) -{ -#if 0 - size = ::read(audio_fd, buffer, size); - if (size < 0) - return 0; - - bytesRead += size; - return size; -#endif - return 0; -} - -int AudioIOMAS::write(void *buffer, int size) -{ - static int ts = 0; - static int seq = 0; - data->header.sequence = seq++; - data->header.media_timestamp = ts; - ts += size / 4; - - assert(size == data->length); - memcpy(data->segment, buffer, size); - - int32 mas_error = mas_send( audio_channel , data ); - if (mas_error < 0) - arts_fatal ("MAS output: problem during mas_send: %s", masc_strmerror(mas_error)); - - writeBufferAvailable -= size; - return size; -} - -#endif /* HAVE_LIBMAS */ diff --git a/flow/audioiomas.cpp b/flow/audioiomas.cpp new file mode 100644 index 0000000..cfebb65 --- /dev/null +++ b/flow/audioiomas.cpp @@ -0,0 +1,619 @@ + /* + + Copyright (C) 2001-2003 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* + * Only compile this AudioIO class if we have MAS + */ +#ifdef HAVE_LIBMAS + +extern "C" { +#include +#include +#include +} + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "audioio.h" +#include "audiosubsys.h" +#include "iomanager.h" +#include "dispatcher.h" + +namespace Arts { + + class AudioIOMAS : public AudioIO, public TimeNotify { + protected: + mas_channel_t audio_channel; + mas_port_t mix_sink; + mas_port_t srate_source, srate_sink; + mas_port_t audio_source, audio_sink; + mas_port_t endian_sink, endian_source; + mas_port_t sbuf_source, sbuf_sink; + mas_port_t squant_sink, squant_source; + mas_port_t open_source; /* (!) */ + mas_device_t endian; + mas_device_t srate; + mas_device_t squant; + mas_device_t sbuf; + mas_data *data; + mas_package package; + int32 mas_error; + + std::list allocated_channels; + std::list allocated_ports; + std::list allocated_devices; + + double lastUpdate, bytesPerSec; + int readBufferAvailable; + int writeBufferAvailable; + + double currentTime(); + void updateBufferSizes(); + +#ifdef WORDS_BIGENDIAN + static const int defaultFormat = 17; +#else + static const int defaultFormat = 16; +#endif + bool close_with_error(const std::string& text); + public: + AudioIOMAS(); + + // Timer callback + void notifyTime(); + + void setParam(AudioParam param, int& value); + int getParam(AudioParam param); + + bool open(); + void close(); + int read(void *buffer, int size); + int write(void *buffer, int size); + }; + + REGISTER_AUDIO_IO(AudioIOMAS,"mas","MAS Audio Input/Output"); + +}; + +using namespace std; +using namespace Arts; + +AudioIOMAS::AudioIOMAS() +{ + /* + * default parameters + */ + param(samplingRate) = 44100; + paramStr(deviceName) = ""; // TODO + param(fragmentSize) = 4096; + param(fragmentCount) = 7; + param(channels) = 2; + param(direction) = 2; + param(format) = defaultFormat; +} + +namespace { + int masInitCount = 0; +} + +// Opens the audio device +bool AudioIOMAS::open() +{ + string& _error = paramStr(lastError); + string& _deviceName = paramStr(deviceName); + int& _channels = param(channels); + int& _fragmentSize = param(fragmentSize); + int& _fragmentCount = param(fragmentCount); + int& _samplingRate = param(samplingRate); + int& _format = param(format); + + /* FIXME: do we need to free what we allocate with mas_init() in close() */ + if (!masInitCount) + { + mas_error = mas_init(); + + if (mas_error < 0) + return close_with_error("error connecting to MAS server"); + } + masInitCount++; + + if (param(direction) != 2) + { + _error = "unsupported direction (currently no full duplex support)"; + return false; + } + + /* + * data path + * + * audio_sink + * audio_channel: data_channel ("artsd") + * audio_source + * | + * V + * endian_sink + * endian: instantiate_device ("endian") + * open_source = endian_source + * | + * V + * [squant_sink] + * [squant] + * [squant_source] + * | + * V + * [srate_sink] + * [srate] + * [srate_source] + * | + * V + * sbuf_sink + * sbuf + * sbuf_source + * | + * V + * mix_sink: port ("default_mix_sink") + */ + + // audio_channel, source & sink + mas_error = mas_make_data_channel("artsd", &audio_channel, &audio_source, &audio_sink); + if (mas_error < 0) + return close_with_error("error initializing MAS data channel"); + + allocated_channels.push_back(audio_channel); + allocated_ports.push_back(audio_source); + allocated_ports.push_back(audio_sink); + + // endian, source & sink + mas_error = mas_asm_instantiate_device( "endian", 0, 0, &endian ); + if ( mas_error < 0 ) + return close_with_error("error initantiating MAS endian device"); + + allocated_devices.push_back(endian); + + mas_error = mas_asm_get_port_by_name( endian, "sink", &endian_sink ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS endian device sink port"); + + allocated_ports.push_back(endian_sink); + + mas_error = mas_asm_get_port_by_name( endian, "source", &endian_source ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS endian device source port"); + + allocated_ports.push_back(endian_source); + + char ratestring[16], resolutionstring[16]; + sprintf (ratestring, "%u", _samplingRate); + sprintf (resolutionstring, "%u", _format); + + mas_data_characteristic* dc; + + dc = (mas_data_characteristic *)MAS_NEW( dc ); + masc_setup_dc( dc, 6 ); + masc_append_dc_key_value( dc, "format", (_format==8) ? "ulinear":"linear" ); + + masc_append_dc_key_value( dc, "resolution", resolutionstring ); + masc_append_dc_key_value( dc, "sampling rate", ratestring ); + masc_append_dc_key_value( dc, "channels", "2" ); + masc_append_dc_key_value( dc, "endian", "little" ); + + mas_error = mas_asm_connect_source_sink( audio_source, endian_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting MAS net audio source to endian sink"); + + /* The next device is 'if needed' only. After the following if() + statement, open_source will contain the current unconnected + source in the path (will be either endian_source or + squant_source in this case) + */ + open_source = endian_source; + + if ( _format != 16 ) + { + arts_debug("MAS output: Sample resolution is not 16 bit/sample, instantiating squant device."); + + // squant, source & sink + mas_error = mas_asm_instantiate_device( "squant", 0, 0, &squant ); + if ( mas_error < 0 ) + return close_with_error("error creating MAS squant device"); + + allocated_devices.push_back(squant); + + mas_error = mas_asm_get_port_by_name( squant, "sink", &squant_sink ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS squant device sink port"); + + allocated_ports.push_back(squant_sink); + + mas_error = mas_asm_get_port_by_name( squant, "source", &squant_source ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS squant device source port"); + + allocated_ports.push_back(squant_source); + + arts_debug( "MAS output: Connecting endian -> squant."); + + masc_strike_dc( dc ); + masc_setup_dc( dc, 6 ); + masc_append_dc_key_value( dc,"format",(_format==8) ? "ulinear":"linear" ); + masc_append_dc_key_value( dc, "resolution", resolutionstring ); + masc_append_dc_key_value( dc, "sampling rate", ratestring ); + masc_append_dc_key_value( dc, "channels", "2" ); + masc_append_dc_key_value( dc, "endian", "host" ); + + mas_error = mas_asm_connect_source_sink( endian_source, squant_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting MAS endian output to squant device"); + + /* sneaky: the squant device is optional -> pretend it isn't there */ + open_source = squant_source; + } + + + /* Another 'if necessary' device, as above */ + if ( _samplingRate != 44100 ) + { + arts_debug ("MAS output: Sample rate is not 44100, instantiating srate device."); + + // srate, source & sink + mas_error = mas_asm_instantiate_device( "srate", 0, 0, &srate ); + if ( mas_error < 0 ) + return close_with_error("error initantiating MAS srate device"); + + allocated_devices.push_back(srate); + + mas_error = mas_asm_get_port_by_name( srate, "sink", &srate_sink ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS srate sink port"); + + allocated_ports.push_back(srate_sink); + + mas_error = mas_asm_get_port_by_name( srate, "source", &srate_source ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS srate source port"); + + allocated_ports.push_back(srate_source); + + arts_debug( "MAS output: Connecting to srate."); + + masc_strike_dc( dc ); + masc_setup_dc( dc, 6 ); + masc_append_dc_key_value( dc, "format", "linear" ); + masc_append_dc_key_value( dc, "resolution", "16" ); + masc_append_dc_key_value( dc, "sampling rate", ratestring ); + masc_append_dc_key_value( dc, "channels", "2" ); + masc_append_dc_key_value( dc, "endian", "host" ); + + mas_error = mas_asm_connect_source_sink( open_source, srate_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting to MAS srate device"); + + open_source = srate_source; + } + + // sbuf, source & sink + mas_error = mas_asm_instantiate_device( "sbuf", 0, 0, &sbuf ); + if ( mas_error < 0 ) + return close_with_error("error initantiating MAS sbuf device"); + + allocated_devices.push_back(sbuf); + + mas_error = mas_asm_get_port_by_name( sbuf, "sink", &sbuf_sink ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS sbuf device sink port"); + + allocated_ports.push_back(sbuf_sink); + + mas_error = mas_asm_get_port_by_name( sbuf, "source", &sbuf_source ); + if ( mas_error < 0 ) + return close_with_error("error getting MAS sbuf device source port"); + + allocated_ports.push_back(sbuf_source); + + masc_strike_dc( dc ); + masc_setup_dc( dc, 6 ); + + masc_append_dc_key_value( dc, "format", "linear" ); + masc_append_dc_key_value( dc, "resolution", "16" ); + masc_append_dc_key_value( dc, "sampling rate", "44100" ); + masc_append_dc_key_value( dc, "channels", "2" ); + masc_append_dc_key_value( dc, "endian", "host" ); + + arts_debug("MAS output: Connecting to sbuf."); + + mas_error = mas_asm_connect_source_sink( open_source, sbuf_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting to MAS mixer device"); + + /* configure sbuf */ + + float BUFTIME_MS = _fragmentSize * _fragmentCount; + BUFTIME_MS *= 1000.0; + BUFTIME_MS /= (float)_channels; + if (_format > 8) + BUFTIME_MS /= 2.0; + BUFTIME_MS /= (float)_samplingRate; + + arts_debug("MAS output: BUFTIME_MS = %f", BUFTIME_MS); + + masc_setup_package( &package, NULL, 0, 0 ); + masc_pushk_uint32( &package, "buftime_ms", (uint32) BUFTIME_MS ); + masc_finalize_package( &package ); + mas_set( sbuf, "buftime_ms", &package ); + masc_strike_package( &package ); + + masc_setup_package( &package, NULL, 0, 0 ); + masc_pushk_int32( &package, "mc_clkid", 9 ); + masc_finalize_package( &package ); + mas_set( sbuf, "mc_clkid", &package ); + masc_strike_package( &package ); + + mas_source_play( sbuf ); + + // mix_sink + mas_error = mas_asm_get_port_by_name( 0, "default_mix_sink", &mix_sink ); + if (mas_error < 0) + return close_with_error("error finding MAS default sink"); + + allocated_ports.push_back(mix_sink); + + arts_debug("MAS output: Connecting sbuf to mix_sink."); + + mas_error = mas_asm_connect_source_sink( sbuf_source, mix_sink, dc ); + if ( mas_error < 0 ) + return close_with_error("error connecting to MAS mixer device"); + + data = (mas_data *)MAS_NEW( data ); + masc_setup_data( data, _fragmentSize ); /* we can reuse this */ + data->length = _fragmentSize; + data->allocated_length = data->length; + data->header.type = 10; + + arts_debug("MAS output: playing."); + + // Install the timer + Dispatcher::the()->ioManager()->addTimer(10, this); + + bytesPerSec = _channels * _samplingRate; + if (_format > 8) + bytesPerSec *= 2; + + lastUpdate = 0; + + return true; +} + +double AudioIOMAS::currentTime() +{ + timeval tv; + gettimeofday(&tv,0); + + return (double)tv.tv_sec + (double)tv.tv_usec/1000000.0; +} + +bool AudioIOMAS::close_with_error(const string& text) +{ + string& error = paramStr(lastError); + error = text; + error += masc_strmerror (mas_error); + return false; +} + +void AudioIOMAS::close() +{ + list::iterator pi; + for (pi = allocated_ports.begin(); pi != allocated_ports.end(); pi++) + mas_free_port (*pi); + allocated_ports.clear(); + + list::iterator ci; + for (ci = allocated_channels.begin(); ci != allocated_channels.end(); ci++) + mas_free_channel (*ci); + allocated_channels.clear(); + + list::iterator di; + for (di = allocated_devices.begin(); di != allocated_devices.end(); di++) + { + mas_device_t device = *di; + mas_error = mas_asm_terminate_device_instance(device, 0); + if (mas_error < 0) + arts_warning ("MAS output: error while closing device: %s", masc_strmerror(mas_error)); + + mas_free_device(device); + } + allocated_devices.clear(); + + Dispatcher::the()->ioManager()->removeTimer(this); +} + +void AudioIOMAS::updateBufferSizes() +{ + double time = currentTime(); + double waterMark = param(fragmentSize); + waterMark *= 1.3; + + if ((time - lastUpdate) * bytesPerSec < waterMark) + return; + + lastUpdate = time; + + uint32 inbuf_ms; + int32 mas_error; + + mas_error = mas_get( sbuf, "inbuf_ms", 0 , &package ); + if ( mas_error < 0 ) + arts_fatal ("MAS output: error getting size of buffer: %s", masc_strmerror(mas_error)); + + masc_pull_uint32( &package, &inbuf_ms ); + masc_strike_package( &package ); + + //arts_debug(" inbuf_ms = %u", inbuf_ms); + + float bytes = inbuf_ms; + bytes /= 1000.0; + bytes *= param(samplingRate); + bytes *= param(channels); + if(param(format) > 8) + bytes *= 2; + + int bytesFree = param(fragmentSize) * param(fragmentCount) - (int)bytes; + + if (bytesFree < param(fragmentSize)) + bytesFree = 0; + + writeBufferAvailable = bytesFree; + + arts_debug ("MAS output buffer: %6d / %6d bytes used => %6d bytes free", + (int)bytes, param(fragmentSize) * param(fragmentCount), writeBufferAvailable); +} + +// This is called on each timer tick +void AudioIOMAS::notifyTime() +{ + updateBufferSizes(); + + int& _direction = param(direction); + int& _fragmentSize = param(fragmentSize); + + for (;;) { + int todo = 0; + + if ((_direction & directionRead) && (getParam(canRead) >= _fragmentSize)) + todo |= AudioSubSystem::ioRead; + + if ((_direction & directionWrite) && (getParam(canWrite) >= _fragmentSize)) + todo |= AudioSubSystem::ioWrite; + + if (!todo) + return; + + AudioSubSystem::the()->handleIO(todo); + } +} + +void AudioIOMAS::setParam(AudioParam p, int& value) +{ + switch(p) { +#if 0 + case fragmentSize: + param(p) = requestedFragmentSize = value; + break; + case fragmentCount: + param(p) = requestedFragmentCount = value; + break; +#endif + default: + param(p) = value; + break; + } +} + +int AudioIOMAS::getParam(AudioParam p) +{ + int bytes; + int count; + + switch(p) + { +#if 0 + case canRead: + if (ioctl(audio_fd, AUDIO_GETINFO, &auinfo) < 0) + return (0); + bytes = (auinfo.record.samples * bytesPerSample) - bytesRead; + if (bytes < 0) { + printf("Error: bytes %d < 0, samples=%u, bytesRead=%u\n", + bytes, auinfo.record.samples, bytesRead); + bytes = 0; + } + return bytes; + + case canWrite: + if (ioctl(audio_fd, AUDIO_GETINFO, &auinfo) < 0) + return (0); + count = SUN_MAX_BUFFER_SIZE - + (bytesWritten - (auinfo.play.samples * bytesPerSample)); + return count; +#endif + case canWrite: + return writeBufferAvailable; + + case autoDetect: + /* + * Fairly small priority, for we haven't tested this a lot + */ + return 3; + + default: + return param(p); + } +} + +int AudioIOMAS::read(void *buffer, int size) +{ +#if 0 + size = ::read(audio_fd, buffer, size); + if (size < 0) + return 0; + + bytesRead += size; + return size; +#endif + return 0; +} + +int AudioIOMAS::write(void *buffer, int size) +{ + static int ts = 0; + static int seq = 0; + data->header.sequence = seq++; + data->header.media_timestamp = ts; + ts += size / 4; + + assert(size == data->length); + memcpy(data->segment, buffer, size); + + int32 mas_error = mas_send( audio_channel , data ); + if (mas_error < 0) + arts_fatal ("MAS output: problem during mas_send: %s", masc_strmerror(mas_error)); + + writeBufferAvailable -= size; + return size; +} + +#endif /* HAVE_LIBMAS */ diff --git a/flow/audioionas.cc b/flow/audioionas.cc deleted file mode 100644 index 543d8c0..0000000 --- a/flow/audioionas.cc +++ /dev/null @@ -1,260 +0,0 @@ - /* - - Copyright (C) 2001 Jochen Hoenicke - jochen@gnu.org - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/** - * only compile nas AudioIO class if libaudio was detected during - * configure - */ -#ifdef HAVE_LIBAUDIONAS - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "audioio.h" -#include "audiosubsys.h" -#include "iomanager.h" -#include "dispatcher.h" - -#include