void ringbuffer_produced(ringbuffer_t *buffer, lcb_size_t nb) { lcb_size_t n = ringbuffer_write(buffer, NULL, nb); lcb_assert(n == nb); }
/** * Extended version of observe command. This allows us to service * various forms of higher level operations which use observe in one way * or another */ lcb_error_t lcb_observe_ex(lcb_t instance, const void *command_cookie, lcb_size_t num, const void *const *items, lcb_observe_type_t type) { lcb_size_t ii; lcb_size_t maxix; lcb_uint32_t opaque; struct lcb_command_data_st ct; struct observe_requests_st reqs; memset(&reqs, 0, sizeof(reqs)); if (instance->type != LCB_TYPE_BUCKET) { return lcb_synchandler_return(instance, LCB_EBADHANDLE); } if (instance->vbucket_config == NULL) { return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL); } if (instance->dist_type != VBUCKET_DISTRIBUTION_VBUCKET) { return lcb_synchandler_return(instance, LCB_NOT_SUPPORTED); } opaque = ++instance->seqno; ct.cookie = command_cookie; maxix = instance->nreplicas; if (type == LCB_OBSERVE_TYPE_CHECK) { maxix = 0; } else { if (type == LCB_OBSERVE_TYPE_DURABILITY) { ct.flags = LCB_CMD_F_OBS_DURABILITY | LCB_CMD_F_OBS_BCAST; } else { ct.flags = LCB_CMD_F_OBS_BCAST; } } reqs.nrequests = instance->nservers; reqs.requests = calloc(reqs.nrequests, sizeof(*reqs.requests)); for (ii = 0; ii < num; ii++) { const void *key, *hashkey; lcb_size_t nkey, nhashkey; int vbid, jj; if (type == LCB_OBSERVE_TYPE_DURABILITY) { const lcb_durability_entry_t *ent = items[ii]; key = ent->request.v.v0.key; nkey = ent->request.v.v0.nkey; hashkey = ent->request.v.v0.hashkey; nhashkey = ent->request.v.v0.nhashkey; } else { const lcb_observe_cmd_t *ocmd = items[ii]; key = ocmd->v.v0.key; nkey = ocmd->v.v0.nkey; hashkey = ocmd->v.v0.hashkey; nhashkey = ocmd->v.v0.nhashkey; } if (!nhashkey) { hashkey = key; nhashkey = nkey; } vbid = vbucket_get_vbucket_by_key(instance->vbucket_config, hashkey, nhashkey); for (jj = -1; jj < (int)maxix; jj++) { struct observe_st *rr; int idx = vbucket_get_replica(instance->vbucket_config, vbid, jj); if (idx < 0 || idx > (int)instance->nservers) { if (jj == -1) { destroy_requests(&reqs); return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER); } continue; } lcb_assert(idx < (int)reqs.nrequests); rr = reqs.requests + idx; if (!rr->allocated) { if (!init_request(rr)) { destroy_requests(&reqs); return lcb_synchandler_return(instance, LCB_CLIENT_ENOMEM); } } { lcb_uint16_t vb = htons((lcb_uint16_t)vbid); lcb_uint16_t len = htons((lcb_uint16_t)nkey); rr->packet.message.header.request.magic = PROTOCOL_BINARY_REQ; rr->packet.message.header.request.opcode = CMD_OBSERVE; rr->packet.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; rr->packet.message.header.request.opaque = opaque; ringbuffer_ensure_capacity(&rr->body, sizeof(vb) + sizeof(len) + nkey); rr->nbody += ringbuffer_write(&rr->body, &vb, sizeof(vb)); rr->nbody += ringbuffer_write(&rr->body, &len, sizeof(len)); rr->nbody += ringbuffer_write(&rr->body, key, nkey); } } } for (ii = 0; ii < reqs.nrequests; ii++) { struct observe_st *rr = reqs.requests + ii; struct lcb_server_st *server = instance->servers + ii; char *tmp; if (!rr->allocated) { continue; } rr->packet.message.header.request.bodylen = ntohl((lcb_uint32_t)rr->nbody); ct.start = gethrtime(); lcb_server_start_packet_ct(server, &ct, rr->packet.bytes, sizeof(rr->packet.bytes)); if (ringbuffer_is_continous(&rr->body, RINGBUFFER_READ, rr->nbody)) { tmp = ringbuffer_get_read_head(&rr->body); TRACE_OBSERVE_BEGIN(&rr->packet, server->authority, tmp, rr->nbody); lcb_server_write_packet(server, tmp, rr->nbody); } else { tmp = malloc(ringbuffer_get_nbytes(&rr->body)); if (!tmp) { /* FIXME by this time some of requests might be scheduled */ destroy_requests(&reqs); return lcb_synchandler_return(instance, LCB_CLIENT_ENOMEM); } else { ringbuffer_read(&rr->body, tmp, rr->nbody); TRACE_OBSERVE_BEGIN(&rr->packet, server->authority, tmp, rr->nbody); lcb_server_write_packet(server, tmp, rr->nbody); } } lcb_server_end_packet(server); lcb_server_send_packets(server); } destroy_requests(&reqs); return lcb_synchandler_return(instance, LCB_SUCCESS); }
LIBCOUCHBASE_API lcb_error_t lcb_observe(lcb_t instance, const void *command_cookie, lcb_size_t num, const lcb_observe_cmd_t *const *items) { int vbid, idx, jj; lcb_size_t ii; lcb_uint32_t opaque; struct observe_st *requests; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { switch (instance->type) { case LCB_TYPE_CLUSTER: return lcb_synchandler_return(instance, LCB_EBADHANDLE); case LCB_TYPE_BUCKET: default: return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL); } } if (instance->dist_type != VBUCKET_DISTRIBUTION_VBUCKET) { return lcb_synchandler_return(instance, LCB_NOT_SUPPORTED); } /* the list of pointers to body buffers for each server */ requests = calloc(instance->nservers, sizeof(struct observe_st)); opaque = ++instance->seqno; for (ii = 0; ii < num; ++ii) { const void *key = items[ii]->v.v0.key; lcb_size_t nkey = items[ii]->v.v0.nkey; const void *hashkey = items[ii]->v.v0.hashkey; lcb_size_t nhashkey = items[ii]->v.v0.nhashkey; if (nhashkey == 0) { hashkey = key; nhashkey = nkey; } vbid = vbucket_get_vbucket_by_key(instance->vbucket_config, hashkey, nhashkey); for (jj = -1; jj < instance->nreplicas; ++jj) { struct observe_st *rr; /* it will increment jj to get server index, so (-1 + 1) = 0 (master) */ idx = vbucket_get_replica(instance->vbucket_config, vbid, jj); if ((idx < 0 || idx > (int)instance->nservers)) { /* the config says that there is no server yet at that position (-1) */ if (jj == -1) { /* master node must be available */ destroy_requests(requests, instance->nservers); return lcb_synchandler_return(instance, LCB_NETWORK_ERROR); } else { continue; } } rr = requests + idx; if (!rr->allocated) { if (!init_request(rr)) { destroy_requests(requests, instance->nservers); return lcb_synchandler_return(instance, LCB_CLIENT_ENOMEM); } rr->req.message.header.request.magic = PROTOCOL_BINARY_REQ; rr->req.message.header.request.opcode = CMD_OBSERVE; rr->req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; rr->req.message.header.request.opaque = opaque; } { lcb_uint16_t vb = htons((lcb_uint16_t)vbid); lcb_uint16_t len = htons((lcb_uint16_t)nkey); ringbuffer_ensure_capacity(&rr->body, sizeof(vb) + sizeof(len) + nkey); rr->nbody += ringbuffer_write(&rr->body, &vb, sizeof(vb)); rr->nbody += ringbuffer_write(&rr->body, &len, sizeof(len)); rr->nbody += ringbuffer_write(&rr->body, key, nkey); } } } for (ii = 0; ii < instance->nservers; ++ii) { struct observe_st *rr = requests + ii; lcb_server_t *server = instance->servers + ii; if (rr->allocated) { char *tmp; rr->req.message.header.request.bodylen = ntohl((lcb_uint32_t)rr->nbody); lcb_server_start_packet(server, command_cookie, rr->req.bytes, sizeof(rr->req.bytes)); if (ringbuffer_is_continous(&rr->body, RINGBUFFER_READ, rr->nbody)) { tmp = ringbuffer_get_read_head(&rr->body); TRACE_OBSERVE_BEGIN(&rr->req, server->authority, tmp, rr->nbody); lcb_server_write_packet(server, tmp, rr->nbody); } else { tmp = malloc(ringbuffer_get_nbytes(&rr->body)); if (!tmp) { /* FIXME by this time some of requests might be scheduled */ destroy_requests(requests, instance->nservers); return lcb_synchandler_return(instance, LCB_CLIENT_ENOMEM); } else { ringbuffer_read(&rr->body, tmp, rr->nbody); TRACE_OBSERVE_BEGIN(&rr->req, server->authority, tmp, rr->nbody); lcb_server_write_packet(server, tmp, rr->nbody); } } lcb_server_end_packet(server); lcb_server_send_packets(server); } } destroy_requests(requests, instance->nservers); return lcb_synchandler_return(instance, LCB_SUCCESS); }
static int socks5_src_do_connect(struct sserver_handle *handle, struct ssession *session) { // 1. parse // 2. clear buf; // 3. connect to dest addr // 4. set session.dstfd // 5. add response to sendbuf; // 6. add fd to writefds // 7. set session state to SSESSION_STATE_TRANSMIT /* rep: 0x00 成功 0x01 一般性失败 0x02 规则不允许转发 0x03 网络不可达 0x04 主机不可达 0x05 连接拒绝 0x06 TTL超时 0x07 不支持请求包中的CMD 0x08 不支持请求包中的ATYP 0x09-0xFF unassigned */ int ret = 0; char ver = 0x00; char cmd = 0x00; char rsv = 0x00; char atyp = 0x00; char ndstaddr = 0x00; uint32_t ip = 0x00; char dstaddr[256] = {0x00}; uint16_t dstport = 0; char rep = 0x00; char nbndaddr = 0x00; char bndaddr[256] = {0x00}; uint16_t bndport = 0; int nread = 0; struct ringbuffer_tran tran; struct ringbuffer *tranrb = NULL; tranrb = ringbuffer_transaction_begin(session->dstbuf, &tran); nread = ringbuffer_transaction_read(tranrb, &ver, 1); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } nread = ringbuffer_transaction_read(tranrb, &cmd, 1); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } nread = ringbuffer_transaction_read(tranrb, &rsv, 1); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } nread = ringbuffer_transaction_read(tranrb, &atyp, 1); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } switch (cmd) { case 0x01: break; case 0x02: case 0x03: default: rep = 0x07; goto pre_send; break; } switch(atyp) { case 0x01: // ipv4 nread = ringbuffer_transaction_read(tranrb, &ip, 4); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } nread = ringbuffer_transaction_read(tranrb, &dstport, 2); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } session->dstfd = tcp_socket_connect_with_ip(ip, dstport); break; case 0x03: // domain nread = ringbuffer_transaction_read(tranrb, &ndstaddr, 1); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } nread = ringbuffer_transaction_read(tranrb, dstaddr, ndstaddr); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } nread = ringbuffer_transaction_read(tranrb, &dstport, 2); if(nread <= 0) { ringbuffer_transaction_rollback(session->dstbuf, &tran); return SE_NEEDMORE; } session->dstfd = tcp_socket_connect_with_domain(dstaddr, dstport); break; case 0x04: // ipv6 rep = 0x08; goto pre_send; break; } if(session->dstfd < 0) { switch (errno) { case ENETUNREACH: rep = 0x03; break; case EHOSTUNREACH: rep = 0x04; break; case ECONNREFUSED: rep = 0x05; break; default: rep = 0x01; break; } } else { FD_SET(session->dstfd, &handle->server->readfds); if(handle->server->maxfd < session->dstfd) handle->server->maxfd = session->dstfd; } pre_send: atyp = 0x01; nbndaddr = 4; bndaddr[0] = '\0'; bndaddr[1] = '\0'; bndaddr[2] = '\0'; bndaddr[3] = '\0'; ringbuffer_clear(session->dstbuf); ringbuffer_write(session->srcbuf, &ver, 1); ringbuffer_write(session->srcbuf, &rep, 1); ringbuffer_write(session->srcbuf, &rsv, 1); ringbuffer_write(session->srcbuf, &atyp, 1); ringbuffer_write(session->srcbuf, &nbndaddr, 1); ringbuffer_write(session->srcbuf, bndaddr, nbndaddr); ringbuffer_write(session->srcbuf, &bndport, 2); FD_SET(session->srcfd, &handle->server->writefds); if(handle->server->maxfd < session->srcfd) handle->server->maxfd = session->srcfd; session->state = SSESSION_STATE_TRANSMIT; return ret; }
int main(int argc, char **argv) { char buf[1024]; fd_set * readselect = malloc(sizeof(fd_set)); fd_set * writeselect = malloc(sizeof(fd_set)); fd_set * errorselect = malloc(sizeof(fd_set)); unsigned int maxfd = 3; readsockets = array_init(); readsockets->name = "read"; writesockets = array_init(); writesockets->name = "write"; errorsockets = array_init(); errorsockets->name = "error"; buffer_socket * stdin_sock = malloc(sizeof(buffer_socket)); stdin_sock->type = SOCKTYPE_LOCAL; stdin_sock->fd = STDIN_FILENO; ringbuffer_init(&stdin_sock->rxbuffer); ringbuffer_init(&stdin_sock->txbuffer); readsockets = array_push(readsockets, stdin_sock); errorsockets = array_push(errorsockets, stdin_sock); char * printer_port = DEFAULT_PORT; int printer_baud = DEFAULT_BAUD; // TODO: parse command line options printer_socket *printer = new_printer_socket(printer_port, printer_baud); file_socket *file = NULL; /***********************************************************************\ * * * Now set up network sockets * * * \***********************************************************************/ new_listen_socket(DEFAULT_LISTEN_PORT, SOCKTYPE_CLIENT); new_listen_socket(DEFAULT_LISTEN_PORT + 1, SOCKTYPE_HTTP); /***********************************************************************\ * * * Main Loop * * * \***********************************************************************/ int running = 1; while (running) { FD_ZERO(readselect); FD_ZERO(writeselect); FD_ZERO(errorselect); for (int i = 0; i < readsockets->length; i++) { local_socket *ls = ((local_socket *) readsockets->data[i]); int fd = ls->fd; //printf("check read %d\n", ((local_socket *) readsockets->data[i])->fd); if ((ls->type == SOCKTYPE_PRINTER) || (printer->tokens > 0)) { FD_SET(fd, readselect); if (fd >= maxfd) maxfd = fd + 1; } } for (int i = 0; i < writesockets->length; i++) { local_socket *ls = ((local_socket *) writesockets->data[i]); int fd = ls->fd; //printf("check write %d\n", ((local_socket *) writesockets->data[i])->fd); if ((ls->type != SOCKTYPE_PRINTER) || (printer->tokens > 0)) { FD_SET(fd, writeselect); if (fd >= maxfd) maxfd = fd + 1; } } for (int i = 0; i < errorsockets->length; i++) { local_socket *ls = ((local_socket *) errorsockets->data[i]); int fd = ls->fd; //printf("check error %d\n", ((local_socket *) errorsockets->data[i])->fd); FD_SET(((local_socket *) errorsockets->data[i])->fd, errorselect); if (fd >= maxfd) maxfd = fd + 1; } select(maxfd, readselect, writeselect, errorselect, NULL); /*******************************************************************\ * * * Check Errors * * * \*******************************************************************/ for (int i = 0; i < errorsockets->length; i++) { local_socket *s = (local_socket *) errorsockets->data[i]; if (FD_ISSET(s->fd, errorselect)) { printf("error on %d: %p\n", s->fd, s); switch (s->type) { case SOCKTYPE_LOCAL: break; case SOCKTYPE_PRINTER: break; case SOCKTYPE_CLIENT: break; case SOCKTYPE_LISTEN: break; } /* switch s->type */ } /* if FD_ISSET fd, errorselect */ } /* for errorsockets */ /*******************************************************************\ * * * Check Readable Sockets * * * \*******************************************************************/ for (int i = 0; i < readsockets->length; i++) { local_socket *s = (local_socket *) readsockets->data[i]; if (FD_ISSET(s->fd, readselect)) { //printf("read %d (type %d)\n", s->fd, s->type); switch (s->type) { case SOCKTYPE_LOCAL: { buffer_socket *sock = (buffer_socket *) s; unsigned int r = ringbuffer_writefromfd(&sock->rxbuffer, s->fd, ringbuffer_canwrite(&sock->rxbuffer)); if (r == 0) { printf("EOF on stdin, exiting...\n"); exit(0); } break; } case SOCKTYPE_CLIENT: { client_socket *sock = (client_socket *) s; unsigned int r = ringbuffer_writefromfd(&sock->inbuffer, s->fd, ringbuffer_canwrite(&sock->inbuffer)); //printf("writefromfd %p %d %d got %d nl %d\n", &sock->rxbuffer, s->fd, ringbuffer_canwrite(&sock->rxbuffer), r, sock->rxbuffer.nl); if (r == 0) { sock2a(&sock->addr, buf, BUFFER_SIZE); printf("client %s disconnected\n", buf); close(sock->fd); readsockets = array_delete(readsockets, sock); writesockets = array_delete(writesockets, sock); errorsockets = array_delete(errorsockets, sock); free(sock); sock = NULL; } else if (sock->inbuffer.nl > 0) { char linebuffer[256]; while (ringbuffer_peekline(&sock->inbuffer, linebuffer, sizeof(linebuffer))) { switch (detect_line_type(linebuffer)) { case LINETYPE_GCODE: { unsigned int i = ringbuffer_readline(&sock->rxbuffer, linebuffer, sizeof(linebuffer)); ringbuffer_write(&sock->rxbuffer, linebuffer, i); break; }; case LINETYPE_SIMPLECMD: { unsigned int i = ringbuffer_readline(&sock->rxbuffer, linebuffer, sizeof(linebuffer)); parse_line(linebuffer); break; }; } } } break; } case SOCKTYPE_PRINTER: { //printf("can read printer\n"); printer_socket *sock = (printer_socket *) s; unsigned int r = ringbuffer_writefromfd(&sock->rxbuffer, s->fd, BUFFER_SIZE); if (r == 0) { //printf(" %d bytes: printer disconnected, trying to reconnect...\n", r); close(s->fd); readsockets = array_delete(readsockets, sock); writesockets = array_delete(writesockets, sock); errorsockets = array_delete(errorsockets, sock); free(sock); sock = NULL; sock = new_printer_socket(printer_port, printer_baud); readsockets = array_push(readsockets, sock); errorsockets = array_push(errorsockets, sock); } else { //printf(" %d bytes, %d newlines", r, sock->rxbuffer.nl); while (sock->rxbuffer.nl > 0) { char line[BUFFER_SIZE]; int r = ringbuffer_readline(&sock->rxbuffer, line, BUFFER_SIZE); if (sock->lastmsgsock->fd > 2) printf("< %s", line); int m = snprintf(buf, BUFFER_SIZE, "< %s", line); if (sock->lastmsgsock->type == SOCKTYPE_LOCAL) { int i = 0; do { i += write(sock->lastmsgsock->fd, &buf[i], m - i); } while (i < m); } else if (sock->lastmsgsock->type == SOCKTYPE_CLIENT) { //printf("client type\n"); client_socket *cs = (client_socket *) sock->lastmsgsock; ringbuffer_write(&cs->txbuffer, line, r); if (array_indexof(writesockets, cs) == -1) { writesockets = array_push(writesockets, cs); //printf("pushed %p/%d to writesockets\n", cs, cs->socket.fd); } } if (strncmp(line, "ok", 2) == 0) { //fprintf(stderr, "got token!"); if (sock->tokens < sock->maxtoken) sock->tokens++; for (int i = 0; i < errorsockets->length; i++) { if (((local_socket *) errorsockets->data[i])->type == SOCKTYPE_CLIENT) readsockets = array_push(readsockets, errorsockets->data[i]); } if (file != NULL) writesockets = array_push(writesockets, sock); //fprintf(stderr, " tokens: %d\n", sock->tokens); } else { //fprintf(stderr, "no token\n"); } } } break; } case SOCKTYPE_LISTEN: { listen_socket *ls = (listen_socket *) s; if (ls->protocol == SOCKTYPE_HTTP) { new_http_socket(ls); } else if (ls->protocol == SOCKTYPE_CLIENT) { new_client_socket(ls); } break; } case SOCKTYPE_FILE: { break; } case SOCKTYPE_HTTP: { http_socket *sock = (http_socket *) s; unsigned int r = ringbuffer_writefromfd(&sock->rxbuffer, s->fd, ringbuffer_canwrite(&sock->rxbuffer)); if (r == 0) { sock2a(&sock->addr, buf, BUFFER_SIZE); printf("client %s disconnected\n", buf); close(sock->fd); readsockets = array_delete(readsockets, sock); writesockets = array_delete(writesockets, sock); errorsockets = array_delete(errorsockets, sock); free(sock); sock = NULL; } else { } break; } } /* switch s->type */ } /* if FD_ISSET fd, readselect */ } /* for readsockets */ /*******************************************************************\ * * * Check Writable Sockets * * * \*******************************************************************/ for (int i = 0; i < writesockets->length; i++) { local_socket *s = (local_socket *) writesockets->data[i]; if (FD_ISSET(s->fd, writeselect)) { //printf("write %d", s->fd); switch (s->type) { case SOCKTYPE_LOCAL: case SOCKTYPE_CLIENT: case SOCKTYPE_HTTP: { //printf("write client socket\n"); buffer_socket *sock = (buffer_socket *) s; if (ringbuffer_canread(&sock->txbuffer) > 0) { //printf("readtofd %d %p: %d\n", s->fd, &sock->txbuffer, ringbuffer_readtofd(&sock->txbuffer, s->fd); //); } if (ringbuffer_canread(&sock->txbuffer) == 0) { //printf("client txbuffer empty\n"); writesockets = array_delete(writesockets, s); } break; } case SOCKTYPE_PRINTER: { printer_socket *sock = (printer_socket *) s; //printf("write: nl: %d\n", sock->txbuffer.nl); if (sock->rxbuffer.nl == 0) { int i = (sock->lastmsgindex + 1) % errorsockets->length; for (int j = 0; j <= errorsockets->length; j++) { buffer_socket * x = errorsockets->data[i]; if (x->type == SOCKTYPE_LOCAL || x->type == SOCKTYPE_CLIENT || x->type == SOCKTYPE_FILE) { int r = ringbuffer_readline(&x->rxbuffer, buf, BUFFER_SIZE); ringbuffer_write(&printer->txbuffer, buf, r); sock->lastmsgsock = (local_socket *) x; sock->lastmsgindex = i; break; } i = (i + 1) % errorsockets->length; } } if (sock->txbuffer.nl > 0) { //printf("write: nl: %d\n", sock->txbuffer.nl); unsigned int r = ringbuffer_readline(&sock->txbuffer, buf, BUFFER_SIZE); buf[r] = 0; printf(">>> %s", buf); int i = 0; do { i += write(s->fd, &buf[i], r - i); } while (i < r); sock->tokens--; if (sock->tokens == 0) { for (int i = 0; i < errorsockets->length; i++) { if (((local_socket *) errorsockets->data[i])->type == SOCKTYPE_CLIENT) readsockets = array_delete(readsockets, errorsockets->data[i]); } } } else if ((sock->tokens > 0) && (file != NULL) && (file->paused == 0)) { if ((ringbuffer_canwrite(&file->rxbuffer) > 0) && (file->eof == 0)) { int w = ringbuffer_writefromfd(&file->rxbuffer, file->fd, BUFFER_SIZE); if (w == 0) file->eof = 1; } if (file->rxbuffer.nl > 0) { int r = ringbuffer_readline(&file->rxbuffer, buf, BUFFER_SIZE); buf[r] = 0; printf(">>> %s", buf); int i = 0; do { i += write(s->fd, &buf[i], r - i); } while (i < r); sock->tokens--; } else if (file->eof) { // file is completely printed printf("File %s complete. Print time: \n", file->filename); // TODO:close file } } if ((ringbuffer_canread(&sock->txbuffer) == 0) || (sock->tokens == 0)) writesockets = array_delete(writesockets, sock); break; } } /* switch s->type */ } /* if FD_ISSET fd, writeselect */ } /* for writesockets */ } /* while running */ return 0; } /* main() */
static libcouchbase_error_t create_memcached(const struct libcouchbase_memcached_st *user, VBUCKET_CONFIG_HANDLE vbconfig) { ringbuffer_t buffer; char *copy = strdup(user->serverlist); char head[1024]; int first; char *ptr = copy; int fail; libcouchbase_ssize_t offset = 0; if (copy == NULL) { return LIBCOUCHBASE_CLIENT_ENOMEM; } if (ringbuffer_initialize(&buffer, 1024) == -1) { free(copy); return LIBCOUCHBASE_CLIENT_ENOMEM; } head[0] = '\0'; offset += snprintf(head + offset, sizeof(head) - offset, "%s", "{"); offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\"bucketType\":\"memcached\","); offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\"nodeLocator\":\"ketama\","); if (user->username != NULL) { offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\"authType\":\"sasl\","); offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\"name\":\""); offset += snprintf(head + offset, sizeof(head) - offset, "%s", user->username); offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\","); if (user->password != NULL) { offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\"saslPassword\":\""); offset += snprintf(head + offset, sizeof(head) - offset, "%s", user->password); offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\","); } } offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\"nodes\": ["); ringbuffer_write(&buffer, head, strlen(head)); /* Let's add the hosts... */ first = 1; do { char *tok; char *next = strchr(ptr, ';'); const char *port = "11211"; libcouchbase_ssize_t length; if (next != NULL) { *next = '\0'; } tok = strchr(ptr, ':'); if (tok != NULL) { *tok = '\0'; port = tok + 1; if ((tok = strchr(ptr, ':')) != NULL) { *tok = '\0'; /* Remove weight for now */ } } length = snprintf(head, sizeof(head), "%c{\"hostname\":\"%s\",\"ports\":{\"direct\":%s}}", first ? ' ' : ',', ptr, port); first = 0; if (ringbuffer_ensure_capacity(&buffer, length) == -1) { free(copy); return LIBCOUCHBASE_CLIENT_ENOMEM; } ringbuffer_write(&buffer, head, length); if (next != NULL) { ptr = next + 1; } else { ptr = NULL; } } while (ptr != NULL); if (ringbuffer_ensure_capacity(&buffer, 3) == -1) { free(copy); return LIBCOUCHBASE_CLIENT_ENOMEM; } ringbuffer_write(&buffer, "]}", 3); /* Include '\0' */ /* Now let's parse the config! */ fail = vbucket_config_parse(vbconfig, LIBVBUCKET_SOURCE_MEMORY, (char *)ringbuffer_get_read_head(&buffer)); free(copy); ringbuffer_destruct(&buffer); if (fail) { /* Hmm... internal error! */ return LIBCOUCHBASE_EINTERNAL; } return LIBCOUCHBASE_SUCCESS; }
static lcb_error_t obs_ctxadd(lcb_MULTICMD_CTX *mctx, const lcb_CMDOBSERVE *cmd) { const void *hk; lcb_SIZE nhk; int vbid; unsigned maxix; int ii; OBSERVECTX *ctx = CTX_FROM_MULTI(mctx); lcb_t instance = ctx->instance; mc_CMDQUEUE *cq = &instance->cmdq; if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) { return LCB_EMPTY_KEY; } if (cq->config == NULL) { return LCB_CLIENT_ETMPFAIL; } if (instance->dist_type != LCBVB_DIST_VBUCKET) { return LCB_NOT_SUPPORTED; } mcreq_extract_hashkey(&cmd->key, &cmd->hashkey, 24, &hk, &nhk); vbid = lcbvb_k2vb(cq->config, hk, nhk); maxix = LCBVB_NREPLICAS(cq->config); for (ii = -1; ii < (int)maxix; ++ii) { struct observe_st *rr; lcb_U16 vb16, klen16; int ix; if (ii == -1) { ix = lcbvb_vbmaster(cq->config, vbid); if (ix < 0) { return LCB_NO_MATCHING_SERVER; } } else { ix = lcbvb_vbreplica(cq->config, vbid, ii); if (ix < 0) { continue; } } lcb_assert(ix < (int)ctx->nrequests); rr = ctx->requests + ix; if (!rr->allocated) { if (!init_request(rr)) { return LCB_CLIENT_ENOMEM; } } vb16 = htons((lcb_U16)vbid); klen16 = htons((lcb_U16)cmd->key.contig.nbytes); ringbuffer_ensure_capacity(&rr->body, sizeof(vb16) + sizeof(klen16)); ringbuffer_write(&rr->body, &vb16, sizeof vb16); ringbuffer_write(&rr->body, &klen16, sizeof klen16); ringbuffer_write(&rr->body, cmd->key.contig.bytes, cmd->key.contig.nbytes); ctx->remaining++; if (cmd->cmdflags & LCB_CMDOBSERVE_F_MASTER_ONLY) { break; } } return LCB_SUCCESS; }
void * DMXThread(void * v_arg) { pthread_t file_thread; struct filenames_t filename_data; char filename_extension[3]; ringbuffer_data_t vec[2]; ssize_t written; ssize_t todo = 0; ssize_t todo2; unsigned char buf[TS_SIZE]; int offset = 0; ssize_t r = 0; struct pollfd pfd = {*(int*)v_arg, POLLIN|POLLERR,0 }; int pres; ringbuffer_t * ringbuf = ringbuffer_create(ringbuffersize); if (!ringbuf) { exit_flag = STREAM2FILE_STATUS_RECORDING_THREADS_FAILED; puts("[stream2file]: error allocating ringbuffer! (out of memory?)"); } else fprintf(stderr, "[stream2file] allocated ringbuffer size: %ld\n", ringbuffer_write_space(ringbuf)); filename_data.ringbuffer = ringbuf; if (v_arg == &dvrfd) { filename_data.extension = "ts"; } else { for (int i = 0; i < MAXPIDS; i++) if (v_arg == (&(demuxfd[i]))) sprintf(filename_extension, "%u", i); filename_data.extension = filename_extension; } if (pthread_create(&file_thread, 0, FileThread, &filename_data) != 0) { exit_flag = STREAM2FILE_STATUS_RECORDING_THREADS_FAILED; puts("[stream2file]: error creating file_thread! (out of memory?)"); } if (v_arg == &dvrfd) while (exit_flag == STREAM2FILE_STATUS_RUNNING) { if ((pres=poll (&pfd, 1, 15000))>0) { if (!(pfd.revents&POLLIN)) { printf ("[stream2file]: PANIC: error reading from demux, bailing out\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } r = read(*(int *)v_arg, &(buf[0]), TS_SIZE); #ifdef HAVE_TRIPLEDRAGON if (r < 0) { perror("stream2file read DMX"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; break; } #endif if (r > 0) { offset = sync_byte_offset(&(buf[0]), r); if (offset != -1) break; } } else if (!pres) { printf ("[stream2file]: timeout from demux\n"); } } else offset = 0; if (exit_flag == STREAM2FILE_STATUS_RUNNING) { written = ringbuffer_write(ringbuf, (char *)&(buf[offset]), r - offset); // TODO: Retry if (written != r - offset) { printf("PANIC: wrote less than requested to ringbuffer, written %d, requested %d\n", written, r - offset); exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW; } todo = IN_SIZE - (r - offset); } /* IN_SIZE > TS_SIZE => todo > 0 */ while (exit_flag == STREAM2FILE_STATUS_RUNNING) { ringbuffer_get_write_vector(ringbuf, &(vec[0])); todo2 = todo - vec[0].len; if (todo2 < 0) { todo2 = 0; } else { if (((size_t)todo2) > vec[1].len) { printf("PANIC: not enough space in ringbuffer, available %d, needed %d\n", vec[0].len + vec[1].len, todo + todo2); exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW; } todo = vec[0].len; } while (exit_flag == STREAM2FILE_STATUS_RUNNING) { if ((pres=poll (&pfd, 1, 5000))>0) { if (!(pfd.revents&POLLIN)) { printf ("PANIC: error reading from demux, bailing out\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } r = read(*(int *)v_arg, vec[0].buf, todo); if (r > 0) { ringbuffer_write_advance(ringbuf, r); if (todo == r) { if (todo2 == 0) goto next; todo = todo2; todo2 = 0; vec[0].buf = vec[1].buf; } else { vec[0].buf += r; todo -= r; } } #ifdef HAVE_TRIPLEDRAGON if (r < 0 && errno != EAGAIN) { perror("[stream2file] read DMX"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; break; } #endif } else if (!pres){ printf ("[stream2file]: timeout reading from demux\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } } next: todo = IN_SIZE; } if (v_arg == &dvrfd) close(*(int *)v_arg); else unsetPesFilter(*(int *)v_arg); pthread_join(file_thread, NULL); if (ringbuf) ringbuffer_free(ringbuf); if (v_arg == &dvrfd) while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); DEC_BUSY_COUNT; if ((v_arg == &dvrfd) || (v_arg == (&(demuxfd[0])))) { CEventServer eventServer; eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock"); stream2file_status2_t s; s.status = exit_flag; strncpy(s.filename,basename(myfilename),512); s.filename[511] = '\0'; strncpy(s.dir,dirname(myfilename),100); s.dir[99] = '\0'; eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s)); printf("[stream2file]: pthreads exit code: %i, dir: '%s', filename: '%s' myfilename: '%s'\n", exit_flag, s.dir, s.filename, myfilename); } pthread_exit(NULL); }
void *VideoLayer::feed() { int got_picture=0; int len1=0 ; int ret=0; bool got_it=false; double now = get_master_clock(); if(paused) return rgba_picture->data[0]; /** * follow user video loop */ if(mark_in!=NO_MARK && mark_out!=NO_MARK && seekable) { if (now >= mark_out) seek((int64_t)mark_in * AV_TIME_BASE); } // operate seek if was requested if(to_seek>=0) { seek(to_seek); to_seek = -1; } got_it=false; while (!got_it) { if(packet_len<=0) { /** * Read one packet from the media and put it in pkt */ while(1) { #ifdef DEBUG func("av_read_frame ..."); #endif ret = av_read_frame(avformat_context, &pkt); #ifdef DEBUG if(pkt.stream_index == video_index) std::cout << "video read packet"; else if(pkt.stream_index == audio_index) std::cout << "audio read packet"; std::cout << " pkt.data=" << pkt.data; std::cout << " pkt.size=" << pkt.size; std::cout << " pkt.pts/dts=" << pkt.pts << "/" << pkt.dts << std::endl; std::cout << "pkt.duration=" << pkt.duration; std::cout << " avformat_context->start_time=" << avformat_context->start_time; std::cout << " avformat_context->duration=" << avformat_context->duration/AV_TIME_BASE << std::endl; std::cout << "avformat_context->duration=" << avformat_context->duration << std::endl; #endif /* TODO(shammash): this may be good for streams but breaks * looping in files, needs fixing. */ // if(!pkt.duration) continue; // if(!pkt.size || !pkt.data) { // return NULL; // } /** * check eof and loop */ if(ret!= 0) { //does not enter if data are available eos->notify(); // eos->dispatcher->do_jobs(); /// XXX hack hack hack ret = seek(avformat_context->start_time); if (ret < 0) { error("VideoLayer::could not loop file"); return rgba_picture->data[0]; } continue; } else if( (pkt.stream_index == video_index) || (pkt.stream_index == audio_index) ) break; /* exit loop */ } } // loop break after a known index is found frame_number++; //std::cout << "frame_number :" << frame_number << std::endl; /** * Decode video */ if(pkt.stream_index == video_index) { len1 = decode_video_packet(&got_picture); AVFrame *yuv_picture=&av_frame; if(len1<0) { // error("VideoLayer::Error while decoding frame"); func("one frame only?"); return NULL; } else if (len1 == 0) { packet_len=0; return NULL; } /** * We've found a picture */ ptr += len1; packet_len -= len1; if (got_picture!=0) { got_it=true; avformat_stream=avformat_context->streams[video_index]; /** Deinterlace input if requested */ if(deinterlaced) deinterlace((AVPicture *)yuv_picture); #ifdef WITH_SWSCALE sws_scale(img_convert_ctx, yuv_picture->data, yuv_picture->linesize, 0, video_codec_ctx->height, rgba_picture->data, rgba_picture->linesize); #else /** * yuv2rgb */ img_convert(rgba_picture, PIX_FMT_RGB32, (AVPicture *)yuv_picture, video_codec_ctx->pix_fmt, //avformat_stream.codec->pix_fmt, video_codec_ctx->width, video_codec_ctx->height); #endif // memcpy(frame_fifo.picture[fifo_position % FIFO_SIZE]->data[0],rgba_picture->data[0],geo.size); /* TODO move */ if(fifo_position == FIFO_SIZE) fifo_position=0; /* workaround since sws_scale conversion from YUV returns an buffer RGBA with alpha set to 0x0 */ { register int bufsize = ( rgba_picture->linesize[0] * video_codec_ctx->height ) /4; int32_t *pbuf = (int32_t*)rgba_picture->data[0]; for(; bufsize>0; bufsize--) { *pbuf = (*pbuf | alpha_bitmask); pbuf++; } } jmemcpy(frame_fifo.picture[fifo_position]->data[0], rgba_picture->data[0], rgba_picture->linesize[0] * video_codec_ctx->height); // avpicture_get_size(PIX_FMT_RGBA32, enc->width, enc->height)); fifo_position++; } } // end video packet decoding //////////////////////// // audio packet decoding else if(pkt.stream_index == audio_index) { // XXX(shammash): audio decoding seems to depend on screen properties, so // we skip decoding audio frames if there's no screen // long unsigned int m_SampleRate = screen->m_SampleRate?*(screen->m_SampleRate):48000; // ringbuffer_write(screen->audio, (const char*)audio_float_buf, samples*sizeof(float)); // ... and so on ... if(use_audio && screen) { int data_size; len1 = decode_audio_packet(&data_size); if (len1 > 0) { int samples = data_size/sizeof(uint16_t); long unsigned int m_SampleRate = screen->m_SampleRate?*(screen->m_SampleRate):48000; double m_ResampleRatio = (double)(m_SampleRate)/(double)audio_samplerate; long unsigned max_buf = ceil(AVCODEC_MAX_AUDIO_FRAME_SIZE * m_ResampleRatio * audio_channels); if (audio_resampled_buf_len < max_buf) { if (audio_resampled_buf) free (audio_resampled_buf); audio_resampled_buf = (float*) malloc(max_buf * sizeof(float)); audio_resampled_buf_len = max_buf; } src_short_to_float_array ((const short*) audio_buf, audio_float_buf, samples); if (m_ResampleRatio == 1.0) { ringbuffer_write(screen->audio, (const char*)audio_float_buf, samples*sizeof(float)); time_t *tm = (time_t *)malloc(sizeof(time_t)); time (tm); // std::cerr << "-- VL:" << asctime(localtime(tm)); } else { src_short_to_float_array ((const short*) audio_buf, audio_float_buf, samples); SRC_DATA src_data; int offset = 0; do { src_data.input_frames = samples/audio_channels; src_data.output_frames = audio_resampled_buf_len/audio_channels - offset; src_data.end_of_input = 0; src_data.src_ratio = m_ResampleRatio; src_data.input_frames_used = 0; src_data.output_frames_gen = 0; src_data.data_in = audio_float_buf + offset; src_data.data_out = audio_resampled_buf + offset; src_simple (&src_data, SRC_SINC_MEDIUM_QUALITY, audio_channels) ; ringbuffer_write(screen->audio, (const char*)audio_resampled_buf, src_data.output_frames_gen * audio_channels *sizeof(float)); offset += src_data.input_frames_used * audio_channels; samples -= src_data.input_frames_used * audio_channels; if (samples>0) warning("resampling left: %i < %i", src_data.input_frames_used, samples/audio_channels); } while (samples > audio_channels); } } } } av_free_packet(&pkt); /* sun's good. love's bad */ } // end of while(!got_it) return frame_fifo.picture[fifo_position-1]->data[0]; }
static void data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_event_flags_t events, void *userdata) { pa_stream *s = userdata; snd_pcm_sframes_t frame_count; size_t frame_size = pa_frame_size(&s->ss); char buf[16 * 1024]; int paused = g_atomic_int_get(&s->paused); if (events & (PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT)) { #if HAVE_SND_PCM_AVAIL frame_count = snd_pcm_avail(s->ph); #else snd_pcm_hwsync(s->ph); frame_count = snd_pcm_avail_update(s->ph); #endif if (frame_count < 0) { if (frame_count == -EBADFD) { // stream was closed return; } int cnt = 0, ret; do { cnt ++; ret = snd_pcm_recover(s->ph, frame_count, 1); } while (ret == -1 && errno == EINTR && cnt < 5); #if HAVE_SND_PCM_AVAIL frame_count = snd_pcm_avail(s->ph); #else snd_pcm_hwsync(s->ph); frame_count = snd_pcm_avail_update(s->ph); #endif if (frame_count < 0) { trace_error("%s, can't recover after failed snd_pcm_avail (%d)\n", __func__, (int)frame_count); return; } } } else { return; } if (events & PA_IO_EVENT_OUTPUT) { if (paused) { // client stream is corked. Pass silence to ALSA size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size); memset(buf, 0, bytecnt); snd_pcm_writei(s->ph, buf, bytecnt / frame_size); } else { size_t writable_size = pa_stream_writable_size(s); if (s->write_cb && writable_size > 0) s->write_cb(s, writable_size, s->write_cb_userdata); size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size); bytecnt = ringbuffer_read(s->rb, buf, bytecnt); if (bytecnt == 0) { // application is not ready yet, play silence bytecnt = MIN(sizeof(buf), frame_count * frame_size); memset(buf, 0, bytecnt); } snd_pcm_writei(s->ph, buf, bytecnt / frame_size); } } if (events & PA_IO_EVENT_INPUT) { if (paused) { // client stream is corked. Read data from ALSA and discard them size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size); snd_pcm_readi(s->ph, buf, bytecnt / frame_size); } else { size_t bytecnt = ringbuffer_writable_size(s->rb); if (bytecnt == 0) { // ringbuffer is full because app doesn't read data fast enough. // Make some room ringbuffer_drop(s->rb, frame_count * frame_size); bytecnt = ringbuffer_writable_size(s->rb); } bytecnt = MIN(bytecnt, frame_count * frame_size); bytecnt = MIN(bytecnt, sizeof(buf)); if (bytecnt > 0) { snd_pcm_readi(s->ph, buf, bytecnt / frame_size); ringbuffer_write(s->rb, buf, bytecnt); } size_t readable_size = pa_stream_readable_size(s); if (s->read_cb && readable_size > 0) s->read_cb(s, readable_size, s->read_cb_userdata); } } }
int JackClient::Process(jack_nframes_t nframes, void *self) { int j = 0; bool isEncoded = ((JackClient*) self)->m_Encoded; for(std::map<int, JackPort*>::iterator i = m_InputPortMap.begin(); i != m_InputPortMap.end(); i++) { if(jack_port_connected(i->second->Port)) { sample_t *in = (sample_t *) jack_port_get_buffer(i->second->Port, nframes); // memcpy (i->second->Buf, in, sizeof (sample_t) * m_BufferSize); //m_BufferSize -> 2nd AudioCollector parameter //Buff attribué par SetInputBuf dans le construcAteur de AudioCollector if(isEncoded) { //Added this to write in the buffer only if //the encoder is in action if(!j) { //only streams the 1st Jack Input port if(ringbuffer_write_space(((JackClient*) self)->first) >= (sizeof(sample_t) * nframes)) { ringbuffer_write(((JackClient*) self)->first, (char *)in, (sizeof(sample_t) * nframes)); } /* else { std::cerr << "-----------Pas suffisament de place dans audio_fred !!!" << std::endl; }*/ j++; } } } } int channels = ((JackClient*) self)->m_ringbufferchannels; bool output_available = false; //m_ringbuffer created by ViewPort::add_audio //1024*512 rounded up to the next power of two. if(((JackClient*) self)->m_ringbuffer) { // static int firsttime = 1 + ceil(4096/nframes); // XXX pre-buffer TODO decrease this and compensate latency if(ringbuffer_read_space(((JackClient*) self)->m_ringbuffer) >= /*firsttime */ channels * nframes * sizeof(float)) { // firsttime=1; size_t rv = ringbuffer_read(((JackClient*) self)->m_ringbuffer, ((JackClient*) self)->m_inbuf, channels * nframes * sizeof(float)); if(isEncoded) { //Added this to write in the buffer only if //the encoder is in action if(ringbuffer_write_space(((JackClient*) self)->audio_mix_ring) >= rv) { // unsigned char *aPtr = (unsigned char *)((JackClient*) self)->m_inbuf; size_t rf = ringbuffer_write(((JackClient*) self)->audio_mix_ring, ((JackClient*) self)->m_inbuf, rv); if(rf != rv) std::cerr << "---" << rf << " : au lieu de :" << rv << " octets ecrits dans le ringbuffer !!" \ << std::endl; } else { std::cerr << "-----------Not enough room in audio_mix_ring !!!" << std::endl; } } //reads m_ringbuffer and puts it in m_inbuf //m_inbuf created in SetRingbufferPtr called by add_audio //4096 * channels * sizeof(float) if(rv >= channels * nframes * sizeof(float)) { output_available = true; } } #if 0 else if(firsttime == 1) fprintf(stderr, "AUDIO BUFFER UNDERRUN: %i samples < %i\n", ringbuffer_read_space(((JackClient*) self)->m_ringbuffer) / sizeof(float) / channels, nframes); #endif } j = 0; for(std::map<int, JackPort*>::iterator i = m_OutputPortMap.begin(); i != m_OutputPortMap.end(); i++) { if(output_available && j < channels) { sample_t *out = (sample_t *) jack_port_get_buffer(i->second->Port, nframes); memset(out, 0, sizeof(jack_default_audio_sample_t) * nframes); deinterleave(((JackClient*) self)->m_inbuf, out, channels , j, nframes); //writes nframes of channels m_inbuf to out //two times if stereo (shifted by the channel number) #if 0 // test-noise: int i; for(i = 0; i < nframes; i++) out[i] = (float) i / (float)nframes; #endif } else { // no output availaible, clear sample_t *out = (sample_t *) jack_port_get_buffer(i->second->Port, nframes); memset(out, 0, sizeof(sample_t) * nframes); } j++; } m_BufferSize = nframes; // if(RunCallback&&RunContext) // { // // do the work // RunCallback(RunContext, nframes); // } return 0; }
int ilctts_pcm_write(TTSRENDER_STATE_T *st, void *data, int length) { return ringbuffer_write(st->ringbuffer, data, length << 1); } // end ilctts_pcm_write