Statistics
| Branch: | Revision:

root / audio / dsoundaudio.c @ 1d14ffa9

History | View | Annotate | Download (26.4 kB)

1
/*
2
 * QEMU DirectSound audio driver
3
 *
4
 * Copyright (c) 2005 Vassili Karpov (malc)
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
/*
26
 * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
27
 */
28

    
29
#include "vl.h"
30

    
31
#define AUDIO_CAP "dsound"
32
#include "audio_int.h"
33

    
34
#include <windows.h>
35
#include <objbase.h>
36
#include <dsound.h>
37

    
38
/* #define DEBUG_DSOUND */
39

    
40
struct full_fmt {
41
    int freq;
42
    int nchannels;
43
    audfmt_e fmt;
44
};
45

    
46
static struct {
47
    int lock_retries;
48
    int restore_retries;
49
    int getstatus_retries;
50
    int set_primary;
51
    int bufsize_in;
52
    int bufsize_out;
53
    struct full_fmt full_fmt;
54
    int latency_millis;
55
} conf = {
56
    1,
57
    1,
58
    1,
59
    0,
60
    16384,
61
    16384,
62
    {
63
        44100,
64
        2,
65
        AUD_FMT_S16
66
    },
67
    10
68
};
69

    
70
typedef struct {
71
    LPDIRECTSOUND dsound;
72
    LPDIRECTSOUNDCAPTURE dsound_capture;
73
    LPDIRECTSOUNDBUFFER dsound_primary_buffer;
74
    struct full_fmt fmt;
75
} dsound;
76

    
77
static dsound glob_dsound;
78

    
79
typedef struct {
80
    HWVoiceOut hw;
81
    LPDIRECTSOUNDBUFFER dsound_buffer;
82
    DWORD old_pos;
83
    int first_time;
84
#ifdef DEBUG_DSOUND
85
    DWORD old_ppos;
86
    DWORD played;
87
    DWORD mixed;
88
#endif
89
} DSoundVoiceOut;
90

    
91
typedef struct {
92
    HWVoiceIn hw;
93
    int first_time;
94
    LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
95
} DSoundVoiceIn;
96

    
97
static void dsound_log_hresult (HRESULT hr)
98
{
99
    const char *str = "BUG";
100

    
101
    switch (hr) {
102
    case DS_OK:
103
        str = "The method succeeded";
104
        break;
105
#ifdef DS_NO_VIRTUALIZATION
106
    case DS_NO_VIRTUALIZATION:
107
        str = "The buffer was created, but another 3D algorithm was substituted";
108
        break;
109
#endif
110
#ifdef DS_INCOMPLETE
111
    case DS_INCOMPLETE:
112
        str = "The method succeeded, but not all the optional effects were obtained";
113
        break;
114
#endif
115
#ifdef DSERR_ACCESSDENIED
116
    case DSERR_ACCESSDENIED:
117
        str = "The request failed because access was denied";
118
        break;
119
#endif
120
#ifdef DSERR_ALLOCATED
121
    case DSERR_ALLOCATED:
122
        str = "The request failed because resources, such as a priority level, were already in use by another caller";
123
        break;
124
#endif
125
#ifdef DSERR_ALREADYINITIALIZED
126
    case DSERR_ALREADYINITIALIZED:
127
        str = "The object is already initialized";
128
        break;
129
#endif
130
#ifdef DSERR_BADFORMAT
131
    case DSERR_BADFORMAT:
132
        str = "The specified wave format is not supported";
133
        break;
134
#endif
135
#ifdef DSERR_BADSENDBUFFERGUID
136
    case DSERR_BADSENDBUFFERGUID:
137
        str = "The GUID specified in an audiopath file does not match a valid mix-in buffer";
138
        break;
139
#endif
140
#ifdef DSERR_BUFFERLOST
141
    case DSERR_BUFFERLOST:
142
        str = "The buffer memory has been lost and must be restored";
143
        break;
144
#endif
145
#ifdef DSERR_BUFFERTOOSMALL
146
    case DSERR_BUFFERTOOSMALL:
147
        str = "The buffer size is not great enough to enable effects processing";
148
        break;
149
#endif
150
#ifdef DSERR_CONTROLUNAVAIL
151
    case DSERR_CONTROLUNAVAIL:
152
        str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC";
153
        break;
154
#endif
155
#ifdef DSERR_DS8_REQUIRED
156
    case DSERR_DS8_REQUIRED:
157
        str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface";
158
        break;
159
#endif
160
#ifdef DSERR_FXUNAVAILABLE
161
    case DSERR_FXUNAVAILABLE:
162
        str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software";
163
        break;
164
#endif
165
#ifdef DSERR_GENERIC
166
    case DSERR_GENERIC :
167
        str = "An undetermined error occurred inside the DirectSound subsystem";
168
        break;
169
#endif
170
#ifdef DSERR_INVALIDCALL
171
    case DSERR_INVALIDCALL:
172
        str = "This function is not valid for the current state of this object";
173
        break;
174
#endif
175
#ifdef DSERR_INVALIDPARAM
176
    case DSERR_INVALIDPARAM:
177
        str = "An invalid parameter was passed to the returning function";
178
        break;
179
#endif
180
#ifdef DSERR_NOAGGREGATION
181
    case DSERR_NOAGGREGATION:
182
        str = "The object does not support aggregation";
183
        break;
184
#endif
185
#ifdef DSERR_NODRIVER
186
    case DSERR_NODRIVER:
187
        str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID";
188
        break;
189
#endif
190
#ifdef DSERR_NOINTERFACE
191
    case DSERR_NOINTERFACE:
192
        str = "The requested COM interface is not available";
193
        break;
194
#endif
195
#ifdef DSERR_OBJECTNOTFOUND
196
    case DSERR_OBJECTNOTFOUND:
197
        str = "The requested object was not found";
198
        break;
199
#endif
200
#ifdef DSERR_OTHERAPPHASPRIO
201
    case DSERR_OTHERAPPHASPRIO:
202
        str = "Another application has a higher priority level, preventing this call from succeeding";
203
        break;
204
#endif
205
#ifdef DSERR_OUTOFMEMORY
206
    case DSERR_OUTOFMEMORY:
207
        str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request";
208
        break;
209
#endif
210
#ifdef DSERR_PRIOLEVELNEEDED
211
    case DSERR_PRIOLEVELNEEDED:
212
        str = "A cooperative level of DSSCL_PRIORITY or higher is required";
213
        break;
214
#endif
215
#ifdef DSERR_SENDLOOP
216
    case DSERR_SENDLOOP:
217
        str = "A circular loop of send effects was detected";
218
        break;
219
#endif
220
#ifdef DSERR_UNINITIALIZED
221
    case DSERR_UNINITIALIZED:
222
        str = "The Initialize method has not been called or has not been called successfully before other methods were called";
223
        break;
224
#endif
225
#ifdef DSERR_UNSUPPORTED
226
    case DSERR_UNSUPPORTED:
227
        str = "The function called is not supported at this time";
228
        break;
229
#endif
230
    default:
231
        AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr);
232
        return;
233
    }
234

    
235
    AUD_log (AUDIO_CAP, "Reason: %s\n", str);
236
}
237

    
238
static void GCC_FMT_ATTR (2, 3) dsound_logerr (
239
    HRESULT hr,
240
    const char *fmt,
241
    ...
242
    )
243
{
244
    va_list ap;
245

    
246
    va_start (ap, fmt);
247
    AUD_vlog (AUDIO_CAP, fmt, ap);
248
    va_end (ap);
249

    
250
    dsound_log_hresult (hr);
251
}
252

    
253
static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
254
    HRESULT hr,
255
    const char *typ,
256
    const char *fmt,
257
    ...
258
    )
259
{
260
    va_list ap;
261

    
262
    AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ);
263
    va_start (ap, fmt);
264
    AUD_vlog (AUDIO_CAP, fmt, ap);
265
    va_end (ap);
266

    
267
    dsound_log_hresult (hr);
268
}
269

    
270
static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis)
271
{
272
    return (millis * info->bytes_per_second) / 1000;
273
}
274

    
275
#ifdef DEBUG_DSOUND
276
static void print_wave_format (WAVEFORMATEX *wfx)
277
{
278
    dolog ("tag             = %d\n", wfx->wFormatTag);
279
    dolog ("nChannels       = %d\n", wfx->nChannels);
280
    dolog ("nSamplesPerSec  = %ld\n", wfx->nSamplesPerSec);
281
    dolog ("nAvgBytesPerSec = %ld\n", wfx->nAvgBytesPerSec);
282
    dolog ("nBlockAlign     = %d\n", wfx->nBlockAlign);
283
    dolog ("wBitsPerSample  = %d\n", wfx->wBitsPerSample);
284
    dolog ("cbSize          = %d\n", wfx->cbSize);
285
}
286
#endif
287

    
288
static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
289
{
290
    HRESULT hr;
291
    int i;
292

    
293
    for (i = 0; i < conf.restore_retries; ++i) {
294
        hr = IDirectSoundBuffer_Restore (dsb);
295

    
296
        switch (hr) {
297
        case DS_OK:
298
            return 0;
299

    
300
        case DSERR_BUFFERLOST:
301
            continue;
302

    
303
        default:
304
            dsound_logerr (hr, "Can not restore playback buffer\n");
305
            return -1;
306
        }
307
    }
308

    
309
    dolog ("%d attempts to restore playback buffer failed\n", i);
310
    return -1;
311
}
312

    
313
static int waveformat_from_full_fmt (WAVEFORMATEX *wfx,
314
                                     struct full_fmt *full_fmt)
315
{
316
    memset (wfx, 0, sizeof (*wfx));
317

    
318
    wfx->wFormatTag = WAVE_FORMAT_PCM;
319
    wfx->nChannels = full_fmt->nchannels;
320
    wfx->nSamplesPerSec = full_fmt->freq;
321
    wfx->nAvgBytesPerSec = full_fmt->freq << (full_fmt->nchannels == 2);
322
    wfx->nBlockAlign = 1 << (full_fmt->nchannels == 2);
323
    wfx->cbSize = 0;
324

    
325
    switch (full_fmt->fmt) {
326
    case AUD_FMT_S8:
327
        wfx->wBitsPerSample = 8;
328
        break;
329

    
330
    case AUD_FMT_U8:
331
        wfx->wBitsPerSample = 8;
332
        break;
333

    
334
    case AUD_FMT_S16:
335
        wfx->wBitsPerSample = 16;
336
        wfx->nAvgBytesPerSec <<= 1;
337
        wfx->nBlockAlign <<= 1;
338
        break;
339

    
340
    case AUD_FMT_U16:
341
        wfx->wBitsPerSample = 16;
342
        wfx->nAvgBytesPerSec <<= 1;
343
        wfx->nBlockAlign <<= 1;
344
        break;
345

    
346
    default:
347
        dolog ("Internal logic error: Bad audio format %d\n",
348
               full_fmt->freq);
349
        return -1;
350
    }
351

    
352
    return 0;
353
}
354

    
355
static int waveformat_to_full_fmt (WAVEFORMATEX *wfx,
356
                                   struct full_fmt *full_fmt)
357
{
358
    if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
359
        dolog ("Invalid wave format, tag is not PCM, but %d\n",
360
               wfx->wFormatTag);
361
        return -1;
362
    }
363

    
364
    if (!wfx->nSamplesPerSec) {
365
        dolog ("Invalid wave format, frequency is zero\n");
366
        return -1;
367
    }
368
    full_fmt->freq = wfx->nSamplesPerSec;
369

    
370
    switch (wfx->nChannels) {
371
    case 1:
372
        full_fmt->nchannels = 1;
373
        break;
374

    
375
    case 2:
376
        full_fmt->nchannels = 2;
377
        break;
378

    
379
    default:
380
        dolog (
381
            "Invalid wave format, number of channels is not 1 or 2, but %d\n",
382
            wfx->nChannels
383
            );
384
        return -1;
385
    }
386

    
387
    switch (wfx->wBitsPerSample) {
388
    case 8:
389
        full_fmt->fmt = AUD_FMT_U8;
390
        break;
391

    
392
    case 16:
393
        full_fmt->fmt = AUD_FMT_S16;
394
        break;
395

    
396
    default:
397
        dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n",
398
               wfx->wBitsPerSample);
399
        return -1;
400
    }
401

    
402
    return 0;
403
}
404

    
405
#include "dsound_template.h"
406
#define DSBTYPE_IN
407
#include "dsound_template.h"
408
#undef DSBTYPE_IN
409

    
410
static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp)
411
{
412
    HRESULT hr;
413
    int i;
414

    
415
    for (i = 0; i < conf.getstatus_retries; ++i) {
416
        hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
417
        if (FAILED (hr)) {
418
            dsound_logerr (hr, "Can not get playback buffer status\n");
419
            return -1;
420
        }
421

    
422
        if (*statusp & DSERR_BUFFERLOST) {
423
            if (dsound_restore_out (dsb)) {
424
                return -1;
425
            }
426
            continue;
427
        }
428
        break;
429
    }
430

    
431
    return 0;
432
}
433

    
434
static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb,
435
                                 DWORD *statusp)
436
{
437
    HRESULT hr;
438

    
439
    hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp);
440
    if (FAILED (hr)) {
441
        dsound_logerr (hr, "Can not get capture buffer status\n");
442
        return -1;
443
    }
444

    
445
    return 0;
446
}
447

    
448
static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
449
{
450
    int src_len1 = dst_len;
451
    int src_len2 = 0;
452
    int pos = hw->rpos + dst_len;
453
    st_sample_t *src1 = hw->mix_buf + hw->rpos;
454
    st_sample_t *src2 = NULL;
455

    
456
    if (pos > hw->samples) {
457
        src_len1 = hw->samples - hw->rpos;
458
        src2 = hw->mix_buf;
459
        src_len2 = dst_len - src_len1;
460
        pos = src_len2;
461
    }
462

    
463
    if (src_len1) {
464
        hw->clip (dst, src1, src_len1);
465
        mixeng_clear (src1, src_len1);
466
    }
467

    
468
    if (src_len2) {
469
        dst = advance (dst, src_len1 << hw->info.shift);
470
        hw->clip (dst, src2, src_len2);
471
        mixeng_clear (src2, src_len2);
472
    }
473

    
474
    hw->rpos = pos % hw->samples;
475
}
476

    
477
static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb)
478
{
479
    int err;
480
    LPVOID p1, p2;
481
    DWORD blen1, blen2, len1, len2;
482

    
483
    err = dsound_lock_out (
484
        dsb,
485
        &hw->info,
486
        0,
487
        hw->samples << hw->info.shift,
488
        &p1, &p2,
489
        &blen1, &blen2,
490
        1
491
        );
492
    if (err) {
493
        return;
494
    }
495

    
496
    len1 = blen1 >> hw->info.shift;
497
    len2 = blen2 >> hw->info.shift;
498

    
499
#ifdef DEBUG_DSOUND
500
    dolog ("clear %p,%ld,%ld %p,%ld,%ld\n",
501
           p1, blen1, len1,
502
           p2, blen2, len2);
503
#endif
504

    
505
    if (p1 && len1) {
506
        audio_pcm_info_clear_buf (&hw->info, p1, len1);
507
    }
508

    
509
    if (p2 && len2) {
510
        audio_pcm_info_clear_buf (&hw->info, p2, len2);
511
    }
512

    
513
    dsound_unlock_out (dsb, p1, p2, blen1, blen2);
514
}
515

    
516
static void dsound_close (dsound *s)
517
{
518
    HRESULT hr;
519

    
520
    if (s->dsound_primary_buffer) {
521
        hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer);
522
        if (FAILED (hr)) {
523
            dsound_logerr (hr, "Can not release primary buffer\n");
524
        }
525
        s->dsound_primary_buffer = NULL;
526
    }
527
}
528

    
529
static int dsound_open (dsound *s)
530
{
531
    int err;
532
    HRESULT hr;
533
    WAVEFORMATEX wfx;
534
    DSBUFFERDESC dsbd;
535
    HWND hwnd;
536

    
537
    hwnd = GetForegroundWindow ();
538
    hr = IDirectSound_SetCooperativeLevel (
539
        s->dsound,
540
        hwnd,
541
        DSSCL_PRIORITY
542
        );
543

    
544
    if (FAILED (hr)) {
545
        dsound_logerr (hr, "Can not set cooperative level for window %p\n",
546
                       hwnd);
547
        return -1;
548
    }
549

    
550
    if (!conf.set_primary) {
551
        return 0;
552
    }
553

    
554
    err = waveformat_from_full_fmt (&wfx, &conf.full_fmt);
555
    if (err) {
556
        return -1;
557
    }
558

    
559
    memset (&dsbd, 0, sizeof (dsbd));
560
    dsbd.dwSize = sizeof (dsbd);
561
    dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
562
    dsbd.dwBufferBytes = 0;
563
    dsbd.lpwfxFormat = NULL;
564

    
565
    hr = IDirectSound_CreateSoundBuffer (
566
        s->dsound,
567
        &dsbd,
568
        &s->dsound_primary_buffer,
569
        NULL
570
        );
571
    if (FAILED (hr)) {
572
        dsound_logerr (hr, "Can not create primary playback buffer\n");
573
        return -1;
574
    }
575

    
576
    hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx);
577
    if (FAILED (hr)) {
578
        dsound_logerr (hr, "Can not set primary playback buffer format\n");
579
    }
580

    
581
    hr = IDirectSoundBuffer_GetFormat (
582
        s->dsound_primary_buffer,
583
        &wfx,
584
        sizeof (wfx),
585
        NULL
586
        );
587
    if (FAILED (hr)) {
588
        dsound_logerr (hr, "Can not get primary playback buffer format\n");
589
        goto fail0;
590
    }
591

    
592
#ifdef DEBUG_DSOUND
593
    dolog ("Primary\n");
594
    print_wave_format (&wfx);
595
#endif
596

    
597
    err = waveformat_to_full_fmt (&wfx, &s->fmt);
598
    if (err) {
599
        goto fail0;
600
    }
601

    
602
    return 0;
603

    
604
 fail0:
605
    dsound_close (s);
606
    return -1;
607
}
608

    
609
static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
610
{
611
    HRESULT hr;
612
    DWORD status;
613
    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
614
    LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
615

    
616
    if (!dsb) {
617
        dolog ("Attempt to control voice without a buffer\n");
618
        return 0;
619
    }
620

    
621
    switch (cmd) {
622
    case VOICE_ENABLE:
623
        if (dsound_get_status_out (dsb, &status)) {
624
            return -1;
625
        }
626

    
627
        if (status & DSBSTATUS_PLAYING) {
628
            dolog ("warning: voice is already playing\n");
629
            return 0;
630
        }
631

    
632
        dsound_clear_sample (hw, dsb);
633

    
634
        hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
635
        if (FAILED (hr)) {
636
            dsound_logerr (hr, "Can not start playing buffer\n");
637
            return -1;
638
        }
639
        break;
640

    
641
    case VOICE_DISABLE:
642
        if (dsound_get_status_out (dsb, &status)) {
643
            return -1;
644
        }
645

    
646
        if (status & DSBSTATUS_PLAYING) {
647
            hr = IDirectSoundBuffer_Stop (dsb);
648
            if (FAILED (hr)) {
649
                dsound_logerr (hr, "Can not stop playing buffer\n");
650
                return -1;
651
            }
652
        }
653
        else {
654
            dolog ("warning: voice is not playing\n");
655
        }
656
        break;
657
    }
658
    return 0;
659
}
660

    
661
static int dsound_write (SWVoiceOut *sw, void *buf, int len)
662
{
663
    return audio_pcm_sw_write (sw, buf, len);
664
}
665

    
666
static int dsound_run_out (HWVoiceOut *hw)
667
{
668
    int err;
669
    HRESULT hr;
670
    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
671
    LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
672
    int live, len, hwshift;
673
    DWORD blen1, blen2;
674
    DWORD len1, len2;
675
    DWORD decr;
676
    DWORD wpos, ppos, old_pos;
677
    LPVOID p1, p2;
678

    
679
    if (!dsb) {
680
        dolog ("Attempt to run empty with playback buffer\n");
681
        return 0;
682
    }
683

    
684
    hwshift = hw->info.shift;
685

    
686
    live = audio_pcm_hw_get_live_out (hw);
687

    
688
    hr = IDirectSoundBuffer_GetCurrentPosition (
689
        dsb,
690
        &ppos,
691
        ds->first_time ? &wpos : NULL
692
        );
693
    if (FAILED (hr)) {
694
        dsound_logerr (hr, "Can not get playback buffer position\n");
695
        return 0;
696
    }
697

    
698
    len = live << hwshift;
699

    
700
    if (ds->first_time) {
701
        if (conf.latency_millis) {
702
            DWORD cur_blat = audio_ring_dist (wpos, ppos, hw->bufsize);
703

    
704
            ds->first_time = 0;
705
            old_pos = wpos;
706
            old_pos +=
707
                millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat;
708
            old_pos %= hw->bufsize;
709
            old_pos &= ~hw->info.align;
710
        }
711
        else {
712
            old_pos = wpos;
713
        }
714
#ifdef DEBUG_DSOUND
715
        ds->played = 0;
716
        ds->mixed = 0;
717
#endif
718
    }
719
    else {
720
        if (ds->old_pos == ppos) {
721
#ifdef DEBUG_DSOUND
722
            dolog ("old_pos == ppos\n");
723
#endif
724
            return 0;
725
        }
726

    
727
#ifdef DEBUG_DSOUND
728
        ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize);
729
#endif
730
        old_pos = ds->old_pos;
731
    }
732

    
733
    if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
734
        len = ppos - old_pos;
735
    }
736
    else {
737
        if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->bufsize))) {
738
            len = hw->bufsize - old_pos + ppos;
739
        }
740
    }
741

    
742
    if (audio_bug (AUDIO_FUNC, len < 0 || len > hw->bufsize)) {
743
        dolog ("len=%d hw->bufsize=%d old_pos=%ld ppos=%ld\n",
744
               len, hw->bufsize, old_pos, ppos);
745
        return 0;
746
    }
747

    
748
    len &= ~hw->info.align;
749
    if (!len) {
750
        return 0;
751
    }
752

    
753
#ifdef DEBUG_DSOUND
754
    ds->old_ppos = ppos;
755
#endif
756
    err = dsound_lock_out (
757
        dsb,
758
        &hw->info,
759
        old_pos,
760
        len,
761
        &p1, &p2,
762
        &blen1, &blen2,
763
        0
764
        );
765
    if (err) {
766
        return 0;
767
    }
768

    
769
    len1 = blen1 >> hwshift;
770
    len2 = blen2 >> hwshift;
771
    decr = len1 + len2;
772

    
773
    if (p1 && len1) {
774
        dsound_write_sample (hw, p1, len1);
775
    }
776

    
777
    if (p2 && len2) {
778
        dsound_write_sample (hw, p2, len2);
779
    }
780

    
781
    dsound_unlock_out (dsb, p1, p2, blen1, blen2);
782
    ds->old_pos = (old_pos + (decr << hwshift)) % hw->bufsize;
783

    
784
#ifdef DEBUG_DSOUND
785
    ds->mixed += decr << hwshift;
786

    
787
    dolog ("played %lu mixed %lu diff %ld sec %f\n",
788
           ds->played,
789
           ds->mixed,
790
           ds->mixed - ds->played,
791
           abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second);
792
#endif
793
    return decr;
794
}
795

    
796
static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
797
{
798
    HRESULT hr;
799
    DWORD status;
800
    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
801
    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
802

    
803
    if (!dscb) {
804
        dolog ("Attempt to control capture voice without a buffer\n");
805
        return -1;
806
    }
807

    
808
    switch (cmd) {
809
    case VOICE_ENABLE:
810
        if (dsound_get_status_in (dscb, &status)) {
811
            return -1;
812
        }
813

    
814
        if (status & DSCBSTATUS_CAPTURING) {
815
            dolog ("warning: voice is already capturing\n");
816
            return 0;
817
        }
818

    
819
        /* clear ?? */
820

    
821
        hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
822
        if (FAILED (hr)) {
823
            dsound_logerr (hr, "Can not start capturing\n");
824
            return -1;
825
        }
826
        break;
827

    
828
    case VOICE_DISABLE:
829
        if (dsound_get_status_in (dscb, &status)) {
830
            return -1;
831
        }
832

    
833
        if (status & DSCBSTATUS_CAPTURING) {
834
            hr = IDirectSoundCaptureBuffer_Stop (dscb);
835
            if (FAILED (hr)) {
836
                dsound_logerr (hr, "Can not stop capturing\n");
837
                return -1;
838
            }
839
        }
840
        else {
841
            dolog ("warning: voice is not capturing\n");
842
        }
843
        break;
844
    }
845
    return 0;
846
}
847

    
848
static int dsound_read (SWVoiceIn *sw, void *buf, int len)
849
{
850
    return audio_pcm_sw_read (sw, buf, len);
851
}
852

    
853
static int dsound_run_in (HWVoiceIn *hw)
854
{
855
    int err;
856
    HRESULT hr;
857
    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
858
    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
859
    int live, len, dead;
860
    DWORD blen1, blen2;
861
    DWORD len1, len2;
862
    DWORD decr;
863
    DWORD cpos, rpos;
864
    LPVOID p1, p2;
865
    int hwshift;
866

    
867
    if (!dscb) {
868
        dolog ("Attempt to run without capture buffer\n");
869
        return 0;
870
    }
871

    
872
    hwshift = hw->info.shift;
873

    
874
    live = audio_pcm_hw_get_live_in (hw);
875
    dead = hw->samples - live;
876
    if (!dead) {
877
        return 0;
878
    }
879

    
880
    hr = IDirectSoundCaptureBuffer_GetCurrentPosition (
881
        dscb,
882
        &cpos,
883
        ds->first_time ? &rpos : NULL
884
        );
885
    if (FAILED (hr)) {
886
        dsound_logerr (hr, "Can not get capture buffer position\n");
887
        return 0;
888
    }
889

    
890
    if (ds->first_time) {
891
        ds->first_time = 0;
892
        if (rpos & hw->info.align) {
893
            ldebug ("warning: misaligned capture read position %ld(%d)\n",
894
                    rpos, hw->info.align);
895
        }
896
        hw->wpos = rpos >> hwshift;
897
    }
898

    
899
    if (cpos & hw->info.align) {
900
        ldebug ("warning: misaligned capture position %ld(%d)\n",
901
                cpos, hw->info.align);
902
    }
903
    cpos >>= hwshift;
904

    
905
    len = audio_ring_dist (cpos, hw->wpos, hw->samples);
906
    if (!len) {
907
        return 0;
908
    }
909
    len = audio_MIN (len, dead);
910

    
911
    err = dsound_lock_in (
912
        dscb,
913
        &hw->info,
914
        hw->wpos << hwshift,
915
        len << hwshift,
916
        &p1,
917
        &p2,
918
        &blen1,
919
        &blen2,
920
        0
921
        );
922
    if (err) {
923
        return 0;
924
    }
925

    
926
    len1 = blen1 >> hwshift;
927
    len2 = blen2 >> hwshift;
928
    decr = len1 + len2;
929

    
930
    if (p1 && len1) {
931
        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
932
    }
933

    
934
    if (p2 && len2) {
935
        hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
936
    }
937

    
938
    dsound_unlock_in (dscb, p1, p2, blen1, blen2);
939
    hw->wpos = (hw->wpos + decr) % hw->samples;
940
    return decr;
941
}
942

    
943
static void dsound_audio_fini (void *opaque)
944
{
945
    HRESULT hr;
946
    dsound *s = opaque;
947

    
948
    if (!s->dsound) {
949
        return;
950
    }
951

    
952
    hr = IDirectSound_Release (s->dsound);
953
    if (FAILED (hr)) {
954
        dsound_logerr (hr, "Can not release DirectSound\n");
955
    }
956
    s->dsound = NULL;
957

    
958
    if (!s->dsound_capture) {
959
        return;
960
    }
961

    
962
    hr = IDirectSoundCapture_Release (s->dsound_capture);
963
    if (FAILED (hr)) {
964
        dsound_logerr (hr, "Can not release DirectSoundCapture\n");
965
    }
966
    s->dsound_capture = NULL;
967
}
968

    
969
static void *dsound_audio_init (void)
970
{
971
    int err;
972
    HRESULT hr;
973
    dsound *s = &glob_dsound;
974

    
975
    hr = CoInitialize (NULL);
976
    if (FAILED (hr)) {
977
        dsound_logerr (hr, "Can not initialize COM\n");
978
        return NULL;
979
    }
980

    
981
    hr = CoCreateInstance (
982
        &CLSID_DirectSound,
983
        NULL,
984
        CLSCTX_ALL,
985
        &IID_IDirectSound,
986
        (void **) &s->dsound
987
        );
988
    if (FAILED (hr)) {
989
        dsound_logerr (hr, "Can not create DirectSound instance\n");
990
        return NULL;
991
    }
992

    
993
    hr = IDirectSound_Initialize (s->dsound, NULL);
994
    if (FAILED (hr)) {
995
        dsound_logerr (hr, "Can not initialize DirectSound\n");
996
        return NULL;
997
    }
998

    
999
    hr = CoCreateInstance (
1000
        &CLSID_DirectSoundCapture,
1001
        NULL,
1002
        CLSCTX_ALL,
1003
        &IID_IDirectSoundCapture,
1004
        (void **) &s->dsound_capture
1005
        );
1006
    if (FAILED (hr)) {
1007
        dsound_logerr (hr, "Can not create DirectSoundCapture instance\n");
1008
    }
1009
    else {
1010
        hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
1011
        if (FAILED (hr)) {
1012
            dsound_logerr (hr, "Can not initialize DirectSoundCapture\n");
1013

    
1014
            hr = IDirectSoundCapture_Release (s->dsound_capture);
1015
            if (FAILED (hr)) {
1016
                dsound_logerr (hr, "Can not release DirectSoundCapture\n");
1017
            }
1018
            s->dsound_capture = NULL;
1019
        }
1020
    }
1021

    
1022
    err = dsound_open (s);
1023
    if (err) {
1024
        dsound_audio_fini (s);
1025
        return NULL;
1026
    }
1027

    
1028
    return s;
1029
}
1030

    
1031
static struct audio_option dsound_options[] = {
1032
    {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries,
1033
     "Number of times to attempt locking the buffer", NULL, 0},
1034
    {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries,
1035
     "Number of times to attempt restoring the buffer", NULL, 0},
1036
    {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries,
1037
     "Number of times to attempt getting status of the buffer", NULL, 0},
1038
    {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary,
1039
     "Set the parameters of primary buffer", NULL, 0},
1040
    {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis,
1041
     "(undocumented)", NULL, 0},
1042
    {"PRIMARY_FREQ", AUD_OPT_INT, &conf.full_fmt.freq,
1043
     "Primary buffer frequency", NULL, 0},
1044
    {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.full_fmt.nchannels,
1045
     "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0},
1046
    {"PRIMARY_FMT", AUD_OPT_FMT, &conf.full_fmt.fmt,
1047
     "Primary buffer format", NULL, 0},
1048
    {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out,
1049
     "(undocumented)", NULL, 0},
1050
    {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in,
1051
     "(undocumented)", NULL, 0},
1052
    {NULL, 0, NULL, NULL, NULL, 0}
1053
};
1054

    
1055
static struct audio_pcm_ops dsound_pcm_ops = {
1056
    dsound_init_out,
1057
    dsound_fini_out,
1058
    dsound_run_out,
1059
    dsound_write,
1060
    dsound_ctl_out,
1061

    
1062
    dsound_init_in,
1063
    dsound_fini_in,
1064
    dsound_run_in,
1065
    dsound_read,
1066
    dsound_ctl_in
1067
};
1068

    
1069
struct audio_driver dsound_audio_driver = {
1070
    INIT_FIELD (name           = ) "dsound",
1071
    INIT_FIELD (descr          = )
1072
    "DirectSound http://wikipedia.org/wiki/DirectSound",
1073
    INIT_FIELD (options        = ) dsound_options,
1074
    INIT_FIELD (init           = ) dsound_audio_init,
1075
    INIT_FIELD (fini           = ) dsound_audio_fini,
1076
    INIT_FIELD (pcm_ops        = ) &dsound_pcm_ops,
1077
    INIT_FIELD (can_be_default = ) 1,
1078
    INIT_FIELD (max_voices_out = ) INT_MAX,
1079
    INIT_FIELD (max_voices_in  = ) 1,
1080
    INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut),
1081
    INIT_FIELD (voice_size_in  = ) sizeof (DSoundVoiceIn)
1082
};