Ignore:
Timestamp:
Apr 3, 2006 9:43:36 AM (18 years ago)
Author:
bennylp
Message:

Added DirectSound? sound implementation

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/dsound.c

    r121 r371  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
     19#include <pjmedia/sound.h> 
     20#include <pjmedia/errno.h> 
     21#include <pj/assert.h> 
     22#include <pj/log.h> 
     23#include <pj/os.h> 
     24#include <pj/string.h> 
     25 
     26#if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_WIN32_DIRECT_SOUND 
     27 
    1928#ifdef _MSC_VER 
    20 //# pragma warning(disable: 4201)   // non-standard extension: nameless struct/union 
    21 # pragma warning(push, 3) 
     29#   pragma warning(push, 3) 
    2230#endif 
    23 #include <pj/config.h> 
    24 #include <pj/os.h> 
    25 #include <pj/log.h> 
    26  
     31 
     32#include <windows.h> 
     33#include <mmsystem.h> 
    2734#include <dsound.h> 
    28 #include <stdio.h> 
    29 #include <assert.h> 
    30 #include <pjmedia/sound.h> 
    31  
    32 #define THIS_FILE   "dsound.c" 
    33  
    34 /* 
    35  * Constants 
    36  */ 
    37 #define PACKET_BUFFER_COUNT 4 
    38  
    39 typedef struct PJ_Direct_Sound_Device PJ_Direct_Sound_Device; 
    40  
    41  
    42 /* 
    43  * DirectSound Factory Operations 
    44  */ 
    45 static pj_status_t dsound_init(void); 
    46 static const char *dsound_get_name(void); 
    47 static pj_status_t dsound_destroy(void); 
    48 static pj_status_t dsound_enum_devices(int *count, char *dev_names[]); 
    49 static pj_status_t dsound_create_dev(const char *dev_name, pj_snd_dev *dev); 
    50 static pj_status_t dsound_destroy_dev(pj_snd_dev *dev); 
    51  
    52  
    53 /* 
    54  * DirectSound Device Operations 
    55  */ 
    56 static pj_status_t dsound_dev_open( pj_snd_dev *dev, pj_snd_role_t role ); 
    57 static pj_status_t dsound_dev_close( pj_snd_dev *dev ); 
    58 static pj_status_t dsound_dev_play( pj_snd_dev *dev ); 
    59 static pj_status_t dsound_dev_record( pj_snd_dev *dev ); 
    60  
    61 /* 
    62  * Utils. 
    63  */ 
    64 static pj_status_t dsound_destroy_dsound_dev( PJ_Direct_Sound_Device *dsDev ); 
    65  
    66  
    67 static pj_snd_dev_factory dsound_factory =  
    68 { 
    69     &dsound_init, 
    70     &dsound_get_name, 
    71     &dsound_destroy, 
    72     &dsound_enum_devices, 
    73     &dsound_create_dev, 
    74     &dsound_destroy_dev 
     35 
     36#ifdef _MSC_VER 
     37#   pragma warning(pop) 
     38#endif 
     39 
     40 
     41 
     42#define THIS_FILE           "dsound.c" 
     43#define BITS_PER_SAMPLE     16 
     44#define BYTES_PER_SAMPLE    (BITS_PER_SAMPLE/8) 
     45 
     46#define MAX_PACKET_BUFFER_COUNT     32 
     47#define DEFAULT_BUFFER_COUNT        5 
     48 
     49 
     50 
     51/* Individual DirectSound capture/playback stream descriptor */ 
     52struct dsound_stream 
     53{ 
     54    union  
     55    { 
     56        struct 
     57        { 
     58            LPDIRECTSOUND           lpDs; 
     59            LPDIRECTSOUNDBUFFER     lpDsBuffer; 
     60        } play; 
     61 
     62        struct 
     63        { 
     64            LPDIRECTSOUNDCAPTURE        lpDs; 
     65            LPDIRECTSOUNDCAPTUREBUFFER  lpDsBuffer; 
     66        } capture; 
     67    } ds; 
     68 
     69    HANDLE                  hEvent; 
     70    LPDIRECTSOUNDNOTIFY     lpDsNotify; 
     71    DWORD                   dwBytePos; 
     72    DWORD                   dwDsBufferSize; 
     73    pj_timestamp            timestamp; 
    7574}; 
    7675 
    77 static struct pj_snd_dev_op dsound_dev_op =  
    78 { 
    79     &dsound_dev_open, 
    80     &dsound_dev_close, 
    81     &dsound_dev_play, 
    82     &dsound_dev_record 
     76 
     77/* Sound stream.    */ 
     78struct pjmedia_snd_stream 
     79{ 
     80    pjmedia_dir             dir;                /**< Sound direction.       */ 
     81    pj_pool_t              *pool;               /**< Memory pool.           */ 
     82   
     83    pjmedia_snd_rec_cb      rec_cb;             /**< Capture callback.      */ 
     84    pjmedia_snd_play_cb     play_cb;            /**< Playback callback.     */ 
     85    void                   *user_data;          /**< Application data.      */ 
     86 
     87    struct dsound_stream    play_strm;          /**< Playback stream.       */ 
     88    struct dsound_stream    rec_strm;           /**< Capture stream.        */ 
     89 
     90    void                   *buffer;             /**< Temp. frame buffer.    */ 
     91    unsigned                samples_per_frame;  /**< Samples per frame.     */ 
     92 
     93    pj_thread_t            *thread;             /**< Thread handle.         */ 
     94    pj_bool_t               thread_quit_flag;   /**< Quit signal to thread  */ 
    8395}; 
    8496 
    85 #define DSOUND_TYPE_PLAYER      1 
    86 #define DSOUND_TYPE_RECORDER    2 
    87  
    88 typedef struct Direct_Sound_Descriptor 
    89 { 
    90     int                 type; 
    91  
    92     LPDIRECTSOUND       lpDsPlay; 
    93     LPDIRECTSOUNDBUFFER lpDsPlayBuffer; 
    94  
    95     LPDIRECTSOUNDCAPTURE        lpDsCapture; 
    96     LPDIRECTSOUNDCAPTUREBUFFER  lpDsCaptureBuffer; 
    97  
    98     LPDIRECTSOUNDNOTIFY lpDsNotify; 
    99     HANDLE              hEvent; 
    100     HANDLE              hThread; 
    101     HANDLE              hStartEvent; 
    102     DWORD               dwThreadQuitFlag; 
    103     pj_thread_desc      thread_desc; 
    104     pj_thread_t        *thread; 
    105 } Direct_Sound_Descriptor; 
    106  
    107 struct PJ_Direct_Sound_Device 
    108 { 
    109     Direct_Sound_Descriptor playDesc; 
    110     Direct_Sound_Descriptor recDesc; 
    111 }; 
    112  
    113 struct Thread_Param 
    114 { 
    115     pj_snd_dev      *dev; 
    116     Direct_Sound_Descriptor *desc; 
    117 }; 
    118  
    119 PJ_DEF(pj_snd_dev_factory*) pj_dsound_get_factory() 
    120 { 
    121     return &dsound_factory; 
    122 } 
    123  
    124 /* 
    125  * Init DirectSound. 
    126  */ 
    127 static pj_status_t dsound_init(void) 
    128 { 
    129     /* Nothing to do. */ 
    130     return 0; 
    131 } 
    132  
    133 /* 
    134  * Get the name of the factory. 
    135  */ 
    136 static const char *dsound_get_name(void) 
    137 { 
    138     return "DirectSound"; 
    139 } 
    140  
    141 /* 
    142  * Destroy DirectSound. 
    143  */ 
    144 static pj_status_t dsound_destroy(void) 
    145 { 
    146     /* TODO: clean up devices in case application haven't done it. */ 
    147     return 0; 
    148 } 
    149  
    150 /* 
    151  * Enum devices in the system. 
    152  */ 
    153 static pj_status_t dsound_enum_devices(int *count, char *dev_names[]) 
    154 { 
    155     dev_names[0] = "DirectSound Default Device"; 
    156     *count = 1; 
    157     return 0; 
    158 } 
    159  
    160 /* 
    161  * Create DirectSound device. 
    162  */ 
    163 static pj_status_t dsound_create_dev(const char *dev_name, pj_snd_dev *dev) 
    164 { 
    165     PJ_Direct_Sound_Device *dsDev; 
    166  
    167     /* TODO: create based on the name. */ 
    168     PJ_TODO(DSOUND_CREATE_DEVICE_BY_NAME); 
    169      
    170     /* Create DirectSound structure. */ 
    171     dsDev = malloc(sizeof(*dsDev)); 
    172     if (!dsDev) { 
    173         PJ_LOG(1,(THIS_FILE, "No memory to allocate device!")); 
    174         return -1; 
    175     } 
    176     memset(dsDev, 0, sizeof(*dsDev)); 
    177  
    178     /* Associate DirectSound device with device. */ 
    179     dev->device = dsDev; 
    180     dev->op = &dsound_dev_op; 
    181  
    182     return 0; 
    183 } 
    184  
    185 /* 
    186  * Destroy DirectSound device. 
    187  */ 
    188 static pj_status_t dsound_destroy_dev( pj_snd_dev *dev ) 
    189 { 
    190     if (dev->device) { 
    191         free(dev->device); 
    192         dev->device = NULL; 
    193     } 
    194     return 0; 
    195 } 
    196  
    197 static void dsound_release_descriptor(Direct_Sound_Descriptor *desc) 
    198 { 
    199     if (desc->lpDsNotify) 
    200         IDirectSoundNotify_Release( desc->lpDsNotify ); 
    201      
    202     if (desc->hEvent) 
    203         CloseHandle(desc->hEvent); 
    204  
    205     if (desc->lpDsPlayBuffer) 
    206         IDirectSoundBuffer_Release( desc->lpDsPlayBuffer ); 
    207  
    208     if (desc->lpDsPlay) 
    209         IDirectSound_Release( desc->lpDsPlay ); 
    210  
    211     if (desc->lpDsCaptureBuffer) 
    212         IDirectSoundCaptureBuffer_Release(desc->lpDsCaptureBuffer); 
    213  
    214     if (desc->lpDsCapture) 
    215         IDirectSoundCapture_Release(desc->lpDsCapture); 
    216 } 
    217  
    218 /* 
    219  * Destroy DirectSound resources. 
    220  */ 
    221 static pj_status_t dsound_destroy_dsound_dev( PJ_Direct_Sound_Device *dsDev ) 
    222 { 
    223     dsound_release_descriptor( &dsDev->playDesc ); 
    224     dsound_release_descriptor( &dsDev->recDesc ); 
    225     memset(dsDev, 0, sizeof(*dsDev)); 
    226     return 0; 
    227 } 
    228  
    229 static void init_waveformatex (PCMWAVEFORMAT *pcmwf, pj_snd_dev *dev) 
    230 { 
    231     memset(pcmwf, 0, sizeof(PCMWAVEFORMAT));  
     97 
     98static pj_pool_factory *pool_factory; 
     99 
     100 
     101static void init_waveformatex (PCMWAVEFORMAT *pcmwf,  
     102                               unsigned clock_rate, 
     103                               unsigned channel_count) 
     104{ 
     105    pj_memset(pcmwf, 0, sizeof(PCMWAVEFORMAT));  
    232106    pcmwf->wf.wFormatTag = WAVE_FORMAT_PCM;  
    233     pcmwf->wf.nChannels = 1; 
    234     pcmwf->wf.nSamplesPerSec = dev->param.samples_per_sec; 
    235     pcmwf->wf.nBlockAlign = dev->param.bytes_per_frame; 
    236     pcmwf->wf.nAvgBytesPerSec =  
    237         dev->param.samples_per_sec * dev->param.bytes_per_frame; 
    238     pcmwf->wBitsPerSample = dev->param.bits_per_sample; 
    239 } 
     107    pcmwf->wf.nChannels = (pj_uint16_t)channel_count; 
     108    pcmwf->wf.nSamplesPerSec = clock_rate; 
     109    pcmwf->wf.nBlockAlign = (pj_uint16_t)(channel_count * BYTES_PER_SAMPLE); 
     110    pcmwf->wf.nAvgBytesPerSec = clock_rate * channel_count * BYTES_PER_SAMPLE; 
     111    pcmwf->wBitsPerSample = BITS_PER_SAMPLE; 
     112} 
     113 
    240114 
    241115/* 
    242116 * Initialize DirectSound player device. 
    243117 */ 
    244 static pj_status_t dsound_init_player (pj_snd_dev *dev) 
     118static pj_status_t init_player_stream( struct dsound_stream *ds_strm, 
     119                                       unsigned clock_rate, 
     120                                       unsigned channel_count, 
     121                                       unsigned samples_per_frame, 
     122                                       unsigned buffer_count) 
    245123{ 
    246124    HRESULT hr; 
     
    248126    PCMWAVEFORMAT pcmwf;  
    249127    DSBUFFERDESC dsbdesc; 
    250     DSBPOSITIONNOTIFY dsPosNotify[PACKET_BUFFER_COUNT]; 
     128    DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT]; 
     129    unsigned bytes_per_frame; 
    251130    unsigned i; 
    252     PJ_Direct_Sound_Device *dsDev = dev->device; 
    253  
    254     /* 
    255      * Check parameters. 
    256      */ 
    257     if (dev->play_cb == NULL) { 
    258         assert(0); 
    259         return -1; 
    260     } 
    261     if (dev->device == NULL) { 
    262         assert(0); 
    263         return -1; 
    264     } 
    265  
    266     PJ_LOG(4,(THIS_FILE, "Creating DirectSound player device")); 
     131 
     132 
     133    PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL); 
    267134 
    268135    /* 
    269136     * Create DirectSound device. 
    270137     */ 
    271     hr = DirectSoundCreate(NULL, &dsDev->playDesc.lpDsPlay, NULL); 
     138    hr = DirectSoundCreate(NULL, &ds_strm->ds.play.lpDs, NULL); 
    272139    if (FAILED(hr)) 
    273         goto on_error; 
     140        return PJ_RETURN_OS_ERROR(hr); 
    274141 
    275142    hwnd = GetForegroundWindow(); 
     
    277144        hwnd = GetDesktopWindow(); 
    278145    }     
    279     hr = IDirectSound_SetCooperativeLevel( dsDev->playDesc.lpDsPlay, hwnd,  
     146    hr = IDirectSound_SetCooperativeLevel( ds_strm->ds.play.lpDs, hwnd,  
    280147                                           DSSCL_PRIORITY); 
    281148    if FAILED(hr) 
    282         goto on_error; 
     149        return PJ_RETURN_OS_ERROR(hr); 
    283150     
    284151    /* 
    285      * Create DirectSound play buffer. 
    286      */     
    287     // Set up wave format structure.  
    288     init_waveformatex (&pcmwf, dev); 
    289  
    290     // Set up DSBUFFERDESC structure.  
    291     memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));  
     152     * Set up wave format structure for initialize DirectSound play 
     153     * buffer.  
     154     */ 
     155    init_waveformatex(&pcmwf, clock_rate, channel_count); 
     156    bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE; 
     157 
     158    /* Set up DSBUFFERDESC structure. */ 
     159    pj_memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));  
    292160    dsbdesc.dwSize = sizeof(DSBUFFERDESC);  
    293     dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY | 
    294                       DSBCAPS_GETCURRENTPOSITION2; 
    295  
    296     dsbdesc.dwBufferBytes =  
    297         (PACKET_BUFFER_COUNT * dev->param.bytes_per_frame *  
    298          dev->param.frames_per_packet);  
     161    dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY; 
     162    /* DSBCAPS_GETCURRENTPOSITION2 */ 
     163 
     164    dsbdesc.dwBufferBytes = buffer_count * bytes_per_frame; 
    299165    dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;  
    300166 
    301     // Create buffer.  
    302     hr = IDirectSound_CreateSoundBuffer(dsDev->playDesc.lpDsPlay, &dsbdesc,  
    303                                         &dsDev->playDesc.lpDsPlayBuffer, NULL);  
     167    /* 
     168     * Create DirectSound playback buffer.  
     169     */ 
     170    hr = IDirectSound_CreateSoundBuffer(ds_strm->ds.play.lpDs, &dsbdesc,  
     171                                        &ds_strm->ds.play.lpDsBuffer, NULL);  
    304172    if (FAILED(hr) ) 
    305         goto on_error; 
     173        return PJ_RETURN_OS_ERROR(hr); 
    306174 
    307175    /* 
    308176     * Create event for play notification. 
    309177     */ 
    310     dsDev->playDesc.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL); 
    311     if (dsDev->playDesc.hEvent == NULL) 
    312         goto on_error; 
     178    ds_strm->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL); 
     179    if (ds_strm->hEvent == NULL) 
     180        return pj_get_os_error(); 
    313181 
    314182    /* 
    315183     * Setup notification for play. 
    316184     */ 
    317     hr = IDirectSoundBuffer_QueryInterface( dsDev->playDesc.lpDsPlayBuffer,  
     185    hr = IDirectSoundBuffer_QueryInterface( ds_strm->ds.play.lpDsBuffer,  
    318186                                            &IID_IDirectSoundNotify,  
    319                                             (LPVOID *)&dsDev->playDesc.lpDsNotify);  
     187                                            (LPVOID *)&ds_strm->lpDsNotify);  
    320188    if (FAILED(hr)) 
    321         goto on_error; 
    322  
    323      
    324     for (i=0; i<PACKET_BUFFER_COUNT; ++i) { 
    325         dsPosNotify[i].dwOffset = i * dev->param.bytes_per_frame *  
    326                                   dev->param.frames_per_packet; 
    327         dsPosNotify[i].hEventNotify = dsDev->playDesc.hEvent; 
    328     } 
    329      
    330     hr = IDirectSoundNotify_SetNotificationPositions( dsDev->playDesc.lpDsNotify,  
    331                                                       PACKET_BUFFER_COUNT,  
     189        return PJ_RETURN_OS_ERROR(hr); 
     190 
     191     
     192    for (i=0; i<buffer_count; ++i) { 
     193        dsPosNotify[i].dwOffset = i * bytes_per_frame; 
     194        dsPosNotify[i].hEventNotify = ds_strm->hEvent; 
     195    } 
     196     
     197    hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify,  
     198                                                      buffer_count,  
    332199                                                      dsPosNotify); 
    333200    if (FAILED(hr)) 
    334         goto on_error; 
     201        return PJ_RETURN_OS_ERROR(hr); 
     202 
     203 
     204    hr = IDirectSoundBuffer_SetCurrentPosition(ds_strm->ds.play.lpDsBuffer, 0); 
     205    if (FAILED(hr)) 
     206        return PJ_RETURN_OS_ERROR(hr); 
     207 
     208 
     209    ds_strm->dwBytePos = 0; 
     210    ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame; 
     211    ds_strm->timestamp.u64 = 0; 
     212 
    335213 
    336214    /* Done setting up play device. */ 
    337     PJ_LOG(4,(THIS_FILE, "DirectSound player device created")); 
    338  
    339     return 0; 
    340  
    341 on_error: 
    342     PJ_LOG(2,(THIS_FILE, "Error creating player device, hresult=0x%x", hr)); 
    343     dsound_destroy_dsound_dev(dsDev); 
    344     return -1; 
    345 } 
     215    PJ_LOG(5,(THIS_FILE, " DirectSound player stream initialized")); 
     216 
     217    return PJ_SUCCESS; 
     218} 
     219 
    346220 
    347221/* 
    348222 * Initialize DirectSound recorder device 
    349223 */ 
    350 static pj_status_t dsound_init_recorder (pj_snd_dev *dev) 
     224static pj_status_t init_capture_stream( struct dsound_stream *ds_strm, 
     225                                        unsigned clock_rate, 
     226                                        unsigned channel_count, 
     227                                        unsigned samples_per_frame, 
     228                                        unsigned buffer_count) 
    351229{ 
    352230    HRESULT hr; 
    353231    PCMWAVEFORMAT pcmwf;  
    354232    DSCBUFFERDESC dscbdesc; 
    355     DSBPOSITIONNOTIFY dsPosNotify[PACKET_BUFFER_COUNT]; 
     233    DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT]; 
     234    unsigned bytes_per_frame; 
    356235    unsigned i; 
    357     PJ_Direct_Sound_Device *dsDev = dev->device; 
    358  
    359     /* 
    360      * Check parameters. 
    361      */ 
    362     if (dev->rec_cb == NULL) { 
    363         assert(0); 
    364         return -1; 
    365     } 
    366     if (dev->device == NULL) { 
    367         assert(0); 
    368         return -1; 
    369     } 
    370  
    371     PJ_LOG(4,(THIS_FILE, "Creating DirectSound recorder device")); 
     236 
     237 
     238    PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL); 
     239 
    372240 
    373241    /* 
    374242     * Creating recorder device. 
    375243     */ 
    376     hr = DirectSoundCaptureCreate(NULL, &dsDev->recDesc.lpDsCapture, NULL); 
     244    hr = DirectSoundCaptureCreate(NULL, &ds_strm->ds.capture.lpDs, NULL); 
    377245    if (FAILED(hr)) 
    378         goto on_error; 
    379  
    380     /* Init wave format */ 
    381     init_waveformatex (&pcmwf, dev); 
     246        return PJ_RETURN_OS_ERROR(hr); 
     247 
     248 
     249    /* Init wave format to initialize buffer */ 
     250    init_waveformatex( &pcmwf, clock_rate, channel_count); 
     251    bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE; 
    382252 
    383253    /*  
     
    385255     * to play buffer creation earlier. 
    386256     */ 
    387     memset(&dscbdesc, 0, sizeof(DSCBUFFERDESC)); 
     257    pj_memset(&dscbdesc, 0, sizeof(DSCBUFFERDESC)); 
    388258    dscbdesc.dwSize = sizeof(DSCBUFFERDESC);  
    389259    dscbdesc.dwFlags = DSCBCAPS_WAVEMAPPED ; 
    390     dscbdesc.dwBufferBytes =  
    391         (PACKET_BUFFER_COUNT * dev->param.bytes_per_frame *  
    392          dev->param.frames_per_packet);  
     260    dscbdesc.dwBufferBytes = buffer_count * bytes_per_frame;  
    393261    dscbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;  
    394262 
    395     hr = IDirectSoundCapture_CreateCaptureBuffer( dsDev->recDesc.lpDsCapture, 
     263    hr = IDirectSoundCapture_CreateCaptureBuffer( ds_strm->ds.capture.lpDs, 
    396264                                                  &dscbdesc,  
    397                                                   &dsDev->recDesc.lpDsCaptureBuffer,  
     265                                                  &ds_strm->ds.capture.lpDsBuffer, 
    398266                                                  NULL); 
    399267    if (FAILED(hr)) 
    400         goto on_error; 
     268        return PJ_RETURN_OS_ERROR(hr); 
    401269 
    402270    /* 
    403271     * Create event for play notification. 
    404272     */ 
    405     dsDev->recDesc.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL); 
    406     if (dsDev->recDesc.hEvent == NULL) 
    407         goto on_error; 
     273    ds_strm->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL); 
     274    if (ds_strm->hEvent == NULL) 
     275        return pj_get_os_error(); 
    408276 
    409277    /* 
    410278     * Setup notifications for recording. 
    411279     */ 
    412     hr = IDirectSoundCaptureBuffer_QueryInterface( dsDev->recDesc.lpDsCaptureBuffer,  
     280    hr = IDirectSoundCaptureBuffer_QueryInterface( ds_strm->ds.capture.lpDsBuffer,  
    413281                                                   &IID_IDirectSoundNotify,  
    414                                                    (LPVOID *)&dsDev->recDesc.lpDsNotify);  
     282                                                   (LPVOID *)&ds_strm->lpDsNotify);  
    415283    if (FAILED(hr)) 
    416         goto on_error; 
    417  
    418      
    419     for (i=0; i<PACKET_BUFFER_COUNT; ++i) { 
    420         dsPosNotify[i].dwOffset = i * dev->param.bytes_per_frame *  
    421                                   dev->param.frames_per_packet; 
    422         dsPosNotify[i].hEventNotify = dsDev->recDesc.hEvent; 
    423     } 
    424      
    425     hr = IDirectSoundNotify_SetNotificationPositions( dsDev->recDesc.lpDsNotify,  
    426                                                       PACKET_BUFFER_COUNT,  
     284        return PJ_RETURN_OS_ERROR(hr); 
     285 
     286     
     287    for (i=0; i<buffer_count; ++i) { 
     288        dsPosNotify[i].dwOffset = i * bytes_per_frame; 
     289        dsPosNotify[i].hEventNotify = ds_strm->hEvent; 
     290    } 
     291     
     292    hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify,  
     293                                                      buffer_count,  
    427294                                                      dsPosNotify); 
    428295    if (FAILED(hr)) 
    429         goto on_error; 
     296        return PJ_RETURN_OS_ERROR(hr); 
     297 
     298    hr = IDirectSoundCaptureBuffer_GetCurrentPosition( ds_strm->ds.capture.lpDsBuffer,  
     299                                                       NULL, &ds_strm->dwBytePos ); 
     300    if (FAILED(hr)) 
     301        return PJ_RETURN_OS_ERROR(hr); 
     302 
     303    ds_strm->timestamp.u64 = 0; 
     304    ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame; 
    430305 
    431306    /* Done setting up recorder device. */ 
    432     PJ_LOG(4,(THIS_FILE, "DirectSound recorder device created")); 
    433  
    434     return 0; 
    435  
    436 on_error: 
    437     PJ_LOG(4,(THIS_FILE, "Error creating device, hresult=%d", hr)); 
    438     dsound_destroy_dsound_dev(dsDev); 
    439     return -1; 
    440 } 
    441  
    442 /* 
    443  * Initialize DirectSound device. 
    444  */ 
    445 static pj_status_t dsound_dev_open( pj_snd_dev *dev, pj_snd_role_t role ) 
    446 { 
    447     PJ_Direct_Sound_Device *dsDev = dev->device; 
    448     pj_status_t status; 
    449  
    450     dsDev->playDesc.type = DSOUND_TYPE_PLAYER; 
    451     dsDev->recDesc.type = DSOUND_TYPE_RECORDER; 
    452  
    453     if (role & PJ_SOUND_PLAYER) { 
    454         status = dsound_init_player (dev); 
    455         if (status != 0) 
    456             return status; 
    457     } 
    458  
    459     if (role & PJ_SOUND_RECORDER) { 
    460         status = dsound_init_recorder (dev); 
    461         if (status != 0) 
    462             return status; 
    463     } 
    464  
    465     return 0; 
    466 } 
    467  
    468 /* 
    469  * Close DirectSound device. 
    470  */ 
    471 static pj_status_t dsound_dev_close( pj_snd_dev *dev ) 
    472 { 
    473     PJ_LOG(4,(THIS_FILE, "Closing DirectSound device")); 
    474  
    475     if (dev->device) { 
    476         PJ_Direct_Sound_Device *dsDev = dev->device; 
    477  
    478         if (dsDev->playDesc.hThread) { 
    479             PJ_LOG(4,(THIS_FILE, "Stopping DirectSound player")); 
    480             dsDev->playDesc.dwThreadQuitFlag = 1; 
    481             SetEvent(dsDev->playDesc.hEvent); 
    482             if (WaitForSingleObject(dsDev->playDesc.hThread, 1000) != WAIT_OBJECT_0) { 
    483                 PJ_LOG(4,(THIS_FILE, "Timed out waiting player thread to quit")); 
    484                 TerminateThread(dsDev->playDesc.hThread, -1); 
    485                 IDirectSoundBuffer_Stop( dsDev->playDesc.lpDsPlayBuffer ); 
    486             } 
    487              
    488             pj_thread_destroy (dsDev->playDesc.thread); 
    489         } 
    490  
    491         if (dsDev->recDesc.hThread) { 
    492             PJ_LOG(4,(THIS_FILE, "Stopping DirectSound recorder")); 
    493             dsDev->recDesc.dwThreadQuitFlag = 1; 
    494             SetEvent(dsDev->recDesc.hEvent); 
    495             if (WaitForSingleObject(dsDev->recDesc.hThread, 1000) != WAIT_OBJECT_0) { 
    496                 PJ_LOG(4,(THIS_FILE, "Timed out waiting recorder thread to quit")); 
    497                 TerminateThread(dsDev->recDesc.hThread, -1); 
    498                 IDirectSoundCaptureBuffer_Stop( dsDev->recDesc.lpDsCaptureBuffer ); 
    499             } 
    500              
    501             pj_thread_destroy (dsDev->recDesc.thread); 
    502         } 
    503  
    504         dsound_destroy_dsound_dev( dev->device ); 
    505         dev->op = NULL; 
    506     } 
    507  
    508     PJ_LOG(4,(THIS_FILE, "DirectSound device closed")); 
    509     return 0; 
    510 } 
     307    PJ_LOG(5,(THIS_FILE, " DirectSound capture stream initialized")); 
     308 
     309    return PJ_SUCCESS; 
     310} 
     311 
     312 
    511313 
    512314static BOOL AppReadDataFromBuffer(LPDIRECTSOUNDCAPTUREBUFFER lpDsb, // The buffer. 
     
    584386 * Player thread. 
    585387 */ 
    586 static DWORD WINAPI dsound_dev_thread(void *arg) 
    587 { 
    588     struct Thread_Param *param = arg; 
    589     pj_snd_dev *dev = param->dev; 
    590     Direct_Sound_Descriptor *desc = param->desc; 
    591     unsigned bytes_per_pkt = dev->param.bytes_per_frame * 
    592                              dev->param.frames_per_packet; 
    593     unsigned samples_per_pkt = dev->param.samples_per_frame * 
    594                                dev->param.frames_per_packet; 
    595     void *buffer = NULL; 
    596     DWORD size; 
     388static int dsound_dev_thread(void *arg) 
     389{ 
     390    pjmedia_snd_stream *strm = arg; 
     391    HANDLE events[2]; 
     392    unsigned eventCount; 
    597393    pj_status_t status; 
    598     DWORD sample_pos; 
    599     DWORD byte_pos; 
    600     DWORD buffer_size =  
    601         (PACKET_BUFFER_COUNT * dev->param.bytes_per_frame *  
    602          dev->param.frames_per_packet); 
    603     HRESULT hr; 
    604  
    605     PJ_LOG(4,(THIS_FILE, "DirectSound thread starting")); 
    606  
    607     /* Allocate buffer for sound data */ 
    608     buffer = malloc(bytes_per_pkt); 
    609     if (!buffer) { 
    610         PJ_LOG(1,(THIS_FILE, "Unable to allocate packet buffer!")); 
    611         return (DWORD)-1; 
    612     } 
    613  
    614     desc->thread = pj_thread_register ("dsound", desc->thread_desc); 
    615     if (desc->thread == NULL) 
    616         return (DWORD)-1; 
    617  
    618     /* 
    619      * Start playing or recording! 
    620      */ 
    621     if (desc->type == DSOUND_TYPE_PLAYER) { 
    622         hr = IDirectSoundBuffer_SetCurrentPosition( desc->lpDsPlayBuffer, 0); 
    623         if (FAILED(hr)) { 
    624             PJ_LOG(1,(THIS_FILE, "DirectSound play: SetCurrentPosition() error %d", hr)); 
    625             goto on_error; 
    626         } 
    627  
    628         hr = IDirectSoundBuffer_Play(desc->lpDsPlayBuffer, 0, 0, DSBPLAY_LOOPING); 
    629         if (FAILED(hr)) { 
    630             PJ_LOG(1,(THIS_FILE, "DirectSound: Play() error %d", hr)); 
    631             goto on_error; 
    632         } 
    633     } else { 
    634         hr = IDirectSoundCaptureBuffer_Start(desc->lpDsCaptureBuffer, DSCBSTART_LOOPING ); 
    635         if (FAILED(hr)) { 
    636             PJ_LOG(1,(THIS_FILE, "DirectSound: Record() error %d", hr)); 
    637             goto on_error; 
    638         } 
    639     } 
    640  
    641     /* 
    642      * Reset initial positions. 
    643      */ 
    644     byte_pos = 0xFFFFFFFF; 
    645     sample_pos = 0; 
    646  
    647     /* 
    648      * Wait to get the first notification. 
    649      */ 
    650     if (WaitForSingleObject(desc->hEvent, 100) != WAIT_OBJECT_0) { 
    651         PJ_LOG(1,(THIS_FILE, "DirectSound: error getting notification")); 
    652         goto on_error; 
    653     } 
    654  
    655          
    656     /* Get initial byte position. */ 
    657     if (desc->type == DSOUND_TYPE_PLAYER) { 
    658         hr = IDirectSoundBuffer_GetCurrentPosition( desc->lpDsPlayBuffer,  
    659                                                     NULL, &byte_pos ); 
    660         if (FAILED(hr)) { 
    661             PJ_LOG(1,(THIS_FILE, "DirectSound: unable to get " 
    662                                  "position, err %d", hr)); 
    663             goto on_error; 
    664         } 
    665     } else { 
    666         hr = IDirectSoundCaptureBuffer_GetCurrentPosition( desc->lpDsCaptureBuffer,  
    667                                                            NULL, &byte_pos ); 
    668         if (FAILED(hr)) { 
    669             PJ_LOG(1,(THIS_FILE, "DirectSound: unable to get " 
    670                                  "position, err %d", hr)); 
    671             goto on_error; 
    672         } 
    673     } 
    674  
    675     /* Signal main thread that we're running. */ 
    676     assert( desc->hStartEvent ); 
    677     SetEvent( desc->hStartEvent ); 
     394 
     395 
     396    eventCount = 0; 
     397    if (strm->dir & PJMEDIA_DIR_PLAYBACK) 
     398        events[eventCount++] = strm->play_strm.hEvent; 
     399    if (strm->dir & PJMEDIA_DIR_CAPTURE) 
     400        events[eventCount++] = strm->rec_strm.hEvent; 
     401 
     402 
     403    /* Raise self priority */ 
     404    SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 
    678405 
    679406    /* 
     
    682409     * application and write it to DirectSound buffer. 
    683410     */ 
    684     do { 
     411    while (!strm->thread_quit_flag) { 
    685412         
    686         /* Call callback to get sound data */ 
    687         if (desc->type == DSOUND_TYPE_PLAYER) { 
    688             size = bytes_per_pkt; 
    689             status = (*dev->play_cb)(dev, sample_pos, buffer, &size); 
     413        DWORD rc; 
     414        pjmedia_dir signalled_dir; 
     415        struct dsound_stream *dsound_strm; 
     416 
     417        rc = WaitForMultipleObjects(eventCount, events, FALSE, 100); 
     418        if (rc < WAIT_OBJECT_0 || rc >= WAIT_OBJECT_0+eventCount) 
     419            continue; 
     420 
     421 
     422        if (rc == WAIT_OBJECT_0) { 
     423            if (events[0] == strm->play_strm.hEvent) 
     424                signalled_dir = PJMEDIA_DIR_PLAYBACK; 
     425            else 
     426                signalled_dir = PJMEDIA_DIR_CAPTURE; 
     427        } else { 
     428            if (events[1] == strm->play_strm.hEvent) 
     429                signalled_dir = PJMEDIA_DIR_PLAYBACK; 
     430            else 
     431                signalled_dir = PJMEDIA_DIR_CAPTURE; 
     432        } 
     433 
     434 
     435        if (signalled_dir == PJMEDIA_DIR_PLAYBACK) { 
     436             
     437            dsound_strm = &strm->play_strm; 
     438 
     439            /* Get frame from application. */ 
     440            status = (*strm->play_cb)(strm->user_data,  
     441                                      dsound_strm->timestamp.u32.lo, 
     442                                      strm->buffer, 
     443                                      strm->samples_per_frame *  
     444                                        BYTES_PER_SAMPLE); 
     445            if (status != PJ_SUCCESS) 
     446                break; 
     447 
     448            /* Write to DirectSound buffer. */ 
     449            AppWriteDataToBuffer( dsound_strm->ds.play.lpDsBuffer,  
     450                                  dsound_strm->dwBytePos, 
     451                                  (LPBYTE)strm->buffer,  
     452                                  strm->samples_per_frame * BYTES_PER_SAMPLE); 
     453 
     454        } else { 
     455            BOOL rc; 
     456 
     457            dsound_strm = &strm->rec_strm; 
     458 
     459            /* Capture from DirectSound buffer. */ 
     460            rc = AppReadDataFromBuffer(dsound_strm->ds.capture.lpDsBuffer,  
     461                                       dsound_strm->dwBytePos, 
     462                                       (LPBYTE)strm->buffer,  
     463                                       strm->samples_per_frame *  
     464                                        BYTES_PER_SAMPLE); 
     465             
     466            if (!rc) { 
     467                pj_memset(strm->buffer, 0, strm->samples_per_frame *  
     468                                            BYTES_PER_SAMPLE); 
     469            } 
     470 
     471            /* Call callback */ 
     472            status = (*strm->rec_cb)(strm->user_data,  
     473                                     dsound_strm->timestamp.u32.lo,  
     474                                     strm->buffer,  
     475                                     strm->samples_per_frame *  
     476                                        BYTES_PER_SAMPLE); 
    690477 
    691478            /* Quit thread on error. */ 
    692             if (status != 0) 
     479            if (status != PJ_SUCCESS) 
    693480                break; 
    694481 
    695             /* Write zeroes when we've got nothing from application. */ 
    696             if (size == 0) { 
    697                 memset(buffer, 0, bytes_per_pkt); 
    698                 size = bytes_per_pkt; 
    699             } 
    700  
    701             /* Write to DirectSound buffer. */ 
    702             AppWriteDataToBuffer( desc->lpDsPlayBuffer, byte_pos, 
    703                                   (LPBYTE)buffer, size); 
    704  
    705         } else { 
    706             /* Capture from DirectSound buffer. */ 
    707             size = bytes_per_pkt; 
    708             if (AppReadDataFromBuffer( desc->lpDsCaptureBuffer, byte_pos, 
    709                                        (LPBYTE)buffer, size)) { 
    710  
    711             } else { 
    712                 memset(buffer, 0, size); 
    713             } 
    714  
    715             /* Call callback */ 
    716             status = (*dev->rec_cb)(dev, sample_pos, buffer, size); 
    717  
    718             /* Quit thread on error. */ 
    719             if (status != 0) 
    720                 break; 
    721482        } 
    722483 
    723484        /* Increment position. */ 
    724         byte_pos += size; 
    725         if (byte_pos >= buffer_size) 
    726             byte_pos -= buffer_size; 
    727         sample_pos += samples_per_pkt; 
    728  
    729         while (WaitForSingleObject(desc->hEvent, 500) != WAIT_OBJECT_0 && 
    730                (!desc->dwThreadQuitFlag))  
    731         { 
    732             Sleep(1); 
     485        dsound_strm->dwBytePos += strm->samples_per_frame * BYTES_PER_SAMPLE; 
     486        if (dsound_strm->dwBytePos >= dsound_strm->dwDsBufferSize) 
     487            dsound_strm->dwBytePos -= dsound_strm->dwDsBufferSize; 
     488        dsound_strm->timestamp.u64 += strm->samples_per_frame; 
     489    } 
     490 
     491 
     492    PJ_LOG(5,(THIS_FILE, "DirectSound: thread stopping..")); 
     493 
     494    return 0; 
     495} 
     496 
     497 
     498 
     499/* 
     500 * Init sound library. 
     501 */ 
     502PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory) 
     503{ 
     504    pool_factory = factory; 
     505    return PJ_SUCCESS; 
     506} 
     507 
     508/* 
     509 * Deinitialize sound library. 
     510 */ 
     511PJ_DEF(pj_status_t) pjmedia_snd_deinit(void) 
     512{ 
     513    return PJ_SUCCESS; 
     514} 
     515 
     516/* 
     517 * Get device count. 
     518 */ 
     519PJ_DEF(int) pjmedia_snd_get_dev_count(void) 
     520{ 
     521    return 1; 
     522} 
     523 
     524/* 
     525 * Get device info. 
     526 */ 
     527PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index) 
     528{ 
     529    static pjmedia_snd_dev_info info; 
     530 
     531    PJ_UNUSED_ARG(index); 
     532 
     533    pj_memset(&info, 0, sizeof(info)); 
     534 
     535    info.default_samples_per_sec = 44100; 
     536    info.input_count = 1; 
     537    info.output_count = 1; 
     538    pj_ansi_strcpy(info.name, "Default DirectSound Device"); 
     539 
     540    return &info; 
     541} 
     542 
     543 
     544/* 
     545 * Open stream. 
     546 */ 
     547static pj_status_t open_stream( pjmedia_dir dir, 
     548                                int rec_id, 
     549                                int play_id, 
     550                                unsigned clock_rate, 
     551                                unsigned channel_count, 
     552                                unsigned samples_per_frame, 
     553                                unsigned bits_per_sample, 
     554                                pjmedia_snd_rec_cb rec_cb, 
     555                                pjmedia_snd_play_cb play_cb, 
     556                                void *user_data, 
     557                                pjmedia_snd_stream **p_snd_strm) 
     558{ 
     559    pj_pool_t *pool; 
     560    pjmedia_snd_stream *strm; 
     561    pj_status_t status; 
     562 
     563 
     564    /* Make sure sound subsystem has been initialized with 
     565     * pjmedia_snd_init() 
     566     */ 
     567    PJ_ASSERT_RETURN( pool_factory != NULL, PJ_EINVALIDOP ); 
     568 
     569 
     570    /* Can only support 16bits per sample */ 
     571    PJ_ASSERT_RETURN(bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL); 
     572 
     573    /* Don't support device at present */ 
     574    PJ_UNUSED_ARG(rec_id); 
     575    PJ_UNUSED_ARG(play_id); 
     576     
     577 
     578    /* Create and Initialize stream descriptor */ 
     579    pool = pj_pool_create(pool_factory, "dsound-dev", 1000, 1000, NULL); 
     580    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); 
     581 
     582    strm = pj_pool_zalloc(pool, sizeof(pjmedia_snd_stream)); 
     583    strm->dir = dir; 
     584    strm->pool = pool; 
     585    strm->rec_cb = rec_cb; 
     586    strm->play_cb = play_cb; 
     587    strm->user_data = user_data; 
     588 
     589    strm->samples_per_frame = samples_per_frame; 
     590    strm->buffer = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE); 
     591    if (!strm->buffer) { 
     592        pj_pool_release(pool); 
     593        return PJ_ENOMEM; 
     594    } 
     595 
     596    /* Create player stream */ 
     597    if (dir & PJMEDIA_DIR_PLAYBACK) { 
     598        status = init_player_stream( &strm->play_strm, clock_rate, 
     599                                     channel_count, samples_per_frame, 
     600                                     DEFAULT_BUFFER_COUNT ); 
     601        if (status != PJ_SUCCESS) { 
     602            pjmedia_snd_stream_close(strm); 
     603            return status; 
    733604        } 
    734     } while (!desc->dwThreadQuitFlag); 
    735  
    736  
    737     PJ_LOG(4,(THIS_FILE, "DirectSound: stopping..")); 
    738  
    739     free(buffer); 
    740     if (desc->type == DSOUND_TYPE_PLAYER) { 
    741         IDirectSoundBuffer_Stop( desc->lpDsPlayBuffer ); 
    742     } else { 
    743         IDirectSoundCaptureBuffer_Stop( desc->lpDsCaptureBuffer ); 
    744     } 
    745     return 0; 
    746  
    747 on_error: 
    748     PJ_LOG(4,(THIS_FILE, "DirectSound play stopping")); 
    749  
    750     if (buffer)  
    751         free(buffer); 
    752     if (desc->type == DSOUND_TYPE_PLAYER) { 
    753         IDirectSoundBuffer_Stop( desc->lpDsPlayBuffer ); 
    754     } else { 
    755         IDirectSoundCaptureBuffer_Stop( desc->lpDsCaptureBuffer ); 
    756     } 
    757     desc->dwThreadQuitFlag = 1; 
    758  
    759     /* Signal main thread that we failed to initialize */ 
    760     assert( desc->hStartEvent ); 
    761     SetEvent( desc->hStartEvent ); 
    762     return -1; 
    763 } 
    764  
    765  
    766 /* 
    767  * Generic starter for play/record. 
    768  */ 
    769 static pj_status_t dsound_dev_play_record( pj_snd_dev *dev, 
    770                                            Direct_Sound_Descriptor *desc ) 
    771 { 
    772     DWORD threadId; 
    773     int op_type = desc->type; 
    774     const char *op_name = (op_type == DSOUND_TYPE_PLAYER) ? "play" : "record"; 
    775     struct Thread_Param param; 
    776  
    777     PJ_LOG(4,(THIS_FILE, "DirectSound %s()", op_name)); 
    778  
    779     /* 
    780      * Create event for the thread to signal us that it is starting or 
    781      * quitting during startup. 
    782      */ 
    783     desc->hStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 
    784     if (desc->hStartEvent == NULL) { 
    785         PJ_LOG(1,(THIS_FILE, "DirectSound %s: unable to create event", op_name)); 
    786         return -1; 
    787     } 
    788  
    789     param.dev = dev; 
    790     param.desc = desc; 
    791  
    792     /* 
    793      * Create thread to handle feeding up data to player/recorder. 
    794      */ 
    795     desc->hThread = NULL; 
    796     desc->dwThreadQuitFlag = 0; 
    797     desc->hThread = CreateThread( NULL, 0, &dsound_dev_thread, &param,  
    798                                             CREATE_SUSPENDED, &threadId); 
    799     if (!desc->hThread) { 
    800         PJ_LOG(1,(THIS_FILE, "DirectSound %s(): unable to create thread", op_name)); 
    801         return -1; 
    802     } 
    803  
    804     SetThreadPriority( desc->hThread, THREAD_PRIORITY_HIGHEST); 
    805  
    806     /* 
    807      * Resume thread. 
    808      */ 
    809     if (ResumeThread(desc->hThread) == (DWORD)-1) { 
    810         PJ_LOG(1,(THIS_FILE, "DirectSound %s(): unable to resume thread", op_name)); 
    811         goto on_error; 
    812     } 
    813  
    814     /* 
    815      * Wait until we've got signal from the thread that it has successfully 
    816      * started, or when it is quitting. 
    817      */ 
    818     WaitForSingleObject( desc->hStartEvent, INFINITE); 
    819  
    820     /* We can destroy the event now. */ 
    821     CloseHandle( desc->hStartEvent ); 
    822     desc->hStartEvent = NULL; 
    823  
    824     /* Examine thread status. */ 
    825     if (desc->dwThreadQuitFlag != 0) { 
    826         /* Thread failed to initialize */ 
    827         WaitForSingleObject(desc->hThread, INFINITE); 
    828         CloseHandle(desc->hThread); 
    829         desc->hThread = NULL; 
    830         return -1; 
    831     } 
    832  
    833     return 0; 
    834  
    835 on_error: 
    836     TerminateThread(desc->hThread, -1); 
    837     CloseHandle(desc->hThread); 
    838     desc->hThread = NULL; 
    839     return -1; 
    840 } 
    841  
    842 /* 
    843  * Start playing. 
    844  */ 
    845 static pj_status_t dsound_dev_play( pj_snd_dev *dev ) 
    846 { 
    847     PJ_Direct_Sound_Device *dsDev = dev->device; 
    848  
    849     assert(dsDev); 
    850     if (!dsDev) { 
    851         assert(0); 
    852         return -1; 
    853     } 
    854  
    855     return dsound_dev_play_record( dev, &dsDev->playDesc ); 
    856 } 
    857  
    858 /* 
    859  * Start recording. 
    860  */ 
    861 static pj_status_t dsound_dev_record( pj_snd_dev *dev ) 
    862 { 
    863     PJ_Direct_Sound_Device *dsDev = dev->device; 
    864  
    865     assert(dsDev); 
    866     if (!dsDev) { 
    867         assert(0); 
    868         return -1; 
    869     } 
    870  
    871     return dsound_dev_play_record( dev, &dsDev->recDesc ); 
    872 } 
    873  
    874 #ifdef _MSC_VER 
    875 # pragma warning(pop) 
    876 # pragma warning(disable: 4514) // unreferenced inline function has been removed 
    877 #endif 
     605    } 
     606 
     607    /* Create capture stream */ 
     608    if (dir & PJMEDIA_DIR_CAPTURE) { 
     609        status = init_capture_stream( &strm->rec_strm, clock_rate, 
     610                                      channel_count, samples_per_frame, 
     611                                      DEFAULT_BUFFER_COUNT); 
     612        if (status != PJ_SUCCESS) { 
     613            pjmedia_snd_stream_close(strm); 
     614            return status; 
     615        } 
     616    } 
     617 
     618 
     619    /* Create and start the thread */ 
     620    status = pj_thread_create(pool, "dsound", &dsound_dev_thread, strm, 
     621                              0, 0, &strm->thread); 
     622    if (status != PJ_SUCCESS) { 
     623        pjmedia_snd_stream_close(strm); 
     624        return status; 
     625    } 
     626 
     627    *p_snd_strm = strm; 
     628 
     629    return PJ_SUCCESS; 
     630} 
     631 
     632/* 
     633 * Open stream. 
     634 */ 
     635PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index, 
     636                                          unsigned clock_rate, 
     637                                          unsigned channel_count, 
     638                                          unsigned samples_per_frame, 
     639                                          unsigned bits_per_sample, 
     640                                          pjmedia_snd_rec_cb rec_cb, 
     641                                          void *user_data, 
     642                                          pjmedia_snd_stream **p_snd_strm) 
     643{ 
     644    PJ_ASSERT_RETURN(rec_cb && p_snd_strm, PJ_EINVAL); 
     645 
     646    return open_stream( PJMEDIA_DIR_CAPTURE, index, -1, 
     647                        clock_rate, channel_count, samples_per_frame, 
     648                        bits_per_sample, rec_cb, NULL, user_data, 
     649                        p_snd_strm); 
     650} 
     651 
     652PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index, 
     653                                        unsigned clock_rate, 
     654                                        unsigned channel_count, 
     655                                        unsigned samples_per_frame, 
     656                                        unsigned bits_per_sample, 
     657                                        pjmedia_snd_play_cb play_cb, 
     658                                        void *user_data, 
     659                                        pjmedia_snd_stream **p_snd_strm) 
     660{ 
     661    PJ_ASSERT_RETURN(play_cb && p_snd_strm, PJ_EINVAL); 
     662 
     663    return open_stream( PJMEDIA_DIR_PLAYBACK, -1, index, 
     664                        clock_rate, channel_count, samples_per_frame, 
     665                        bits_per_sample, NULL, play_cb, user_data, 
     666                        p_snd_strm); 
     667} 
     668 
     669/* 
     670 * Open both player and recorder. 
     671 */ 
     672PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id, 
     673                                      int play_id, 
     674                                      unsigned clock_rate, 
     675                                      unsigned channel_count, 
     676                                      unsigned samples_per_frame, 
     677                                      unsigned bits_per_sample, 
     678                                      pjmedia_snd_rec_cb rec_cb, 
     679                                      pjmedia_snd_play_cb play_cb, 
     680                                      void *user_data, 
     681                                      pjmedia_snd_stream **p_snd_strm) 
     682{ 
     683    PJ_ASSERT_RETURN(rec_cb && play_cb && p_snd_strm, PJ_EINVAL); 
     684 
     685    return open_stream( PJMEDIA_DIR_CAPTURE_PLAYBACK, rec_id, play_id, 
     686                        clock_rate, channel_count, samples_per_frame, 
     687                        bits_per_sample, rec_cb, play_cb, user_data, 
     688                        p_snd_strm ); 
     689} 
     690 
     691/* 
     692 * Start stream. 
     693 */ 
     694PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream) 
     695{ 
     696    HRESULT hr; 
     697 
     698    PJ_UNUSED_ARG(stream); 
     699 
     700    if (stream->play_strm.ds.play.lpDsBuffer) { 
     701        hr = IDirectSoundBuffer_Play(stream->play_strm.ds.play.lpDsBuffer,  
     702                                     0, 0, DSBPLAY_LOOPING); 
     703        if (FAILED(hr)) 
     704            return PJ_RETURN_OS_ERROR(hr); 
     705    } 
     706     
     707    if (stream->rec_strm.ds.capture.lpDsBuffer) { 
     708        hr = IDirectSoundCaptureBuffer_Start(stream->rec_strm.ds.capture.lpDsBuffer, 
     709                                             DSCBSTART_LOOPING ); 
     710        if (FAILED(hr)) 
     711            return PJ_RETURN_OS_ERROR(hr); 
     712    } 
     713 
     714    return PJ_SUCCESS; 
     715} 
     716 
     717/* 
     718 * Stop stream. 
     719 */ 
     720PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream) 
     721{ 
     722    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); 
     723 
     724    if (stream->play_strm.ds.play.lpDsBuffer) { 
     725        PJ_LOG(5,(THIS_FILE, "Stopping DirectSound playback stream")); 
     726        IDirectSoundBuffer_Stop( stream->play_strm.ds.play.lpDsBuffer ); 
     727    } 
     728 
     729    if (stream->rec_strm.ds.capture.lpDsBuffer) { 
     730        PJ_LOG(5,(THIS_FILE, "Stopping DirectSound capture stream")); 
     731        IDirectSoundCaptureBuffer_Stop(stream->rec_strm.ds.capture.lpDsBuffer); 
     732    } 
     733 
     734    return PJ_SUCCESS; 
     735} 
     736 
     737 
     738/* 
     739 * Destroy stream. 
     740 */ 
     741PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream) 
     742{ 
     743    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); 
     744 
     745    pjmedia_snd_stream_stop(stream); 
     746 
     747    if (stream->play_strm.lpDsNotify) { 
     748        IDirectSoundNotify_Release( stream->play_strm.lpDsNotify ); 
     749        stream->play_strm.lpDsNotify = NULL; 
     750    } 
     751     
     752    if (stream->play_strm.hEvent) { 
     753        CloseHandle(stream->play_strm.hEvent); 
     754        stream->play_strm.hEvent = NULL; 
     755    } 
     756 
     757    if (stream->play_strm.ds.play.lpDsBuffer) { 
     758        IDirectSoundBuffer_Release( stream->play_strm.ds.play.lpDsBuffer ); 
     759        stream->play_strm.ds.play.lpDsBuffer = NULL; 
     760    } 
     761 
     762    if (stream->play_strm.ds.play.lpDs) { 
     763        IDirectSound_Release( stream->play_strm.ds.play.lpDs ); 
     764        stream->play_strm.ds.play.lpDs = NULL; 
     765    } 
     766 
     767    if (stream->rec_strm.lpDsNotify) { 
     768        IDirectSoundNotify_Release( stream->rec_strm.lpDsNotify ); 
     769        stream->rec_strm.lpDsNotify = NULL; 
     770    } 
     771     
     772    if (stream->rec_strm.hEvent) { 
     773        CloseHandle(stream->rec_strm.hEvent); 
     774        stream->rec_strm.hEvent = NULL; 
     775    } 
     776 
     777    if (stream->rec_strm.ds.capture.lpDsBuffer) { 
     778        IDirectSoundCaptureBuffer_Release( stream->rec_strm.ds.capture.lpDsBuffer ); 
     779        stream->rec_strm.ds.capture.lpDsBuffer = NULL; 
     780    } 
     781 
     782    if (stream->rec_strm.ds.capture.lpDs) { 
     783        IDirectSoundCapture_Release( stream->rec_strm.ds.capture.lpDs ); 
     784        stream->rec_strm.ds.capture.lpDs = NULL; 
     785    } 
     786 
     787    if (stream->thread) { 
     788        stream->thread_quit_flag = 1; 
     789        pj_thread_join(stream->thread); 
     790        pj_thread_destroy(stream->thread); 
     791        stream->thread = NULL; 
     792    } 
     793 
     794    pj_pool_release(stream->pool); 
     795 
     796    return PJ_SUCCESS; 
     797} 
     798 
     799 
     800#endif  /* PJMEDIA_SOUND_IMPLEMENTATION */ 
     801 
Note: See TracChangeset for help on using the changeset viewer.