/* This thread can lock, do whatever it wants, and read from/write to the jack * ring buffers * XXX: Access to shared state (i.e. member variables) should be synchronized if needed */ void JackLayer::ringbuffer_worker() { flushMain(); flushUrgent(); while (true) { std::unique_lock<std::mutex> lock(ringbuffer_thread_mutex_); // may have changed, we don't want to wait for a notification we won't get if (status_ != Status::Started) return; // FIXME this is all kinds of evil usleep(20000); capture(); playback(); // wait until process() signals more data // FIXME: this checks for spurious wakes, but the predicate // is rather arbitrary. We should wait until ring has/needs data // and jack has/needs data. data_ready_.wait(lock, [&] { // Note: lock is released while waiting, and held when woken // up, so this predicate is called while holding the lock return status_ != Status::Started or ringbuffer_ready_for_read(in_ringbuffers_[0]); }); } }
int main(int argc, char *argv[]) { writei_func = snd_pcm_writei; int err; char *pcm_name = "default"; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); stream = SND_PCM_STREAM_PLAYBACK; err = snd_pcm_open(&handle, pcm_name, stream, open_mode); if (err < 0) { // error(_("audio open error: %s"), snd_strerror(err)); return 1; } if ((err = snd_pcm_info(handle, info)) < 0) { // error(_("info error: %s"), snd_strerror(err)); return 1; } snd_pcm_nonblock(handle, 0); printf("set_params!!\n"); // set_params(); //playbackv(&argv[1], argc0); printf("playback!!\n"); playback(argv[1]); return 0; }
/*Initializes all the actions(buttons)*/ void MainWindow::loadActions() { for (int i = 5; i <= 100; i= i+5) { string sizes = to_string(i); char const *pchar = sizes.c_str(); QAction *action = new QAction(tr(pchar), this); action->setData(i); connect(action, SIGNAL(triggered()), this, SLOT(resizeBrush())); sizeActions.append(action); } for (int i = 1; i <= 3; ++i) { string sizes = to_string(i); char const *pchar = sizes.c_str(); QAction *action = new QAction(tr("Map %1").arg(pchar) , this); action->setData(i); connect(action, SIGNAL(triggered()), this, SLOT(map())); mapActions.append(action); } playbackAction = new QAction(tr("&PlayBack"), this); connect(playbackAction, SIGNAL(triggered()), drawArea, SLOT(playback())); saveAction = new QAction(tr("&Save"), this); connect(saveAction, SIGNAL(triggered()), this, SLOT(saveGesture())); openAction = new QAction(tr("&Open"), this); connect(openAction, SIGNAL(triggered()), this, SLOT(openGesture())); clearScreenAction = new QAction(tr("&ClearScreen"), this); clearScreenAction->setShortcut(tr("Ctrl+L")); connect(clearScreenAction, SIGNAL(triggered()), drawArea, SLOT(clearScreen())); }
int main(void) { // playbackRandom(); capture(0); printf("Capture done, sleeping for 5 secs\n"); sleep(5); playback(); return 0; }
void main(){ initialize(STEREO,RESOLUTION,SAMPLINGRATE); // MONO/STEREO, 16/24-bit, sampling rate (48 kHz or 96 kHz) printf("\nPlayback Loop\n"); playback(); while(1); }
int do_play(char* file_name) { char *pcm_name = "default"; int tmp, err, c; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); err = snd_output_stdio_attach(&log, stderr, 0); assert(err >= 0); stream = SND_PCM_STREAM_PLAYBACK; chunk_size = -1; rhwparams.format = DEFAULT_FORMAT; rhwparams.rate = DEFAULT_SPEED; rhwparams.channels = 1; err = snd_pcm_open(&handle, pcm_name, stream, open_mode); if (err < 0) { error(_("audio open error: %s"), snd_strerror(err)); return 1; } if ((err = snd_pcm_info(handle, info)) < 0) { error(_("info error: %s"), snd_strerror(err)); return 1; } if (nonblock) { err = snd_pcm_nonblock(handle, 1); if (err < 0) { error(_("nonblock setting error: %s"), snd_strerror(err)); return 1; } } chunk_size = 1024; hwparams = rhwparams; audiobuf = (u_char *)malloc(1024); if (audiobuf == NULL) { error(_("not enough memory")); return 1; } signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGABRT, signal_handler); playback(file_name); snd_pcm_close(handle); free(audiobuf); snd_output_close(log); snd_config_update_free_global(); return EXIT_SUCCESS; }
SkPicture* SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data) { if (!data) { return nullptr; } SkPicturePlayback playback(data); SkPictureRecorder r; playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/); return r.endRecording(); }
void AlsaLayer::audioCallback() { if (!playbackHandle_ or !captureHandle_) return; notifyIncomingCall(); snd_pcm_wait(playbackHandle_, 20); int playbackAvailFrames = 0; if (not safeUpdate(playbackHandle_, playbackAvailFrames)) return; unsigned framesToGet = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID); if (framesToGet > 0) { // Urgent data (dtmf, incoming call signal) come first. framesToGet = std::min(framesToGet, (unsigned)playbackAvailFrames); playbackBuff_.setFormat(audioFormat_); playbackBuff_.resize(framesToGet); urgentRingBuffer_.get(playbackBuff_, MainBuffer::DEFAULT_ID); playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); playbackBuff_.interleave(playbackIBuff_); write(playbackIBuff_.data(), framesToGet, playbackHandle_); // Consume the regular one as well (same amount of frames) Manager::instance().getMainBuffer().discard(framesToGet, MainBuffer::DEFAULT_ID); } else { // regular audio data playback(playbackAvailFrames); } if (ringtoneHandle_) { AudioLoop *file_tone = Manager::instance().getTelephoneFile(); int ringtoneAvailFrames = 0; if (not safeUpdate(ringtoneHandle_, ringtoneAvailFrames)) return; playbackBuff_.setFormat(audioFormat_); playbackBuff_.resize(ringtoneAvailFrames); if (file_tone) { DEBUG("playback gain %d", playbackGain_); file_tone->getNext(playbackBuff_, playbackGain_); } playbackBuff_.interleave(playbackIBuff_); write(playbackIBuff_.data(), ringtoneAvailFrames, ringtoneHandle_); } // Additionally handle the mic's audio stream if (is_capture_running_) capture(); }
sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data, const SkReadBuffer* buffer) { if (!data) { return nullptr; } SkPicturePlayback playback(data); SkPictureRecorder r; playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer); return r.finishRecordingAsPicture(); }
static SkTimedPicturePlayback* CreateFromStream(SkStream* stream, const SkPictInfo& info, SkPicture::InstallPixelRefProc proc, const SkTDArray<bool>& deletedCommands) { // Mimics SkPicturePlayback::CreateFromStream SkAutoTDelete<SkTimedPicturePlayback> playback(SkNEW_ARGS(SkTimedPicturePlayback, (deletedCommands))); if (!playback->parseStream(stream, info, proc)) { return NULL; // we're invalid } return playback.detach(); }
int main(void) { volatile long int char_count = 0; volatile long int* char_count_pointer = &char_count; robot_status = ENABLED; print("Robot Enabled!\n"); pause(1000); #ifdef TEST test(char_count_pointer); return 0; #endif #ifdef PLAYBACK //make sure this is before LOG because it will reopen file with write logInit(); playback("Main.txt", LOG_SIZE); pause(5000); #endif #ifdef LOG logInit(); logData("Main.txt", "Hello File World!\n", 0, char_count_pointer); #endif #ifdef DRIVE initDrive(); #endif filter_count = 0; counter = 0; print("Hello Robot\n"); low(LED_2); low(LED_1); //distance_parallel(); while(1)//main loop { debug("loop\n",0); //debug("Loop\n", 0); //button(); navigate(); //checkDriveTrain(); //pause(100); counter++; //VERY IMPORTANT } print("Robot disabled!\n"); }
void VideoPlayer::run() { stopPlayback = false; while(true && !stopPlayback) { garbageCollection(); deinitCodec(); initCodec(); while(playback() && !stopPlayback) { } } }
sk_sp<SkFlattenable> SkRecordedDrawable::CreateProc(SkReadBuffer& buffer) { // Read the bounds. SkRect bounds; buffer.readRect(&bounds); // Unflatten into a SkPictureData. SkPictInfo info; info.fCullRect = bounds; SkAutoTDelete<SkPictureData> pictureData(SkPictureData::CreateFromBuffer(buffer, info)); if (!pictureData) { return nullptr; } // Create a drawable. SkPicturePlayback playback(pictureData); SkPictureRecorder recorder; playback.draw(recorder.beginRecording(bounds), nullptr, &buffer); return recorder.finishRecordingAsDrawable(); }
int USBH_USR_MSC_Application() { static uint8_t is_rdy = 0; if(is_rdy) { if(HCD_IsDeviceConnected(&USB_OTG_Core) != 1) while(1); playback(result); //write_file("audio.wav", (void*)data, sizeof(uint16_t)*MAX_BUF_SIZE); f_mount(0, 0); STM_EVAL_LEDOff(LED6); while(1); } else { if(f_mount( 0, &fatfs ) != FR_OK ) while(1); if(USBH_MSC_Param.MSWriteProtect == DISK_WRITE_PROTECTED) while(1); is_rdy = 1; } return 0; }
bool Editor::exportMovieCLI(QString filePath, LayerCamera *cameraLayer, int width, int height, int startFrame, int endFrame) { if (width < 0) { width = cameraLayer->getViewRect().width(); } if (height < 0) { height = cameraLayer->getViewRect().height(); } if (startFrame < 1) { startFrame = 1; } if (endFrame < -1) { endFrame = mLayerManager->animationLength(); } if (endFrame < 0) { endFrame = mLayerManager->animationLength(false); } QSize exportSize = QSize(width, height); ExportMovieDesc desc; desc.strFileName = filePath; desc.startFrame = startFrame; desc.endFrame = endFrame; desc.fps = playback()->fps(); desc.exportSize = exportSize; desc.strCameraName = cameraLayer->name(); MovieExporter ex; ex.run(object(), desc, [](float,float){}, [](float){}, [](QString){}); return true; }
bool SkMultiPictureDocumentRead(SkStreamSeekable* stream, SkDocumentPage* dstArray, int dstArrayCount, const SkDeserialProcs* procs) { if (!SkMultiPictureDocumentReadPageSizes(stream, dstArray, dstArrayCount)) { return false; } SkSize joined = {0.0f, 0.0f}; for (int i = 0; i < dstArrayCount; ++i) { joined = SkSize{SkTMax(joined.width(), dstArray[i].fSize.width()), SkTMax(joined.height(), dstArray[i].fSize.height())}; } auto picture = SkPicture::MakeFromStream(stream, procs); PagerCanvas canvas(joined.toCeil(), dstArray, dstArrayCount); // Must call playback(), not drawPicture() to reach // PagerCanvas::onDrawAnnotation(). picture->playback(&canvas); if (canvas.fIndex != dstArrayCount) { SkDEBUGF("Malformed SkMultiPictureDocument\n"); } return true; }
int main(int argc, char *argv[]) { pid_t fpid; int msgid = -1; msgid = msgget((key_t)1234, 0666 | IPC_CREAT); if(msgid == -1) { fprintf(stderr, "msgget failed with error: %d\n", errno); exit(-1); } fpid=fork(); if(fpid<0) printf("fork failed\n"); else if(fpid==0) { //child process,capture audio when main process send start cmd, finish when receive stop cmd //rec((char *)argv[1]); long int msgtype = 8;//MAIN_TO_AUDIO 8 struct msg_st data_r; while(1) { printf("waiting audio capt cmd...\n"); msgrcv(msgid, (void*)&data_r, sizeof(struct msg_st)-sizeof(long int), msgtype, 0); printf("data_r id %d,text %d\n",data_r.msg_type,data_r.id); switch (data_r.id) { case 0://start rec { rec("/tmp/rec.avi"); } break; case 2://start transfer string and play { play(data_r.text,"/tmp/3.wav"); playback("/tmp/3.wav"); } break; default: break; } } } else { //father process long int msgtype = 8;//MAIN_TO_AUDIO 8 struct msg_st data_r; int status; while(1) { ms_sleep(2); data_r.msg_type = 8; data_r.id=0; printf("start record\n"); if(msgsnd(msgid, (void*)&data_r, sizeof(struct msg_st)-sizeof(long int), IPC_NOWAIT) == -1) { fprintf(stderr, "msgsnd failed %s msgid %d\n",strerror(errno),msgid); exit(1); } ms_sleep(3); data_r.msg_type = 8; data_r.id=1; printf("stop record\n"); if(msgsnd(msgid, (void*)&data_r, sizeof(struct msg_st)-sizeof(long int), IPC_NOWAIT) == -1) { fprintf(stderr, "msgsnd failed %s\n",strerror(errno)); exit(1); } printf("waiting message 7\n"); msgtype=7; msgrcv(msgid, (void*)&data_r, sizeof(struct msg_st)-sizeof(long int), msgtype, 0); printf("Get Result %s\n",data_r.text); data_r.msg_type = 8; //注意2 data_r.id=2; printf("start transfer and playback\n"); if(msgsnd(msgid, (void*)&data_r, sizeof(struct msg_st)-sizeof(long int), IPC_NOWAIT) == -1) { fprintf(stderr, "msgsnd failed %s\n",strerror(errno)); exit(1); } system("rm /tmp/rec.avi"); //system("ipcs -q"); } waitpid(fpid, &status, 0); } return 0; }
void doState(states_t command, SAMPLE* sptr) { int tempi; switch(command) { // ring buffer contents are initialized // next state determined by caller case S_INIT: currentSTATE = S_INIT; zeroMemory(sptr); break; // filling the ring buffer with samples // next state determined by caller case S_COLLECTING: currentSTATE = S_COLLECTING; //printf("\n=== Now recording!! ===\n"); //fflush(stdout); break; // simple playback of last NUM_PLAYBACK_SECONDS seconds case S_REWIND_10: currentSTATE = S_REWIND_10; greenLED = ON; digitalWrite (LED_PIN, ON) ; // tell playback callback how many frames to play data.maxFrameIndex = totalFrames = NUM_PLAYBACK_SECONDS * SAMPLE_RATE; // reset playback count data.frameIndex = 0; // playback NUM_PLAYBACK_SECONDS // adjust pointers with mod RING_BUFFER_LEN arithmetic tempi = ringbufferWPTR - (data.maxFrameIndex * NUM_CHANNELS); if(tempi < 0) tempi += RING_BUFFER_LEN; ringbufferRPTR = tempi; playbackDirection = FWD; buttonPress = FALSE; buttonHold = FALSE; // Playback recorded data. ---------------------------------- // advance state to playback currentSTATE = S_PLAYBACK; break; // rewind playback while button is held // playback from top of buffer but at faster sample rate // when button is release, advance state and playback at // normal sample rate from where we released button // the FWD/REV i/o pin tells to go from the top of the buffer // in the REV speech direction or all the way from the start of the // buffer (5 min back in time) in the FWD speech direction case S_REWIND_PLAYBACK: currentSTATE = S_REWIND_PLAYBACK; //+++++++++++++++++++++++++++++++++++++++++++++++++++++ greenLED = ON; digitalWrite (LED_PIN, ON) ; // tell playback how many frames to play // say all of them but we will use the button // unpress to stop before this data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE - 4; // reset playback count data.frameIndex = 0; buttonPress = FALSE; buttonHold = FALSE; if(digitalRead(DIRECTION_PIN) == 1) { // playback fast and in reverse from current write pointer playbackDirection = REV; // start at buffer head ringbufferRPTR = ringbufferWPTR; // fast playback 4X speed playback(32000); // stays here until rewind playback finished // will return here when button is released } else { // playback fast and in forward direction // from buffer start playbackDirection = FWD; // all the way back 5 minutes in time tempi = ringbufferWPTR - ( NUM_SECONDS * SAMPLE_RATE * NUM_CHANNELS - 4); if(tempi < 0) tempi += RING_BUFFER_LEN; ringbufferRPTR = tempi; // fast playback 2X speed playback(16000); // stays here until rewind playback finished // will return here when button is released } //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // we are finished rewinding playback // now do regular forward playback from read pointer which has // been going in the reverse direction // (or forward direction depending on io pin) // how far did we go back? // we started at buffer head // ringbufferRPTR = ringbufferWPTR; // we held the button this many samples tempi = ringbufferWPTR - ringbufferRPTR; if(tempi < 0) tempi += RING_BUFFER_LEN; // tell playback how many frames to play // pointers are in samples // maxFrameIndex is in frames--duh! data.maxFrameIndex = totalFrames = tempi / NUM_CHANNELS; // reset playback count data.frameIndex = 0; // reset RPTR // playback NUM_PLAYBACK_SECONDS tempi = ringbufferWPTR - (data.maxFrameIndex * NUM_CHANNELS); if(tempi < 0) tempi += RING_BUFFER_LEN; ringbufferRPTR = tempi; playbackDirection = FWD; buttonPress = FALSE; buttonHold = FALSE; // Playback recorded data. ---------------------------------- // advance state to playback currentSTATE = S_PLAYBACK; break; // playback from top of buffer at normal sample rate // data.maxFrameIndex should be set case S_PLAYBACK: currentSTATE = S_PLAYBACK; // playback from the top of the buffer // will only run interrupts until playback finished // state machine will not run until returns playback(8000); // stays here until playback finished greenLED = OFF; digitalWrite (LED_PIN, OFF) ; // will return here when all samples have been played currentSTATE = S_STOP; break; // all stop--pointer rudder is amidship // ring buffer contents are preserved // to exit this state, power down. // todo(maybe?): to exit this state, five button presses? // how would I remember that? Add more buttons? Labels? ... case S_STOP: currentSTATE = S_STOP; // leave the S_STOP state (LED OFF) when button is pressed once // (10 second rewind) or held pressed (rewind playback FWD or REV // 4X/2X speed) // Not implemented-- re-enter S_COLLECTING and overwrite samples // with 5 button presses (?) or something... // like another hardware switch if(digitalRead(REBOOT_PIN) == 0) { system("/home/pi/reboot.py"); } tempi = checkButton(); if(tempi == OFF) break; if(tempi == 1) { //printf("button press\n"); //fflush(stdout); currentSTATE = S_REWIND_10; break; } else { // checkButton returned minus //printf("button hold\n"); //fflush(stdout); currentSTATE = S_REWIND_PLAYBACK; //terminate = TRUE; //printf("terminate\n"); //fflush(stdout); break; } break; default: break; } }
int main(int argc, char *argv[]) { int rc=0; signal(SIGINT, ctrlc); oscstreamdb_defaults(); init_playmode_default(argv[0]); if (cmdline(argc, argv)) return 1; if (n_device_strings < 1) { printf("You must specify a device name to record. (-d)\n"); return 1; } switch (backend) { case BACKEND_TEXT: backend_start = text_start; backend_stop = text_stop; backend_poll = text_poll; backend_write_value = text_write_value; backend_write_generic = text_write_generic; backend_seek_start = text_seek_start; backend_read = text_read; break; case BACKEND_BINARY: backend_start = binary_start; backend_stop = binary_stop; backend_poll = binary_poll; backend_write_value = binary_write_value; //WIP //backend_write_generic = binary_write_generic; break; case BACKEND_OSCSTREAMDB: if (backend_oscstreamdb_options.stream==0) { help(); return 1; } backend_start = oscstreamdb_start; backend_stop = oscstreamdb_stop; backend_poll = oscstreamdb_poll; backend_write_value = oscstreamdb_write_value; //WIP //backend_write_generic = oscstreamdb_write_generic; break; default: printf("Unknown backend selected.\n"); return 1; } if (playback_mode) { playback(0); return 0; } if (backend_start()) { printf("Error starting backend.\n"); rc = 1; goto done; } if (recmonitor_start()) { printf("Error starting monitor.\n"); rc = 1; goto done; } if (recdevice_start()) { printf("Error starting device.\n"); rc = 1; goto done; } while (!(backend_poll() || command_poll() || done)) { recmonitor_poll(); recdevice_poll(100); } done: printf("Exiting.\n"); recmonitor_stop(); recdevice_stop(); backend_stop(); return rc; }
void Visualizer::drawHistory() { glPushMatrix(); /* struct timespec tv; clock_gettime(CLOCK_MONOTONIC, &tv); double time = tv.tv_sec + tv.tv_nsec*1e-9; glRotatef(time*360/mRepeater->getOptions().loopDelay/4, 0, 0, -1); */ mRepeater->getHistory(mHistory); mRoundShader->bind(); ERRORCHECK(); const size_t count = mHistory.history.size(); double maxR = 1e-6; // TODO make these persistent QuadLoop power(count); LineLoop limit(count); QuadLoop expected(count); LineLoop playback(count); { QuadLoop::iterator pi = power.begin(); QuadLoop::iterator ei = expected.begin(); LineLoop::iterator li = limit.begin(); LineLoop::iterator pb = playback.begin(); for (auto dp : mHistory.history) { //maxR = std::max(maxR, li->y = dp.limitPower); li->y = dp.limitPower; li++; maxR = std::max(maxR, ei->out.y = dp.expectedPower); ei++; maxR = std::max(maxR, pi->out.y = dp.recordedPower); pi->in.r = dp.recordedPower/dp.limitPower; pi->out.r = dp.recordedPower; pi->in.a = 0.1; pi->out.a = 0.8; pi++; maxR = std::max(maxR, pb->y = dp.expectedPower*dp.actualGain); pb++; } } mZoom = mZoom*0.9 + 0.1*0.97/maxR; glScalef(mZoom, mZoom, mZoom); glEnableClientState(GL_VERTEX_ARRAY); glColor4f(0.5, 0.5, 0, 0.3); expected.draw(); glColor4f(1, 1, 0, 1); glLineWidth(1); expected.drawOutline(); glEnableClientState(GL_COLOR_ARRAY); power.draw(); glDisableClientState(GL_COLOR_ARRAY); glColor4f(1, 0, 0, 1); glLineWidth(2); limit.draw(); glColor4f(0, 1, 0, 0.5); glLineWidth(0.5); playback.draw(); ERRORCHECK(); glDisableClientState(GL_VERTEX_ARRAY); glLineWidth(2); glBegin(GL_LINES); glColor4f(0, 1, 0, 0.5); glVertex3f(power[mHistory.playPos].in.x, 0, 0); glVertex3f(power[mHistory.playPos].in.x, 100, 0); glColor4f(0, 0, 1, 0.5); glVertex3f(power[mHistory.recordPos].in.x, 0, 0); glVertex3f(power[mHistory.recordPos].in.x, 100, 0); glEnd(); { size_t i = mHistory.recordPos; double x = power[i].in.x; const auto& dp = mHistory.history[i]; mVolume = mVolume*0.95 + dp.expectedPower*0.05; glPointSize(10); glBegin(GL_POINTS); glColor4f(1, 0, 1, 0.5); glVertex3f(x, mVolume*dp.targetGain, 0); glColor4f(0, 0.5, 0.5, 0.5); glVertex3f(x, mVolume*dp.actualGain, 0); glEnd(); glPointSize(7); glBegin(GL_POINTS); glColor4f(0, 0.7, 0.7, 0.7); glVertex3f(x, mVolume*dp.actualGain, 0); glEnd(); } ERRORCHECK(); glPopMatrix(); }
static int handle(struct device *dv) { int r; unsigned short revents; struct alsa *alsa = (struct alsa*)dv->local; /* Check input buffer for timecode capture */ r = pcm_revents(&alsa->capture, &revents); if (r < 0) return -1; if (revents & POLLIN) { r = capture(dv); if (r < 0) { if (r == -EPIPE) { fputs("ALSA: capture xrun.\n", stderr); r = snd_pcm_prepare(alsa->capture.pcm); if (r < 0) { alsa_error("prepare", r); return -1; } r = snd_pcm_start(alsa->capture.pcm); if (r < 0) { alsa_error("start", r); return -1; } } else { alsa_error("capture", r); return -1; } } } /* Check the output buffer for playback */ r = pcm_revents(&alsa->playback, &revents); if (r < 0) return -1; if (revents & POLLOUT) { r = playback(dv); if (r < 0) { if (r == -EPIPE) { fputs("ALSA: playback xrun.\n", stderr); r = snd_pcm_prepare(alsa->playback.pcm); if (r < 0) { alsa_error("prepare", r); return -1; } /* The device starts when data is written. POLLOUT * events are generated in prepared state. */ } else { alsa_error("playback", r); return -1; } } } return 0; }
/* Takes pointer to a playlist, forks off a playback process and tries to play the next track in the playlist. If there's already a playback process, it's killed first (which means the currently played track is skipped). */ int play(struct playlist * list) { unsigned i; int pipefd[2]; char * keys [] = { "creator", "title", "album", "duration", "station", "lastfm:trackauth", "trackpage", "artistpage", "albumpage", "image", "freeTrackURL", }; assert(list != NULL); if(!list->left) return 0; if(playfork) { kill(playfork, SIGUSR1); return !0; } enable(QUIET); empty(& track); for(i = 0; i < (sizeof(keys) / sizeof(char *)); ++i) set(& track, keys[i], value(& list->track->track, keys[i])); if(pipe(pipefd) != 0) return !0; playfork = fork(); if(!playfork) { FILE * fd = NULL; const char * location = value(& list->track->track, "location"); close(pipefd[1]); rmsckif(); subfork = 0; if(location != NULL) { fetch(location, & fd, NULL, NULL); if(fd != NULL) { /* If there was an error, tell the main process about it by sending SIGUSR2. */ if(!playback(fd, pipefd[0])) kill(getppid(), SIGUSR2); close(pipefd[0]); fshutdown(& fd); } } exit(EXIT_SUCCESS); } close(pipefd[0]); if(playpipe != 0) close(playpipe); playpipe = pipefd[1]; return !0; }