Changeset 25678 in vbox
- Timestamp:
- Jan 7, 2010 8:18:05 AM (15 years ago)
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 2 edited
-
pulse_stubs.c (modified) (7 diffs)
-
pulseaudio.c (modified) (32 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/pulse_stubs.c
r22647 r25678 79 79 (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata), 80 80 (s, cb, userdata)) 81 PROXY_STUB (pa_stream_ flush, pa_operation*,81 PROXY_STUB (pa_stream_drain, pa_operation*, 82 82 (pa_stream *s, pa_stream_success_cb_t cb, void *userdata), 83 83 (s, cb, userdata)) 84 PROXY_STUB (pa_stream_trigger, pa_operation*, 85 (pa_stream *s, pa_stream_success_cb_t cb, void *userdata), 86 (s, cb, userdata)) 84 87 PROXY_STUB (pa_stream_new, pa_stream*, 85 88 (pa_context *c, const char *name, const pa_sample_spec *ss, … … 98 101 (pa_stream *p), 99 102 (p)) 100 PROXY_STUB (pa_stream_trigger, pa_operation*,101 (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),102 (s, cb, userdata))103 103 PROXY_STUB (pa_stream_writable_size, size_t, 104 104 (pa_stream *p), … … 154 154 (m)) 155 155 PROXY_STUB (pa_bytes_per_second, size_t, 156 (const pa_sample_spec *spec), 157 (spec)) 158 PROXY_STUB (pa_frame_size, size_t, 156 159 (const pa_sample_spec *spec), 157 160 (spec)) … … 168 171 (pa_operation *o), 169 172 (o)) 173 PROXY_STUB (pa_operation_get_state, pa_operation_state_t, 174 (pa_operation *o), 175 (o)) 170 176 PROXY_STUB (pa_strerror, const char*, 171 177 (int error), 172 178 (error)) 179 PROXY_STUB (pa_stream_readable_size, size_t, 180 (pa_stream *p), 181 (p)) 173 182 174 183 … … 191 200 ELEMENT(pa_stream_get_state), 192 201 ELEMENT(pa_stream_set_state_callback), 193 ELEMENT(pa_stream_flush), 202 ELEMENT(pa_stream_drain), 203 ELEMENT(pa_stream_trigger), 194 204 ELEMENT(pa_stream_new), 195 205 ELEMENT(pa_stream_get_buffer_attr), … … 197 207 ELEMENT(pa_stream_cork), 198 208 ELEMENT(pa_stream_drop), 199 ELEMENT(pa_stream_trigger),200 209 ELEMENT(pa_stream_writable_size), 201 210 ELEMENT(pa_context_connect), … … 216 225 ELEMENT(pa_threaded_mainloop_lock), 217 226 ELEMENT(pa_bytes_per_second), 227 ELEMENT(pa_frame_size), 218 228 ELEMENT(pa_sample_format_to_string), 219 229 ELEMENT(pa_sample_spec_valid), 220 230 ELEMENT(pa_channel_map_init_auto), 221 231 ELEMENT(pa_operation_unref), 232 ELEMENT(pa_operation_get_state), 222 233 ELEMENT(pa_strerror), 234 ELEMENT(pa_stream_readable_size) 223 235 }; 224 236 #undef ELEMENT -
trunk/src/VBox/Devices/Audio/pulseaudio.c
r22153 r25678 49 49 typedef struct PulseVoice 50 50 { 51 HWVoiceOut hw; 52 void *pPCMBuf; 53 pa_stream *pStream; 54 int fOpSuccess; 55 unsigned cErrors; 51 HWVoiceOut hw; 52 /** DAC buffer */ 53 void *pPCMBuf; 54 /** Pulse stream */ 55 pa_stream *pStream; 56 /** Pulse sample format and attribute specification */ 57 pa_sample_spec SampleSpec; 58 /** Pulse playback and buffer metrics */ 59 pa_buffer_attr BufAttr; 60 int fOpSuccess; 61 /** number of logged errors */ 62 unsigned cErrors; 63 const uint8_t *pu8PeekBuf; 64 size_t cbPeekBuf; 65 size_t offPeekBuf; 56 66 } PulseVoice; 57 67 68 /* The desired max buffer size in milliseconds. The desired latency will be 69 * calculated to be 1/10 of the value */ 58 70 static struct 59 71 { … … 64 76 { 65 77 INIT_FIELD (.buffer_msecs_out = ) 100, 66 INIT_FIELD (.buffer_msecs_in = ) 100,78 INIT_FIELD (.buffer_msecs_in = ) 300, 67 79 }; 68 69 struct pulse_params_req70 {71 int freq;72 pa_sample_format_t pa_format;73 int nchannels;74 };75 76 struct pulse_params_obt77 {78 int freq;79 pa_sample_format_t pa_format;80 int nchannels;81 unsigned long buffer_size;82 };83 84 static void pulse_check_fatal (PulseVoice *pulse, int rc)85 {86 if (rc == PA_ERR_CONNECTIONTERMINATED)87 {88 /* XXX runtime warning */89 LogRel(("Pulse: Audio input/output stopped!\n"));90 pulse->cErrors = MAX_LOG_REL_ERRORS;91 }92 }93 80 94 81 static pa_sample_format_t aud_to_pulsefmt (audfmt_e fmt) … … 155 142 static void context_state_callback(pa_context *c, void *userdata) 156 143 { 144 PulseVoice *pPulse = (PulseVoice *)userdata; 157 145 switch (pa_context_get_state(c)) 158 146 { 159 147 case PA_CONTEXT_READY: 160 148 case PA_CONTEXT_TERMINATED: 149 pa_threaded_mainloop_signal(g_pMainLoop, 0); 150 break; 151 161 152 case PA_CONTEXT_FAILED: 153 LogRel(("Pulse: Audio input/output stopped!\n")); 154 pPulse->cErrors = MAX_LOG_REL_ERRORS; 162 155 pa_threaded_mainloop_signal(g_pMainLoop, 0); 163 156 break; 157 164 158 default: 165 159 break; … … 176 170 pa_threaded_mainloop_signal(g_pMainLoop, 0); 177 171 break; 172 178 173 default: 179 174 break; … … 181 176 } 182 177 183 static void stream_latency_update_callback(pa_stream *s, void *userdata) 184 { 185 pa_threaded_mainloop_signal(g_pMainLoop, 0); 186 } 187 188 static int pulse_open (int fIn, struct pulse_params_req *req, 189 struct pulse_params_obt *obt, pa_stream **ppStream) 190 { 191 pa_sample_spec sspec; 192 pa_channel_map cmap; 178 static int pulse_open (int fIn, pa_stream **ppStream, pa_sample_spec *pSampleSpec, 179 pa_buffer_attr *pBufAttr) 180 { 181 const pa_buffer_attr *pBufAttrObtained; 193 182 pa_stream *pStream = NULL; 194 pa_buffer_attr bufAttr; 195 const pa_buffer_attr *pBufAttr; 196 const pa_sample_spec *pSampSpec; 197 char achPCMName[64]; 198 pa_stream_flags_t flags; 199 int ms = fIn ? conf.buffer_msecs_in : conf.buffer_msecs_out; 183 char achPCMName[64]; 184 pa_stream_flags_t flags = 0; 200 185 const char *stream_name = audio_get_stream_name(); 201 186 … … 205 190 fIn ? "pcm_in" : "pcm_out", 206 191 stream_name ? ")" : ""); 207 sspec.rate = req->freq;208 sspec.channels = req->nchannels;209 sspec.format = req->pa_format;210 192 211 193 LogRel(("Pulse: open %s rate=%dHz channels=%d format=%s\n", 212 fIn ? "PCM_IN" : "PCM_OUT", req->freq, req->nchannels,213 pa_sample_format_to_string( req->pa_format)));214 215 if (!pa_sample_spec_valid( &sspec))194 fIn ? "PCM_IN" : "PCM_OUT", pSampleSpec->rate, pSampleSpec->channels, 195 pa_sample_format_to_string(pSampleSpec->format))); 196 197 if (!pa_sample_spec_valid(pSampleSpec)) 216 198 { 217 199 LogRel(("Pulse: Unsupported sample specification\n")); … … 219 201 } 220 202 221 pa_channel_map_init_auto(&cmap, sspec.channels, PA_CHANNEL_MAP_ALSA);222 223 #if 0224 pa_cvolume_reset(&volume, sspec.channels);225 #endif226 227 203 pa_threaded_mainloop_lock(g_pMainLoop); 228 204 229 if (!(pStream = pa_stream_new(g_pContext, achPCMName, &sspec, &cmap)))205 if (!(pStream = pa_stream_new(g_pContext, achPCMName, pSampleSpec, /*channel_map=*/NULL))) 230 206 { 231 207 LogRel(("Pulse: Cannot create stream %s\n", achPCMName)); … … 233 209 } 234 210 235 pSampSpec = pa_stream_get_sample_spec(pStream);236 obt->pa_format = pSampSpec->format;237 obt->nchannels = pSampSpec->channels;238 obt->freq = pSampSpec->rate;239 240 211 pa_stream_set_state_callback(pStream, stream_state_callback, NULL); 241 pa_stream_set_latency_update_callback(pStream, stream_latency_update_callback, NULL); 242 243 memset(&bufAttr, 0, sizeof(bufAttr)); 244 bufAttr.tlength = (pa_bytes_per_second(pSampSpec) * ms) / 1000; 245 bufAttr.maxlength = (bufAttr.tlength*3) / 2; 246 bufAttr.minreq = pa_bytes_per_second(pSampSpec) / 100; /* 10ms */ 247 bufAttr.prebuf = bufAttr.tlength - bufAttr.minreq; 248 bufAttr.fragsize = pa_bytes_per_second(pSampSpec) / 100; /* 10ms */ 249 250 flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; 212 213 #if PA_API_VERSION >= 12 214 /* XXX */ 215 flags |= PA_STREAM_ADJUST_LATENCY; 216 #endif 217 251 218 if (fIn) 252 219 { 253 if (pa_stream_connect_record(pStream, /*dev=*/NULL, &bufAttr, flags) < 0) 254 { 255 LogRel(("Pulse: Cannot connect record stream : %s\n", 220 LogRel(("Pulse: Requested record buffer attributes: maxlength=%d fragsize=%d\n", 221 pBufAttr->maxlength, pBufAttr->fragsize)); 222 #if 0 223 /* not applicable as we don't use pa_stream_get_latency() and pa_stream_get_time() */ 224 flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; 225 #endif 226 if (pa_stream_connect_record(pStream, /*dev=*/NULL, pBufAttr, flags) < 0) 227 { 228 LogRel(("Pulse: Cannot connect record stream: %s\n", 256 229 pa_strerror(pa_context_errno(g_pContext)))); 257 230 goto disconnect_unlock_and_fail; … … 260 233 else 261 234 { 262 if (pa_stream_connect_playback(pStream, /*dev=*/NULL, &bufAttr, flags, 263 NULL, NULL) < 0) 235 LogRel(("Pulse: Requested playback buffer attributes: maxlength=%d tlength=%d prebuf=%d minreq=%d\n", 236 pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq)); 237 238 flags |= PA_STREAM_START_CORKED; 239 240 if (pa_stream_connect_playback(pStream, /*dev=*/NULL, pBufAttr, flags, 241 /*cvolume=*/NULL, /*sync_stream=*/NULL) < 0) 264 242 { 265 243 LogRel(("Pulse: Cannot connect playback stream: %s\n", … … 274 252 pa_stream_state_t sstate; 275 253 pa_threaded_mainloop_wait(g_pMainLoop); 254 276 255 sstate = pa_stream_get_state(pStream); 277 256 if (sstate == PA_STREAM_READY) … … 284 263 } 285 264 286 pBufAttr = pa_stream_get_buffer_attr(pStream); 287 obt->buffer_size = pBufAttr->maxlength; 265 pBufAttrObtained = pa_stream_get_buffer_attr(pStream); 266 memcpy(pBufAttr, pBufAttrObtained, sizeof(pa_buffer_attr)); 267 268 LogRel(("Pulse: Obtained buffer attributes: tlength=%d maxlength=%d prebuf=%d minreq=%d fragsize=%d\n", 269 pBufAttr->tlength, pBufAttr->maxlength, pBufAttr->prebuf, pBufAttr->minreq, pBufAttr->fragsize)); 288 270 289 271 pa_threaded_mainloop_unlock(g_pMainLoop); 290 291 LogRel(("Pulse: buffer settings: max=%d tlength=%d prebuf=%d minreq=%d\n",292 pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));293 294 272 *ppStream = pStream; 295 273 return 0; … … 311 289 static int pulse_init_out (HWVoiceOut *hw, audsettings_t *as) 312 290 { 313 PulseVoice *pulse = (PulseVoice *) hw; 314 struct pulse_params_req req; 315 struct pulse_params_obt obt; 316 audfmt_e effective_fmt; 317 int endianness; 291 PulseVoice *pPulse = (PulseVoice *) hw; 318 292 audsettings_t obt_as; 319 320 req.pa_format = aud_to_pulsefmt (as->fmt); 321 req.freq = as->freq; 322 req.nchannels = as->nchannels; 323 324 if (pulse_open (/*fIn=*/0, &req, &obt, &pulse->pStream)) 293 int cbBuf; 294 295 pPulse->SampleSpec.format = aud_to_pulsefmt (as->fmt); 296 pPulse->SampleSpec.rate = as->freq; 297 pPulse->SampleSpec.channels = as->nchannels; 298 299 /* Note that setting maxlength to -1 does not work for older PulseAudio libraries 300 * (at least not for 0.9.10). So use the suggested value of 3/2 of tlength */ 301 pPulse->BufAttr.tlength = (pa_bytes_per_second(&pPulse->SampleSpec) 302 * conf.buffer_msecs_out) / 1000; 303 pPulse->BufAttr.maxlength = (pPulse->BufAttr.tlength * 3) / 2; 304 pPulse->BufAttr.prebuf = -1; /* Same as tlength */ 305 pPulse->BufAttr.minreq = -1; /* Pulse should set something sensible for minreq on it's own */ 306 307 /* Notice that the struct BufAttr is updated to the obtained values after this call */ 308 if (pulse_open (0, &pPulse->pStream, &pPulse->SampleSpec, &pPulse->BufAttr)) 325 309 return -1; 326 310 327 if (pulse_to_audfmt ( obt.pa_format, &effective_fmt, &endianness))328 { 329 LogRel(("Pulse: Cannot find audio format %d\n", obt.pa_format));311 if (pulse_to_audfmt (pPulse->SampleSpec.format, &obt_as.fmt, &obt_as.endianness)) 312 { 313 LogRel(("Pulse: Cannot find audio format %d\n", pPulse->SampleSpec.format)); 330 314 return -1; 331 315 } 332 316 333 obt_as.freq = obt.freq; 334 obt_as.nchannels = obt.nchannels; 335 obt_as.fmt = effective_fmt; 336 obt_as.endianness = endianness; 317 obt_as.freq = pPulse->SampleSpec.rate; 318 obt_as.nchannels = pPulse->SampleSpec.channels; 337 319 338 320 audio_pcm_init_info (&hw->info, &obt_as); 339 hw->samples = obt.buffer_size >> hw->info.shift;340 341 p ulse->pPCMBuf = RTMemAllocZ(obt.buffer_size);342 if (!p ulse->pPCMBuf)343 { 344 LogRel(("Pulse: Could not allocate DAC buffer of %d bytes\n", obt.buffer_size));321 cbBuf = audio_MIN(pPulse->BufAttr.tlength * 2, pPulse->BufAttr.maxlength); 322 323 pPulse->pPCMBuf = RTMemAllocZ(cbBuf); 324 if (!pPulse->pPCMBuf) 325 { 326 LogRel(("Pulse: Could not allocate DAC buffer of %d bytes\n", cbBuf)); 345 327 return -1; 346 328 } 347 329 330 /* Convert from bytes to frames (aka samples) */ 331 hw->samples = cbBuf >> hw->info.shift; 332 348 333 return 0; 349 334 } … … 351 336 static void pulse_fini_out (HWVoiceOut *hw) 352 337 { 353 PulseVoice *pulse = (PulseVoice *)hw; 354 if (pulse->pStream) 355 { 356 pa_stream_disconnect(pulse->pStream); 357 pa_stream_unref(pulse->pStream); 358 pulse->pStream = NULL; 359 } 360 if (pulse->pPCMBuf) 361 { 362 RTMemFree (pulse->pPCMBuf); 363 pulse->pPCMBuf = NULL; 338 PulseVoice *pPulse = (PulseVoice *)hw; 339 340 if (pPulse->pStream) 341 { 342 pa_threaded_mainloop_lock(g_pMainLoop); 343 pa_stream_disconnect(pPulse->pStream); 344 pa_stream_unref(pPulse->pStream); 345 pa_threaded_mainloop_unlock(g_pMainLoop); 346 pPulse->pStream = NULL; 347 } 348 349 if (pPulse->pPCMBuf) 350 { 351 RTMemFree (pPulse->pPCMBuf); 352 pPulse->pPCMBuf = NULL; 364 353 } 365 354 } … … 367 356 static int pulse_run_out (HWVoiceOut *hw) 368 357 { 369 PulseVoice *pulse = (PulseVoice *) hw; 370 int csLive, csDecr = 0, csSamples, csToWrite, csAvail; 371 size_t cbAvail, cbToWrite; 358 PulseVoice *pPulse = (PulseVoice *) hw; 359 int cFramesLive; 360 int cFramesWritten = 0; 361 int csSamples; 362 int cFramesToWrite; 363 int cFramesAvail; 364 size_t cbAvail; 365 size_t cbToWrite; 372 366 uint8_t *pu8Dst; 373 367 st_sample_t *psSrc; 374 368 375 c sLive = audio_pcm_hw_get_live_out (hw);376 if (!c sLive)369 cFramesLive = audio_pcm_hw_get_live_out (hw); 370 if (!cFramesLive) 377 371 return 0; 378 372 379 373 pa_threaded_mainloop_lock(g_pMainLoop); 380 374 381 cbAvail = pa_stream_writable_size (p ulse->pStream);375 cbAvail = pa_stream_writable_size (pPulse->pStream); 382 376 if (cbAvail == (size_t)-1) 383 377 { 384 if (p ulse->cErrors < MAX_LOG_REL_ERRORS)378 if (pPulse->cErrors < MAX_LOG_REL_ERRORS) 385 379 { 386 380 int rc = pa_context_errno(g_pContext); 387 p ulse->cErrors++;381 pPulse->cErrors++; 388 382 LogRel(("Pulse: Failed to determine the writable size: %s\n", 389 383 pa_strerror(rc))); 390 pulse_check_fatal(pulse, rc);391 384 } 392 385 goto unlock_and_exit; 393 386 } 394 387 395 c sAvail = cbAvail >> hw->info.shift; /* bytes => samples */396 c sDecr = audio_MIN (csLive, csAvail);397 csSamples = csDecr;388 cFramesAvail = cbAvail >> hw->info.shift; /* bytes => samples */ 389 cFramesWritten = audio_MIN (cFramesLive, cFramesAvail); 390 csSamples = cFramesWritten; 398 391 399 392 while (csSamples) 400 393 { 401 394 /* split request at the end of our samples buffer */ 402 c sToWrite = audio_MIN (csSamples, hw->samples - hw->rpos);403 cbToWrite = csToWrite << hw->info.shift;404 psSrc = hw->mix_buf + hw->rpos;405 pu8Dst = advance (pulse->pPCMBuf, hw->rpos << hw->info.shift);406 407 hw->clip (pu8Dst, psSrc, c sToWrite);408 409 if (pa_stream_write (p ulse->pStream, pu8Dst, cbToWrite,395 cFramesToWrite = audio_MIN (csSamples, hw->samples - hw->rpos); 396 cbToWrite = cFramesToWrite << hw->info.shift; 397 psSrc = hw->mix_buf + hw->rpos; 398 pu8Dst = advance (pPulse->pPCMBuf, hw->rpos << hw->info.shift); 399 400 hw->clip (pu8Dst, psSrc, cFramesToWrite); 401 402 if (pa_stream_write (pPulse->pStream, pu8Dst, cbToWrite, 410 403 /*cleanup_callback=*/NULL, 0, PA_SEEK_RELATIVE) < 0) 411 404 { 412 405 LogRel(("Pulse: Failed to write %d samples: %s\n", 413 c sToWrite, pa_strerror(pa_context_errno(g_pContext))));414 break; 415 } 416 hw->rpos = (hw->rpos + c sToWrite) % hw->samples;417 csSamples -= c sToWrite;406 cFramesToWrite, pa_strerror(pa_context_errno(g_pContext)))); 407 break; 408 } 409 hw->rpos = (hw->rpos + cFramesToWrite) % hw->samples; 410 csSamples -= cFramesToWrite; 418 411 } 419 412 … … 421 414 pa_threaded_mainloop_unlock(g_pMainLoop); 422 415 423 return c sDecr;416 return cFramesWritten; 424 417 } 425 418 … … 431 424 static void stream_success_callback(pa_stream *pStream, int success, void *userdata) 432 425 { 433 PulseVoice *p ulse = (PulseVoice *) userdata;434 p ulse->fOpSuccess = success;426 PulseVoice *pPulse = (PulseVoice *) userdata; 427 pPulse->fOpSuccess = success; 435 428 pa_threaded_mainloop_signal(g_pMainLoop, 0); 436 429 } … … 438 431 typedef enum 439 432 { 440 Unpause = 0,441 Pause = 1,442 Flush = 2,443 Trigger = 3433 Unpause, 434 Pause, 435 Trigger, 436 Drain 444 437 } pulse_cmd_t; 445 438 446 static int pulse_ctrl (HWVoiceOut *hw, pulse_cmd_t cmd) 447 { 448 PulseVoice *pulse = (PulseVoice *) hw; 439 static int pulse_ctrl (PulseVoice *pPulse, pulse_cmd_t cmd) 440 { 449 441 pa_operation *op = NULL; 450 451 if (!pulse->pStream) 442 const char *cmd_str = cmd == Unpause ? "unpause" : 443 cmd == Pause ? "pause" : 444 cmd == Trigger ? "trigger" : 445 cmd == Drain ? "drain" : NULL; 446 447 if (!pPulse->pStream) 452 448 return 0; 449 450 LogRel(("Pulse: ctrl cmd=%s\n", cmd_str)); 453 451 454 452 pa_threaded_mainloop_lock(g_pMainLoop); … … 456 454 { 457 455 case Pause: 458 op = pa_stream_cork(p ulse->pStream, 1, stream_success_callback, pulse);456 op = pa_stream_cork(pPulse->pStream, 1, stream_success_callback, pPulse); 459 457 break; 460 458 case Unpause: 461 op = pa_stream_cork(p ulse->pStream, 0, stream_success_callback, pulse);462 break; 463 case Flush:464 op = pa_stream_ flush(pulse->pStream, stream_success_callback, pulse);459 op = pa_stream_cork(pPulse->pStream, 0, stream_success_callback, pPulse); 460 break; 461 case Drain: 462 op = pa_stream_drain(pPulse->pStream, stream_success_callback, pPulse); 465 463 break; 466 464 case Trigger: 467 op = pa_stream_trigger(p ulse->pStream, stream_success_callback, pulse);465 op = pa_stream_trigger(pPulse->pStream, stream_success_callback, pPulse); 468 466 break; 469 467 default: … … 472 470 if (!op) 473 471 { 474 if (p ulse->cErrors < MAX_LOG_REL_ERRORS)472 if (pPulse->cErrors < MAX_LOG_REL_ERRORS) 475 473 { 476 474 int rc = pa_context_errno(g_pContext); 477 pulse->cErrors++; 478 LogRel(("Pulse: Failed ctrl cmd=%d to stream: %s\n", 479 cmd, pa_strerror(pa_context_errno(g_pContext)))); 480 pulse_check_fatal(pulse, rc); 475 pPulse->cErrors++; 476 LogRel(("Pulse: Failed ctrl cmd=%s to stream: %s\n", cmd_str, pa_strerror(rc))); 481 477 } 482 478 } 483 479 else 480 { 481 while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) 482 pa_threaded_mainloop_wait(g_pMainLoop); 484 483 pa_operation_unref(op); 484 } 485 485 486 486 unlock_and_exit: … … 494 494 { 495 495 case VOICE_ENABLE: 496 pulse_ctrl( hw, Unpause);497 pulse_ctrl(hw, Trigger);498 break; 496 pulse_ctrl((PulseVoice *)hw, Unpause); 497 break; 498 499 499 case VOICE_DISABLE: 500 pulse_ctrl(hw, Flush); 501 break; 500 pulse_ctrl((PulseVoice *)hw, Trigger); 501 pulse_ctrl((PulseVoice *)hw, Drain); 502 pulse_ctrl((PulseVoice *)hw, Pause); 503 break; 504 502 505 default: 503 506 return -1; … … 508 511 static int pulse_init_in (HWVoiceIn *hw, audsettings_t *as) 509 512 { 510 PulseVoice *pulse = (PulseVoice *) hw; 511 struct pulse_params_req req; 512 struct pulse_params_obt obt; 513 audfmt_e effective_fmt; 514 int endianness; 513 PulseVoice *pPulse = (PulseVoice *) hw; 515 514 audsettings_t obt_as; 516 515 517 req.pa_format = aud_to_pulsefmt (as->fmt); 518 req.freq = as->freq; 519 req.nchannels = as->nchannels; 520 521 if (pulse_open (/*fIn=*/1, &req, &obt, &pulse->pStream)) 516 pPulse->SampleSpec.format = aud_to_pulsefmt (as->fmt); 517 pPulse->SampleSpec.rate = as->freq; 518 pPulse->SampleSpec.channels = as->nchannels; 519 520 /* XXX check these values */ 521 pPulse->BufAttr.fragsize = (pa_bytes_per_second(&pPulse->SampleSpec) 522 * conf.buffer_msecs_in) / 2000; /* one tenth */ 523 pPulse->BufAttr.maxlength = (pa_bytes_per_second(&pPulse->SampleSpec) 524 * conf.buffer_msecs_in) / 1000; 525 /* Other memebers of pa_buffer_attr are ignored for record streams */ 526 527 if (pulse_open (1, &pPulse->pStream, &pPulse->SampleSpec, &pPulse->BufAttr)) 522 528 return -1; 523 529 524 if (pulse_to_audfmt ( obt.pa_format, &effective_fmt, &endianness))525 { 526 LogRel(("Pulse: Cannot find audio format %d\n", obt.pa_format));530 if (pulse_to_audfmt (pPulse->SampleSpec.format, &obt_as.fmt, &obt_as.endianness)) 531 { 532 LogRel(("Pulse: Cannot find audio format %d\n", pPulse->SampleSpec.format)); 527 533 return -1; 528 534 } 529 535 530 obt_as.freq = obt.freq; 531 obt_as.nchannels = obt.nchannels; 532 obt_as.fmt = effective_fmt; 533 obt_as.endianness = endianness; 534 536 obt_as.freq = pPulse->SampleSpec.rate; 537 obt_as.nchannels = pPulse->SampleSpec.channels; 535 538 audio_pcm_init_info (&hw->info, &obt_as); 536 537 /* pcm_in: reserve twice as the maximum buffer length because of peek()/drop(). */ 538 hw->samples = 2 * (obt.buffer_size >> hw->info.shift); 539 540 /* no buffer for input */ 541 pulse->pPCMBuf = NULL; 539 hw->samples = audio_MIN(pPulse->BufAttr.fragsize * 10, pPulse->BufAttr.maxlength) 540 >> hw->info.shift; 541 pPulse->pu8PeekBuf = NULL; 542 542 543 543 return 0; … … 546 546 static void pulse_fini_in (HWVoiceIn *hw) 547 547 { 548 PulseVoice *pulse = (PulseVoice *)hw; 549 if (pulse->pStream) 550 { 551 pa_stream_disconnect(pulse->pStream); 552 pa_stream_unref(pulse->pStream); 553 pulse->pStream = NULL; 554 } 555 if (pulse->pPCMBuf) 556 { 557 RTMemFree (pulse->pPCMBuf); 558 pulse->pPCMBuf = NULL; 548 PulseVoice *pPulse = (PulseVoice *)hw; 549 550 if (pPulse->pStream) 551 { 552 pa_threaded_mainloop_lock(g_pMainLoop); 553 pa_stream_disconnect(pPulse->pStream); 554 pa_stream_unref(pPulse->pStream); 555 pa_threaded_mainloop_unlock(g_pMainLoop); 556 pPulse->pStream = NULL; 559 557 } 560 558 } … … 562 560 static int pulse_run_in (HWVoiceIn *hw) 563 561 { 564 PulseVoice *pulse = (PulseVoice *) hw; 565 int csDead, csDecr = 0, csSamples, csRead, csAvail; 566 size_t cbAvail; 567 const void *pu8Src; 568 st_sample_t *psDst; 569 570 csDead = hw->samples - audio_pcm_hw_get_live_in (hw); 571 572 if (!csDead) 573 return 0; /* no buffer available */ 574 562 PulseVoice *pPulse = (PulseVoice *) hw; 563 const int hwshift = hw->info.shift; 564 int cFramesRead = 0; /* total frames which have been read this call */ 565 int cFramesAvail; /* total frames available from pulse at start of call */ 566 int cFramesToRead; /* the largest amount we want/can get this call */ 567 int cFramesToPeek; /* the largest amount we want/can get this peek */ 568 569 /* We should only call pa_stream_readable_size() once and trust the first value */ 575 570 pa_threaded_mainloop_lock(g_pMainLoop); 576 577 if (pa_stream_peek(pulse->pStream, &pu8Src, &cbAvail) < 0) 578 { 579 LogRel(("Pulse: Peek failed: %s\n", 580 pa_strerror(pa_context_errno(g_pContext)))); 581 goto unlock_and_exit; 582 } 583 if (!pu8Src) 584 goto unlock_and_exit; 585 586 csAvail = cbAvail >> hw->info.shift; 587 csDecr = audio_MIN (csDead, csAvail); 588 589 csSamples = csDecr; 590 591 while (csSamples) 592 { 593 /* split request at the end of our samples buffer */ 594 psDst = hw->conv_buf + hw->wpos; 595 csRead = audio_MIN (csSamples, hw->samples - hw->wpos); 596 hw->conv (psDst, pu8Src, csRead, &nominal_volume); 597 hw->wpos = (hw->wpos + csRead) % hw->samples; 598 csSamples -= csRead; 599 pu8Src = (const void*)((uint8_t*)pu8Src + (csRead << hw->info.shift)); 600 } 601 602 pa_stream_drop(pulse->pStream); 603 604 unlock_and_exit: 571 cFramesAvail = pa_stream_readable_size(pPulse->pStream) >> hwshift; 605 572 pa_threaded_mainloop_unlock(g_pMainLoop); 606 573 607 return csDecr; 574 /* If the buffer was not dropped last call, add what remains */ 575 if (pPulse->pu8PeekBuf) 576 cFramesAvail += (pPulse->cbPeekBuf - pPulse->offPeekBuf) >> hwshift; 577 578 cFramesToRead = audio_MIN(cFramesAvail, hw->samples - audio_pcm_hw_get_live_in(hw)); 579 for (; cFramesToRead; cFramesToRead -= cFramesToPeek) 580 { 581 /* If there is no data, do another peek */ 582 if (!pPulse->pu8PeekBuf) 583 { 584 pa_threaded_mainloop_lock(g_pMainLoop); 585 pa_stream_peek(pPulse->pStream, (const void**)&pPulse->pu8PeekBuf, &pPulse->cbPeekBuf); 586 pa_threaded_mainloop_unlock(g_pMainLoop); 587 pPulse->offPeekBuf = 0; 588 if (!pPulse->cbPeekBuf) 589 break; 590 } 591 592 cFramesToPeek = audio_MIN((signed)( pPulse->cbPeekBuf 593 - pPulse->offPeekBuf) >> hwshift, 594 cFramesToRead); 595 596 /* Check for wrapping around the buffer end */ 597 if (hw->wpos + cFramesToPeek > hw->samples) 598 { 599 int cFramesDelta = hw->samples - hw->wpos; 600 601 hw->conv(hw->conv_buf + hw->wpos, 602 pPulse->pu8PeekBuf + pPulse->offPeekBuf, 603 cFramesDelta, 604 &nominal_volume); 605 606 hw->conv(hw->conv_buf, 607 pPulse->pu8PeekBuf + pPulse->offPeekBuf + (cFramesDelta << hwshift), 608 cFramesToPeek - cFramesDelta, 609 &nominal_volume); 610 } 611 else 612 { 613 hw->conv(hw->conv_buf + hw->wpos, 614 pPulse->pu8PeekBuf + pPulse->offPeekBuf, 615 cFramesToPeek, 616 &nominal_volume); 617 } 618 619 cFramesRead += cFramesToPeek; 620 hw->wpos = (hw->wpos + cFramesToPeek) % hw->samples; 621 pPulse->offPeekBuf += cFramesToPeek << hwshift; 622 623 /* If the buffer is done, drop it */ 624 if (pPulse->offPeekBuf == pPulse->cbPeekBuf) 625 { 626 pa_threaded_mainloop_lock(g_pMainLoop); 627 pa_stream_drop(pPulse->pStream); 628 pa_threaded_mainloop_unlock(g_pMainLoop); 629 pPulse->pu8PeekBuf = NULL; 630 } 631 } 632 633 return cFramesRead; 608 634 } 609 635 … … 615 641 static int pulse_ctl_in (HWVoiceIn *hw, int cmd, ...) 616 642 { 643 PulseVoice *pPulse = (PulseVoice *)hw; 644 645 switch (cmd) 646 { 647 case VOICE_ENABLE: 648 pulse_ctrl((PulseVoice *)hw, Unpause); 649 break; 650 case VOICE_DISABLE: 651 if (pPulse->pu8PeekBuf) 652 { 653 pa_stream_drop(pPulse->pStream); 654 pPulse->pu8PeekBuf = NULL; 655 } 656 pulse_ctrl((PulseVoice *)hw, Pause); 657 break; 658 default: 659 return -1; 660 } 617 661 return 0; 618 662 } … … 628 672 return NULL; 629 673 } 674 630 675 if (!(g_pMainLoop = pa_threaded_mainloop_new())) 631 676 { … … 634 679 goto fail; 635 680 } 681 636 682 if (!(g_pContext = pa_context_new(pa_threaded_mainloop_get_api(g_pMainLoop), "VBox"))) 637 683 { … … 640 686 goto fail; 641 687 } 688 642 689 if (pa_threaded_mainloop_start(g_pMainLoop) < 0) 643 690 { … … 689 736 g_pContext = NULL; 690 737 } 738 691 739 if (g_pMainLoop) 692 740 { … … 694 742 g_pMainLoop = NULL; 695 743 } 744 696 745 return NULL; 697 746 } … … 701 750 if (g_pMainLoop) 702 751 pa_threaded_mainloop_stop(g_pMainLoop); 752 703 753 if (g_pContext) 704 754 { … … 707 757 g_pContext = NULL; 708 758 } 759 709 760 if (g_pMainLoop) 710 761 { … … 712 763 g_pMainLoop = NULL; 713 764 } 765 714 766 (void) opaque; 715 767 }
Note:
See TracChangeset
for help on using the changeset viewer.

