static gboolean gst_nas_sink_unprepare (GstAudioSink * asink) { GstNasSink *sink = GST_NAS_SINK (asink); if (sink->flow != AuNone) { AuBool clocked; int num_elements; AuStatus status; AuElement *oldelems; GST_DEBUG_OBJECT (sink, "flushing buffer"); NAS_flush (sink); oldelems = AuGetElements (sink->audio, sink->flow, &clocked, &num_elements, &status); if (num_elements > 0) { GST_DEBUG_OBJECT (sink, "GetElements status: %i", status); if (oldelems) AuFreeElements (sink->audio, num_elements, oldelems); } AuStopFlow (sink->audio, sink->flow, NULL); AuReleaseScratchFlow (sink->audio, sink->flow, NULL); sink->flow = AuNone; } sink->need_data = 0; return TRUE; }
int ao_plugin_close(ao_device *device) { ao_nas_internal *internal = (ao_nas_internal *) device->internal; if(internal->aud) { AuStopFlow(internal->aud, internal->flow, 0); AuCloseServer(internal->aud); } return 1; }
static void gst_nas_sink_reset (GstAudioSink * asink) { GstNasSink *sink = GST_NAS_SINK (asink); GST_DEBUG_OBJECT (sink, "reset"); if (sink->flow != AuNone) AuStopFlow (sink->audio, sink->flow, NULL); }
static int nas_close(WINE_WAVEOUT* wwo) { AuEvent ev; nas_free(wwo); AuStopFlow(wwo->AuServ, wwo->AuFlow, NULL); AuDestroyFlow(wwo->AuServ, wwo->AuFlow, NULL); AuFlush(wwo->AuServ); AuNextEvent(wwo->AuServ, AuTrue, &ev); AuDispatchEvent(wwo->AuServ, &ev); wwo->AuFlow = 0; wwo->open = 0; wwo->BufferUsed = 0; wwo->freeBytes = 0; wwo->SoundBuffer = NULL; return 1; }
static AuBool nas_event_handler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *hnd) { AuElementNotifyEvent *event = (AuElementNotifyEvent*)ev; audio_job_t aj = hnd->data; snsd_t *snsd = audio_job_device_data(aj); NAS_DEBUG_EV("event_handler(): " "type %s kind %s state %s->%s reason %s " "numbytes %u\n", nas_event_type(event->type), nas_elementnotify_kind(event->kind), nas_state(event->prev_state), nas_state(event->cur_state), nas_reason(event->reason), (uint32_t)event->num_bytes); if (event->num_bytes > INT_MAX) { NAS_CRITICAL("num_bytes > 2GB, server buggy?\n"); } switch (event->reason) { case AuReasonWatermark: nas_read(aj, event->num_bytes); break; case AuReasonUnderrun: /* buffer underrun -> refill buffer */ if (nas_read(aj, event->num_bytes) != 0) { event->cur_state = AuStateStart; NAS_DEBUG_EV("restarting\n"); break; } NAS_DEBUG_S("Can't refill buffer, stopping flow.\n"); AuStopFlow(aud, snsd->flow, NULL); aj->play_state = MTPSTATE_STOP; break; default: break; } return AuTrue; }
static gboolean gst_nas_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) { GstNasSink *sink = GST_NAS_SINK (asink); /*spec->bytes_per_sample = sink->rate * NAS_SOUND_PORT_DURATION; */ /*spec->bytes_per_sample = (spec->width / 8) * spec->channels; */ memset (spec->silence_sample, 0, spec->bytes_per_sample); GST_DEBUG_OBJECT (sink, "Sample %d", spec->bytes_per_sample); if (sink->audio == NULL) return TRUE; if (sink->flow != AuNone) { GST_DEBUG_OBJECT (sink, "flushing buffer"); NAS_flush (sink); AuStopFlow (sink->audio, sink->flow, NULL); AuReleaseScratchFlow (sink->audio, sink->flow, NULL); sink->flow = AuNone; } return NAS_createFlow (sink, spec); }
static gboolean gst_nas_sink_close (GstAudioSink * asink) { GstNasSink *sink = GST_NAS_SINK (asink); if (sink->audio == NULL) return TRUE; if (sink->flow != AuNone) { NAS_flush (sink); AuStopFlow (sink->audio, sink->flow, NULL); AuReleaseScratchFlow (sink->audio, sink->flow, NULL); sink->flow = AuNone; } sink->need_data = 0; AuCloseServer (sink->audio); sink->audio = NULL; GST_DEBUG_OBJECT (sink, "closed audio device"); return TRUE; }
static AuBool NAS_EventHandler (AuServer * aud, AuEvent * ev, AuEventHandlerRec * handler) { GstNasSink *sink = (GstNasSink *) handler->data; AuElementNotifyEvent *notify; switch (ev->type) { case AuEventTypeElementNotify: notify = (AuElementNotifyEvent *) ev; switch (notify->kind) { case AuElementNotifyKindLowWater: NAS_sendData (sink, notify->num_bytes); break; case AuElementNotifyKindState: switch (notify->cur_state) { case AuStateStop: if (sink->flow != AuNone) { if (notify->reason == AuReasonEOF) AuStopFlow (handler->aud, sink->flow, NULL); AuReleaseScratchFlow (handler->aud, sink->flow, NULL); sink->flow = AuNone; } AuUnregisterEventHandler (handler->aud, handler); break; case AuStatePause: switch (notify->reason) { case AuReasonUnderrun: case AuReasonOverrun: case AuReasonEOF: case AuReasonWatermark: NAS_sendData (sink, notify->num_bytes); break; case AuReasonHardware: if (AuSoundRestartHardwarePauses) AuStartFlow (handler->aud, sink->flow, NULL); else AuStopFlow (handler->aud, sink->flow, NULL); break; } break; } break; } break; } return AuTrue; }
static int sound_nas_play(audio_job_t aj) { /* stream stuff */ Lisp_Media_Stream *ms; media_substream *mss; /* thread stuff */ media_thread_play_state mtp; /* device stuff */ Lisp_Object device; Lisp_Audio_Device *lad = NULL; sound_nas_data_t *snd = NULL; /* nas stuff */ AuElement elms[3]; AuStatus as; int bsize = 0; /* subthread stuff */ sound_nas_aj_data_t _snsd, *snsd = &_snsd; sxe_mse_volume_args _volargs, *volargs = &_volargs; sxe_mse_rerate_args _rrargs, *rrargs = &_rrargs; /* cache stuff */ int alloced_myself = 0; SOUND_UNPACK_MT(aj, device, ms, mss, lad, snd, snsd->mtap); /* refuse to do anything if the AuServer pointer is not set */ if (snd->aud == NULL) { NAS_DEBUG_C("b0rked connection, gute Nacht!\n"); return 0; } /* install error handlers before anything else */ AuSetErrorHandler(snd->aud, nas_error_handler); AuSetIOErrorHandler(snd->aud, nas_IOerror_handler); /* find physical output device */ snsd->dev = nas_find_device(snd->aud, snsd->mtap->channels); if (snsd->dev == AuNone || !(snsd->flow = AuCreateFlow(snd->aud, NULL))) { /* No physical output device found or flow creation failed. */ NAS_DEBUG_C("no physical devices for this stream\n"); return 0; } /* A system call interrupted with a SIGALRM or SIGIO comes back here */ if (SETJMP(nas_server_sig)) { NAS_CRITICAL("Caught the lethal signal.\n"); snd->aud = NULL; sound_nas_finish(snd); goto uhoh; } /* init the snsd */ snsd->samplerate = 0; snsd->framesize = (snsd->channels = snsd->mtap->channels) * sizeof(int16_t); snsd->msf = MEDIA_SAMPLE_FORMAT(sxe_msf_S16); snsd->coe_ch_cnt = 0; snsd->resolution = (snsd->mtap->samplerate * MTPSTATE_REACT_TIME) / 1000000; bsize = (snsd->resolution + NAS_FRAG_SIZE - 1) & ~(NAS_FRAG_SIZE-1); snsd->snd = snd; snsd->buffer_size = bsize; snsd->writepos = snsd->readpos = 0; snsd->overfill = snsd->underrun = 0; /* set up flow */ AuMakeElementImportClient(elms+0, snsd->mtap->samplerate, AuFormatLinearSigned16LSB, snsd->mtap->channels, AuTrue, bsize, bsize / 2, 0, NULL); snsd->gain = AuFixedPointFromFraction(1, 1); AuMakeElementMultiplyConstant(elms+1, 0, snsd->gain); AuMakeElementExportDevice(elms+2, 0, snsd->dev, snsd->mtap->samplerate, AuUnlimitedSamples, 0, NULL); AuSetElements(snd->aud, snsd->flow, AuTrue, 3, elms, &as); if (as != AuSuccess) { NAS_DEBUG_C("play(): AuSetElements failed\n"); return 0; } #if 0 /* atm we insist on having stereo access */ /* the channel effect */ ADD_MEDIA_SAMPLE_EFFECT( snsd->coe_chain, snsd->coe_ch_cnt, MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch), NULL); #endif /* the volume effect */ ADD_MEDIA_SAMPLE_EFFECT( snsd->coe_chain, snsd->coe_ch_cnt, MEDIA_SAMPLE_EFFECT(sxe_mse_volume), volargs); volargs->num_channels = snsd->channels; snsd->volargs = volargs; /* the rerate effect */ ADD_MEDIA_SAMPLE_EFFECT( snsd->coe_chain, snsd->coe_ch_cnt, MEDIA_SAMPLE_EFFECT(sxe_mse_rerate), rrargs); rrargs->num_channels = snsd->channels; rrargs->srcrate = rrargs->tgtrate = 1; snsd->rrargs = rrargs; AuRegisterEventHandler(snd->aud, AuEventHandlerIDMask | AuEventHandlerTypeMask, AuEventTypeElementNotify, snsd->flow, nas_event_handler, (AuPointer)aj); /* rewind the stream */ media_stream_meth(ms, rewind)(mss); /* play chunks of the stream */ SXE_MUTEX_LOCK(&aj->mtx); if (aj->buffer_alloc_size < SOUND_MAX_AUDIO_FRAME_SIZE) { alloced_myself = 1; aj->buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE); aj->buffer_alloc_size = SOUND_MAX_AUDIO_FRAME_SIZE; } SXE_MUTEX_UNLOCK(&aj->mtx); snsd->mtp = MTPSTATE_STOP; snsd->volume = -1; audio_job_device_data(aj) = snsd; /* prefill the buffer */ NAS_DEBUG_S("prefill the buffer: %d\n", 4*bsize); if (!nas_fill(aj, 4*bsize)) goto uhoh; while (aj->play_state != MTPSTATE_STOP) { #if 0 if (aj->volume != snsd->volume) { AuElementParameters aep; NAS_DEBUG_S("Setting volume.\n"); snsd->volume = aj->volume; snsd->gain = AU_FIXED_POINT_SCALE*(snsd->volume)/127; aep.parameters[AuParmsMultiplyConstantConstant] = snsd->gain; aep.flow = snd->flow; aep.element_num = 1; aep.num_parameters = AuParmsMultiplyConstant; AuSetElementParameters(snd->aud, 1, &aep, &as); if (as != AuSuccess) { NAS_DEBUG_S("Setting volume failed.\n"); } } #endif #ifdef EF_USE_ASYNEQ /* events for me audio-job? */ if (audio_job_queue(aj)) { sound_nas_handle_aj_events(aj); } #endif SXE_MUTEX_LOCK(&aj->mtx); mtp = aj->play_state; SXE_MUTEX_UNLOCK(&aj->mtx); switch (mtp) { case MTPSTATE_RUN: if (snsd->mtp != mtp) { NAS_DEBUG("ah, gotta work again\n"); AuStartFlow(snd->aud, snsd->flow, &as); if (as != AuSuccess) { NAS_DEBUG_C("play(): " "AuStartFlow failed\n"); aj->play_state = MTPSTATE_STOP; } } nas_empty_event_queue(snsd); usleep(snsd->resolution); break; case MTPSTATE_PAUSE: if (snsd->mtp != mtp) { NAS_DEBUG("sleeping for %d\n", snsd->resolution); AuStopFlow(snd->aud, snsd->flow, &as); } usleep(snsd->resolution); break; case MTPSTATE_UNKNOWN: case MTPSTATE_STOP: case NUMBER_OF_MEDIA_THREAD_PLAY_STATES: default: NAS_DEBUG("ACK, quit\n"); AuStopFlow(snd->aud, snsd->flow, &as); SXE_MUTEX_LOCK(&aj->mtx); aj->play_state = MTPSTATE_STOP; SXE_MUTEX_UNLOCK(&aj->mtx); break; } snsd->mtp = mtp; } uhoh: /* -- Close and shutdown -- */ SXE_MUTEX_LOCK(&aj->mtx); if (alloced_myself && aj->buffer) { xfree(aj->buffer); } aj->buffer = NULL; aj->buffer_alloc_size = 0; SXE_MUTEX_UNLOCK(&aj->mtx); return 1; }