logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

ALSA - Modyfikacja kodu do obsługi dźwięku: open, close, record, play

tomaszo 17 Cze 2005 13:34 3060 21
  • #1 1585160
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Witam po raz kolejny z nowym wyzwaniem...
    Ogolnie mam za zadanie wykonac taka "skrzyneczke" - przerobic w sumie kod podany ponizej - :

    <-open,
    <-close,
    <-record start,
    <-record stop,
    <-play.

    Ogolnie czuje sie zle - zostalem wrzucony na glebokie wody przez ignorancje niektorych... nieistotne, mam nadzieje, ze uronicie conieco ze swej wiedzy...

    
    
    #include "soundLayer.h"
    
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <sys/fcntl.h>
    #include <sys/soundcard.h>
    #include <string.h>
    
    #include "datapacket.h"
    #include "soundDeviceMsg.h"
    #include "libs/slog.h"
    
    soundLayer::soundLayer(abstractScheduler* _sched)
      : abstractAudioLayer(_sched)
    {
      name = "soundLayer";
    }
    
    soundLayer::~soundLayer()
    {
      if (audio_fd>0)
        close(audio_fd);
    }
    
    char soundLayer::openToPlay()
    {
      if (_record) {
        slog(Slog::levelWarning)<<name<<": Device is occupied\n";
        return (-1);
      }
    
      slog(Slog::levelDebug)<<name<<": opening device to Play\n";
    
      // we should enqueue this ..
      int open_mode = O_WRONLY;
    
      //    std::cerr<<"opening device\n";
      if ((audio_fd = open(devName.c_str(), open_mode, 0)) == -1) {
        /* Opening device failed */
        perror(devName.c_str());
        return(-1);
      }
    
      // set audio sampling format: 16 bit signed:
      int format = AFMT_S16_LE;
      if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) 
        perror("can't set soundcard format");
    
      // frequency is 8kHz
      // left out - hope sc will take default value
    
      int arg = 0x7fff0009; // 256 Byte packets
      if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &arg))
        perror("setting dsp fragment failed");
    
      // play nothing ...
      int size = startBufferSize;
      char zero[size];
      bzero(zero,size);
    
      //    std::cerr <<"write nothing";
      if (write(audio_fd, zero , size) == -1) {
        perror("audio write");
        return(-1);
      }
    
      _play = 4;
    
      return(0);
    }
    
    char soundLayer::closePlay()
    {
      _play = 0;
      if (audio_fd > 0) {
        close(audio_fd);
        audio_fd = -1;
        return(0); 
      }
      return(-1); // device was not open
    }
    
    void soundLayer::initSchedule()
    {
      Event to1(SignalID::timeout, timerWait+getTics());
      setEvent(to1);
    }
    
    void soundLayer::timerHandler(Event e)
    {
      if (_play)
        _play--;
     
      if ((!_play) && (!_record) && (audio_fd > 0)) {
          slog(Slog::levelDebug)<<name<<": closing audio device (playing)\n";
          closePlay();
        }
    
      Event to1(SignalID::timeout, timerWait+getTics());
      setEvent(to1);
    
    }
    
    
    void soundLayer::upperQueueHandler(Event e)
    {
      if (!_play) {
        slog(Slog::levelDebug)<<name<<"start playing\n";
        if (openToPlay() < 0)
          return; // packets will be queued until next call - not nice
      }
    
      while(!UpperQueue_empty()){
    
        transferItem tr(getFromUpper());
        tr.dec_layer();
     
        datapacket* pack = GETIPACKTYPE(datapacket*,tr);
    
        slog(Slog::levelDebug)<<"p";
    
        if (write(audio_fd, pack->getData(), pack->getBodyLength()) == -1) {
        perror("audio write failed");
        continue;
        }
        _play = 2; //pack->getBodyLength()/7650;
    
      }
    }
    
    void soundLayer::descHandler(Event e)
    {
      if (!_record)
        return;
    
      audio_buf_info info; 
      ioctl(audio_fd, SNDCTL_DSP_GETISPACE, &info);
    
      if (info.bytes == 0) {
        //    slog(Slog::levelWarning)<<"we are called with no data available!?\n";
        return;
      }
    
      // where will this packet be deleted?
      char* sample = new char[info.bytes+2];
      int size;
      //    std::cerr<<"space: "<<info.bytes<<" ";
      if ((size = read(audio_fd, sample+2, info.bytes)) <= 0) {  
        perror("audio read failed");  
        delete sample;
        return;
      }
      *((unsigned short*)(sample)) = (unsigned short) size;
    
      // adjust record level, if this is a bullshit windows driver only card 
      if (recordLevel) {
        unsigned short* adjustSamples = (unsigned short*) sample+2;
        for(unsigned int i=0; i < (unsigned int)(info.bytes/2); ++i)
          adjustSamples[i] = adjustSamples[i] << recordLevel; // exponential level
      }
    
      transferItem tr;
      tr.setdata(new ICI(0,0,size,2,false));
      tr.setRaw(sample,size+2);
    
      slog(Slog::levelDebug)<<"r";
    
      Layer* to = UpperLayer.findLayer();
    
      //  tr.getItem()->print();
    
      if (to)
        to->transferFromLower(tr,0);
    }
    
    char soundLayer::openToRecord()
    {
      if (_play) {
        slog(Slog::levelWarning)<<name<<": can't record -> device is occupied\n";
        return (-1);
      }
    
      slog(Slog::levelDebug)<<name<<": opening device to Record\n";
    
        // just open the device and wait for the samples
        int open_mode = O_RDONLY;
    
        if ((audio_fd = open(devName.c_str(), open_mode, 0)) == -1) {
          /* Opening device failed */
          perror(devName.c_str());
          return (-1);
        }
    
        // set audio sampling format: 16 bit signed:
        int format = AFMT_S16_LE;
        if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) 
          perror("can't set soundcard format");
    
        int arg = 0x7fff0009;
        if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &arg)) {
          perror("dsp fragment failed");
          return (-2);
        }
    
        // tell scheduler, that we want to be informed on soundcard events 
        sched->add_select(this, audio_fd);
    
        _record = 1;
        return (0);
    }
    
    char soundLayer::closeRecord()
    {
      if (_record) {
        _record = 0;
        if (audio_fd > 0) {
          slog(Slog::levelDebug)<<name<<": closing audioDevice (recording)\n";
          sched->del_select(audio_fd);
          close(audio_fd);
          audio_fd = -1;
        }
        else
          return(-1);
      }
      else
        return (-1);
      return(0);
    }
    
    void soundLayer::controlPlaneMsgHandler(controlMsg& msg)
    {
      /**** start/stop recording *******/
    
      if (msg.getName() == "Record") {
        RecordMsg* am = dynamic_cast<RecordMsg*>(&msg);
        if (am && (am->status == RecordMsg::start))
          openToRecord();
        else
          if (am && (am->status == RecordMsg::stop))
    	closeRecord();
          else
    	slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    
      /**** close soundcard for playing *******/
    
      if (msg.getName() == "closePlay") {
        closePlayMsg* am = dynamic_cast<closePlayMsg*>(&msg);
        if (am)
          closePlay();
        else
          slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    
      /**** set record level ******/
    
      if (msg.getName() == "setRecordLevel") {
        recordLevelMsg* am = dynamic_cast<recordLevelMsg*>(&msg);
        if (am){
          if (am->recordLevel < 5)
    	recordLevel = am->recordLevel;
        }
        else
          slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    
      /**** set record device ******/
    
      if (msg.getName() == "setDevice") {
        setDeviceMsg* am = dynamic_cast<setDeviceMsg*>(&msg);
        if (am)
          setDeviceName(am->device);
        else
          slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    
      /**** request availabel byte for output *****/
    
      if (msg.getName() == "getOutBufferSize") {
        bufferInfoMsg* bi = dynamic_cast<bufferInfoMsg*>(&msg);
        if (bi) {
          audio_buf_info info; 
          if (audio_fd <= 0) {
    	int open_mode = O_RDONLY;
    	int afd;
    	if ((afd = open(devName.c_str(), open_mode, 0)) == -1) {
    	  /* Opening device failed */
    	  //perror(devName.c_str());
    	  bi->size = 0;
    	  return;
    	}
    	else {
    	  ioctl(afd, SNDCTL_DSP_GETOSPACE, &info);
    	  close(afd);
    	}
          }
          else // audio_fd is set!
    	ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
    	
          bi->size = info.bytes;
          slog(Slog::levelDebug)<<"bytes = "<<(int) info.bytes<<oendl;
        }
        else
          slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    }
    
    



    Trzeba to przerobic "na ALSA-e"... Przynajmniej tak zrozumialem.
  • #3 1592513
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    Wszystko fajnie ale przydaly by sie wszystkie pliki tegoz projektu (tzn. naglowki ktore sa w "") bo moze tam byc sporo ciekawych informacji.
  • #4 1592747
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    http://www.linuxjournal.com/node/6735

    Jeszcze jeden link... Warto zassac stad te 4 programiki :
    ftp.ssc.com/pub/lj/listings/issue126/6735.tgz.



    Sluchajcie, najciekawsze, ze mam robic kolejny segmencik projektu nie widziawszy jeszcze calosci, mam tzw. blokowe pojecie poki co... Moze o to chodzi, zeby robic i za szybko nie zrobic ale mnie osobiscie morduje taki system...
    Nie mam dostepu do calosci naturalnie... Scisle tajne psia krew...
    Jutro bede zapewne wiedzial co ma tak do konca powstac w oparciu o te 4 programiki spod linka - dzis nie da rady, bo nie moga zainstalowac gcc...No czeski film...

    Hehe - no w teorii moze sie uda calosc pozniej skopiowac, ale moglby byc niezly dym w razie czego (nie wiem, czy to bedzie jakos sprzedawane, czy jak potem...).
  • Pomocny post
    #5 1592776
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    O ile dobrze zrozumialem to masz to przerobic ten program tak aby korzystal z serwera dzwieku ALSA a nie na zywca ze sterownika karty dzwiekowej czy tak ? Problemem jest jednak to ze oficjalna strona ALSY nie odpowiada a wiec przestudiowanie jej API jest nieco utrudnione.Moze taki link cos ci pomoze:
    http://equalarea.com/paul/alsa-audio.html
    Jest tu kilka przykladow jak port otwierac i ustawiac aczkolwiek przydalby sie pelny opis API.

    P.S. Jaki masz problem z zainstalowaniem GCC, moze bede w stanie pomoc.Najlepiej zapodaj log-a z bledami.
  • #6 1594827
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Dzieki Fantom Gcc to pikus - zainsaluej się jutro Koles (szefu) pije za duzo kawy po prostu...

    Dobrze zrozumiales :) Wlasnie to mamy uczynic, ze wskazaniem na mnie...


    ------------------------------

    Fantom - brawo! To znaczy ogolnie z Twojego linku programiki Playback i Capture sa odpowiednie, ale nie dzialaja...

    Playback wywala : cannot open audio device /dev/dsp (No such file or directory) bez wzgledu na to, co mu tam ladujemy... bedziemy to meczyc - moze zaraz dopisze cos.

    Kolejny pomocny link z kilkoma odnosnikami na dole...
    http://www.suse.de/~mana/alsa090_howto.html


    
    
            #include <stdio.h>
    	#include <stdlib.h>
    	#include <alsa/asoundlib.h>
    	      
    	main (int argc, char *argv[])
    	{
    		int i;
    		int err;
    		short buf[128];
    		snd_pcm_t *playback_handle;
    		snd_pcm_hw_params_t *hw_params;
    	
        /* Name of the PCM device, like plughw:0,0          */
        /* The first number is the number of the soundcard, */
        /* the second number is the number of the device.   */
        char *pcm_name;
      
    
        /* Init pcm_name. Of course, later you */
        /* will make this configurable ;-)     */
        pcm_name = strdup("plughw:0,0");
      
    
        /* Allocate the snd_pcm_hw_params_t structure on the stack. */
        //snd_pcm_hw_params_alloca(&hwparams);
      
    
    
    		if ((err = snd_pcm_open (&playback_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
    			fprintf (stderr, "cannot open audio device %s (%s)\n", 
    				 argv[1],
    				 snd_strerror (err));
    			exit (1);
    		}
    		   
    		if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
    			fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    				 
    		if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) {
    			fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
    			fprintf (stderr, "cannot set access type (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
    			fprintf (stderr, "cannot set sample format (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    		
    		unsigned int freq(44100);
    		if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, &freq, 0)) < 0) {
    			fprintf (stderr, "cannot set sample rate (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0) {
    			fprintf (stderr, "cannot set channel count (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) {
    			fprintf (stderr, "cannot set parameters (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		snd_pcm_hw_params_free (hw_params);
    	
    		if ((err = snd_pcm_prepare (playback_handle)) < 0) {
    			fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		for (i = 0; i < 1000; ++i) {
    			for (int i=0; i<128; i++)
    			  buf[i] = (char) (256*rand()/(RAND_MAX+1.0))-127;
    			if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) {
    				fprintf (stderr, "write to audio interface failed (%s)\n",
    					 snd_strerror (err));
    				exit (1);
    			}
    		}
    	
    		snd_pcm_close (playback_handle);
    		exit (0);
    	}
    
    


    Ten programik odtwarza jakas tam piiiiii - kilka sinusoid razem, czas w zaleznosci od licznika i w ostatniej petli. Bede przerabial na mozliwosc odtwarzania konkretnego pliku teraz (masakra). To jest przerobiona wersja Playback z linka.
  • #7 1594917
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    A masz plik urzadzenia /dev/dsp ? Jesli nie masz to zrob sobie w /dev link symboliczny (np: ln -s /dev/audio /dev/dsp) do jakiegos /dev/audio lub cos w tym stylu.
  • #8 1594946
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    /dev/dsp jest.

    Mecze sie, zeby to powyzej otwieralo wskazany plik wave.
  • #9 1594968
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    Po mojemu to bufor probek odczytany z pliku wave nalezy wepchnac do ALSY za pomoca snd_pcm_writei() ale moze sie myle.
  • #10 1595015
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Nie mylisz sie. Wlasnie tak... probowalem bez tego calego HDRSIZE itd.. ale wychodzil jakis syf - zblizony do odpowiedzi tego pierwszego programu-generatorka.

    Wladowalem wszystko, co sie dalo, zmiejszona jest cz. probkowania do 22050 Hz... Wychodzi jakies sinusoidalnopodobne dziadostwo - nie czyta jednym slowem mojego spreparowanego pliku "wave1stereo"...

    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <alsa/asoundlib.h>
    
    #include <iostream>
    	      
    #define BLOCKSIZE 256
    int rmHeader(FILE* fd, FILE* out = 0)
    {
       int counter(4);
       int size;
       char bufor[4];
       fread(bufor,sizeof(char),4,fd);
       if (out)
         fwrite(bufor,sizeof(char),4,out);
       while(strncmp(bufor,"data",4))
       {
          counter ++;
          bufor[0]=bufor[1];
          bufor[1]=bufor[2];
          bufor[2]=bufor[3];
          fread(&bufor[3],sizeof(char),1,fd);
          if (out)
           fwrite(&bufor[3],sizeof(char),1,out);
       }
       fread(&size,sizeof(int),1,fd);
       if (out)
         fwrite(&size,sizeof(int),1,out);
       std::cout<<"HdrSize: "<<counter<<"\n";
       return(size);
    }
    
    main (int argc, char *argv[])
    	{
    		int i;
    		int err;
    		short buf[BLOCKSIZE];
    		snd_pcm_t *playback_handle;
    		snd_pcm_hw_params_t *hw_params;
    	
        /* Name of the PCM device, like plughw:0,0          */
        /* The first number is the number of the soundcard, */
        /* the second number is the number of the device.   */
                    char *pcm_name;
      
    
        /* Init pcm_name. Of course, later you */
        /* will make this configurable ;-)     */
                   pcm_name = strdup("plughw:0,0");
      
    
        /* Allocate the snd_pcm_hw_params_t structure on the stack. */
        //snd_pcm_hw_params_alloca(&hwparams);
      
    
    
    		if ((err = snd_pcm_open (&playback_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
    			fprintf (stderr, "cannot open audio device %s (%s)\n", 
    				 argv[1],
    				 snd_strerror (err));
    			exit (1);
    		}
    		   
    		if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
    			fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    				 
    		if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) {
    			fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
    			fprintf (stderr, "cannot set access type (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
    			fprintf (stderr, "cannot set sample format (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    		
    		unsigned int freq(22050);
    		if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, &freq, 0)) < 0) {
    			fprintf (stderr, "cannot set sample rate (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0) {
    			fprintf (stderr, "cannot set channel count (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) {
    			fprintf (stderr, "cannot set parameters (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		snd_pcm_hw_params_free (hw_params);
    	
    		if ((err = snd_pcm_prepare (playback_handle)) < 0) {
    			fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
    				 snd_strerror (err));
    			exit (1);
    		}
    	
    		
     
                         
    			
                    FILE* f1;
                    f1 = fopen("wave1stereo","rb");
    		std::cout << "open file wave1stereo\n";
    		rmHeader(f1);
                    while (fread(buf,sizeof(char),BLOCKSIZE,f1)==BLOCKSIZE) {
                      if ((err = snd_pcm_writei(playback_handle, buf, BLOCKSIZE)) != BLOCKSIZE)
                      {
    		    fprintf (stderr, "write to audio interface failed (%s)\n",snd_strerror (err));
      		    snd_pcm_close (playback_handle);
                        fclose(f1);
    		    exit (1);
    	          }
    		}
    	
    		snd_pcm_close (playback_handle);
                    fclose(f1);
    		exit (0);
    	}
    
    


    Co jest nie tak? Braklo mi pomyslow...

    Tutaj uzywaja "frames" http://www.suse.de/~mana/alsa090_howto.html - ale ta ramka to co innego, niz kombinacje z HDR lub BLOCKSIZE... O zesz w morde!
  • Pomocny post
    #11 1595127
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    Wyglada to calkiem dobrze.Napewno trzeba wepchnac same probki (bez naglowka) bo inaczej to bedzie bez sensu.Wydaje mi sie ze problem tkwi w prawidlowej konfiguracji ALSY.BTW: Dlaczego 22050 Hz ?
    Znalazlem jednak blad.Moze problem lezy tu:
    
    zamiast:
    while (fread(buf,sizeof(char),BLOCKSIZE,f1)==BLOCKSIZE) 
    powinno byc:
    while (fread(buf,sizeof(short),BLOCKSIZE,f1)==BLOCKSIZE) { 
    
  • #12 1595289
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Zmienilem cz. probkowania, bo jakims dziwnym trafem rejestrator mimo innych ustawien tak poczynil nagranie - ale jest to drugorzedna w tej chwili kwestia.

    Fantom - wielkie dzieki, jutro bedzie sie dzialo dalej, sprobuje sugerowana zmiane wprowadzic (ze tez nie sprobowalem, myslalem o tym...).
  • Pomocny post
    #13 1596765
    loleslaw_potezny
    Poziom 2  
    Posty: 2
    Pomógł: 1
    Witam wszystkich.

    Troche sie pobawiłem przykładowymi programami do alsy i udało mi się skrobnąć coś co odtwarza standardowego wav-a (44100 stereo). Kod poniżej.

    tomaszoo problem tkwii w użyciu funkcji:
    snd_pcm_writei(handle, buffer, frames);
    ostatni argument to nie liczba bajtów jaką zapisuje sie do urządzenia, ale liczba ramek. Na razie za bardzo nie rozumiem co to sa te ramki i dlaczego 32 działają dobrze (a np. 4 nie za bardzo). Muszę jeszcze przestudiować nieco dokumentacje (znaczy pliki nagłówkowe alsy)


    /* Use the newer ALSA API */
    #define ALSA_PCM_NEW_HW_PARAMS_API
    
    #include <iostream>
    #include <alsa/asoundlib.h>
    
    int rmHeader(FILE* fd, FILE* out = 0)
    {
       int counter(4);
       int size;
       char bufor[4];
       fread(bufor,sizeof(char),4,fd);
       if (out)
         fwrite(bufor,sizeof(char),4,out);
       while(strncmp(bufor,"data",4))
       {
          counter ++;
          bufor[0]=bufor[1];
          bufor[1]=bufor[2];
          bufor[2]=bufor[3];
          fread(&bufor[3],sizeof(char),1,fd);
          if (out)
           fwrite(&bufor[3],sizeof(char),1,out);
       }
       fread(&size,sizeof(int),1,fd);
       if (out)
         fwrite(&size,sizeof(int),1,out);
       std::cout<<"HdrSize: "<<counter<<"\n";
       return(size);
    } 
    
    int main() {
      long loops;
      int rc;
      int size;
      snd_pcm_t *handle;
      snd_pcm_hw_params_t *params;
      unsigned int val;
      int dir;
      snd_pcm_uframes_t frames;
      char *buffer;
    
      /* Open PCM device for playback. */
      rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
      if (rc < 0) {
        fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
        exit(1);
      }
    
      /* Allocate a hardware parameters object. */
      snd_pcm_hw_params_alloca(&params);
    
      /* Fill it in with default values. */
      snd_pcm_hw_params_any(handle, params);
    
      /* Set the desired hardware parameters. */
    
      /* Interleaved mode */
      snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    
      /* Signed 16-bit little-endian format */
      snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);
    
      /* Two channels (stereo) */
      snd_pcm_hw_params_set_channels(handle, params, 2);
    
      /* 44100 bits/second sampling rate (CD quality) */
      val = 44100;
      snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
    
      /* Set period size to 32 frames. */
      /* !!!! ale dlaczego 32 !!!! */
      frames = 32;
      snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
    
      /* Write the parameters to the driver */
      rc = snd_pcm_hw_params(handle, params);
      if (rc < 0) {
        fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
        exit(1);
      }
    
      /* Use a buffer large enough to hold one period */
      /* !!!!! tu alokowany jest bufor na wielkosc 32 ramek = jeden period */
      snd_pcm_hw_params_get_period_size(params, &frames, &dir);
      size = frames * 4; /* 2 bytes/sample, 2 channels */
      buffer = (char *) malloc(size);
    
      /* We want to loop for 5 seconds */
      snd_pcm_hw_params_get_period_time(params, &val, &dir);
      /* 5 seconds in microseconds divided by 
       * period time */
      loops = 5000000 / val;
    
      FILE *f = fopen("amon.wav", "r");
      rmHeader(f);
    
      while (loops > 0) {
        loops--;
        rc = fread(buffer, 1, size, f);
        if (rc == 0) {
          fprintf(stderr, "end of file on input\n");
          break;
        } else if (rc != size) {
          fprintf(stderr, "short read: read %d bytes\n", rc);
        }
        rc = snd_pcm_writei(handle, buffer, frames);
        if (rc == -EPIPE) {
          /* EPIPE means underrun */
          fprintf(stderr, "underrun occurred\n");
          snd_pcm_prepare(handle);
        } else if (rc < 0) {
          fprintf(stderr, "error from writei: %s\n", snd_strerror(rc));
        }  else if (rc != (int)frames) {
          fprintf(stderr, "short write, write %d frames\n", rc);
        }
      }
    
      snd_pcm_drain(handle);
      snd_pcm_close(handle);
      free(buffer);
    
      return 0;
    }


    Dodano po 28 [minuty]:

    Zaczynam chyba rozumieć.

    Karta dźwiekowa ma hardware-owy bufor na dane. ALSA trzyma sobie bufor z danymi w przestrzeni użytkownika. Gdy bufor alsy jest dostatecznie pełny (cokolwiek to nie oznacza) następuje przekopiowanie go do bufora karty.

    Rozmiar bufora ALSY można programowo ustalić. Żeby nie było jednak opóźnień (latency) i aby nie transmitować karcie zbyt dużo danych na raz bufor podzielony jest na fragmenty (periods). Trzeba ustawić ile ramek ma mieć period. Ramka to informacja dla karty "w danej chwili", czyli mając 2 kanały i 16 bitow mamy w sumie (a właściwie w iloczynie 2*2) 4 bajtową ramkę.

    Stąd jeśli odczyta się 256 bajtów, przy 16bit, 2 kanaly, 32 ramki, to period ma rozmiar = 2 * 2 * 32 = 128 bajtów, a więc mamy 2 ramki.

    A wszystkiego tego dowiedziałem się z http://www.linuxjournal.com/node/6735
  • #14 1597397
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Lolo! Jak milo widziec! Prawie spadlem z krzesla :D

    Jestes rzeczywiscie potezny heheh. Jeszcze jedno - jak juz wlazles, masz pisac tutaj! Pomagac ludziom potrzebujacym! No.
  • #15 1597464
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    To fakt oprocz wczesniejszej zmiany musisz dodac w funkcji snd_pcm_writei przedostatni argument jako BLOCKSIZE/2 jako ze mamy dwa kanaly.W obecniej chwili wyglada na to ze sa dodatkowo wsysane bajty spoza tablicy buf.Cud ze nie robi segmentation fault chyba ze ALSA jest na tyle inteligentna ze sprawdza wielkosc bufora.Na koniec jeszcze dodam ze dziala juz strona http://www.alsa-project.org/alsa-doc/alsa-lib/index.html najlepszy informator do ALSA API.
  • #16 1597760
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Super Lolo! Dziala...


    Wlasnie Fantom - widac sprawdza...


    Teraz zmieniamy sprawe tak, zeby dzialalo z sygnalem mono... Potem to bedzie wykorzystane do dzialania w czasie rzeczywistym - jeszcze nie wiem dokladnie jak :/



    
    
    /* Use the newer ALSA API */
    #define ALSA_PCM_NEW_HW_PARAMS_API
    
    #include <iostream>
    #include <alsa/asoundlib.h>
    
    
    
    int rmHeader(FILE* fd, FILE* out = 0)
    {
       int counter(4);
       int size;
       char bufor[4];
       fread(bufor,sizeof(char),4,fd);
       if (out)
         fwrite(bufor,sizeof(char),4,out);
       while(strncmp(bufor,"data",4))
       {
          counter ++;
          bufor[0]=bufor[1];
          bufor[1]=bufor[2];
          bufor[2]=bufor[3];
          fread(&bufor[3],sizeof(char),1,fd);
          if (out)
           fwrite(&bufor[3],sizeof(char),1,out);
       }
       fread(&size,sizeof(int),1,fd);
       if (out)
         fwrite(&size,sizeof(int),1,out);
       std::cout<<"HdrSize: "<<counter<<"\n";
       return(size);
    }
    
    int main() {
      long loops;
      int rc;
      int size;
      snd_pcm_t *handle;
      snd_pcm_hw_params_t *params;
      unsigned int val;
      int dir;
      snd_pcm_uframes_t frames;
      char *buffer;
    
      /* Open PCM device for playback. */
      rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
      if (rc < 0) {
        fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
        exit(1);
      }
    
      /* Allocate a hardware parameters object. */
      snd_pcm_hw_params_alloca(&params);
    
      /* Fill it in with default values. */
      snd_pcm_hw_params_any(handle, params);
    
      /* Set the desired hardware parameters. */
    
      /* Interleaved mode */
      snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    
      /* Signed 16-bit little-endian format */
      snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);
    
      /* Two channels (stereo) */
     // snd_pcm_hw_params_set_channels(handle, params, 2);
    
       // MONO        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    snd_pcm_hw_params_set_channels(handle, params, 1);
    
      /* 44100 bits/second sampling rate (CD quality) */
      val = 44100;
      snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
    
      /* Set period size to 32 frames. */
      /* !!!! ale dlaczego 32 !!!! */
      frames = 480; //32
      snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
    
      /* Write the parameters to the driver */
      rc = snd_pcm_hw_params(handle, params);
      if (rc < 0) {
        fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
        exit(1);
      }
    
      /* Use a buffer large enough to hold one period */
      /* !!!!! tu alokowany jest bufor na wielkosc 32 ramek = jeden period */
      snd_pcm_hw_params_get_period_size(params, &frames, &dir);
    
      //size = frames * 4; /* 2 bytes/sample, 2 channels */
      
    // MONO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    size = frames * 2; /* 2 bytes/sample, 1 channel */
    
    buffer = (char *) malloc(size);
    
      /* We want to loop for 5 seconds */
      snd_pcm_hw_params_get_period_time(params, &val, &dir);
      /* 5 seconds in microseconds divided by
       * period time */
      loops = 5000000 / val;
    
      FILE *f = fopen("wave1mono", "r");
      rmHeader(f);
    
      while (loops > 0) {
        loops--;
        rc = fread(buffer, 1, size, f);
        if (rc == 0) {
          fprintf(stderr, "end of file on input\n");
          break;
        } else if (rc != size) {
          fprintf(stderr, "short read: read %d bytes\n", rc);
        }
        
        rc = snd_pcm_writei(handle, buffer, frames);
        if (rc == -EPIPE) {
          /* EPIPE means underrun */
          fprintf(stderr, "underrun occurred\n");
          snd_pcm_prepare(handle);
        } else if (rc < 0) {
          fprintf(stderr, "error from writei: %s\n", snd_strerror(rc));
        }  else if (rc != (int)frames) {
          fprintf(stderr, "short write, write %d frames\n", rc);
        }
      }
     
    
      std::cout << "-\n";
    
      snd_pcm_drain(handle);
      snd_pcm_close(handle);
      free(buffer);
    
      return 0;
    }
    
    



    Sprawa zmiany banalna - ale jest KLOPOT! Zobaczcie kiedy ten "-" sie wypluje - zawsze tuz przed koncem odtwarzania, bez wzgledu na ilosc ramek - teraz dalem 480...

    Musi to wyslac i nie blokowac sie, tutaj jest klopot.
    Sprobuje dac mu jescze wyswietlanie czasu - zobaczymy jak to robi ...
  • #17 1597997
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    Chyba wiem czemu tak sie robi.Wyglada na to ze ALSA nie zdarzyla jeszcze przetworzyc calego strumienia.Mozna odczytac stan za pomoca snd_pcm_state() i poczekac az nie bedzie w stanie running albo jesli uzylbys snd_pcm_drain() przed std::out to prawdopodobnie wyrzucil by to na ekran dopiero po zakonczeniu odtwarzania.Zerknij sobie tu http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html w podpunkcie "Handshake between application and library" oraz "Obtaining stream status"
  • #18 1601099
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Tak... khm... Co to jest w sumie to "loops" ? Dlaczego jest 5 sekund w mikrosekundach? dlaczego zmiana tego na np. 100000 nic nie przynosi?...

    Ja nie moge...

    Program wzial sie poniekad stad..
    http://www.linuxjournal.com/node/6735/print



    Zerknijcie tutaj... Uzycie :
    
    rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
    

    w zamian za wczesniejsza wersje powoduje odegranie kawaleczka i potem wywala :" error from writei: Resource temporarily unavaliable"

    
     /* Use the newer ALSA API */
    #define ALSA_PCM_NEW_HW_PARAMS_API
    
    #include <iostream>
    #include <alsa/asoundlib.h>
    
    
    int rmHeader(FILE* fd, FILE* out = 0)
    {
       int counter(4);
       int size;
       char bufor[4];
       fread(bufor,sizeof(char),4,fd);
       if (out)
         fwrite(bufor,sizeof(char),4,out);
       while(strncmp(bufor,"data",4))
       {
          counter ++;
          bufor[0]=bufor[1];
          bufor[1]=bufor[2];
          bufor[2]=bufor[3];
          fread(&bufor[3],sizeof(char),1,fd);
          if (out)
           fwrite(&bufor[3],sizeof(char),1,out);
       }
       fread(&size,sizeof(int),1,fd);
       if (out)
         fwrite(&size,sizeof(int),1,out);
       std::cout<<"HdrSize: "<<counter<<"\n";
       return(size);
    }
    
    int main() {
      long loops;
      int rc;
      int size;
      snd_pcm_t *handle;
      snd_pcm_hw_params_t *params;
      unsigned int val;
      int dir;
      snd_pcm_uframes_t frames;
      char *buffer;
    
      /* Open PCM device for playback. */
      rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
      if (rc < 0) {
        fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
        exit(1);
      }
    
      /* Allocate a hardware parameters object. */
      snd_pcm_hw_params_alloca(&params);
    
      /* Fill it in with default values. */
      snd_pcm_hw_params_any(handle, params);
    
      /* Set the desired hardware parameters. */
    
      /* Interleaved mode */
      snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    
      /* Signed 16-bit little-endian format */
      snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);
    
      /* Two channels (stereo) */
     // snd_pcm_hw_params_set_channels(handle, params, 2);
    
       // MONO        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    snd_pcm_hw_params_set_channels(handle, params, 1);
    
      /* 44100 bits/second sampling rate (CD quality) */
      val = 44100;
      snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
    
      /* Set period size to 32 frames. */
      /* !!!! ale dlaczego 32 !!!! */
    //  frames = 480; //32
      frames = 32; //32
      snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
    
      /* Write the parameters to the driver */
      rc = snd_pcm_hw_params(handle, params);
      if (rc < 0) {
        fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
        exit(1);
      }
    
      /* Use a buffer large enough to hold one period */
      /* !!!!! tu alokowany jest bufor na wielkosc 32 ramek = jeden period */
      snd_pcm_hw_params_get_period_size(params, &frames, &dir);
    
      //size = frames * 4; /* 2 bytes/sample, 2 channels */
     
    // MONO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    size = frames * 2; /* 2 bytes/sample, 1 channel */
    
    buffer = (char *) malloc(size);
    
      /* We want to loop for 5 seconds */
      snd_pcm_hw_params_get_period_time(params, &val, &dir);
      /* 5 seconds in microseconds divided by
       * period time */
      loops = 1000000 / val;
    
      FILE *f = fopen("wave1mono", "r");
      rmHeader(f);
    
      while (loops > 0) {
        loops--;
        rc = fread(buffer, 1, size, f);
        if (rc == 0) {
          fprintf(stderr, "end of file on input\n");
          break;
        } else if (rc != size) {
          fprintf(stderr, "short read: read %d bytes\n", rc);
        }
       
        rc = snd_pcm_writei(handle, buffer, frames);
        if (rc == -EPIPE) {
          /* EPIPE means underrun */
          fprintf(stderr, "underrun occurred\n");
          snd_pcm_prepare(handle);
        } else if (rc < 0) {
          fprintf(stderr, "error from writei: %s\n", snd_strerror(rc));
        }  else if (rc != (int)frames) {
          fprintf(stderr, "short write, write %d frames\n", rc);
        } else
    	fprintf(stderr, "-");
      }
     
      std::cout << "-\n";
    
      snd_pcm_drain(handle);
      snd_pcm_close(handle);
      free(buffer);
    
      return 0;
    }
    
    
  • #19 1601193
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    Wyglada na to ze bardzo slusznie robi.Spojrz sobie na podpunkt "Blocked and non-blocked open" w linku ktory podalem powyzej.Jesli otworzyles serwer w trybie nie blokujacym i jest on zajety (przetwarza poprzednie probki) to nie przyblokuje wywolania snd_pcm_writei ale zwroci kod bledu ~EBUSY.Poniewaz wylapujesz ten blad jako szkodliwy dla twojej aplikacji "else if(rc<0)" to pozniej sie nie dziw ze masz taki efekt :D.No a co do Loops to teoretycznie sluzy do wyplucia tyle razy podanego pliku ile jest mu podane a czemu tamte obliczenia musza byc podawane w mikrosekundach to juz sie trzeba tworcow ALSY spytac ;-).Tu http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___h_w___params.html#a65 masz opis funkcji snd_pcm_hw_params_get_period_time().
  • #20 1603472
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Juz rozumiem :) Dzieki Fantom.

    Tutaj poazalem wielkosc tego bufora calego - po okolo 30 kB wywala EBUSY - a maksimum okresla czas w mikrosekundach...

    
    #define ALSA_PCM_NEW_HW_PARAMS_API
    
    #include <iostream>
    #include <alsa/asoundlib.h>
    
    
    
    
    int rmHeader(FILE* fd, FILE* out = 0)
    {
       int counter(4);
       int size;
       char bufor[4];
       fread(bufor,sizeof(char),4,fd);
       if (out)
         fwrite(bufor,sizeof(char),4,out);
       while(strncmp(bufor,"data",4))
       {
          counter ++;
          bufor[0]=bufor[1];
          bufor[1]=bufor[2];
          bufor[2]=bufor[3];
          fread(&bufor[3],sizeof(char),1,fd);
          if (out)
           fwrite(&bufor[3],sizeof(char),1,out);
       }
       fread(&size,sizeof(int),1,fd);
       if (out)
         fwrite(&size,sizeof(int),1,out);
       std::cout<<"HdrSize: "<<counter<<"\n";
       return(size);
    }
    
    int main() {
      long loops;
      int rc;
      int size;
      snd_pcm_t *handle;
      snd_pcm_hw_params_t *params;
      unsigned int val;
      int dir;
      snd_pcm_uframes_t frames;
      char *buffer;
    
      /* Open PCM device for playback. */
      rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
      if (rc < 0) {
        fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
        exit(1);
      }
    
      /* Allocate a hardware parameters object. */
      snd_pcm_hw_params_alloca(&params);
    
      /* Fill it in with default values. */
      snd_pcm_hw_params_any(handle, params);
    
      /* Set the desired hardware parameters. */
    
      /* Interleaved mode */
      snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    
      /* Signed 16-bit little-endian format */
      snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);
    
      /* Two channels (stereo) */
     // snd_pcm_hw_params_set_channels(handle, params, 2);
    
       // MONO        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    snd_pcm_hw_params_set_channels(handle, params, 1);
    
      /* 44100 bits/second sampling rate (CD quality) */
      val = 44100;
      snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
    
      /* Set period size to 32 frames. */
      /* !!!! ale dlaczego 32 !!!! */
    //  frames = 480; //32
      frames = 32; //32
      snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
    
      /* Write the parameters to the driver */
      rc = snd_pcm_hw_params(handle, params);
      if (rc < 0) {
        fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
        exit(1);
      }
    
      /* Use a buffer large enough to hold one period */
      /* !!!!! tu alokowany jest bufor na wielkosc 32 ramek = jeden period */
      snd_pcm_hw_params_get_period_size(params, &frames, &dir);
    
      //size = frames * 4; /* 2 bytes/sample, 2 channels */
     
    // MONO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    size = frames * 2; /* 2 bytes/sample, 1 channel */
    
    int counter(0);
    
    buffer = (char *) malloc(size);
    
      /* We want to loop for 5 seconds */
      snd_pcm_hw_params_get_period_time(params, &val, &dir);
      /* 5 seconds in microseconds divided by
       * period time */
      loops = 5000000 / val;
    
      FILE *f = fopen("wave1mono", "r");
      rmHeader(f);
    
      while (loops > 0) {
        loops--;
        rc = fread(buffer, 1, size, f);
        if (rc == 0) {
          fprintf(stderr, "end of file on input\n");
          break;
        } else if (rc != size) {
          fprintf(stderr, "short read: read %d bytes\n", rc);
        }
        counter++;
        rc = snd_pcm_writei(handle, buffer, frames);
        if (rc == -EPIPE) {
          /* EPIPE means underrun */
          fprintf(stderr, "underrun occurred\n");
          snd_pcm_prepare(handle);
        } else if (rc < 0) {
          fprintf(stderr, "error from writei: <%d> %s\n", counter*size, snd_strerror(rc));
          
        }  else if (rc != (int)frames) {
          fprintf(stderr, "short write, write %d frames\n", rc);
        } else
    	fprintf(stderr, "-");
      }
     
    
    // _---------------- probe ---------------------_
    
      std::cout << "-\n";
    
      snd_pcm_drain(handle);
      snd_pcm_close(handle);
      free(buffer);
    
      return 0;
    }
    


    Teraz trzeba to dopasowac tutaj :

    
    #include "soundLayer.h"
    
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <sys/fcntl.h>
    #include <sys/soundcard.h>
    #include <string.h>
    
    #include "datapacket.h"
    #include "soundDeviceMsg.h"
    #include "libs/slog.h"
    
    soundLayer::soundLayer(abstractScheduler* _sched)
      : abstractAudioLayer(_sched)
    {
      name = "soundLayer";
    }
    
    soundLayer::~soundLayer()
    {
      if (audio_fd>0)
        close(audio_fd);
    }
    
    char soundLayer::openToPlay()
    {
    }
    
    char soundLayer::closePlay()
    {
    }
    
    void soundLayer::initSchedule()
    {
      Event to1(SignalID::timeout, timerWait+getTics());
      setEvent(to1);
    }
    
    void soundLayer::timerHandler(Event e)
    {
      if (_play)
        _play--;
     
      if ((!_play) && (!_record) && (audio_fd > 0)) {
          slog(Slog::levelDebug)<<name<<": closing audio device (playing)\n";
          closePlay();
        }
    
      Event to1(SignalID::timeout, timerWait+getTics());
      setEvent(to1);
    
    }
    
    
    void soundLayer::upperQueueHandler(Event e)
    {
      if (!_play) {
        slog(Slog::levelDebug)<<name<<"start playing\n";
        if (openToPlay() < 0)
          return; // packets will be queued until next call - not nice
      }
    
      while(!UpperQueue_empty()){
    
        transferItem tr(getFromUpper());
        tr.dec_layer();
     
        datapacket* pack = GETIPACKTYPE(datapacket*,tr);
    
        slog(Slog::levelDebug)<<"p";
    
        if (write(audio_fd, pack->getData(), pack->getBodyLength()) == -1) {
        perror("audio write failed");
        continue;
        }
        _play = 2; //pack->getBodyLength()/7650;
    
      }
    }
    
    void soundLayer::descHandler(Event e)
    {
      if (!_record)
        return;
    
      audio_buf_info info; 
      ioctl(audio_fd, SNDCTL_DSP_GETISPACE, &info);
    
      if (info.bytes == 0) {
        //    slog(Slog::levelWarning)<<"we are called with no data available!?\n";
        return;
      }
    
      // where will this packet be deleted?
      char* sample = new char[info.bytes+2];
      int size;
      //    std::cerr<<"space: "<<info.bytes<<" ";
      if ((size = read(audio_fd, sample+2, info.bytes)) <= 0) {  
        perror("audio read failed");  
        delete sample;
        return;
      }
      *((unsigned short*)(sample)) = (unsigned short) size;
    
      // adjust record level, if this is a bullshit windows driver only card 
      if (recordLevel) {
        unsigned short* adjustSamples = (unsigned short*) sample+2;
        for(unsigned int i=0; i < (unsigned int)(info.bytes/2); ++i)
          adjustSamples[i] = adjustSamples[i] << recordLevel; // exponential level
      }
    
      transferItem tr;
      tr.setdata(new ICI(0,0,size,2,false));
      tr.setRaw(sample,size+2);
    
      slog(Slog::levelDebug)<<"r";
    
      Layer* to = UpperLayer.findLayer();
    
      //  tr.getItem()->print();
    
      if (to)
        to->transferFromLower(tr,0);
    }
    
    char soundLayer::openToRecord()
    {
    }
    
    char soundLayer::closeRecord()
    {
    }
    
    void soundLayer::controlPlaneMsgHandler(controlMsg& msg)
    {
      /**** start/stop recording *******/
    
      if (msg.getName() == "Record") {
        RecordMsg* am = dynamic_cast<RecordMsg*>(&msg);
        if (am && (am->status == RecordMsg::start))
          openToRecord();
        else
          if (am && (am->status == RecordMsg::stop))
    	closeRecord();
          else
    	slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    
      /**** close soundcard for playing *******/
    
      if (msg.getName() == "closePlay") {
        closePlayMsg* am = dynamic_cast<closePlayMsg*>(&msg);
        if (am)
          closePlay();
        else
          slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    
      /**** set record level ******/
    
      if (msg.getName() == "setRecordLevel") {
        recordLevelMsg* am = dynamic_cast<recordLevelMsg*>(&msg);
        if (am){
          if (am->recordLevel < 5)
    	recordLevel = am->recordLevel;
        }
        else
          slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    
      /**** set record device ******/
    
      if (msg.getName() == "setDevice") {
        setDeviceMsg* am = dynamic_cast<setDeviceMsg*>(&msg);
        if (am)
          setDeviceName(am->device);
        else
          slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    
      /**** request availabel byte for output *****/
    
      if (msg.getName() == "getOutBufferSize") {
        bufferInfoMsg* bi = dynamic_cast<bufferInfoMsg*>(&msg);
        if (bi) {
          audio_buf_info info; 
          if (audio_fd <= 0) {
    	int open_mode = O_RDONLY;
    	int afd;
    	if ((afd = open(devName.c_str(), open_mode, 0)) == -1) {
    	  /* Opening device failed */
    	  //perror(devName.c_str());
    	  bi->size = 0;
    	  return;
    	}
    	else {
    	  ioctl(afd, SNDCTL_DSP_GETOSPACE, &info);
    	  close(afd);
    	}
          }
          else // audio_fd is set!
    	ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
    	
          bi->size = info.bytes;
          slog(Slog::levelDebug)<<"bytes = "<<(int) info.bytes<<oendl;
        }
        else
          slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
      }
    }
    
    


    Dodano po 6 [minuty]:

    Zapomnialem dodac bilblioteke :

    
    #ifndef soundLayer_h
    #define soundLayer_h
    
    #include <string>
    #include "abstractAudioLayer.h"
    
    class soundLayer : public abstractAudioLayer {
    
     protected:
      virtual char openToPlay();
      virtual char closePlay();
      virtual char openToRecord();
      virtual char closeRecord();
    
      virtual void initSchedule();
    
      //! timer will be used to close the soundcard
      /* if a packet arrives and is played at the soundcard,
         it will not be closed automatically, therefor a timeout
         will close the soundcard after a short while. 
         (The same with record) */
      virtual void timerHandler(Event e);
    
      //! description handler to handle soundcard events
      /* this handler is called, if the next sample recorded
         by the soundcard is ready to be transmitted to an
         upper layer.*/
      virtual void descHandler(Event e);
    
      //! Handler to hand out a sample to the soundcard
      /* this handler receives a packet from an upper layer
         to be written to the soundcard. */
      virtual void upperQueueHandler(Event e);
    
     public:
      soundLayer(abstractScheduler* sched = 0);
      ~soundLayer();
    
      virtual Layer* clone()
      {return (new soundLayer(sched)); }
    
      virtual void controlPlaneMsgHandler(controlMsg& msg);
    
    };
    
    #define init_soundLayer layerFactoryObject.addPrototype("soundLayer",new soundLayer());
    
    #endif
    
    
    


    Dodano po 1 [godziny] 7 [minuty]:

    Jest jeszcze kupa dodatkowych rzeczy... Teraz dodalem w sumie bezsensownie...zrobilo sie naprawde skomplikowanie.
  • #21 1650298
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Czas na podsumowanie...

    Ogolnie wprowadzilismy pierwsza sekwencje do programu glownego - zawiera się w nim okolo 10 napisanych bibliotek, plus okolo 12 podprogramow, razem jest tego trochu...

    Nie dziala jeszcze jak powinno, wysyla pakiety, otrzymuje pakiety - ale ich nie prrzetwarza. Mysle, ze juz niedlugo dojdziemy do ladu, moze nawet zamieszcze tutaj conieco :)

    Bardzo pomogliscie - jestem nieslychanie wdzieczny! Przyciski powciskalem, ale na osobna pochwale zasluguje Fantom, ktory bardzo się postaral... Dlatego taki skromny podarek - 50 pkt. :) się nalezy!



    ----------------------------------------
    Wykorzystamy niektore tricki z udostepniongo Kphone - bo z ALSA dojsc do ladu nie jest latwo..

    BARDZO przydatna sprawa !

    http://cvs.wirlab.net/cgi-bin/viewcvs.cgi/kphone/kphone/
  • #22 1662695
    tomaszo
    VIP Zasłużony dla elektroda
    Posty: 4358
    Pomógł: 139
    Ocena: 100
    Udalo sie! Dzis po modyfikacjach wpasowalo u nas i dziala!
    Teraz przechodzimy to samo z funkcja Record...

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy modyfikacji kodu obsługującego dźwięk w systemie Linux z wykorzystaniem ALSA (Advanced Linux Sound Architecture). Zadaniem było zaimplementowanie funkcji open, close, record start, record stop oraz play w oparciu o istniejący kod korzystający z interfejsu dźwiękowego. Problemy obejmowały m.in. brak dostępu do pełnego projektu, trudności z konfiguracją i obsługą urządzenia dźwiękowego, błędy przy odtwarzaniu plików WAV, a także obsługę buforów i synchronizację strumienia audio. Wskazano na konieczność usunięcia nagłówka pliku WAV przed przesłaniem próbek do ALSA oraz prawidłowe ustawienie parametrów sprzętowych (częstotliwość próbkowania, liczba kanałów). Omówiono różnice między trybem blokującym a nieblokującym otwarcia urządzenia oraz znaczenie funkcji snd_pcm_writei(), gdzie ostatni argument to liczba ramek, a nie bajtów. Podkreślono znaczenie monitorowania stanu urządzenia za pomocą snd_pcm_state() i stosowania funkcji snd_pcm_drain() dla poprawnego zakończenia odtwarzania. W toku dyskusji udostępniono fragmenty kodu i linki do dokumentacji ALSA oraz przykładów, co pozwoliło na uruchomienie odtwarzania dźwięku stereo i mono. Ostatecznie udało się zintegrować funkcję odtwarzania w głównym programie, a następnie rozpoczęto prace nad funkcją nagrywania. Wskazano również na wykorzystanie elementów projektu Kphone jako pomocnych trików w pracy z ALSA.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA