📄 ao_dsound.c
字号:
// Lock the buffer res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); // If the buffer was lost, restore and retry lock. if (DSERR_BUFFERLOST == res) { IDirectSoundBuffer_Restore(hdsbuf); res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); } if (SUCCEEDED(res)) { if( (ao_data.channels == 6) && (ao_data.format!=AF_FORMAT_AC3) ) { // reorder channels while writing to pointers. // it's this easy because buffer size and len are always // aligned to multiples of channels*bytespersample // there's probably some room for speed improvements here const int chantable[6] = {0, 1, 4, 5, 2, 3}; // reorder "matrix" int i, j; int numsamp,sampsize; sampsize = af_fmt2bits(ao_data.format)>>3; // bytes per sample numsamp = dwBytes1 / (ao_data.channels * sampsize); // number of samples for each channel in this buffer for( i = 0; i < numsamp; i++ ) for( j = 0; j < ao_data.channels; j++ ) { memcpy(lpvPtr1+(i*ao_data.channels*sampsize)+(chantable[j]*sampsize),data+(i*ao_data.channels*sampsize)+(j*sampsize),sampsize); } if (NULL != lpvPtr2 ) { numsamp = dwBytes2 / (ao_data.channels * sampsize); for( i = 0; i < numsamp; i++ ) for( j = 0; j < ao_data.channels; j++ ) { memcpy(lpvPtr2+(i*ao_data.channels*sampsize)+(chantable[j]*sampsize),data+dwBytes1+(i*ao_data.channels*sampsize)+(j*sampsize),sampsize); } } write_offset+=dwBytes1+dwBytes2; if(write_offset>=buffer_size)write_offset=dwBytes2; } else { // Write to pointers without reordering. memcpy(lpvPtr1,data,dwBytes1); if (NULL != lpvPtr2 )memcpy(lpvPtr2,data+dwBytes1,dwBytes2); write_offset+=dwBytes1+dwBytes2; if(write_offset>=buffer_size)write_offset=dwBytes2; } // Release the data back to DirectSound. res = IDirectSoundBuffer_Unlock(hdsbuf,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); if (SUCCEEDED(res)) { // Success. DWORD status; IDirectSoundBuffer_GetStatus(hdsbuf, &status); if (!(status & DSBSTATUS_PLAYING)){ res = IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING); } return dwBytes1+dwBytes2; } } // Lock, Unlock, or Restore failed. return 0;}/***************************************************************************************//**\brief handle control commands\param cmd command\param arg argument\return CONTROL_OK or -1 in case the command can't be handled*/static int control(int cmd, void *arg){ DWORD volume; switch (cmd) { case AOCONTROL_GET_VOLUME: { ao_control_vol_t* vol = (ao_control_vol_t*)arg; IDirectSoundBuffer_GetVolume(hdsbuf, &volume); vol->left = vol->right = (float)(volume+10000) / 100.0; //printf("ao_dsound: volume: %f\n",vol->left); return CONTROL_OK; } case AOCONTROL_SET_VOLUME: { ao_control_vol_t* vol = (ao_control_vol_t*)arg; volume = (vol->right * 100.0)-10000; IDirectSoundBuffer_SetVolume(hdsbuf, volume); //printf("ao_dsound: volume: %f\n",vol->left); return CONTROL_OK; } } return -1;}/** \brief setup sound device\param rate samplerate\param channels number of channels\param format format\param flags unused\return 1=success 0=fail*/static int init(int rate, int channels, int format, int flags){ int res; if (!InitDirectSound()) return 0; // ok, now create the buffers WAVEFORMATEXTENSIBLE wformat; DSBUFFERDESC dsbpridesc; DSBUFFERDESC dsbdesc; //check if the format is supported in general switch(format){ case AF_FORMAT_AC3: case AF_FORMAT_S24_LE: case AF_FORMAT_S16_LE: case AF_FORMAT_S8: break; default: mp_msg(MSGT_AO, MSGL_V,"ao_dsound: format %s not supported defaulting to Signed 16-bit Little-Endian\n",af_fmt2str_short(format)); format=AF_FORMAT_S16_LE; } //fill global ao_data ao_data.channels = channels; ao_data.samplerate = rate; ao_data.format = format; ao_data.bps = channels * rate * (af_fmt2bits(format)>>3); if(ao_data.buffersize==-1) ao_data.buffersize = ao_data.bps; // space for 1 sec mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, channels, af_fmt2str_short(format)); mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Buffersize:%d bytes (%d msec)\n", ao_data.buffersize, ao_data.buffersize / ao_data.bps * 1000); //fill waveformatex ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE)); wformat.Format.cbSize = (channels > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0; wformat.Format.nChannels = channels; wformat.Format.nSamplesPerSec = rate; if (format == AF_FORMAT_AC3) { wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; wformat.Format.wBitsPerSample = 16; wformat.Format.nBlockAlign = 4; } else { wformat.Format.wFormatTag = (channels > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM; wformat.Format.wBitsPerSample = af_fmt2bits(format); wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); } // fill in primary sound buffer descriptor memset(&dsbpridesc, 0, sizeof(DSBUFFERDESC)); dsbpridesc.dwSize = sizeof(DSBUFFERDESC); dsbpridesc.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbpridesc.dwBufferBytes = 0; dsbpridesc.lpwfxFormat = NULL; // fill in the secondary sound buffer (=stream buffer) descriptor memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */ | DSBCAPS_GLOBALFOCUS /** Allows background playing */ | DSBCAPS_CTRLVOLUME; /** volume control enabled */ if (channels > 2) { wformat.dwChannelMask = channel_mask[channels - 3]; wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample; // Needed for 5.1 on emu101k - shit soundblaster dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE; } wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign; dsbdesc.dwBufferBytes = ao_data.buffersize; dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat; buffer_size = dsbdesc.dwBufferBytes; write_offset = 0; min_free_space = wformat.Format.nBlockAlign; ao_data.outburst = wformat.Format.nBlockAlign * 512; // create primary buffer and set its format res = IDirectSound_CreateSoundBuffer( hds, &dsbpridesc, &hdspribuf, NULL ); if ( res != DS_OK ) { UninitDirectSound(); mp_msg(MSGT_AO, MSGL_ERR,"ao_dsound: cannot create primary buffer (%s)\n", dserr2str(res)); return 0; } res = IDirectSoundBuffer_SetFormat( hdspribuf, (WAVEFORMATEX *)&wformat ); if ( res != DS_OK ) mp_msg(MSGT_AO, MSGL_WARN,"ao_dsound: cannot set primary buffer format (%s), using standard setting (bad quality)", dserr2str(res)); mp_msg(MSGT_AO, MSGL_V, "ao_dsound: primary buffer created\n"); // now create the stream buffer res = IDirectSound_CreateSoundBuffer(hds, &dsbdesc, &hdsbuf, NULL); if (res != DS_OK) { if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) { // Try without DSBCAPS_LOCHARDWARE dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; res = IDirectSound_CreateSoundBuffer(hds, &dsbdesc, &hdsbuf, NULL); } if (res != DS_OK) { UninitDirectSound(); mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot create secondary (stream)buffer (%s)\n", dserr2str(res)); return 0; } } mp_msg(MSGT_AO, MSGL_V, "ao_dsound: secondary (stream)buffer created\n"); return 1;}/**\brief stop playing and empty buffers (for seeking/pause)*/static void reset(){ IDirectSoundBuffer_Stop(hdsbuf); // reset directsound buffer IDirectSoundBuffer_SetCurrentPosition(hdsbuf, 0); write_offset=0;}/**\brief stop playing, keep buffers (for pause)*/static void audio_pause(){ IDirectSoundBuffer_Stop(hdsbuf);}/**\brief resume playing, after audio_pause()*/static void audio_resume(){ IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING);}/** \brief close audio device\param immed stop playback immediately*/static void uninit(int immed){ if(immed)reset(); else{ DWORD status; IDirectSoundBuffer_Play(hdsbuf, 0, 0, 0); while(!IDirectSoundBuffer_GetStatus(hdsbuf,&status) && (status&DSBSTATUS_PLAYING)) usec_sleep(20000); } DestroyBuffer(); UninitDirectSound();}/**\brief find out how many bytes can be written into the audio buffer without\return free space in bytes, has to return 0 if the buffer is almost full*/static int get_space(){ int space; DWORD play_offset; IDirectSoundBuffer_GetCurrentPosition(hdsbuf,&play_offset,NULL); space=buffer_size-(write_offset-play_offset); // | | <-- const --> | | | // buffer start play_cursor write_cursor write_offset buffer end // play_cursor is the actual postion of the play cursor // write_cursor is the position after which it is assumed to be save to write data // write_offset is the postion where we actually write the data to if(space > buffer_size)space -= buffer_size; // write_offset < play_offset if(space < min_free_space)return 0; return space-min_free_space;}/**\brief play 'len' bytes of 'data'\param data pointer to the data to play\param len size in bytes of the data buffer, gets rounded down to outburst*n\param flags currently unused\return number of played bytes*/static int play(void* data, int len, int flags){ DWORD play_offset; int space; // make sure we have enough space to write data IDirectSoundBuffer_GetCurrentPosition(hdsbuf,&play_offset,NULL); space=buffer_size-(write_offset-play_offset); if(space > buffer_size)space -= buffer_size; // write_offset < play_offset if(space < len) len = space; len = (len / ao_data.outburst) * ao_data.outburst; return write_buffer(data, len);}/**\brief get the delay between the first and last sample in the buffer\return delay in seconds*/static float get_delay(){ DWORD play_offset; int space; IDirectSoundBuffer_GetCurrentPosition(hdsbuf,&play_offset,NULL); space=play_offset-write_offset; if(space <= 0)space += buffer_size; return (float)(buffer_size - space) / (float)ao_data.bps;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -