[C#] Goede implementatie Callback_Window

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Ik heb problemen met de opbouw van een stuk code dat geluid sampelt met de waveIn API. Ik gebruik CALLBACK_WINDOW om te reageren op binnenkomende data. Het is nog belangrijk om te vermelden dat waveInReset de invoer stopzet en alle huidige buffers leeg laat terugkomen.

Wat ik nu heb (vereenvoudigd):
C#: Form1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  private WaveInSampler sampler = new WaveInSampler(...);

  protected override void WndProc(ref Message m)
  {
    switch (m.Msg)
    {
      case WinAudio.MM_WIM_OPEN:
        Console.WriteLine("WaveIn device opened.");
        break;
      case WinAudio.MM_WIM_CLOSE:
        Console.WriteLine("WaveIn device closed.");
        break;
      case WinAudio.MM_WIM_DATA:
        sampler.handleData(m);
        break;
      default:
        base.WndProc(ref m);
        break;
      }
   }

  private void Start()
  {
    Stop();

    sampler.start();
  }

  private void Stop()
  {
    sampler.stop();
  }


C#: WaveInSampler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
        private List<Buffer> buffers = new List<Buffer>();

        public void start()
        {
            // Open the specified waveIn device
            WinAudio.waveInOpen(..., WinAudio.CALLBACK_WINDOW);

            // Start recording. Notice nothing will actually happen
            // as long as no buffer is supplied to the device.
            WinAudio.waveInStart(hwavein);

            running = true;

            // Add first buffers
            addBuffer(hwavein);
            addBuffer(hwavein);
        }

        public void stop()
        {
            if (running)
            {
                WinAudio.waveInReset(hwavein);
                clearAllBuffers();
                WinAudio.waveInClose(hwavein);
                running = false;
            }
        }

        private void addBuffer(IntPtr hwave)
        {
            //Don't create a new buffer if not running anymore
            if (!running)
                return;

            Buffer buf = new Buffer(...);
            buffers.Add(buf);
        }

        public void handleData(Message m)
        {
            if (running)
            {
                // immediately add a new buffer
                addBuffer(hwavein);

                // received buffer must be first in the list
                Buffer buf = buffers[0];

                // process buffer only if its filled properly
                if (buf.complete)
                {
                  // do stuff
                }

                buf.Dispose();
                buffers.RemoveAt(0);
            }
            else
            {
                // Empty buffer returned by waveInReset function... ignore
            }
        }

        ~WaveInSampler()
        {
            stop();
        }


Het probleem ontstaat als de gebruiker iets doet (bijvoorbeeld de bitrate aanpassen) waardoor de sampler wordt gestopt en onmiddelijk weer wordt gestart. Mijn applicatie zou dan moeten wachten met herstarten tot het stoppen is voltooid, dwz totdat alle lege buffers zijn teruggekomen via een Windows Message. Momenteel loopt dat door elkaar (waveInStart wordt gecalled voordat de lege buffers terug zijn) wat voor problemen zorgt.

Hoe moet ik dit nou netjes opzetten? Ik zou met wat boolean flags kunnen werken (starting, restarting, stopping, etc), maar mijn ervaring is dat dat snel een rommeltje wordt. Ik denk dat de netste oplossing is om met threads te werken, maar dan krijg ik problemen met data access.

Kunnen jullie me de goede kant op sturen?

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • HawVer
  • Registratie: Februari 2002
  • Laatst online: 13-09 16:51
Ik vind het geen duidelijk verhaal. Zolang de code in WaveInSampler draait zal de applicatie geen windows messages behandelen. Wat wil je precies? Wil je de code WaveInSampler draaien in een aparte thread? Bekijk anders eens de BackgroundWorker class. Dat is een vereenvoudigde versie van een thread die je kan starten en stoppen en die zijn voortgang kan teruggeven aan de aanroepen class.

http://hawvie.deviantart.com/


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Als je de code bekijkt zie je dat er geen "code blijft draaien in WaveInSampler". De main thread kan dus gewoon Windows messages afhandelen. De huidige code werkt eigenlijk prima, totdat ik stop() en start() achter elkaar call, zoals in de startpost is beschreven.

Die backgroundWorker class lijkt me sowieso interessant, daar zal ik vast naar kijken.


edit: ik heb het nu toch maar opgelost met boolean vlaggetjes. Het is oerlelijk maar het werkt...
C#: Form1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WinAudio.MM_WIM_OPEN:
                    Console.WriteLine("Open");
                    sampler.setRunningStatus(true);
                    break;
                case WinAudio.MM_WIM_CLOSE:
                    Console.WriteLine("Close");                    
                    sampler.setRunningStatus(false);
                    break;
                case WinAudio.MM_WIM_DATA:
                    sampler.handleData(m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }


C#: WaveInSampler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
        private bool running;
        private bool restart;

        private List<Buffer> buffers = new List<Buffer>();

        public void setRunningStatus(bool newStatus)
        {
            running = newStatus;
            if (!running && restart)
            {
                restart = false;
                rc = start(...);
            }
        }

        public void start()
        {
            if (running)
            {
                Console.WriteLine("Already Running. Queueing restart.");
                restart = true;
                return();
            }
            // Open the specified waveIn device
            WinAudio.waveInOpen(..., WinAudio.CALLBACK_WINDOW);

            // Start recording. Notice nothing will actually happen
            // as long as no buffer is supplied to the device.
            WinAudio.waveInStart(hwavein);

            running = true;

            // Add first buffers
            addBuffer(hwavein);
            addBuffer(hwavein);
        }

        public void stop()
        {
            if (running)
            {
                WinAudio.waveInReset(hwavein);
                clearAllBuffers();
                WinAudio.waveInClose(hwavein);
            }
        } 


Als er errors zouden optreden loopt de hele boel in de soep maar dat is een zorg voor later :P

[ Voor 76% gewijzigd door Bozozo op 14-01-2010 16:40 ]

TabCinema : NiftySplit