Пример #1
0
/* Thread */
void *janus_pfunix_thread(void *data) {
	JANUS_LOG(LOG_INFO, "Unix Sockets thread started\n");

	int fds = 0;
	struct pollfd poll_fds[1024];	/* FIXME Should we allow for more clients? */
	char buffer[BUFFER_SIZE];
	struct iovec iov[1];
	struct msghdr msg;
	memset(&msg, 0, sizeof(msg));
	memset(iov, 0, sizeof(iov));
	iov[0].iov_base = buffer;
	iov[0].iov_len = sizeof(buffer);
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
		/* Prepare poll list of file descriptors */
		fds = 0;
		/* Writeable monitor */
		poll_fds[fds].fd = write_fd[0];
		poll_fds[fds].events = POLLIN;
		fds++;
		if(pfd > -1) {
			/* Janus API */
			poll_fds[fds].fd = pfd;
			poll_fds[fds].events = POLLIN;
			fds++;
		}
		if(admin_pfd > -1) {
			/* Admin API */
			poll_fds[fds].fd = admin_pfd;
			poll_fds[fds].events = POLLIN;
			fds++;
		}
		/* Iterate on available clients, to see if we need to POLLIN or POLLOUT too */
		janus_mutex_lock(&clients_mutex);
		GHashTableIter iter;
		gpointer value;
		g_hash_table_iter_init(&iter, clients_by_fd);
		while(g_hash_table_iter_next(&iter, NULL, &value)) {
			janus_pfunix_client *client = value;
			if(client->fd > -1) {
				poll_fds[fds].fd = client->fd;
				poll_fds[fds].events = g_async_queue_length(client->messages) > 0 ? POLLIN | POLLOUT : POLLIN;
				fds++;
			}
		}
		janus_mutex_unlock(&clients_mutex);

		/* Start polling */
		int res = poll(poll_fds, fds, -1);
		if(res == 0)
			continue;
		if(res < 0) {
			JANUS_LOG(LOG_ERR, "poll() failed\n");
			break;
		}
		int i = 0;
		for(i=0; i<fds; i++) {
			if(poll_fds[i].revents & (POLLERR | POLLHUP)) {
				/* Socket error? Shall we do something? */
				if(poll_fds[i].fd == write_fd[0]) {
					/* Error in the wake-up socketpair, that sucks: try recreating it */
					JANUS_LOG(LOG_WARN, "Error polling wake-up socketpair: %s...\n",
						poll_fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
					close(write_fd[0]);
					write_fd[0] = -1;
					close(write_fd[1]);
					write_fd[1] = -1;
					if(socketpair(PF_LOCAL, SOCK_STREAM, 0, write_fd) < 0) {
						JANUS_LOG(LOG_FATAL, "Error creating socket pair for writeable events: %d, %s\n", errno, strerror(errno));
						continue;
					}
				} else if(poll_fds[i].fd == pfd) {
					/* Error in the Janus API socket */
					JANUS_LOG(LOG_WARN, "Error polling Unix Sockets Janus API interface (%s), disabling it\n",
						poll_fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
					close(pfd);
					pfd = -1;
					continue;
				} else if(poll_fds[i].fd == admin_pfd) {
					/* Error in the Admin API socket */
					JANUS_LOG(LOG_WARN, "Error polling Unix Sockets Admin API interface (%s), disabling it\n",
						poll_fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
					close(admin_pfd);
					admin_pfd = -1;
					continue;
				} else {
					/* Error in a client socket, find and remove it */
					janus_mutex_lock(&clients_mutex);
					janus_pfunix_client *client = g_hash_table_lookup(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
					if(client == NULL) {
						/* We're not handling this, ignore */
						continue;
					}
					JANUS_LOG(LOG_INFO, "Unix Sockets client disconnected (%d)\n", poll_fds[i].fd);
					/* Notify core */
					gateway->transport_gone(&janus_pfunix_transport, client);
					/* Close socket */
					shutdown(SHUT_RDWR, poll_fds[i].fd);
					close(poll_fds[i].fd);
					client->fd = -1;
					/* Destroy the client */
					g_hash_table_remove(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
					g_hash_table_remove(clients, client);
					if(client->messages != NULL) {
						char *response = NULL;
						while((response = g_async_queue_try_pop(client->messages)) != NULL) {
							g_free(response);
						}
						g_async_queue_unref(client->messages);
					}
					g_free(client);
					janus_mutex_unlock(&clients_mutex);
					continue;
				}
				continue;
			}
			if(poll_fds[i].revents & POLLOUT) {
				/* Find the client from its file descriptor */
				janus_mutex_lock(&clients_mutex);
				janus_pfunix_client *client = g_hash_table_lookup(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
				if(client != NULL) {
					char *payload = NULL;
					while((payload = g_async_queue_try_pop(client->messages)) != NULL) {
						int res = 0;
						do {
							res = write(client->fd, payload, strlen(payload));
						} while(res == -1 && errno == EINTR);
						/* FIXME Should we check if sent everything? */
						JANUS_LOG(LOG_HUGE, "Written %d/%zu bytes on %d\n", res, strlen(payload), client->fd);
						g_free(payload);
					}
				}
				janus_mutex_unlock(&clients_mutex);
			}
			if(poll_fds[i].revents & POLLIN) {
				if(poll_fds[i].fd == write_fd[0]) {
					/* Read and ignore: we use this to unlock the poll if there's data to write */
					res = read(poll_fds[i].fd, buffer, BUFFER_SIZE);
				} else if(poll_fds[i].fd == pfd || poll_fds[i].fd == admin_pfd) {
					/* Janus/Admin API: accept the new client (SOCK_SEQPACKET) or receive data (SOCK_DGRAM) */
					struct sockaddr_un address;
					socklen_t addrlen = sizeof(address);
					if((poll_fds[i].fd == pfd && !dgram) || (poll_fds[i].fd == admin_pfd && !admin_dgram)) {
						/* SOCK_SEQPACKET */
						int cfd = accept(poll_fds[i].fd, (struct sockaddr *) &address, &addrlen);
						if(cfd > -1) {
							JANUS_LOG(LOG_INFO, "Got new Unix Sockets %s API client: %d\n",
								poll_fds[i].fd == pfd ? "Janus" : "Admin", cfd);
							/* Allocate new client */
							janus_pfunix_client *client = g_malloc0(sizeof(janus_pfunix_client));
							client->fd = cfd;
							client->admin = (poll_fds[i].fd == admin_pfd);	/* API client type */
							client->messages = g_async_queue_new();
							client->session_timeout = FALSE;
							/* Take note of this new client */
							janus_mutex_lock(&clients_mutex);
							g_hash_table_insert(clients_by_fd, GINT_TO_POINTER(cfd), client);
							g_hash_table_insert(clients, client, client);
							janus_mutex_unlock(&clients_mutex);
						}
					} else {
						/* SOCK_DGRAM */
						struct sockaddr_storage address;
						res = recvfrom(poll_fds[i].fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&address, &addrlen);
						if(res < 0) {
							if(errno != EAGAIN && errno != EWOULDBLOCK) {
								JANUS_LOG(LOG_ERR, "Error reading from client (%s API)...\n",
									poll_fds[i].fd == pfd ? "Janus" : "Admin");
							}
							continue;
						}
						buffer[res] = '\0';
						/* Is this a new client, or one we knew about already? */
						struct sockaddr_un *uaddr = (struct sockaddr_un *)&address;
						if(strlen(uaddr->sun_path) == 0) {
							/* No path provided, drop the packet */
							JANUS_LOG(LOG_WARN, "Dropping packet from unknown source (no path provided)\n");
							continue;
						}
						janus_mutex_lock(&clients_mutex);
						janus_pfunix_client *client = g_hash_table_lookup(clients_by_path, uaddr->sun_path);
						if(client == NULL) {
							JANUS_LOG(LOG_INFO, "Got new Unix Sockets %s API client: %s\n",
								poll_fds[i].fd == pfd ? "Janus" : "Admin", uaddr->sun_path);
							/* Allocate new client */
							client = g_malloc0(sizeof(janus_pfunix_client));
							client->fd = -1;
							memcpy(&client->addr, uaddr, sizeof(struct sockaddr_un));
							client->admin = (poll_fds[i].fd == admin_pfd);	/* API client type */
							client->messages = g_async_queue_new();
							client->session_timeout = FALSE;
							/* Take note of this new client */
							g_hash_table_insert(clients_by_path, uaddr->sun_path, client);
							g_hash_table_insert(clients, client, client);
						}
						janus_mutex_unlock(&clients_mutex);
						JANUS_LOG(LOG_VERB, "Message from client %s (%d bytes)\n", uaddr->sun_path, res);
						JANUS_LOG(LOG_HUGE, "%s\n", buffer);
						/* Parse the JSON payload */
						json_error_t error;
						json_t *root = json_loads(buffer, 0, &error);
						/* Notify the core, passing both the object and, since it may be needed, the error */
						gateway->incoming_request(&janus_pfunix_transport, client, NULL, client->admin, root, &error);
					}
				} else {
					/* Client data: receive message */
					iov[0].iov_len = sizeof(buffer);
					res = recvmsg(poll_fds[i].fd, &msg, MSG_WAITALL);
					if(res < 0) {
						if(errno != EAGAIN && errno != EWOULDBLOCK) {
							JANUS_LOG(LOG_ERR, "Error reading from client %d...\n", poll_fds[i].fd);
						}
						continue;
					}
					if(msg.msg_flags & MSG_TRUNC) {
						/* Apparently our buffer is not large enough? */
						JANUS_LOG(LOG_WARN, "Incoming message from client %d truncated (%d bytes), dropping it...\n", poll_fds[i].fd, res);
						continue;
					}
					/* Find the client from its file descriptor */
					janus_mutex_lock(&clients_mutex);
					janus_pfunix_client *client = g_hash_table_lookup(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
					if(client == NULL) {
						janus_mutex_unlock(&clients_mutex);
						JANUS_LOG(LOG_WARN, "Got data from unknown Unix Sockets client %d, closing connection...\n", poll_fds[i].fd);
						/* Close socket */
						shutdown(SHUT_RDWR, poll_fds[i].fd);
						close(poll_fds[i].fd);
						continue;
					}
					if(res == 0) {
						JANUS_LOG(LOG_INFO, "Unix Sockets client disconnected (%d)\n", poll_fds[i].fd);
						/* Notify core */
						gateway->transport_gone(&janus_pfunix_transport, client);
						/* Close socket */
						shutdown(SHUT_RDWR, poll_fds[i].fd);
						close(poll_fds[i].fd);
						client->fd = -1;
						/* Destroy the client */
						g_hash_table_remove(clients_by_fd, GINT_TO_POINTER(poll_fds[i].fd));
						g_hash_table_remove(clients, client);
						if(client->messages != NULL) {
							char *response = NULL;
							while((response = g_async_queue_try_pop(client->messages)) != NULL) {
								g_free(response);
							}
							g_async_queue_unref(client->messages);
						}
						g_free(client);
						janus_mutex_unlock(&clients_mutex);
						continue;
					}
					janus_mutex_unlock(&clients_mutex);
					/* If we got here, there's data to handle */
					buffer[res] = '\0';
					JANUS_LOG(LOG_VERB, "Message from client %d (%d bytes)\n", poll_fds[i].fd, res);
					JANUS_LOG(LOG_HUGE, "%s\n", buffer);
					/* Parse the JSON payload */
					json_error_t error;
					json_t *root = json_loads(buffer, 0, &error);
					/* Notify the core, passing both the object and, since it may be needed, the error */
					gateway->incoming_request(&janus_pfunix_transport, client, NULL, client->admin, root, &error);
				}
			}
		}
	}

	if(pfd > -1)
		close(pfd);
	pfd = -1;
	if(admin_pfd > -1)
		close(admin_pfd);
	admin_pfd = -1;

	g_hash_table_destroy(clients_by_path);
	g_hash_table_destroy(clients_by_fd);
	g_hash_table_destroy(clients);

	/* Done */
	JANUS_LOG(LOG_INFO, "Unix Sockets thread ended\n");
	return NULL;
}
Пример #2
0
void*
ags_thread_pool_creation_thread(void *ptr)
{
  AgsThreadPool *thread_pool;
  AgsThread *thread;
  GList *tmplist;
  guint n_threads, max_threads;
  guint i, i_stop;
  
  thread_pool = AGS_THREAD_POOL(ptr);
  
#ifdef AGS_DEBUG
  g_message("ags_thread_pool_creation_thread\0");
#endif
  
  while((AGS_THREAD_POOL_RUNNING & (g_atomic_int_get(&(thread_pool->flags)))) != 0){
#ifdef AGS_DEBUG
    g_message("ags_thread_pool_creation_thread@loopStart\0");
#endif
    
    pthread_mutex_lock(thread_pool->creation_mutex);
    
    g_atomic_int_or(&(thread_pool->flags),
		    AGS_THREAD_POOL_READY);
    
    while(g_atomic_int_get(&(thread_pool->newly_pulled)) == 0){
      pthread_cond_wait(thread_pool->creation_cond,
			thread_pool->creation_mutex);
    }

    n_threads = g_atomic_int_get(&(thread_pool->n_threads));
    max_threads = g_atomic_int_get(&(thread_pool->max_threads));

    i_stop = g_atomic_int_get(&(thread_pool->newly_pulled));
    g_atomic_int_set(&(thread_pool->newly_pulled),
		     0);
    
#ifdef AGS_DEBUG
    g_message("ags_thread_pool_creation_thread@loop0\0");
#endif
    
    g_atomic_int_and(&(thread_pool->flags),
		     (~AGS_THREAD_POOL_READY));
    
    if(n_threads < max_threads){
      for(i = 0; i < i_stop && n_threads < max_threads; i++){
	thread = (AgsThread *) ags_returnable_thread_new(thread_pool);
	tmplist = g_atomic_pointer_get(&(thread_pool->returnable_thread));
	g_atomic_pointer_set(&(thread_pool->returnable_thread),
			     g_list_prepend(tmplist, thread));      
	ags_thread_add_child(AGS_THREAD(thread_pool->parent),
			     thread);
	ags_connectable_connect(AGS_CONNECTABLE(thread));
	g_atomic_int_inc(&(thread_pool->n_threads));

	n_threads++;
      }
    }

    pthread_mutex_unlock(thread_pool->creation_mutex);
    
#ifdef AGS_DEBUG
    g_message("ags_thread_pool_creation_thread@loopEND\0");
#endif
  }
}
Пример #3
0
/**
 * gst_buffer_pool_set_config:
 * @pool: a #GstBufferPool
 * @config: (transfer full): a #GstStructure
 *
 * Set the configuration of the pool. If the pool is already configured, and
 * the configuration haven't change, this function will return %TRUE. If the
 * pool is active, this function will try deactivating it. Buffers allocated
 * form this pool must be returned or else this function will do nothing and
 * return %FALSE.
 *
 * @config is a #GstStructure that contains the configuration parameters for
 * the pool. A default and mandatory set of parameters can be configured with
 * gst_buffer_pool_config_set_params(), gst_buffer_pool_config_set_allocator()
 * and gst_buffer_pool_config_add_option().
 *
 * If the parameters in @config can not be set exactly, this function returns
 * %FALSE and will try to update as much state as possible. The new state can
 * then be retrieved and refined with gst_buffer_pool_get_config().
 *
 * This function takes ownership of @config.
 *
 * Returns: %TRUE when the configuration could be set.
 */
gboolean
gst_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
{
  gboolean result;
  GstBufferPoolClass *pclass;
  GstBufferPoolPrivate *priv;

  g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), FALSE);
  g_return_val_if_fail (config != NULL, FALSE);

  priv = pool->priv;

  GST_BUFFER_POOL_LOCK (pool);

  /* nothing to do if config is unchanged */
  if (priv->configured && gst_structure_is_equal (config, priv->config))
    goto config_unchanged;

  /* can't change the settings when active */
  if (priv->active) {
    GST_BUFFER_POOL_UNLOCK (pool);
    if (!gst_buffer_pool_set_active (pool, FALSE)) {
      GST_BUFFER_POOL_LOCK (pool);
      goto was_active;
    }
    GST_BUFFER_POOL_LOCK (pool);

    /* not likely but as we released the lock */
    if (priv->active)
      goto was_active;
  }

  /* we can't change when outstanding buffers */
  if (g_atomic_int_get (&priv->outstanding) != 0)
    goto have_outstanding;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  /* set the new config */
  if (G_LIKELY (pclass->set_config))
    result = pclass->set_config (pool, config);
  else
    result = FALSE;

  /* save the config regardless of the result so user can read back the
   * modified config and evaluate if the changes are acceptable */
  if (priv->config)
    gst_structure_free (priv->config);
  priv->config = config;

  if (result) {
    /* now we are configured */
    priv->configured = TRUE;
  }
  GST_BUFFER_POOL_UNLOCK (pool);

  return result;

config_unchanged:
  {
    gst_structure_free (config);
    GST_BUFFER_POOL_UNLOCK (pool);
    return TRUE;
  }
  /* ERRORS */
was_active:
  {
    gst_structure_free (config);
    GST_WARNING_OBJECT (pool, "can't change config, we are active");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
have_outstanding:
  {
    gst_structure_free (config);
    GST_WARNING_OBJECT (pool, "can't change config, have outstanding buffers");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
}
Пример #4
0
static GstFlowReturn
gst_avdtp_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
    GstBuffer ** outbuf)
{
  GstAvdtpSrc *avdtpsrc = GST_AVDTP_SRC (bsrc);
  GstBuffer *buf = NULL;
  GstMapInfo info;
  int ret;

  if (g_atomic_int_get (&avdtpsrc->unlocked))
    return GST_FLOW_FLUSHING;

  /* We don't operate in GST_FORMAT_BYTES, so offset is ignored */

  while ((ret = gst_poll_wait (avdtpsrc->poll, GST_CLOCK_TIME_NONE))) {
    if (g_atomic_int_get (&avdtpsrc->unlocked))
      /* We're unlocked, time to gtfo */
      return GST_FLOW_FLUSHING;

    if (ret < 0)
      /* Something went wrong */
      goto read_error;

    if (ret > 0)
      /* Got some data */
      break;
  }

  ret = GST_BASE_SRC_CLASS (parent_class)->alloc (bsrc, offset, length, outbuf);
  if (G_UNLIKELY (ret != GST_FLOW_OK))
    goto alloc_failed;

  buf = *outbuf;

  gst_buffer_map (buf, &info, GST_MAP_WRITE);

  ret = read (avdtpsrc->pfd.fd, info.data, length);

  if (ret < 0)
    goto read_error;
  else if (ret == 0) {
    GST_INFO_OBJECT (avdtpsrc, "Got EOF on the transport fd");
    goto eof;
  }

  if (ret < length)
    gst_buffer_set_size (buf, ret);

  GST_LOG_OBJECT (avdtpsrc, "Read %d bytes", ret);

  gst_buffer_unmap (buf, &info);
  *outbuf = buf;

  return GST_FLOW_OK;

alloc_failed:
  {
    GST_DEBUG_OBJECT (bsrc, "alloc failed: %s", gst_flow_get_name (ret));
    return ret;
  }

read_error:
  GST_ERROR_OBJECT (avdtpsrc, "Error while reading audio data: %s",
      strerror (errno));
  gst_buffer_unref (buf);
  return GST_FLOW_ERROR;

eof:
  gst_buffer_unref (buf);
  return GST_FLOW_EOS;
}
Пример #5
0
static liHandlerResult fastcgi_statemachine(liVRequest *vr, fastcgi_connection *fcon) {
	liPlugin *p = fcon->ctx->plugin;

	switch (fcon->state) {
	case FS_WAIT_FOR_REQUEST:
		/* wait until we have either all data or the cqlimit is full */
		if (-1 == vr->request.content_length || vr->request.content_length != vr->in->length) {
			if (0 != li_chunkqueue_limit_available(vr->in))
				return LI_HANDLER_GO_ON;
		}
		fcon->state = FS_CONNECT;

		/* fall through */
	case FS_CONNECT:
		do {
			fcon->fd = socket(fcon->ctx->socket.addr->plain.sa_family, SOCK_STREAM, 0);
		} while (-1 == fcon->fd && errno == EINTR);
		if (-1 == fcon->fd) {
			if (errno == EMFILE) {
				li_server_out_of_fds(vr->wrk->srv);
			} else if (errno != g_atomic_int_get(&fcon->ctx->last_errno)) {
				g_atomic_int_set(&fcon->ctx->last_errno, errno);
				VR_ERROR(vr, "Couldn't open socket: %s", g_strerror(errno));
			}
			return LI_HANDLER_ERROR;
		}
		li_fd_init(fcon->fd);
		ev_io_set(&fcon->fd_watcher, fcon->fd, EV_READ | EV_WRITE);
		ev_io_start(vr->wrk->loop, &fcon->fd_watcher);

		/* fall through */
	case FS_CONNECTING:
		if (-1 == connect(fcon->fd, &fcon->ctx->socket.addr->plain, fcon->ctx->socket.len)) {
			switch (errno) {
			case EINPROGRESS:
			case EALREADY:
			case EINTR:
				fcon->state = FS_CONNECTING;
				return LI_HANDLER_GO_ON;
			case EAGAIN: /* backend overloaded */
				fastcgi_close(vr, p);
				li_vrequest_backend_overloaded(vr);
				return LI_HANDLER_GO_ON;
			case EISCONN:
				break;
			default:
				if (errno != g_atomic_int_get(&fcon->ctx->last_errno)) {
					g_atomic_int_set(&fcon->ctx->last_errno, errno);
					VR_ERROR(vr, "Couldn't connect to '%s': %s",
						li_sockaddr_to_string(fcon->ctx->socket, vr->wrk->tmp_str, TRUE)->str,
						g_strerror(errno));
				}
				fastcgi_close(vr, p);
				li_vrequest_backend_dead(vr);
				return LI_HANDLER_GO_ON;
			}
		}

		g_atomic_int_set(&fcon->ctx->last_errno, 0);

		fcon->state = FS_CONNECTED;

		/* prepare stream */
		fastcgi_send_begin(fcon);
		fastcgi_send_env(vr, fcon);

		/* fall through */
	case FS_CONNECTED:
		fastcgi_forward_request(vr, fcon);
		break;

	case FS_DONE:
		break;
	}

	return LI_HANDLER_GO_ON;
}
Пример #6
0
void
ags_soundcard_thread_run(AgsThread *thread)
{
  AgsSoundcardThread *soundcard_thread;

  GObject *soundcard;

  GList *poll_fd;
  
  gboolean is_playing, is_recording;
  
  GError *error;

  soundcard_thread = AGS_SOUNDCARD_THREAD(thread);

  soundcard = soundcard_thread->soundcard;

  /* real-time setup */
#ifdef AGS_WITH_RT
  if((AGS_THREAD_RT_SETUP & (g_atomic_int_get(&(thread->flags)))) == 0){
    struct sched_param param;
    
    /* Declare ourself as a real time task */
    param.sched_priority = AGS_RT_PRIORITY;
      
    if(sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
      perror("sched_setscheduler failed");
    }

    g_atomic_int_or(&(thread->flags),
		    AGS_THREAD_RT_SETUP);
  }
#endif

  /* playback */
  if((AGS_SOUNDCARD_CAPABILITY_PLAYBACK & (soundcard_thread->soundcard_capability)) != 0){
    is_playing = ags_soundcard_is_playing(AGS_SOUNDCARD(soundcard));
  
    if(is_playing){
      error = NULL;
      ags_soundcard_play(AGS_SOUNDCARD(soundcard),
			 &error);

      if(error != NULL){
	//TODO:JK: implement me

	g_warning("%s",
		  error->message);
      }
    }
  }

  /* capture */
  if((AGS_SOUNDCARD_CAPABILITY_CAPTURE & (soundcard_thread->soundcard_capability)) != 0){
    is_recording = ags_soundcard_is_recording(AGS_SOUNDCARD(soundcard));
  
    if(is_recording){
      error = NULL;
      ags_soundcard_record(AGS_SOUNDCARD(soundcard),
			   &error);

      if(error != NULL){
	//TODO:JK: implement me

	g_warning("%s",
		  error->message);
      }
    }
  }

  /* duplex */
  if((AGS_SOUNDCARD_CAPABILITY_DUPLEX & (soundcard_thread->soundcard_capability)) != 0){
    //TODO:JK: implement me
  }
}
Пример #7
0
/* Thread to handle incoming messages */
static void *janus_echotest_handler(void *data) {
	JANUS_LOG(LOG_VERB, "Joining EchoTest handler thread\n");
	janus_echotest_message *msg = NULL;
	int error_code = 0;
	char *error_cause = g_malloc0(512);
	if(error_cause == NULL) {
		JANUS_LOG(LOG_FATAL, "Memory error!\n");
		return NULL;
	}
	json_t *root = NULL;
	while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
		msg = g_async_queue_pop(messages);
		if(msg == NULL)
			continue;
		if(msg == &exit_message)
			break;
		if(msg->handle == NULL) {
			janus_echotest_message_free(msg);
			continue;
		}
		janus_echotest_session *session = NULL;
		janus_mutex_lock(&sessions_mutex);
		if(g_hash_table_lookup(sessions, msg->handle) != NULL ) {
			session = (janus_echotest_session *)msg->handle->plugin_handle;
		}
		janus_mutex_unlock(&sessions_mutex);
		if(!session) {
			JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
			janus_echotest_message_free(msg);
			continue;
		}
		if(session->destroyed) {
			janus_echotest_message_free(msg);
			continue;
		}
		/* Handle request */
		error_code = 0;
		root = NULL;
		JANUS_LOG(LOG_VERB, "Handling message: %s\n", msg->message);
		if(msg->message == NULL) {
			JANUS_LOG(LOG_ERR, "No message??\n");
			error_code = JANUS_ECHOTEST_ERROR_NO_MESSAGE;
			g_snprintf(error_cause, 512, "%s", "No message??");
			goto error;
		}
		json_error_t error;
		root = json_loads(msg->message, 0, &error);
		if(!root) {
			JANUS_LOG(LOG_ERR, "JSON error: on line %d: %s\n", error.line, error.text);
			error_code = JANUS_ECHOTEST_ERROR_INVALID_JSON;
			g_snprintf(error_cause, 512, "JSON error: on line %d: %s", error.line, error.text);
			goto error;
		}
		if(!json_is_object(root)) {
			JANUS_LOG(LOG_ERR, "JSON error: not an object\n");
			error_code = JANUS_ECHOTEST_ERROR_INVALID_JSON;
			g_snprintf(error_cause, 512, "JSON error: not an object");
			goto error;
		}
		/* Parse request */
		json_t *audio = json_object_get(root, "audio");
		if(audio && !json_is_boolean(audio)) {
			JANUS_LOG(LOG_ERR, "Invalid element (audio should be a boolean)\n");
			error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
			g_snprintf(error_cause, 512, "Invalid value (audio should be a boolean)");
			goto error;
		}
		json_t *video = json_object_get(root, "video");
		if(video && !json_is_boolean(video)) {
			JANUS_LOG(LOG_ERR, "Invalid element (video should be a boolean)\n");
			error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
			g_snprintf(error_cause, 512, "Invalid value (video should be a boolean)");
			goto error;
		}
		json_t *bitrate = json_object_get(root, "bitrate");
		if(bitrate && (!json_is_integer(bitrate) || json_integer_value(bitrate) < 0)) {
			JANUS_LOG(LOG_ERR, "Invalid element (bitrate should be a positive integer)\n");
			error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
			g_snprintf(error_cause, 512, "Invalid value (bitrate should be a positive integer)");
			goto error;
		}
		json_t *record = json_object_get(root, "record");
		if(record && !json_is_boolean(record)) {
			JANUS_LOG(LOG_ERR, "Invalid element (record should be a boolean)\n");
			error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
			g_snprintf(error_cause, 512, "Invalid value (record should be a boolean)");
			goto error;
		}
		json_t *recfile = json_object_get(root, "filename");
		if(recfile && !json_is_string(recfile)) {
			JANUS_LOG(LOG_ERR, "Invalid element (filename should be a string)\n");
			error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
			g_snprintf(error_cause, 512, "Invalid value (filename should be a string)");
			goto error;
		}
		/* Enforce request */
		if(audio) {
			session->audio_active = json_is_true(audio);
			JANUS_LOG(LOG_VERB, "Setting audio property: %s\n", session->audio_active ? "true" : "false");
		}
		if(video) {
			if(!session->video_active && json_is_true(video)) {
				/* Send a PLI */
				JANUS_LOG(LOG_VERB, "Just (re-)enabled video, sending a PLI to recover it\n");
				char buf[12];
				memset(buf, 0, 12);
				janus_rtcp_pli((char *)&buf, 12);
				gateway->relay_rtcp(session->handle, 1, buf, 12);
			}
			session->video_active = json_is_true(video);
			JANUS_LOG(LOG_VERB, "Setting video property: %s\n", session->video_active ? "true" : "false");
		}
		if(bitrate) {
			session->bitrate = json_integer_value(bitrate);
			JANUS_LOG(LOG_VERB, "Setting video bitrate: %"SCNu64"\n", session->bitrate);
			if(session->bitrate > 0) {
				/* FIXME Generate a new REMB (especially useful for Firefox, which doesn't send any we can cap later) */
				char buf[24];
				memset(buf, 0, 24);
				janus_rtcp_remb((char *)&buf, 24, session->bitrate);
				JANUS_LOG(LOG_VERB, "Sending REMB\n");
				gateway->relay_rtcp(session->handle, 1, buf, 24);
				/* FIXME How should we handle a subsequent "no limit" bitrate? */
			}
		}
		if(record) {
			if(msg->sdp) {
				session->has_audio = (strstr(msg->sdp, "m=audio") != NULL);
				session->has_video = (strstr(msg->sdp, "m=video") != NULL);
			}
			gboolean recording = json_is_true(record);
			const char *recording_base = json_string_value(recfile);
			JANUS_LOG(LOG_VERB, "Recording %s (base filename: %s)\n", recording ? "enabled" : "disabled", recording_base ? recording_base : "not provided");
			if(!recording) {
				/* Not recording (anymore?) */
				if(session->arc) {
					janus_recorder_close(session->arc);
					JANUS_LOG(LOG_INFO, "Closed audio recording %s\n", session->arc->filename ? session->arc->filename : "??");
					janus_recorder_free(session->arc);
				}
				session->arc = NULL;
				if(session->vrc) {
					janus_recorder_close(session->vrc);
					JANUS_LOG(LOG_INFO, "Closed video recording %s\n", session->vrc->filename ? session->vrc->filename : "??");
					janus_recorder_free(session->vrc);
				}
				session->vrc = NULL;
			} else {
				/* We've started recording, send a PLI and go on */
				char filename[255];
				gint64 now = janus_get_real_time();
				if(session->has_audio) {
					/* FIXME We assume we're recording Opus, here */
					memset(filename, 0, 255);
					if(recording_base) {
						/* Use the filename and path we have been provided */
						g_snprintf(filename, 255, "%s-audio", recording_base);
						session->arc = janus_recorder_create(NULL, "opus", filename);
						if(session->arc == NULL) {
							/* FIXME We should notify the fact the recorder could not be created */
							JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this EchoTest user!\n");
						}
					} else {
						/* Build a filename */
						g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-audio", session, now);
						session->arc = janus_recorder_create(NULL, "opus", filename);
						if(session->arc == NULL) {
							/* FIXME We should notify the fact the recorder could not be created */
							JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this EchoTest user!\n");
						}
					}
				}
				if(session->has_video) {
					/* FIXME We assume we're recording VP8, here */
					memset(filename, 0, 255);
					if(recording_base) {
						/* Use the filename and path we have been provided */
						g_snprintf(filename, 255, "%s-video", recording_base);
						session->vrc = janus_recorder_create(NULL, "vp8", filename);
						if(session->vrc == NULL) {
							/* FIXME We should notify the fact the recorder could not be created */
							JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this EchoTest user!\n");
						}
					} else {
						/* Build a filename */
						g_snprintf(filename, 255, "echotest-%p-%"SCNi64"-video", session, now);
						session->vrc = janus_recorder_create(NULL, "vp8", filename);
						if(session->vrc == NULL) {
							/* FIXME We should notify the fact the recorder could not be created */
							JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this EchoTest user!\n");
						}
					}
					/* Send a PLI */
					JANUS_LOG(LOG_VERB, "Recording video, sending a PLI to kickstart it\n");
					char buf[12];
					memset(buf, 0, 12);
					janus_rtcp_pli((char *)&buf, 12);
					gateway->relay_rtcp(session->handle, 1, buf, 12);
				}
			}
		}
		/* Any SDP to handle? */
		if(msg->sdp) {
			JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg->sdp_type, msg->sdp);
			session->has_audio = (strstr(msg->sdp, "m=audio") != NULL);
			session->has_video = (strstr(msg->sdp, "m=video") != NULL);
		}

		if(!audio && !video && !bitrate && !record && !msg->sdp) {
			JANUS_LOG(LOG_ERR, "No supported attributes (audio, video, bitrate, record, jsep) found\n");
			error_code = JANUS_ECHOTEST_ERROR_INVALID_ELEMENT;
			g_snprintf(error_cause, 512, "Message error: no supported attributes (audio, video, bitrate, record, jsep) found");
			goto error;
		}

		json_decref(root);
		/* Prepare JSON event */
		json_t *event = json_object();
		json_object_set_new(event, "echotest", json_string("event"));
		json_object_set_new(event, "result", json_string("ok"));
		char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
		json_decref(event);
		JANUS_LOG(LOG_VERB, "Pushing event: %s\n", event_text);
		if(!msg->sdp) {
			int ret = gateway->push_event(msg->handle, &janus_echotest_plugin, msg->transaction, event_text, NULL, NULL);
			JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
		} else {
			/* Forward the same offer to the gateway, to start the echo test */
			const char *type = NULL;
			if(!strcasecmp(msg->sdp_type, "offer"))
				type = "answer";
			if(!strcasecmp(msg->sdp_type, "answer"))
				type = "offer";
			/* Any media direction that needs to be fixed? */
			char *sdp = g_strdup(msg->sdp);
			if(strstr(sdp, "a=recvonly")) {
				/* Turn recvonly to inactive, as we simply bounce media back */
				sdp = janus_string_replace(sdp, "a=recvonly", "a=inactive");
			} else if(strstr(sdp, "a=sendonly")) {
				/* Turn sendonly to recvonly */
				sdp = janus_string_replace(sdp, "a=sendonly", "a=recvonly");
				/* FIXME We should also actually not echo this media back, though... */
			}
			/* Make also sure we get rid of ULPfec, red, etc. */
			if(strstr(sdp, "ulpfec")) {
				/* FIXME This really needs some better code */
				sdp = janus_string_replace(sdp, "a=rtpmap:116 red/90000\r\n", "");
				sdp = janus_string_replace(sdp, "a=rtpmap:117 ulpfec/90000\r\n", "");
				sdp = janus_string_replace(sdp, "a=rtpmap:96 rtx/90000\r\n", "");
				sdp = janus_string_replace(sdp, "a=fmtp:96 apt=100\r\n", "");
				sdp = janus_string_replace(sdp, "a=rtpmap:97 rtx/90000\r\n", "");
				sdp = janus_string_replace(sdp, "a=fmtp:97 apt=101\r\n", "");
				sdp = janus_string_replace(sdp, "a=rtpmap:98 rtx/90000\r\n", "");
				sdp = janus_string_replace(sdp, "a=fmtp:98 apt=116\r\n", "");
				sdp = janus_string_replace(sdp, " 116", "");
				sdp = janus_string_replace(sdp, " 117", "");
				sdp = janus_string_replace(sdp, " 96", "");
				sdp = janus_string_replace(sdp, " 97", "");
				sdp = janus_string_replace(sdp, " 98", "");
			}
			/* How long will the gateway take to push the event? */
			g_atomic_int_set(&session->hangingup, 0);
			gint64 start = janus_get_monotonic_time();
			int res = gateway->push_event(msg->handle, &janus_echotest_plugin, msg->transaction, event_text, type, sdp);
			JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (took %"SCNu64" us)\n",
				res, janus_get_monotonic_time()-start);
			g_free(sdp);
		}
		g_free(event_text);
		janus_echotest_message_free(msg);
		continue;
		
error:
		{
			if(root != NULL)
				json_decref(root);
			/* Prepare JSON error event */
			json_t *event = json_object();
			json_object_set_new(event, "echotest", json_string("event"));
			json_object_set_new(event, "error_code", json_integer(error_code));
			json_object_set_new(event, "error", json_string(error_cause));
			char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
			json_decref(event);
			JANUS_LOG(LOG_VERB, "Pushing event: %s\n", event_text);
			int ret = gateway->push_event(msg->handle, &janus_echotest_plugin, msg->transaction, event_text, NULL, NULL);
			JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
			g_free(event_text);
			janus_echotest_message_free(msg);
		}
	}
	g_free(error_cause);
	JANUS_LOG(LOG_VERB, "Leaving EchoTest handler thread\n");
	return NULL;
}
Пример #8
0
static void
output_loop (gpointer data)
{
  GstPad *pad;
  GOmxCore *gomx;
  GOmxPort *out_port;
  GstOmxBaseFilter *self;
  GstFlowReturn ret = GST_FLOW_OK;

  pad = data;
  self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
  gomx = self->gomx;

  GST_LOG_OBJECT (self, "begin");

  /* do not bother if we have been setup to bail out */
  if ((ret = g_atomic_int_get (&self->last_pad_push_return)) != GST_FLOW_OK)
    goto leave;

  if (!self->ready) {
    g_error ("not ready");
    return;
  }

  out_port = self->out_port;

  if (G_LIKELY (out_port->enabled)) {
    OMX_BUFFERHEADERTYPE *omx_buffer = NULL;

    GST_LOG_OBJECT (self, "request buffer");
    omx_buffer = g_omx_port_request_buffer (out_port);

    GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);

    if (G_UNLIKELY (!omx_buffer)) {
      GST_WARNING_OBJECT (self, "null buffer: leaving");
      ret = GST_FLOW_WRONG_STATE;
      goto leave;
    }

    log_buffer (self, omx_buffer);

    if (G_LIKELY (omx_buffer->nFilledLen > 0)) {
      GstBuffer *buf;

#if 1
            /** @todo remove this check */
      if (G_LIKELY (self->in_port->enabled)) {
        GstCaps *caps = NULL;

        caps = gst_pad_get_negotiated_caps (self->srcpad);

#ifdef ANDROID
        if (!caps || gomx->settings_changed) {
#else
        if (!caps) {
#endif
                    /** @todo We shouldn't be doing this. */
          GST_WARNING_OBJECT (self, "faking settings changed notification");
          if (gomx->settings_changed_cb)
            gomx->settings_changed_cb (gomx);
#ifdef ANDROID
          gomx->settings_changed = FALSE;
#endif
        } else {
          GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps);
          gst_caps_unref (caps);
        }
      }
#endif

      /* buf is always null when the output buffer pointer isn't shared. */
      buf = omx_buffer->pAppPrivate;

            /** @todo we need to move all the caps handling to one single
             * place, in the output loop probably. */
      if (G_UNLIKELY (omx_buffer->nFlags & 0x80)) {
        GstCaps *caps = NULL;
        GstStructure *structure;
        GValue value = { 0, {{0}
            }
        };

        caps = gst_pad_get_negotiated_caps (self->srcpad);
        caps = gst_caps_make_writable (caps);
        structure = gst_caps_get_structure (caps, 0);

        g_value_init (&value, GST_TYPE_BUFFER);
        buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
        memcpy (GST_BUFFER_DATA (buf),
            omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
        gst_value_set_buffer (&value, buf);
        gst_buffer_unref (buf);
        gst_structure_set_value (structure, "codec_data", &value);
        g_value_unset (&value);

        gst_pad_set_caps (self->srcpad, caps);
      } else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
        GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
        if (self->use_timestamps) {
          GST_BUFFER_TIMESTAMP (buf) =
              gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND,
              OMX_TICKS_PER_SECOND);
        }

        omx_buffer->pAppPrivate = NULL;
        omx_buffer->pBuffer = NULL;

        ret = push_buffer (self, buf);

        gst_buffer_unref (buf);
      } else {
        /* This is only meant for the first OpenMAX buffers,
         * which need to be pre-allocated. */
        /* Also for the very last one. */
        ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
            GST_BUFFER_OFFSET_NONE,
            omx_buffer->nFilledLen, GST_PAD_CAPS (self->srcpad), &buf);

        if (G_LIKELY (buf)) {
          memcpy (GST_BUFFER_DATA (buf),
              omx_buffer->pBuffer + omx_buffer->nOffset,
              omx_buffer->nFilledLen);
          if (self->use_timestamps) {
            GST_BUFFER_TIMESTAMP (buf) =
                gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND,
                OMX_TICKS_PER_SECOND);
          }

          if (self->share_output_buffer) {
            GST_WARNING_OBJECT (self, "couldn't zero-copy");
            /* If pAppPrivate is NULL, it means it was a dummy
             * allocation, free it. */
            if (!omx_buffer->pAppPrivate) {
              g_free (omx_buffer->pBuffer);
              omx_buffer->pBuffer = NULL;
            }
          }

          ret = push_buffer (self, buf);
        } else {
          GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %lu",
              omx_buffer->nFilledLen);
        }
      }
    } else {
      GST_WARNING_OBJECT (self, "empty buffer");
    }

    if (self->share_output_buffer &&
        !omx_buffer->pBuffer && omx_buffer->nOffset == 0) {
      GstBuffer *buf;
      GstFlowReturn result;

      GST_LOG_OBJECT (self, "allocate buffer");
      result = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
          GST_BUFFER_OFFSET_NONE,
          omx_buffer->nAllocLen, GST_PAD_CAPS (self->srcpad), &buf);

      if (G_LIKELY (result == GST_FLOW_OK)) {
        gst_buffer_ref (buf);
        omx_buffer->pAppPrivate = buf;

        omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
        omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
      } else {
        GST_WARNING_OBJECT (self,
            "could not pad allocate buffer, using malloc");
        omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
      }
    }

    if (self->share_output_buffer && !omx_buffer->pBuffer) {
      GST_ERROR_OBJECT (self, "no input buffer to share");
    }

    if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
      GST_DEBUG_OBJECT (self, "got eos");
      gst_pad_push_event (self->srcpad, gst_event_new_eos ());
      omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
      ret = GST_FLOW_UNEXPECTED;
    }

    omx_buffer->nFilledLen = 0;
    GST_LOG_OBJECT (self, "release_buffer");
    g_omx_port_release_buffer (out_port, omx_buffer);
  }

leave:

  self->last_pad_push_return = ret;

  if (gomx->omx_error != OMX_ErrorNone)
    ret = GST_FLOW_ERROR;

  if (ret != GST_FLOW_OK) {
    GST_INFO_OBJECT (self, "pause task, reason:  %s", gst_flow_get_name (ret));
    gst_pad_pause_task (self->srcpad);
  }

  GST_LOG_OBJECT (self, "end");

  gst_object_unref (self);
}

static GstFlowReturn
pad_chain (GstPad * pad, GstBuffer * buf)
{
  GOmxCore *gomx;
  GOmxPort *in_port;
  GstOmxBaseFilter *self;
  GstFlowReturn ret = GST_FLOW_OK;

  self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));

  gomx = self->gomx;

  GST_LOG_OBJECT (self, "begin");
  GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf));

  GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);

  if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded)) {
    g_mutex_lock (self->ready_lock);

    GST_INFO_OBJECT (self, "omx: prepare");

        /** @todo this should probably go after doing preparations. */
    if (self->omx_setup) {
      self->omx_setup (self);
    }

    setup_ports (self);

    g_omx_core_prepare (self->gomx);

    if (gomx->omx_state == OMX_StateIdle) {
      self->ready = TRUE;
      GST_INFO_OBJECT (self, "start srcpad task");
      gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
    }

    g_mutex_unlock (self->ready_lock);

    if (gomx->omx_state != OMX_StateIdle)
      goto out_flushing;
  }

#ifdef ANDROID
  if (gomx->settings_changed) {
    GST_DEBUG_OBJECT (self, "settings changed called from streaming thread... Android");
    if (gomx->settings_changed_cb)
      gomx->settings_changed_cb (gomx);

    gomx->settings_changed = FALSE;
  }
#endif

  in_port = self->in_port;

  if (G_LIKELY (in_port->enabled)) {
    guint buffer_offset = 0;

    if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle)) {
      GST_INFO_OBJECT (self, "omx: play");
      g_omx_core_start (gomx);

      if (gomx->omx_state != OMX_StateExecuting)
        goto out_flushing;

      /* send buffer with codec data flag */
            /** @todo move to util */
      if (self->codec_data) {
        OMX_BUFFERHEADERTYPE *omx_buffer;

        GST_LOG_OBJECT (self, "request buffer");
        omx_buffer = g_omx_port_request_buffer (in_port);

        if (G_LIKELY (omx_buffer)) {
          omx_buffer->nFlags |= 0x00000080;     /* codec data flag */

          omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data);
          memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
              GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen);

          GST_LOG_OBJECT (self, "release_buffer");
          g_omx_port_release_buffer (in_port, omx_buffer);
        }
      }
    }

    if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) {
      GST_ERROR_OBJECT (self, "Whoa! very wrong");
    }

    while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf))) {
      OMX_BUFFERHEADERTYPE *omx_buffer;

      if (self->last_pad_push_return != GST_FLOW_OK ||
          !(gomx->omx_state == OMX_StateExecuting ||
              gomx->omx_state == OMX_StatePause)) {
        goto out_flushing;
      }

      GST_LOG_OBJECT (self, "request buffer");
      omx_buffer = g_omx_port_request_buffer (in_port);

      GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);

      if (G_LIKELY (omx_buffer)) {
        log_buffer (self, omx_buffer);

        if (omx_buffer->nOffset == 0 && self->share_input_buffer) {
          {
            GstBuffer *old_buf;
            old_buf = omx_buffer->pAppPrivate;

            if (old_buf) {
              gst_buffer_unref (old_buf);
            } else if (omx_buffer->pBuffer) {
              g_free (omx_buffer->pBuffer);
            }
          }

          omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
          omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
          omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf);
          omx_buffer->pAppPrivate = buf;
        } else {
          omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset,
              omx_buffer->nAllocLen - omx_buffer->nOffset);
          memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
              GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen);
        }

        if (self->use_timestamps) {
          GstClockTime timestamp_offset = 0;

          if (buffer_offset && GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) {
            timestamp_offset = gst_util_uint64_scale_int (buffer_offset,
                GST_BUFFER_DURATION (buf), GST_BUFFER_SIZE (buf));
          }

          omx_buffer->nTimeStamp =
              gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf) +
              timestamp_offset, OMX_TICKS_PER_SECOND, GST_SECOND);
        }

        buffer_offset += omx_buffer->nFilledLen;
#ifdef ANDROID
        omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
        log_buffer (self, omx_buffer);
#endif

        GST_LOG_OBJECT (self, "release_buffer");
                /** @todo untaint buffer */
        g_omx_port_release_buffer (in_port, omx_buffer);
      } else {
        GST_WARNING_OBJECT (self, "null buffer");
        ret = GST_FLOW_WRONG_STATE;
        goto out_flushing;
      }
    }
  } else {
    GST_WARNING_OBJECT (self, "done");
    ret = GST_FLOW_UNEXPECTED;
  }

  if (!self->share_input_buffer) {
    gst_buffer_unref (buf);
  }

leave:

  GST_LOG_OBJECT (self, "end");

  return ret;

  /* special conditions */
out_flushing:
  {
    const gchar *error_msg = NULL;

    if (gomx->omx_error) {
      error_msg = "Error from OpenMAX component";
    } else if (gomx->omx_state != OMX_StateExecuting &&
        gomx->omx_state != OMX_StatePause) {
      error_msg = "OpenMAX component in wrong state";
    }

    if (error_msg) {
      GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("%s", error_msg));
      ret = GST_FLOW_ERROR;
    }

    gst_buffer_unref (buf);

    goto leave;
  }
}
Пример #9
0
/* GstAggregator vmethods default implementations */
static gboolean
_sink_event (GstAggregator * self, GstAggregatorPad * aggpad, GstEvent * event)
{
  gboolean res = TRUE;
  GstPad *pad = GST_PAD (aggpad);
  GstAggregatorPrivate *priv = self->priv;
  GstAggregatorPadPrivate *padpriv = aggpad->priv;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
    {
      GstBuffer *tmpbuf;

      g_atomic_int_set (&aggpad->priv->flushing, TRUE);
      /*  Remove pad buffer and wake up the streaming thread */
      tmpbuf = gst_aggregator_pad_steal_buffer (aggpad);
      gst_buffer_replace (&tmpbuf, NULL);
      if (g_atomic_int_compare_and_exchange (&padpriv->pending_flush_start,
              TRUE, FALSE) == TRUE) {
        GST_DEBUG_OBJECT (aggpad, "Expecting FLUSH_STOP now");
        g_atomic_int_set (&padpriv->pending_flush_stop, TRUE);
      }

      if (g_atomic_int_get (&priv->flush_seeking)) {
        /* If flush_seeking we forward the first FLUSH_START */
        if (g_atomic_int_compare_and_exchange (&priv->pending_flush_start,
                TRUE, FALSE) == TRUE) {

          GST_DEBUG_OBJECT (self, "Flushing, pausing srcpad task");
          _stop_srcpad_task (self, event);
          priv->flow_return = GST_FLOW_OK;

          GST_INFO_OBJECT (self, "Getting STREAM_LOCK while seeking");
          GST_PAD_STREAM_LOCK (self->srcpad);
          GST_LOG_OBJECT (self, "GOT STREAM_LOCK");
          event = NULL;
          goto eat;
        }
      }

      /* We forward only in one case: right after flush_seeking */
      goto eat;
    }
    case GST_EVENT_FLUSH_STOP:
    {
      GST_DEBUG_OBJECT (aggpad, "Got FLUSH_STOP");

      _aggpad_flush (aggpad, self);
      if (g_atomic_int_get (&priv->flush_seeking)) {
        g_atomic_int_set (&aggpad->priv->pending_flush_stop, FALSE);

        if (g_atomic_int_get (&priv->flush_seeking)) {
          if (_all_flush_stop_received (self)) {
            /* That means we received FLUSH_STOP/FLUSH_STOP on
             * all sinkpads -- Seeking is Done... sending FLUSH_STOP */
            _flush (self);
            gst_pad_push_event (self->srcpad, event);
            priv->send_eos = TRUE;
            event = NULL;
            _add_aggregate_gsource (self);

            GST_INFO_OBJECT (self, "Releasing source pad STREAM_LOCK");
            GST_PAD_STREAM_UNLOCK (self->srcpad);
            _start_srcpad_task (self);
          }
        }
      }

      /* We never forward the event */
      goto eat;
    }
    case GST_EVENT_EOS:
    {
      GST_DEBUG_OBJECT (aggpad, "EOS");

      /* We still have a buffer, and we don't want the subclass to have to
       * check for it. Mark pending_eos, eos will be set when steal_buffer is
       * called
       */
      PAD_LOCK_EVENT (aggpad);
      if (!aggpad->buffer) {
        aggpad->eos = TRUE;
      } else {
        aggpad->priv->pending_eos = TRUE;
      }
      PAD_UNLOCK_EVENT (aggpad);

      _add_aggregate_gsource (self);
      goto eat;
    }
    case GST_EVENT_SEGMENT:
    {
      PAD_LOCK_EVENT (aggpad);
      gst_event_copy_segment (event, &aggpad->segment);
      PAD_UNLOCK_EVENT (aggpad);
      goto eat;
    }
    case GST_EVENT_STREAM_START:
    {
      goto eat;
    }
    case GST_EVENT_TAG:
    {
      GstTagList *tags;

      gst_event_parse_tag (event, &tags);

      if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_STREAM) {
        gst_aggregator_merge_tags (self, tags, GST_TAG_MERGE_REPLACE);
        gst_event_unref (event);
        event = NULL;
        goto eat;
      }
      break;
    }
    default:
    {
      break;
    }
  }

  GST_DEBUG_OBJECT (pad, "Forwarding event: %" GST_PTR_FORMAT, event);
  return gst_pad_event_default (pad, GST_OBJECT (self), event);

eat:
  GST_DEBUG_OBJECT (pad, "Eating event: %" GST_PTR_FORMAT, event);
  if (event)
    gst_event_unref (event);

  return res;
}
Пример #10
0
/**
 * g_thread_pool_get_num_unused_threads:
 *
 * Returns the number of currently unused threads.
 *
 * Return value: the number of currently unused threads
 */
guint
g_thread_pool_get_num_unused_threads (void)
{
  return g_atomic_int_get (&unused_threads);
}
/* this internal thread does nothing else but write samples to the audio device.
 * It will write each segment in the ringbuffer and will update the play
 * pointer.
 * The start/stop methods control the thread.
 */
static void
audioringbuffer_thread_func (GstAudioRingBuffer * buf)
{
    GstAudioSink *sink;
    GstAudioSinkClass *csink;
    GstAudioSinkRingBuffer *abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf);
    WriteFunc writefunc;
    GstMessage *message;
    GValue val = { 0 };

    sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
    csink = GST_AUDIO_SINK_GET_CLASS (sink);

    GST_DEBUG_OBJECT (sink, "enter thread");

    GST_OBJECT_LOCK (abuf);
    GST_DEBUG_OBJECT (sink, "signal wait");
    GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
    GST_OBJECT_UNLOCK (abuf);

    writefunc = csink->write;
    if (writefunc == NULL)
        goto no_function;

    message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
              GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
    g_value_init (&val, GST_TYPE_G_THREAD);
    g_value_set_boxed (&val, g_thread_self ());
    gst_message_set_stream_status_object (message, &val);
    g_value_unset (&val);
    GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
    gst_element_post_message (GST_ELEMENT_CAST (sink), message);

    while (TRUE) {
        gint left, len;
        guint8 *readptr;
        gint readseg;

        /* buffer must be started */
        if (gst_audio_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
            gint written;

            left = len;
            do {
                written = writefunc (sink, readptr, left);
                GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
                                written, left, readseg);
                if (written < 0 || written > left) {
                    /* might not be critical, it e.g. happens when aborting playback */
                    GST_WARNING_OBJECT (sink,
                                        "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
                                        GST_DEBUG_FUNCPTR_NAME (writefunc),
                                        (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
                    break;
                }
                left -= written;
                readptr += written;
            } while (left > 0);

            /* clear written samples */
            gst_audio_ring_buffer_clear (buf, readseg);

            /* we wrote one segment */
            gst_audio_ring_buffer_advance (buf, 1);
        } else {
            GST_OBJECT_LOCK (abuf);
            if (!abuf->running)
                goto stop_running;
            if (G_UNLIKELY (g_atomic_int_get (&buf->state) ==
                            GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
                GST_OBJECT_UNLOCK (abuf);
                continue;
            }
            GST_DEBUG_OBJECT (sink, "signal wait");
            GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
            GST_DEBUG_OBJECT (sink, "wait for action");
            GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
            GST_DEBUG_OBJECT (sink, "got signal");
            if (!abuf->running)
                goto stop_running;
            GST_DEBUG_OBJECT (sink, "continue running");
            GST_OBJECT_UNLOCK (abuf);
        }
    }

    /* Will never be reached */
    g_assert_not_reached ();
    return;

    /* ERROR */
no_function:
    {
        GST_DEBUG_OBJECT (sink, "no write function, exit thread");
        return;
    }
stop_running:
    {
        GST_OBJECT_UNLOCK (abuf);
        GST_DEBUG_OBJECT (sink, "stop running, exit thread");
        message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
                  GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
        g_value_init (&val, GST_TYPE_G_THREAD);
        g_value_set_boxed (&val, g_thread_self ());
        gst_message_set_stream_status_object (message, &val);
        g_value_unset (&val);
        GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
        gst_element_post_message (GST_ELEMENT_CAST (sink), message);
        return;
    }
}
Пример #12
0
/**
 * g_thread_pool_get_max_unused_threads:
 *
 * Returns the maximal allowed number of unused threads.
 *
 * Return value: the maximal number of unused threads
 */
gint
g_thread_pool_get_max_unused_threads (void)
{
  return g_atomic_int_get (&max_unused_threads);
}
Пример #13
0
static GRealThreadPool*
g_thread_pool_wait_for_new_pool (void)
{
  GRealThreadPool *pool;
  gint local_wakeup_thread_serial;
  guint local_max_unused_threads;
  gint local_max_idle_time;
  gint last_wakeup_thread_serial;
  gboolean have_relayed_thread_marker = FALSE;

  local_max_unused_threads = g_atomic_int_get (&max_unused_threads);
  local_max_idle_time = g_atomic_int_get (&max_idle_time);
  last_wakeup_thread_serial = g_atomic_int_get (&wakeup_thread_serial);

  g_atomic_int_inc (&unused_threads);

  do
    {
      if (g_atomic_int_get (&unused_threads) >= local_max_unused_threads)
        {
          /* If this is a superfluous thread, stop it. */
          pool = NULL;
        }
      else if (local_max_idle_time > 0)
        {
          /* If a maximal idle time is given, wait for the given time. */
          DEBUG_MSG (("thread %p waiting in global pool for %f seconds.",
                      g_thread_self (), local_max_idle_time / 1000.0));

          pool = g_async_queue_timeout_pop (unused_thread_queue,
					    local_max_idle_time * 1000);
        }
      else
        {
          /* If no maximal idle time is given, wait indefinitely. */
          DEBUG_MSG (("thread %p waiting in global pool.", g_thread_self ()));
          pool = g_async_queue_pop (unused_thread_queue);
        }

      if (pool == wakeup_thread_marker)
        {
          local_wakeup_thread_serial = g_atomic_int_get (&wakeup_thread_serial);
          if (last_wakeup_thread_serial == local_wakeup_thread_serial)
            {
              if (!have_relayed_thread_marker)
              {
                /* If this wakeup marker has been received for
                 * the second time, relay it.
                 */
                DEBUG_MSG (("thread %p relaying wakeup message to "
                            "waiting thread with lower serial.",
                            g_thread_self ()));

                g_async_queue_push (unused_thread_queue, wakeup_thread_marker);
                have_relayed_thread_marker = TRUE;

                /* If a wakeup marker has been relayed, this thread
                 * will get out of the way for 100 microseconds to
                 * avoid receiving this marker again.
                 */
                g_usleep (100);
              }
            }
          else
            {
              if (g_atomic_int_add (&kill_unused_threads, -1) > 0)
                {
                  pool = NULL;
                  break;
                }

              DEBUG_MSG (("thread %p updating to new limits.",
                          g_thread_self ()));

              local_max_unused_threads = g_atomic_int_get (&max_unused_threads);
              local_max_idle_time = g_atomic_int_get (&max_idle_time);
              last_wakeup_thread_serial = local_wakeup_thread_serial;

              have_relayed_thread_marker = FALSE;
            }
        }
    }
  while (pool == wakeup_thread_marker);

  g_atomic_int_add (&unused_threads, -1);

  return pool;
}
Пример #14
0
/**
 * g_thread_pool_get_max_idle_time:
 *
 * This function will return the maximum @interval that a
 * thread will wait in the thread pool for new tasks before
 * being stopped.
 *
 * If this function returns 0, threads waiting in the thread
 * pool for new work are not stopped.
 *
 * Return value: the maximum @interval (milliseconds) to wait
 *     for new tasks in the thread pool before stopping the
 *     thread
 *
 * Since: 2.10
 */
guint
g_thread_pool_get_max_idle_time (void)
{
  return g_atomic_int_get (&max_idle_time);
}
Пример #15
0
/**
 * @brief Checks if a consumer is tied to a stopped producer
 *
 * @param consumer The consumer object to get the data from
 *
 * @retval true The producer is currently stopped and no further
 *              elements will be returned by @ref bq_consumer_get.
 * @retval false The producer is still active, if @ref bq_consumer_get
 *               returned NULL, it's because there is currently no
 *               data available.
 *
 * @note This function does not lock @ref Track::lock,
 *       instead it uses atomic operations to get the @ref
 *       Track::stopped value.
 */
gboolean bq_consumer_stopped(RTP_session *consumer) {
    if ( consumer->track == NULL )
        return false;

    return !!g_atomic_int_get(&consumer->track->stopped);
}
Пример #16
0
void li_throttle_pool_acquire(liThrottlePool *pool) {
	assert(g_atomic_int_get(&pool->refcount) > 0);
	g_atomic_int_inc(&pool->refcount);
}
Пример #17
0
/* Transport implementation */
int janus_websockets_init(janus_transport_callbacks *callback, const char *config_path) {
	if(g_atomic_int_get(&stopping)) {
		/* Still stopping from before */
		return -1;
	}
	if(callback == NULL || config_path == NULL) {
		/* Invalid arguments */
		return -1;
	}

	/* This is the callback we'll need to invoke to contact the gateway */
	gateway = callback;

	/* Read configuration */
	char filename[255];
	g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_WEBSOCKETS_PACKAGE);
	JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
	janus_config *config = janus_config_parse(filename);
	if(config != NULL) {
		janus_config_print(config);

		/* Handle configuration */
		janus_config_item *item = janus_config_get_item_drilldown(config, "general", "ws_logging");
		if(item && item->value) {
			ws_log_level = atoi(item->value);
			if(ws_log_level < 0)
				ws_log_level = 0;
		}
		JANUS_LOG(LOG_VERB, "libwebsockets logging: %d\n", ws_log_level);
		lws_set_log_level(ws_log_level, NULL);
		old_wss = NULL;
		janus_mutex_init(&old_wss_mutex);

		/* Any ACL for either the Janus or Admin API? */
		item = janus_config_get_item_drilldown(config, "general", "ws_acl");
		if(item && item->value) {
			gchar **list = g_strsplit(item->value, ",", -1);
			gchar *index = list[0];
			if(index != NULL) {
				int i=0;
				while(index != NULL) {
					if(strlen(index) > 0) {
						JANUS_LOG(LOG_INFO, "Adding '%s' to the Janus API allowed list...\n", index);
						janus_websockets_allow_address(g_strdup(index), FALSE);
					}
					i++;
					index = list[i];
				}
			}
			g_strfreev(list);
			list = NULL;
		}
		item = janus_config_get_item_drilldown(config, "admin", "admin_ws_acl");
		if(item && item->value) {
			gchar **list = g_strsplit(item->value, ",", -1);
			gchar *index = list[0];
			if(index != NULL) {
				int i=0;
				while(index != NULL) {
					if(strlen(index) > 0) {
						JANUS_LOG(LOG_INFO, "Adding '%s' to the Admin/monitor allowed list...\n", index);
						janus_websockets_allow_address(g_strdup(index), TRUE);
					}
					i++;
					index = list[i];
				}
			}
			g_strfreev(list);
			list = NULL;
		}

		/* Setup the Janus API WebSockets server(s) */
		item = janus_config_get_item_drilldown(config, "general", "ws");
		if(!item || !item->value || !janus_is_true(item->value)) {
			JANUS_LOG(LOG_WARN, "WebSockets server disabled\n");
		} else {
			int wsport = 8188;
			item = janus_config_get_item_drilldown(config, "general", "ws_port");
			if(item && item->value)
				wsport = atoi(item->value);
			/* Prepare context */
			struct lws_context_creation_info info;
			memset(&info, 0, sizeof info);
			info.port = wsport;
			info.iface = NULL;
			info.protocols = wss_protocols;
			info.extensions = libwebsocket_get_internal_extensions();
			info.ssl_cert_filepath = NULL;
			info.ssl_private_key_filepath = NULL;
			info.gid = -1;
			info.uid = -1;
			info.options = 0;
			/* Create the WebSocket context */
			wss = libwebsocket_create_context(&info);
			if(wss == NULL) {
				JANUS_LOG(LOG_FATAL, "Error initializing libwebsock...\n");
			} else {
				JANUS_LOG(LOG_INFO, "WebSockets server started (port %d)...\n", wsport);
			}
		}
		item = janus_config_get_item_drilldown(config, "general", "wss");
		if(!item || !item->value || !janus_is_true(item->value)) {
			JANUS_LOG(LOG_WARN, "Secure WebSockets server disabled\n");
		} else {
			int wsport = 8989;
			item = janus_config_get_item_drilldown(config, "general", "wss_port");
			if(item && item->value)
				wsport = atoi(item->value);
			item = janus_config_get_item_drilldown(config, "certificates", "cert_pem");
			if(!item || !item->value) {
				JANUS_LOG(LOG_FATAL, "Missing certificate/key path\n");
			} else {
				char *server_pem = (char *)item->value;
				char *server_key = (char *)item->value;
				item = janus_config_get_item_drilldown(config, "certificates", "cert_key");
				if(item && item->value)
					server_key = (char *)item->value;
				JANUS_LOG(LOG_VERB, "Using certificates:\n\t%s\n\t%s\n", server_pem, server_key);
				/* Prepare secure context */
				struct lws_context_creation_info info;
				memset(&info, 0, sizeof info);
				info.port = wsport;
				info.iface = NULL;
				info.protocols = swss_protocols;
				info.extensions = libwebsocket_get_internal_extensions();
				info.ssl_cert_filepath = server_pem;
				info.ssl_private_key_filepath = server_key;
				info.gid = -1;
				info.uid = -1;
				info.options = 0;
				/* Create the secure WebSocket context */
				swss = libwebsocket_create_context(&info);
				if(swss == NULL) {
					JANUS_LOG(LOG_FATAL, "Error initializing libwebsock...\n");
				} else {
					JANUS_LOG(LOG_INFO, "Secure WebSockets server started (port %d)...\n", wsport);
				}
			}
		}
		/* Do the same for the Admin API, if enabled */
		item = janus_config_get_item_drilldown(config, "admin", "admin_ws");
		if(!item || !item->value || !janus_is_true(item->value)) {
			JANUS_LOG(LOG_WARN, "Admin WebSockets server disabled\n");
		} else {
			int wsport = 7188;
			item = janus_config_get_item_drilldown(config, "admin", "admin_ws_port");
			if(item && item->value)
				wsport = atoi(item->value);
			/* Prepare context */
			struct lws_context_creation_info info;
			memset(&info, 0, sizeof info);
			info.port = wsport;
			info.iface = NULL;
			info.protocols = admin_wss_protocols;
			info.extensions = libwebsocket_get_internal_extensions();
			info.ssl_cert_filepath = NULL;
			info.ssl_private_key_filepath = NULL;
			info.gid = -1;
			info.uid = -1;
			info.options = 0;
			/* Create the WebSocket context */
			admin_wss = libwebsocket_create_context(&info);
			if(admin_wss == NULL) {
				JANUS_LOG(LOG_FATAL, "Error initializing libwebsock...\n");
			} else {
				JANUS_LOG(LOG_INFO, "Admin WebSockets server started (port %d)...\n", wsport);
			}
		}
		item = janus_config_get_item_drilldown(config, "admin", "admin_wss");
		if(!item || !item->value || !janus_is_true(item->value)) {
			JANUS_LOG(LOG_WARN, "Secure Admin WebSockets server disabled\n");
		} else {
			int wsport = 7989;
			item = janus_config_get_item_drilldown(config, "admin", "admin_wss_port");
			if(item && item->value)
				wsport = atoi(item->value);
			item = janus_config_get_item_drilldown(config, "certificates", "cert_pem");
			if(!item || !item->value) {
				JANUS_LOG(LOG_FATAL, "Missing certificate/key path\n");
			} else {
				char *server_pem = (char *)item->value;
				char *server_key = (char *)item->value;
				item = janus_config_get_item_drilldown(config, "certificates", "cert_key");
				if(item && item->value)
					server_key = (char *)item->value;
				JANUS_LOG(LOG_VERB, "Using certificates:\n\t%s\n\t%s\n", server_pem, server_key);
				/* Prepare secure context */
				struct lws_context_creation_info info;
				memset(&info, 0, sizeof info);
				info.port = wsport;
				info.iface = NULL;
				info.protocols = admin_swss_protocols;
				info.extensions = libwebsocket_get_internal_extensions();
				info.ssl_cert_filepath = server_pem;
				info.ssl_private_key_filepath = server_key;
				info.gid = -1;
				info.uid = -1;
				info.options = 0;
				/* Create the secure WebSocket context */
				admin_swss = libwebsocket_create_context(&info);
				if(admin_swss == NULL) {
					JANUS_LOG(LOG_FATAL, "Error initializing libwebsock...\n");
				} else {
					JANUS_LOG(LOG_INFO, "Secure Admin WebSockets server started (port %d)...\n", wsport);
				}
			}
		}
	}
	janus_config_destroy(config);
	config = NULL;
	if(!wss && !swss && !admin_wss && !admin_swss) {
		JANUS_LOG(LOG_FATAL, "No WebSockets server started, giving up...\n");
		return -1;	/* No point in keeping the plugin loaded */
	}
	wss_janus_api_enabled = wss || swss;
	wss_admin_api_enabled = admin_wss || admin_swss;

	GError *error = NULL;
	/* Start the WebSocket service threads */
	if(wss != NULL) {
		wss_thread = g_thread_try_new("websockets thread", &janus_websockets_thread, wss, &error);
		if(!wss_thread) {
			g_atomic_int_set(&initialized, 0);
			JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the WebSockets thread...\n", error->code, error->message ? error->message : "??");
			return -1;
		}
	}
	if(swss != NULL) {
		swss_thread = g_thread_try_new("secure websockets thread", &janus_websockets_thread, swss, &error);
		if(!swss_thread) {
			g_atomic_int_set(&initialized, 0);
			JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Secure WebSockets thread...\n", error->code, error->message ? error->message : "??");
			return -1;
		}
	}
	if(admin_wss != NULL) {
		admin_wss_thread = g_thread_try_new("admin websockets thread", &janus_websockets_thread, admin_wss, &error);
		if(!admin_wss_thread) {
			g_atomic_int_set(&initialized, 0);
			JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Admin WebSockets thread...\n", error->code, error->message ? error->message : "??");
			return -1;
		}
	}
	if(admin_swss != NULL) {
		admin_swss_thread = g_thread_try_new("secure admin websockets thread", &janus_websockets_thread, admin_swss, &error);
		if(!admin_swss_thread) {
			g_atomic_int_set(&initialized, 0);
			JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Secure Admin WebSockets thread...\n", error->code, error->message ? error->message : "??");
			return -1;
		}
	}

	/* Done */
	g_atomic_int_set(&initialized, 1);
	JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_WEBSOCKETS_NAME);
	return 0;
}
Пример #18
0
static void
output_loop (gpointer data)
{
    GstPad *pad;
    GOmxCore *gomx;
    GOmxPort *out_port;
    GstOmxBaseFilter *self;
    GstFlowReturn ret = GST_FLOW_OK;

    pad = data;
    self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
    gomx = self->gomx;

    GST_LOG_OBJECT (self, "begin");

    /* do not bother if we have been setup to bail out */
    if ((ret = g_atomic_int_get (&self->last_pad_push_return)) != GST_FLOW_OK)
        goto leave;

    if (!self->ready)
    {
        g_error ("not ready");
        return;
    }

    out_port = self->out_port;

    if (G_LIKELY (out_port->enabled))
    {
        OMX_BUFFERHEADERTYPE *omx_buffer = NULL;

        GST_LOG_OBJECT (self, "request buffer");
        omx_buffer = g_omx_port_request_buffer (out_port);

        GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);

        if (G_UNLIKELY (!omx_buffer))
        {
            GST_WARNING_OBJECT (self, "null buffer: leaving");
            ret = GST_FLOW_WRONG_STATE;
            goto leave;
        }

        log_buffer (self, omx_buffer);

        if (G_LIKELY (omx_buffer->nFilledLen > 0))
        {
            GstBuffer *buf;

#if 1
            /** @todo remove this check */
            if (G_LIKELY (self->in_port->enabled))
            {
                GstCaps *caps = NULL;

                caps = gst_pad_get_negotiated_caps (self->srcpad);

                if (!caps)
                {
                    /** @todo We shouldn't be doing this. */
                    GST_WARNING_OBJECT (self, "faking settings changed notification");
                    if (gomx->settings_changed_cb)
                        gomx->settings_changed_cb (gomx);
                }
                else
                {
                    GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps);
                    gst_caps_unref (caps);
                }
            }
#endif

            /* buf is always null when the output buffer pointer isn't shared. */
            buf = omx_buffer->pAppPrivate;

            /** @todo we need to move all the caps handling to one single
             * place, in the output loop probably. */
            if (G_UNLIKELY (omx_buffer->nFlags & 0x80))
            {
                GstCaps *caps = NULL;
                GstStructure *structure;
                GValue value = { 0 };

                caps = gst_pad_get_negotiated_caps (self->srcpad);
                caps = gst_caps_make_writable (caps);
                structure = gst_caps_get_structure (caps, 0);

                g_value_init (&value, GST_TYPE_BUFFER);
                buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
                memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
                gst_value_set_buffer (&value, buf);
                gst_buffer_unref (buf);
                gst_structure_set_value (structure, "codec_data", &value);
                g_value_unset (&value);

                gst_pad_set_caps (self->srcpad, caps);
            }
            else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS))
            {
                GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
                if (self->use_timestamps)
                {
                    GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp,
                                                                            GST_SECOND,
                                                                            OMX_TICKS_PER_SECOND);
                }

                omx_buffer->pAppPrivate = NULL;
                omx_buffer->pBuffer = NULL;

                ret = push_buffer (self, buf);

                gst_buffer_unref (buf);
            }
            else
            {
                /* This is only meant for the first OpenMAX buffers,
                 * which need to be pre-allocated. */
                /* Also for the very last one. */
                ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
                                                         GST_BUFFER_OFFSET_NONE,
                                                         omx_buffer->nFilledLen,
                                                         GST_PAD_CAPS (self->srcpad),
                                                         &buf);

                if (G_LIKELY (buf))
                {
                    memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
                    if (self->use_timestamps)
                    {
                        GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp,
                                                                                GST_SECOND,
                                                                                OMX_TICKS_PER_SECOND);
                    }

                    if (self->share_output_buffer)
                    {
                        GST_WARNING_OBJECT (self, "couldn't zero-copy");
                        /* If pAppPrivate is NULL, it means it was a dummy
                         * allocation, free it. */
                        if (!omx_buffer->pAppPrivate)
                        {
                            g_free (omx_buffer->pBuffer);
                            omx_buffer->pBuffer = NULL;
                        }
                    }

                    ret = push_buffer (self, buf);
                }
                else
                {
                    GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %" G_GUINT32_FORMAT,
                                        omx_buffer->nFilledLen);
                }
            }
        }
        else
        {
            GST_WARNING_OBJECT (self, "empty buffer");
        }

        if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS))
        {
            GST_DEBUG_OBJECT (self, "got eos");
            gst_pad_push_event (self->srcpad, gst_event_new_eos ());
            ret = GST_FLOW_UNEXPECTED;
            goto leave;
        }

        if (self->share_output_buffer &&
            !omx_buffer->pBuffer &&
            omx_buffer->nOffset == 0)
        {
            GstBuffer *buf;
            GstFlowReturn result;

            GST_LOG_OBJECT (self, "allocate buffer");
            result = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
                                                        GST_BUFFER_OFFSET_NONE,
                                                        omx_buffer->nAllocLen,
                                                        GST_PAD_CAPS (self->srcpad),
                                                        &buf);

            if (G_LIKELY (result == GST_FLOW_OK))
            {
                gst_buffer_ref (buf);
                omx_buffer->pAppPrivate = buf;

                omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
                omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
            }
            else
            {
                GST_WARNING_OBJECT (self, "could not pad allocate buffer, using malloc");
                omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
            }
        }

        if (self->share_output_buffer &&
            !omx_buffer->pBuffer)
        {
            GST_ERROR_OBJECT (self, "no input buffer to share");
        }

        omx_buffer->nFilledLen = 0;
        GST_LOG_OBJECT (self, "release_buffer");
        g_omx_port_release_buffer (out_port, omx_buffer);
    }

leave:

    self->last_pad_push_return = ret;

    if (gomx->omx_error != OMX_ErrorNone)
        ret = GST_FLOW_ERROR;

    if (ret != GST_FLOW_OK)
    {
        GST_INFO_OBJECT (self, "pause task, reason:  %s",
                         gst_flow_get_name (ret));
        gst_pad_pause_task (self->srcpad);
    }

    GST_LOG_OBJECT (self, "end");

    gst_object_unref (self);
}
static void
maildir_check_mail( XfceMailwatchMaildirMailbox *maildir )
{
    gchar           *path = NULL;
    struct stat     st;

    DBG( "-->>" );
    
    g_mutex_lock( maildir->mutex );
    if ( !maildir->path || !*(maildir->path) ) {
        goto out;
    }

    path = g_build_filename( maildir->path, "new", NULL );
    if ( stat( path, &st ) < 0 ) {
        xfce_mailwatch_log_message( maildir->mailwatch,
                                    XFCE_MAILWATCH_MAILBOX( maildir ),
                                    XFCE_MAILWATCH_LOG_ERROR,
                                    _( "Failed to get status of file %s: %s" ),
                                    path, g_strerror( errno ) );
        goto out;
    }
        
    if ( !S_ISDIR( st.st_mode ) ) {
        xfce_mailwatch_log_message( maildir->mailwatch,
                                    XFCE_MAILWATCH_MAILBOX( maildir ),
                                    XFCE_MAILWATCH_LOG_ERROR,
                                    _( "%s is not a directory. Is %s really a valid maildir?" ),
                                    path, maildir->path );
        goto out;
    }

    if ( st.st_mtime > maildir->mtime ) {
        GDir        *dir;
        GError      *error = NULL;

        dir = g_dir_open( path, 0, &error );
        
        if ( dir ) {
            int             count_new = 0;
            const gchar     *entry;
            
            while ( ( entry = g_dir_read_name( dir ) ) ) {
                count_new++;

                /* only check every 25 entries */
                if( !( count_new % 25 ) ) {
                    if( !g_atomic_int_get( &maildir->running ) ) {
                        g_dir_close( dir );
                        g_atomic_pointer_set( &maildir->thread, NULL );
                        return;
                    }
                }
            }
            g_dir_close( dir );

            xfce_mailwatch_signal_new_messages( maildir->mailwatch,
                    (XfceMailwatchMailbox *) maildir, count_new );
        }
        else {
            xfce_mailwatch_log_message( maildir->mailwatch,
                                        XFCE_MAILWATCH_MAILBOX( maildir ),
                                        XFCE_MAILWATCH_LOG_ERROR,
                                        "%s", error->message );
            g_error_free( error );
        }
        maildir->mtime = st.st_mtime;
    }

out:
    g_mutex_unlock( maildir->mutex );
    if ( path ) {
        g_free( path );
    }

    DBG( "<<--" );
}
static GstFlowReturn
gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame)
{
  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
  GstFlowReturn ret = GST_FLOW_OK;

  GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);

  if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
    goto flushing;

  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
    if (!self->input_state)
      goto not_negotiated;
    if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps))
      goto not_negotiated;
  }

  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
    GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
    GstVideoInfo info;
    GstVideoCodecState *output_state;
    GstBuffer *codec_data;

    GST_DEBUG_OBJECT (self, "Sending header");

    codec_data = self->input_state->codec_data;

    /* We are running in byte-stream mode, so we don't know the headers, but
     * we need to send something, otherwise the decoder will refuse to
     * intialize.
     */
    if (codec_data) {
      gst_buffer_ref (codec_data);
    } else {
      codec_data = frame->input_buffer;
      frame->input_buffer = NULL;
    }

    /* Ensure input internal pool is active */
    if (!gst_buffer_pool_is_active (pool)) {
      GstStructure *config = gst_buffer_pool_get_config (pool);
      gst_buffer_pool_config_set_params (config, self->input_state->caps,
          self->v4l2output->info.size, 2, 2);

      /* There is no reason to refuse this config */
      if (!gst_buffer_pool_set_config (pool, config))
        goto activate_failed;

      if (!gst_buffer_pool_set_active (pool, TRUE))
        goto activate_failed;
    }

    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
    ret =
        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
            v4l2output->pool), &codec_data);
    GST_VIDEO_DECODER_STREAM_LOCK (decoder);

    gst_buffer_unref (codec_data);

    if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info))
      goto not_negotiated;

    output_state = gst_video_decoder_set_output_state (decoder,
        info.finfo->format, info.width, info.height, self->input_state);

    /* Copy the rest of the information, there might be more in the future */
    output_state->info.interlace_mode = info.interlace_mode;
    gst_video_codec_state_unref (output_state);

    if (!gst_video_decoder_negotiate (decoder)) {
      if (GST_PAD_IS_FLUSHING (decoder->srcpad))
        goto flushing;
      else
        goto not_negotiated;
    }

    /* Ensure our internal pool is activated */
    if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool),
            TRUE))
      goto activate_failed;
  }

  if (g_atomic_int_get (&self->processing) == FALSE) {
    /* It's possible that the processing thread stopped due to an error */
    if (self->output_flow != GST_FLOW_OK &&
        self->output_flow != GST_FLOW_FLUSHING) {
      GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
      ret = self->output_flow;
      goto drop;
    }

    GST_DEBUG_OBJECT (self, "Starting decoding thread");

    /* Start the processing task, when it quits, the task will disable input
     * processing to unlock input if draining, or prevent potential block */
    g_atomic_int_set (&self->processing, TRUE);
    if (!gst_pad_start_task (decoder->srcpad,
            (GstTaskFunction) gst_v4l2_video_dec_loop, self,
            (GDestroyNotify) gst_v4l2_video_dec_loop_stopped))
      goto start_task_failed;
  }

  if (frame->input_buffer) {
    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
    ret =
        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output->
            pool), &frame->input_buffer);
    GST_VIDEO_DECODER_STREAM_LOCK (decoder);

    if (ret == GST_FLOW_FLUSHING) {
      if (g_atomic_int_get (&self->processing) == FALSE)
        ret = self->output_flow;
      goto drop;
    } else if (ret != GST_FLOW_OK) {
      goto process_failed;
    }

    /* No need to keep input arround */
    gst_buffer_replace (&frame->input_buffer, NULL);
  }

  gst_video_codec_frame_unref (frame);
  return ret;

  /* ERRORS */
not_negotiated:
  {
    GST_ERROR_OBJECT (self, "not negotiated");
    ret = GST_FLOW_NOT_NEGOTIATED;
    goto drop;
  }
activate_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
        (_("Failed to allocate required memory.")),
        ("Buffer pool activation failed"));
    ret = GST_FLOW_ERROR;
    goto drop;
  }
flushing:
  {
    ret = GST_FLOW_FLUSHING;
    goto drop;
  }

start_task_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
        (_("Failed to start decoding thread.")), (NULL));
    g_atomic_int_set (&self->processing, FALSE);
    ret = GST_FLOW_ERROR;
    goto drop;
  }
process_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
        (_("Failed to process frame.")),
        ("Maybe be due to not enough memory or failing driver"));
    ret = GST_FLOW_ERROR;
    goto drop;
  }
drop:
  {
    gst_video_decoder_drop_frame (decoder, frame);
    return ret;
  }
}
Пример #21
0
/* Thread to handle incoming messages */
static void *janus_videocall_handler(void *data) {
	JANUS_LOG(LOG_VERB, "Joining VideoCall handler thread\n");
	janus_videocall_message *msg = NULL;
	int error_code = 0;
	char error_cause[512];
	json_t *root = NULL;
	while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
		msg = g_async_queue_pop(messages);
		if(msg == NULL)
			continue;
		if(msg == &exit_message)
			break;
		if(msg->handle == NULL) {
			janus_videocall_message_free(msg);
			continue;
		}
		janus_videocall_session *session = (janus_videocall_session *)msg->handle->plugin_handle;
		if(!session) {
			JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
			janus_videocall_message_free(msg);
			continue;
		}
		if(session->destroyed) {
			janus_videocall_message_free(msg);
			continue;
		}
		/* Handle request */
		error_code = 0;
		root = msg->message;
		if(msg->message == NULL) {
			JANUS_LOG(LOG_ERR, "No message??\n");
			error_code = JANUS_VIDEOCALL_ERROR_NO_MESSAGE;
			g_snprintf(error_cause, 512, "%s", "No message??");
			goto error;
		}
		if(!json_is_object(root)) {
			JANUS_LOG(LOG_ERR, "JSON error: not an object\n");
			error_code = JANUS_VIDEOCALL_ERROR_INVALID_JSON;
			g_snprintf(error_cause, 512, "JSON error: not an object");
			goto error;
		}
		JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
			error_code, error_cause, TRUE,
			JANUS_VIDEOCALL_ERROR_MISSING_ELEMENT, JANUS_VIDEOCALL_ERROR_INVALID_ELEMENT);
		if(error_code != 0)
			goto error;
		const char *msg_sdp_type = json_string_value(json_object_get(msg->jsep, "type"));
		const char *msg_sdp = json_string_value(json_object_get(msg->jsep, "sdp"));
		json_t *request = json_object_get(root, "request");
		const char *request_text = json_string_value(request);
		json_t *result = NULL;
		char *sdp_type = NULL, *sdp = NULL;
		if(!strcasecmp(request_text, "list")) {
			result = json_object();
			json_t *list = json_array();
			JANUS_LOG(LOG_VERB, "Request for the list of peers\n");
			/* Return a list of all available mountpoints */
			janus_mutex_lock(&sessions_mutex);
			GHashTableIter iter;
			gpointer value;
			g_hash_table_iter_init(&iter, sessions);
			while (g_hash_table_iter_next(&iter, NULL, &value)) {
				janus_videocall_session *user = value;
				if(user != NULL && user->username != NULL)
					json_array_append_new(list, json_string(user->username));
			}
			json_object_set_new(result, "list", list);
			janus_mutex_unlock(&sessions_mutex);
		} else if(!strcasecmp(request_text, "register")) {
			/* Map this handle to a username */
			if(session->username != NULL) {
				JANUS_LOG(LOG_ERR, "Already registered (%s)\n", session->username);
				error_code = JANUS_VIDEOCALL_ERROR_ALREADY_REGISTERED;
				g_snprintf(error_cause, 512, "Already registered (%s)", session->username);
				goto error;
			}
			JANUS_VALIDATE_JSON_OBJECT(root, username_parameters,
				error_code, error_cause, TRUE,
				JANUS_VIDEOCALL_ERROR_MISSING_ELEMENT, JANUS_VIDEOCALL_ERROR_INVALID_ELEMENT);
			if(error_code != 0)
				goto error;
			json_t *username = json_object_get(root, "username");
			const char *username_text = json_string_value(username);
			janus_mutex_lock(&sessions_mutex);
			if(g_hash_table_lookup(sessions, username_text) != NULL) {
				janus_mutex_unlock(&sessions_mutex);
				JANUS_LOG(LOG_ERR, "Username '%s' already taken\n", username_text);
				error_code = JANUS_VIDEOCALL_ERROR_USERNAME_TAKEN;
				g_snprintf(error_cause, 512, "Username '%s' already taken", username_text);
				goto error;
			}
			janus_mutex_unlock(&sessions_mutex);
			session->username = g_strdup(username_text);
			janus_mutex_lock(&sessions_mutex);
			g_hash_table_insert(sessions, (gpointer)session->username, session);
			janus_mutex_unlock(&sessions_mutex);
			result = json_object();
			json_object_set_new(result, "event", json_string("registered"));
			json_object_set_new(result, "username", json_string(username_text));
			/* Also notify event handlers */
			if(notify_events && gateway->events_is_enabled()) {
				json_t *info = json_object();
				json_object_set_new(info, "event", json_string("registered"));
				json_object_set_new(info, "username", json_string(username_text));
				gateway->notify_event(&janus_videocall_plugin, session->handle, info);
			}
		} else if(!strcasecmp(request_text, "call")) {
			/* Call another peer */
			if(session->username == NULL) {
				JANUS_LOG(LOG_ERR, "Register a username first\n");
				error_code = JANUS_VIDEOCALL_ERROR_REGISTER_FIRST;
				g_snprintf(error_cause, 512, "Register a username first");
				goto error;
			}
			if(session->peer != NULL) {
				JANUS_LOG(LOG_ERR, "Already in a call\n");
				error_code = JANUS_VIDEOCALL_ERROR_ALREADY_IN_CALL;
				g_snprintf(error_cause, 512, "Already in a call");
				goto error;
			}
			JANUS_VALIDATE_JSON_OBJECT(root, username_parameters,
				error_code, error_cause, TRUE,
				JANUS_VIDEOCALL_ERROR_MISSING_ELEMENT, JANUS_VIDEOCALL_ERROR_INVALID_ELEMENT);
			if(error_code != 0)
				goto error;
			json_t *username = json_object_get(root, "username");
			const char *username_text = json_string_value(username);
			if(!strcmp(username_text, session->username)) {
				JANUS_LOG(LOG_ERR, "You can't call yourself... use the EchoTest for that\n");
				error_code = JANUS_VIDEOCALL_ERROR_USE_ECHO_TEST;
				g_snprintf(error_cause, 512, "You can't call yourself... use the EchoTest for that");
				goto error;
			}
			janus_mutex_lock(&sessions_mutex);
			janus_videocall_session *peer = g_hash_table_lookup(sessions, username_text);
			if(peer == NULL || peer->destroyed) {
				janus_mutex_unlock(&sessions_mutex);
				JANUS_LOG(LOG_ERR, "Username '%s' doesn't exist\n", username_text);
				error_code = JANUS_VIDEOCALL_ERROR_NO_SUCH_USERNAME;
				g_snprintf(error_cause, 512, "Username '%s' doesn't exist", username_text);
				goto error;
			}
			if(peer->peer != NULL) {
				janus_mutex_unlock(&sessions_mutex);
				JANUS_LOG(LOG_VERB, "%s is busy\n", username_text);
				result = json_object();
				json_object_set_new(result, "event", json_string("hangup"));
				json_object_set_new(result, "username", json_string(session->username));
				json_object_set_new(result, "reason", json_string("User busy"));
				/* Also notify event handlers */
				if(notify_events && gateway->events_is_enabled()) {
					json_t *info = json_object();
					json_object_set_new(info, "event", json_string("hangup"));
					json_object_set_new(info, "reason", json_string("User busy"));
					gateway->notify_event(&janus_videocall_plugin, session->handle, info);
				}
				gateway->close_pc(session->handle);
			} else {
				janus_mutex_unlock(&sessions_mutex);
				/* Any SDP to handle? if not, something's wrong */
				if(!msg_sdp) {
					JANUS_LOG(LOG_ERR, "Missing SDP\n");
					error_code = JANUS_VIDEOCALL_ERROR_MISSING_SDP;
					g_snprintf(error_cause, 512, "Missing SDP");
					goto error;
				}
				janus_mutex_lock(&sessions_mutex);
				session->peer = peer;
				peer->peer = session;
				session->has_audio = (strstr(msg_sdp, "m=audio") != NULL);
				session->has_video = (strstr(msg_sdp, "m=video") != NULL);
				janus_mutex_unlock(&sessions_mutex);
				JANUS_LOG(LOG_VERB, "%s is calling %s\n", session->username, session->peer->username);
				JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg_sdp_type, msg_sdp);
				/* Send SDP to our peer */
				json_t *call = json_object();
				json_object_set_new(call, "videocall", json_string("event"));
				json_t *calling = json_object();
				json_object_set_new(calling, "event", json_string("incomingcall"));
				json_object_set_new(calling, "username", json_string(session->username));
				json_object_set_new(call, "result", calling);
				json_t *jsep = json_pack("{ssss}", "type", msg_sdp_type, "sdp", msg_sdp);
				g_atomic_int_set(&session->hangingup, 0);
				int ret = gateway->push_event(peer->handle, &janus_videocall_plugin, NULL, call, jsep);
				JANUS_LOG(LOG_VERB, "  >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret));
				g_free(sdp);
				json_decref(call);
				json_decref(jsep);
				/* Send an ack back */
				result = json_object();
				json_object_set_new(result, "event", json_string("calling"));
				/* Also notify event handlers */
				if(notify_events && gateway->events_is_enabled()) {
					json_t *info = json_object();
					json_object_set_new(info, "event", json_string("calling"));
					gateway->notify_event(&janus_videocall_plugin, session->handle, info);
				}
			}
		} else if(!strcasecmp(request_text, "accept")) {
			/* Accept a call from another peer */
			if(session->peer == NULL) {
				JANUS_LOG(LOG_ERR, "No incoming call to accept\n");
				error_code = JANUS_VIDEOCALL_ERROR_NO_CALL;
				g_snprintf(error_cause, 512, "No incoming call to accept");
				goto error;
			}
			/* Any SDP to handle? if not, something's wrong */
			if(!msg_sdp) {
				JANUS_LOG(LOG_ERR, "Missing SDP\n");
				error_code = JANUS_VIDEOCALL_ERROR_MISSING_SDP;
				g_snprintf(error_cause, 512, "Missing SDP");
				goto error;
			}
			JANUS_LOG(LOG_VERB, "%s is accepting a call from %s\n", session->username, session->peer->username);
			JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg_sdp_type, msg_sdp);
			session->has_audio = (strstr(msg_sdp, "m=audio") != NULL);
			session->has_video = (strstr(msg_sdp, "m=video") != NULL);
			/* Send SDP to our peer */
			json_t *jsep = json_pack("{ssss}", "type", msg_sdp_type, "sdp", msg_sdp);
			json_t *call = json_object();
			json_object_set_new(call, "videocall", json_string("event"));
			json_t *calling = json_object();
			json_object_set_new(calling, "event", json_string("accepted"));
			json_object_set_new(calling, "username", json_string(session->username));
			json_object_set_new(call, "result", calling);
			g_atomic_int_set(&session->hangingup, 0);
			int ret = gateway->push_event(session->peer->handle, &janus_videocall_plugin, NULL, call, jsep);
			JANUS_LOG(LOG_VERB, "  >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret));
			json_decref(call);
			json_decref(jsep);
			/* Send an ack back */
			result = json_object();
			json_object_set_new(result, "event", json_string("accepted"));
			/* Also notify event handlers */
			if(notify_events && gateway->events_is_enabled()) {
				json_t *info = json_object();
				json_object_set_new(info, "event", json_string("accepted"));
				gateway->notify_event(&janus_videocall_plugin, session->handle, info);
			}
		} else if(!strcasecmp(request_text, "set")) {
			/* Update the local configuration (audio/video mute/unmute, bitrate cap or recording) */
			JANUS_VALIDATE_JSON_OBJECT(root, set_parameters,
				error_code, error_cause, TRUE,
				JANUS_VIDEOCALL_ERROR_MISSING_ELEMENT, JANUS_VIDEOCALL_ERROR_INVALID_ELEMENT);
			if(error_code != 0)
				goto error;
			json_t *audio = json_object_get(root, "audio");
			json_t *video = json_object_get(root, "video");
			json_t *bitrate = json_object_get(root, "bitrate");
			json_t *record = json_object_get(root, "record");
			json_t *recfile = json_object_get(root, "filename");
			if(audio) {
				session->audio_active = json_is_true(audio);
				JANUS_LOG(LOG_VERB, "Setting audio property: %s\n", session->audio_active ? "true" : "false");
			}
			if(video) {
				if(!session->video_active && json_is_true(video)) {
					/* Send a PLI */
					JANUS_LOG(LOG_VERB, "Just (re-)enabled video, sending a PLI to recover it\n");
					char buf[12];
					janus_rtcp_pli((char *)&buf, 12);
					gateway->relay_rtcp(session->handle, 1, buf, 12);
				}
				session->video_active = json_is_true(video);
				JANUS_LOG(LOG_VERB, "Setting video property: %s\n", session->video_active ? "true" : "false");
			}
			if(bitrate) {
				session->bitrate = json_integer_value(bitrate);
				JANUS_LOG(LOG_VERB, "Setting video bitrate: %"SCNu64"\n", session->bitrate);
				if(session->bitrate > 0) {
					/* FIXME Generate a new REMB (especially useful for Firefox, which doesn't send any we can cap later) */
					char buf[24];
					janus_rtcp_remb((char *)&buf, 24, session->bitrate);
					JANUS_LOG(LOG_VERB, "Sending REMB\n");
					gateway->relay_rtcp(session->handle, 1, buf, 24);
					/* FIXME How should we handle a subsequent "no limit" bitrate? */
				}
			}
			if(record) {
				if(msg_sdp) {
					session->has_audio = (strstr(msg_sdp, "m=audio") != NULL);
					session->has_video = (strstr(msg_sdp, "m=video") != NULL);
				}
				gboolean recording = json_is_true(record);
				const char *recording_base = json_string_value(recfile);
				JANUS_LOG(LOG_VERB, "Recording %s (base filename: %s)\n", recording ? "enabled" : "disabled", recording_base ? recording_base : "not provided");
				janus_mutex_lock(&session->rec_mutex);
				if(!recording) {
					/* Not recording (anymore?) */
					if(session->arc) {
						janus_recorder_close(session->arc);
						JANUS_LOG(LOG_INFO, "Closed audio recording %s\n", session->arc->filename ? session->arc->filename : "??");
						janus_recorder_free(session->arc);
					}
					session->arc = NULL;
					if(session->vrc) {
						janus_recorder_close(session->vrc);
						JANUS_LOG(LOG_INFO, "Closed video recording %s\n", session->vrc->filename ? session->vrc->filename : "??");
						janus_recorder_free(session->vrc);
					}
					session->vrc = NULL;
				} else {
					/* We've started recording, send a PLI and go on */
					char filename[255];
					gint64 now = janus_get_real_time();
					if(session->has_audio) {
						/* FIXME We assume we're recording Opus, here */
						memset(filename, 0, 255);
						if(recording_base) {
							/* Use the filename and path we have been provided */
							g_snprintf(filename, 255, "%s-audio", recording_base);
							session->arc = janus_recorder_create(NULL, "opus", filename);
							if(session->arc == NULL) {
								/* FIXME We should notify the fact the recorder could not be created */
								JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this VideoCall user!\n");
							}
						} else {
							/* Build a filename */
							g_snprintf(filename, 255, "videocall-%s-%s-%"SCNi64"-audio",
								session->username ? session->username : "******",
								(session->peer && session->peer->username) ? session->peer->username : "******",
								now);
							session->arc = janus_recorder_create(NULL, "opus", filename);
							if(session->arc == NULL) {
								/* FIXME We should notify the fact the recorder could not be created */
								JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this VideoCall user!\n");
							}
						}
					}
					if(session->has_video) {
						/* FIXME We assume we're recording VP8, here */
						memset(filename, 0, 255);
						if(recording_base) {
							/* Use the filename and path we have been provided */
							g_snprintf(filename, 255, "%s-video", recording_base);
							session->vrc = janus_recorder_create(NULL, "vp8", filename);
							if(session->vrc == NULL) {
								/* FIXME We should notify the fact the recorder could not be created */
								JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this VideoCall user!\n");
							}
						} else {
							/* Build a filename */
							g_snprintf(filename, 255, "videocall-%s-%s-%"SCNi64"-video",
								session->username ? session->username : "******",
								(session->peer && session->peer->username) ? session->peer->username : "******",
								now);
							session->vrc = janus_recorder_create(NULL, "vp8", filename);
							if(session->vrc == NULL) {
								/* FIXME We should notify the fact the recorder could not be created */
								JANUS_LOG(LOG_ERR, "Couldn't open an video recording file for this VideoCall user!\n");
							}
						}
						/* Send a PLI */
						JANUS_LOG(LOG_VERB, "Recording video, sending a PLI to kickstart it\n");
						char buf[12];
						janus_rtcp_pli((char *)&buf, 12);
						gateway->relay_rtcp(session->handle, 1, buf, 12);
					}
				}
				janus_mutex_unlock(&session->rec_mutex);
			}
			/* Also notify event handlers */
			if(notify_events && gateway->events_is_enabled()) {
				json_t *info = json_object();
				json_object_set_new(info, "event", json_string("configured"));
				json_object_set_new(info, "audio_active", session->audio_active ? json_true() : json_false());
				json_object_set_new(info, "video_active", session->video_active ? json_true() : json_false());
				json_object_set_new(info, "bitrate", json_integer(session->bitrate));
				if(session->arc || session->vrc) {
					json_t *recording = json_object();
					if(session->arc && session->arc->filename)
						json_object_set_new(recording, "audio", json_string(session->arc->filename));
					if(session->vrc && session->vrc->filename)
						json_object_set_new(recording, "video", json_string(session->vrc->filename));
					json_object_set_new(info, "recording", recording);
				}
				gateway->notify_event(&janus_videocall_plugin, session->handle, info);
			}
			/* Send an ack back */
			result = json_object();
			json_object_set_new(result, "event", json_string("set"));
		} else if(!strcasecmp(request_text, "hangup")) {
			/* Hangup an ongoing call or reject an incoming one */
			janus_mutex_lock(&sessions_mutex);
			janus_videocall_session *peer = session->peer;
			if(peer == NULL) {
				JANUS_LOG(LOG_WARN, "No call to hangup\n");
			} else {
				JANUS_LOG(LOG_VERB, "%s is hanging up the call with %s\n", session->username, peer->username);
				session->peer = NULL;
				peer->peer = NULL;
			}
			janus_mutex_unlock(&sessions_mutex);
			/* Notify the success as an hangup message */
			result = json_object();
			json_object_set_new(result, "event", json_string("hangup"));
			json_object_set_new(result, "username", json_string(session->username));
			json_object_set_new(result, "reason", json_string("Explicit hangup"));
			/* Also notify event handlers */
			if(notify_events && gateway->events_is_enabled()) {
				json_t *info = json_object();
				json_object_set_new(info, "event", json_string("hangup"));
				json_object_set_new(info, "reason", json_string("Explicit hangup"));
				gateway->notify_event(&janus_videocall_plugin, session->handle, info);
			}
			gateway->close_pc(session->handle);
			if(peer != NULL) {
				/* Send event to our peer too */
				json_t *call = json_object();
				json_object_set_new(call, "videocall", json_string("event"));
				json_t *calling = json_object();
				json_object_set_new(calling, "event", json_string("hangup"));
				json_object_set_new(calling, "username", json_string(session->username));
				json_object_set_new(calling, "reason", json_string("Remote hangup"));
				json_object_set_new(call, "result", calling);
				gateway->close_pc(peer->handle);
				int ret = gateway->push_event(peer->handle, &janus_videocall_plugin, NULL, call, NULL);
				JANUS_LOG(LOG_VERB, "  >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret));
				json_decref(call);
				/* Also notify event handlers */
				if(notify_events && gateway->events_is_enabled()) {
					json_t *info = json_object();
					json_object_set_new(info, "event", json_string("hangup"));
					json_object_set_new(info, "reason", json_string("Remote hangup"));
					gateway->notify_event(&janus_videocall_plugin, peer->handle, info);
				}
			}
		} else {
			JANUS_LOG(LOG_ERR, "Unknown request (%s)\n", request_text);
			error_code = JANUS_VIDEOCALL_ERROR_INVALID_REQUEST;
			g_snprintf(error_cause, 512, "Unknown request (%s)", request_text);
			goto error;
		}

		/* Prepare JSON event */
		json_t *jsep = sdp ? json_pack("{ssss}", "type", sdp_type, "sdp", sdp) : NULL;
		json_t *event = json_object();
		json_object_set_new(event, "videocall", json_string("event"));
		if(result != NULL)
			json_object_set_new(event, "result", result);
		int ret = gateway->push_event(msg->handle, &janus_videocall_plugin, msg->transaction, event, jsep);
		JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (%s)\n", ret, janus_get_api_error(ret));
		g_free(sdp);
		json_decref(event);
		if(jsep)
			json_decref(jsep);
		janus_videocall_message_free(msg);
		continue;
		
error:
		{
			/* Prepare JSON error event */
			json_t *event = json_object();
			json_object_set_new(event, "videocall", json_string("event"));
			json_object_set_new(event, "error_code", json_integer(error_code));
			json_object_set_new(event, "error", json_string(error_cause));
			int ret = gateway->push_event(msg->handle, &janus_videocall_plugin, msg->transaction, event, NULL);
			JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (%s)\n", ret, janus_get_api_error(ret));
			json_decref(event);
			janus_videocall_message_free(msg);
		}
	}
	JANUS_LOG(LOG_VERB, "Leaving VideoCall handler thread\n");
	return NULL;
}
static gboolean
gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
{
  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
  GstBuffer *buf = frame->buffer;
  GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
  gint off;
  gboolean lost_sync, draining, eac, more = FALSE;
  guint frmsiz, blocks, sid;
  gint have_blocks = 0;

  if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < 6))
    return FALSE;

  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000,
      0, GST_BUFFER_SIZE (buf));

  GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);

  /* didn't find anything that looks like a sync word, skip */
  if (off < 0) {
    *skipsize = GST_BUFFER_SIZE (buf) - 3;
    return FALSE;
  }

  /* possible frame header, but not at offset 0? skip bytes before sync */
  if (off > 0) {
    *skipsize = off;
    return FALSE;
  }

  /* make sure the values in the frame header look sane */
  if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, NULL, NULL,
          &blocks, &sid, &eac)) {
    *skipsize = off + 2;
    return FALSE;
  }

  *framesize = frmsiz;

  if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) ==
          GST_AC3_PARSE_ALIGN_NONE))
    gst_ac3_parse_set_alignment (ac3parse, eac);

  GST_LOG_OBJECT (parse, "got frame");

  lost_sync = GST_BASE_PARSE_LOST_SYNC (parse);
  draining = GST_BASE_PARSE_DRAINING (parse);

  if (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937) {
    /* We need 6 audio blocks from each substream, so we keep going forwards
     * till we have it */

    g_assert (blocks > 0);
    GST_LOG_OBJECT (ac3parse, "Need %d frames before pushing", 6 / blocks);

    if (sid != 0) {
      /* We need the first substream to be the one with id 0 */
      GST_LOG_OBJECT (ac3parse, "Skipping till we find sid 0");
      *skipsize = off + 2;
      return FALSE;
    }

    *framesize = 0;

    /* Loop till we have 6 blocks per substream */
    for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) {
      /* Loop till we get one frame from each substream */
      do {
        *framesize += frmsiz;

        if (!gst_byte_reader_skip (&reader, frmsiz) ||
            GST_BUFFER_SIZE (buf) < (*framesize + 6)) {
          more = TRUE;
          break;
        }

        if (!gst_ac3_parse_frame_header (ac3parse, buf, *framesize, &frmsiz,
                NULL, NULL, NULL, &sid, &eac)) {
          *skipsize = off + 2;
          return FALSE;
        }
      } while (sid);
    }

    /* We're now at the next frame, so no need to skip if resyncing */
    frmsiz = 0;
  }

  if (lost_sync && !draining) {
    guint16 word = 0;

    GST_DEBUG_OBJECT (ac3parse, "resyncing; checking next frame syncword");

    if (more || !gst_byte_reader_skip (&reader, frmsiz) ||
        !gst_byte_reader_get_uint16_be (&reader, &word)) {
      GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data");
      gst_base_parse_set_min_frame_size (parse, *framesize + 6);
      *skipsize = 0;
      return FALSE;
    } else {
      if (word != 0x0b77) {
        GST_DEBUG_OBJECT (ac3parse, "0x%x not OK", word);
        *skipsize = off + 2;
        return FALSE;
      } else {
        /* ok, got sync now, let's assume constant frame size */
        gst_base_parse_set_min_frame_size (parse, *framesize);
      }
    }
  }

  return TRUE;
}
Пример #23
0
static void fastcgi_context_acquire(fastcgi_context *ctx) {
	assert(g_atomic_int_get(&ctx->refcount) > 0);
	g_atomic_int_inc(&ctx->refcount);
}
static GstFlowReturn
gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
{
  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
  GstBuffer *buf = frame->buffer;
  guint fsize, rate, chans, blocks, sid;
  gboolean eac, update_rate = FALSE;

  if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &fsize, &rate, &chans,
          &blocks, &sid, &eac))
    goto broken_header;

  GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", fsize,
      blocks, rate, chans);

  if (G_UNLIKELY (sid)) {
    /* dependent frame, no need to (ac)count for or consider further */
    GST_LOG_OBJECT (parse, "sid: %d", sid);
    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME;
    /* TODO maybe also mark as DELTA_UNIT,
     * if that does not surprise baseparse elsewhere */
    /* occupies same time space as previous base frame */
    if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf)))
      GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf);
    /* only return if we already arranged for caps */
    if (G_LIKELY (ac3parse->sample_rate > 0))
      return GST_FLOW_OK;
  }

  if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans
          || ac3parse->eac != eac)) {
    GstCaps *caps = gst_caps_new_simple (eac ? "audio/x-eac3" : "audio/x-ac3",
        "framed", G_TYPE_BOOLEAN, TRUE, "rate", G_TYPE_INT, rate,
        "channels", G_TYPE_INT, chans, NULL);
    gst_caps_set_simple (caps, "alignment", G_TYPE_STRING,
        g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937 ?
        "iec61937" : "frame", NULL);
    gst_buffer_set_caps (buf, caps);
    gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
    gst_caps_unref (caps);

    ac3parse->sample_rate = rate;
    ac3parse->channels = chans;
    ac3parse->eac = eac;

    update_rate = TRUE;
  }

  if (G_UNLIKELY (ac3parse->blocks != blocks)) {
    ac3parse->blocks = blocks;

    update_rate = TRUE;
  }

  if (G_UNLIKELY (update_rate))
    gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2);

  return GST_FLOW_OK;

/* ERRORS */
broken_header:
  {
    /* this really shouldn't ever happen */
    GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL));
    return GST_FLOW_ERROR;
  }
}
Пример #25
0
	  pthread_mutex_unlock(thread_pool->pull_mutex);

	  break;
	}
	
	list = list->next;
      }
    }while(list == NULL);
  }

  returnable_thread = NULL;

  pthread_mutex_lock(thread_pool->return_mutex);

  max_threads = g_atomic_int_get(&(thread_pool->max_threads));

  if((n_threads = g_atomic_int_get(&(thread_pool->n_threads))) <= max_threads){
    ags_thread_pool_pull_running();
  }else{
    g_atomic_int_inc(&(thread_pool->queued));

    while((n_threads = g_atomic_int_get(&(thread_pool->n_threads))) > max_threads){
      g_message("n_threads >= max_threads\0");
      
      pthread_cond_wait(thread_pool->return_cond,
			thread_pool->return_mutex);
    }

    g_atomic_int_dec_and_test(&(thread_pool->queued));
    ags_thread_pool_pull_running();
Пример #26
0
static
void *
audio_thread(void *param)
{
    struct pollfd  *fds = NULL;
    nfds_t          nfds = 0;
    static char     buf[16 * 1024];

    ppb_message_loop_mark_thread_unsuitable();

    nfds = do_rebuild_fds(&fds);
    pthread_barrier_wait(&stream_list_update_barrier);
    if (nfds == 0)
        goto quit;

    while (1) {
        if (g_atomic_int_get(&terminate_thread))
            goto quit;

        int res = poll(fds, nfds, 10 * 1000);
        if (res == -1) {
            if (errno == EINTR)
                continue;
            trace_error("%s, poll, errno=%d\n", __func__, errno);
            continue;
        }

        if (res == 0 || fds == NULL)
            continue;

        if (fds[0].revents)
            drain_wakeup_pipe(fds[0].fd);

        if (g_atomic_int_get(&rebuild_fds)) {
            nfds = do_rebuild_fds(&fds);
            pthread_barrier_wait(&stream_list_update_barrier);
            if (nfds == 0)
                goto quit;
        }

        for (uintptr_t k = 1; k < nfds; k ++) {
            unsigned short revents = 0;
            audio_stream *as = g_hash_table_lookup(stream_by_fd_ht, GINT_TO_POINTER(fds[k].fd));

            // check if stream was deleted
            if (!as)
                continue;

            snd_pcm_poll_descriptors_revents(as->pcm, &fds[k], 1, &revents);

            if (revents & (~(POLLIN | POLLOUT))) {
                trace_warning("%s, revents have unexpected flags set (%u)\n", __func__,
                              (unsigned int)revents);
                recover_pcm(as->pcm);
            }

            if (revents & (POLLIN | POLLOUT)) {
                int                 paused = g_atomic_int_get(&as->paused);
                snd_pcm_sframes_t   frame_count = snd_pcm_avail(as->pcm);

                if (revents & POLLIN) {
                    // POLLIN
                    const size_t frame_size = 1 * sizeof(int16_t); // mono 16-bit
                    const size_t max_segment_length = MIN(as->sample_frame_count * frame_size,
                                                          sizeof(buf));
                    size_t       to_process = frame_count * frame_size;

                    while (to_process > 0) {
                        snd_pcm_sframes_t frames_read;
                        const size_t segment_length = MIN(to_process, max_segment_length);

                        frames_read = snd_pcm_readi(as->pcm, buf, segment_length / frame_size);
                        if (frames_read < 0) {
                            trace_warning("%s, snd_pcm_readi error %d\n", __func__,
                                          (int)frames_read);
                            recover_pcm(as->pcm);
                            continue;
                        }

                        if (!paused && as->capture_cb)
                            as->capture_cb(buf, frames_read * frame_size, 0, as->cb_user_data);

                        to_process -= frames_read * frame_size;
                    }

                } else {
                    // POLLOUT
                    const size_t frame_size = 2 * sizeof(int16_t); // stereo 16-bit
                    const size_t max_segment_length = MIN(as->sample_frame_count * frame_size,
                                                          sizeof(buf));
                    size_t       to_process = frame_count * frame_size;

                    while (to_process > 0) {
                        snd_pcm_sframes_t frames_written;
                        const size_t segment_length = MIN(to_process, max_segment_length);

                        if (paused || !as->playback_cb)
                            memset(buf, 0, segment_length);
                        else
                            as->playback_cb(buf, segment_length, 0, as->cb_user_data);

                        frames_written = snd_pcm_writei(as->pcm, buf, segment_length / frame_size);

                        if (frames_written < 0) {
                            trace_warning("%s, snd_pcm_writei error %d\n", __func__,
                                          (int)frames_written);
                            recover_pcm(as->pcm);
                            continue;
                        }

                        to_process -= frames_written * frame_size;
                    }
                }
            }
        }
    }

quit:
    free(fds);
    return NULL;
}
Пример #27
0
/**
 * gst_buffer_pool_set_active:
 * @pool: a #GstBufferPool
 * @active: the new active state
 *
 * Control the active state of @pool. When the pool is inactive, new calls to
 * gst_buffer_pool_acquire_buffer() will return with %GST_FLOW_FLUSHING.
 *
 * Activating the bufferpool will preallocate all resources in the pool based on
 * the configuration of the pool.
 *
 * Deactivating will free the resources again when there are no outstanding
 * buffers. When there are outstanding buffers, they will be freed as soon as
 * they are all returned to the pool.
 *
 * Returns: %FALSE when the pool was not configured or when preallocation of the
 * buffers failed.
 */
gboolean
gst_buffer_pool_set_active (GstBufferPool * pool, gboolean active)
{
  gboolean res = TRUE;
  GstBufferPoolPrivate *priv;

  g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), FALSE);

  GST_LOG_OBJECT (pool, "active %d", active);

  priv = pool->priv;

  GST_BUFFER_POOL_LOCK (pool);
  /* just return if we are already in the right state */
  if (priv->active == active)
    goto was_ok;

  /* we need to be configured */
  if (!priv->configured)
    goto not_configured;

  if (active) {
    if (!do_start (pool))
      goto start_failed;

    /* flush_stop my release buffers, setting to active to avoid running
     * do_stop while activating the pool */
    priv->active = TRUE;

    /* unset the flushing state now */
    do_set_flushing (pool, FALSE);
  } else {
    gint outstanding;

    /* set to flushing first */
    do_set_flushing (pool, TRUE);

    /* when all buffers are in the pool, free them. Else they will be
     * freed when they are released */
    outstanding = g_atomic_int_get (&priv->outstanding);
    GST_LOG_OBJECT (pool, "outstanding buffers %d", outstanding);
    if (outstanding == 0) {
      if (!do_stop (pool))
        goto stop_failed;
    }

    priv->active = FALSE;
  }
  GST_BUFFER_POOL_UNLOCK (pool);

  return res;

was_ok:
  {
    GST_DEBUG_OBJECT (pool, "pool was in the right state");
    GST_BUFFER_POOL_UNLOCK (pool);
    return TRUE;
  }
not_configured:
  {
    GST_ERROR_OBJECT (pool, "pool was not configured");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
start_failed:
  {
    GST_ERROR_OBJECT (pool, "start failed");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
stop_failed:
  {
    GST_WARNING_OBJECT (pool, "stop failed");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
}
Пример #28
0
static
audio_stream *
alsa_create_stream(audio_stream_direction direction, unsigned int sample_rate,
                   unsigned int sample_frame_count, const char *pcm_name)
{
    audio_stream *as;
    snd_pcm_hw_params_t *hw_params;
    snd_pcm_sw_params_t *sw_params;
    int dir;

    if (!g_atomic_int_get(&audio_thread_started)) {
        pthread_barrier_init(&stream_list_update_barrier, NULL, 2);
        pthread_create(&audio_thread_id, NULL, audio_thread, NULL);
        g_atomic_int_set(&audio_thread_started, 1);
        pthread_barrier_wait(&stream_list_update_barrier);
    }

    as = calloc(1, sizeof(*as));
    if (!as)
        goto err;

    as->sample_frame_count = sample_frame_count;
    g_atomic_int_set(&as->paused, 1);

#define CHECK_A(funcname, params)                                                       \
    do {                                                                                \
        int errcode___ = funcname params;                                               \
        if (errcode___ < 0) {                                                           \
            trace_error("%s, " #funcname ", %s\n", __func__, snd_strerror(errcode___)); \
            goto err;                                                                   \
        }                                                                               \
    } while (0)

    if (direction == STREAM_PLAYBACK)
        CHECK_A(snd_pcm_open, (&as->pcm, pcm_name, SND_PCM_STREAM_PLAYBACK, 0));
    else
        CHECK_A(snd_pcm_open, (&as->pcm, pcm_name, SND_PCM_STREAM_CAPTURE, 0));

    CHECK_A(snd_pcm_hw_params_malloc, (&hw_params));
    CHECK_A(snd_pcm_hw_params_any, (as->pcm, hw_params));
    CHECK_A(snd_pcm_hw_params_set_access, (as->pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED));
    CHECK_A(snd_pcm_hw_params_set_format, (as->pcm, hw_params, SND_PCM_FORMAT_S16_LE));
    dir = 0;
    unsigned int rate = sample_rate;
    CHECK_A(snd_pcm_hw_params_set_rate_near, (as->pcm, hw_params, &rate, &dir));

    const int channel_count = (direction == STREAM_PLAYBACK) ? 2 : 1;
    CHECK_A(snd_pcm_hw_params_set_channels, (as->pcm, hw_params, channel_count));

    unsigned int period_time = (long long)sample_frame_count * 1000 * 1000 / sample_rate;
    period_time = CLAMP(period_time,
                        1000 * (unsigned int)config.audio_buffer_min_ms,
                        1000 * (unsigned int)config.audio_buffer_max_ms);
    dir = 1;
    CHECK_A(snd_pcm_hw_params_set_period_time_near, (as->pcm, hw_params, &period_time, &dir));

    unsigned int buffer_time = 4 * period_time;
    dir = 1;
    CHECK_A(snd_pcm_hw_params_set_buffer_time_near, (as->pcm, hw_params, &buffer_time, &dir));

    dir = 0;
    CHECK_A(snd_pcm_hw_params_get_buffer_time, (hw_params, &buffer_time, &dir));
    CHECK_A(snd_pcm_hw_params, (as->pcm, hw_params));
    snd_pcm_hw_params_free(hw_params);

    CHECK_A(snd_pcm_sw_params_malloc, (&sw_params));
    CHECK_A(snd_pcm_sw_params_current, (as->pcm, sw_params));
    CHECK_A(snd_pcm_sw_params, (as->pcm, sw_params));
    CHECK_A(snd_pcm_prepare, (as->pcm));
    snd_pcm_sw_params_free(sw_params);

    CHECK_A(snd_pcm_prepare, (as->pcm));

    if (direction == STREAM_CAPTURE)
        CHECK_A(snd_pcm_start, (as->pcm));

    as->nfds = snd_pcm_poll_descriptors_count(as->pcm);
    as->fds = calloc(as->nfds, sizeof(struct pollfd));
    if (!as->fds) {
        trace_error("%s, memory allocation failure\n", __func__);
        goto err;
    }
    snd_pcm_poll_descriptors(as->pcm, as->fds, as->nfds);

    g_hash_table_insert(active_streams_ht, as, GINT_TO_POINTER(1));
    for (uintptr_t k = 0; k < as->nfds; k ++)
        g_hash_table_insert(stream_by_fd_ht, GINT_TO_POINTER(as->fds[k].fd), as);

    wakeup_audio_thread();

#undef CHECK_A

    return as;
err:
    free(as);
    return NULL;
}
Пример #29
0
/**
 * qmi_utils_get_traces_enabled:
 *
 * Checks whether QMI message traces are currently enabled.
 *
 * Returns: %TRUE if traces are enabled, %FALSE otherwise.
 */
gboolean
qmi_utils_get_traces_enabled (void)
{
    return (gboolean) g_atomic_int_get (&__traces_enabled);
}
Пример #30
0
/* Transport implementation */
int janus_pfunix_init(janus_transport_callbacks *callback, const char *config_path) {
	if(g_atomic_int_get(&stopping)) {
		/* Still stopping from before */
		return -1;
	}
	if(callback == NULL || config_path == NULL) {
		/* Invalid arguments */
		return -1;
	}

	/* This is the callback we'll need to invoke to contact the gateway */
	gateway = callback;

	/* Read configuration */
	char filename[255];
	g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_PFUNIX_PACKAGE);
	JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
	janus_config *config = janus_config_parse(filename);
	if(config != NULL) {
		/* Handle configuration */
		janus_config_print(config);

		janus_config_item *item = janus_config_get_item_drilldown(config, "general", "json");
		if(item && item->value) {
			/* Check how we need to format/serialize the JSON output */
			if(!strcasecmp(item->value, "indented")) {
				/* Default: indented, we use three spaces for that */
				json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
			} else if(!strcasecmp(item->value, "plain")) {
				/* Not indented and no new lines, but still readable */
				json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER;
			} else if(!strcasecmp(item->value, "compact")) {
				/* Compact, so no spaces between separators */
				json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
			} else {
				JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', using default (indented)\n", item->value);
				json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
			}
		}

		/* First of all, initialize the socketpair for writeable notifications */
		if(socketpair(PF_LOCAL, SOCK_STREAM, 0, write_fd) < 0) {
			JANUS_LOG(LOG_FATAL, "Error creating socket pair for writeable events: %d, %s\n", errno, strerror(errno));
			return -1;
		}

		/* Setup the Janus API Unix Sockets server(s) */
		item = janus_config_get_item_drilldown(config, "general", "enabled");
		if(!item || !item->value || !janus_is_true(item->value)) {
			JANUS_LOG(LOG_WARN, "Unix Sockets server disabled (Janus API)\n");
		} else {
			item = janus_config_get_item_drilldown(config, "general", "path");
			char *pfname = (char *)(item && item->value ? item->value : "/tmp/ux-janusapi");
			item = janus_config_get_item_drilldown(config, "general", "type");
			const char *type = item && item->value ? item->value : "SOCK_SEQPACKET";
			dgram = FALSE;
			if(!strcasecmp(type, "SOCK_SEQPACKET")) {
				dgram = FALSE;
			} else if(!strcasecmp(type, "SOCK_DGRAM")) {
				dgram = TRUE;
			} else {
				JANUS_LOG(LOG_WARN, "Unknown type %s, assuming SOCK_SEQPACKET\n", type);
				type = "SOCK_SEQPACKET";
			}
			JANUS_LOG(LOG_INFO, "Configuring %s Unix Sockets server (Janus API)\n", type);
			pfd = janus_pfunix_create_socket(pfname, dgram);
		}
		/* Do the same for the Admin API, if enabled */
		item = janus_config_get_item_drilldown(config, "admin", "admin_enabled");
		if(!item || !item->value || !janus_is_true(item->value)) {
			JANUS_LOG(LOG_WARN, "Unix Sockets server disabled (Admin API)\n");
		} else {
			item = janus_config_get_item_drilldown(config, "admin", "admin_path");
			char *pfname = (char *)(item && item->value ? item->value : "/tmp/ux-janusadmin");
			item = janus_config_get_item_drilldown(config, "admin", "admin_type");
			const char *type = item && item->value ? item->value : "SOCK_SEQPACKET";
			if(!strcasecmp(type, "SOCK_SEQPACKET")) {
				admin_dgram = FALSE;
			} else if(!strcasecmp(type, "SOCK_DGRAM")) {
				admin_dgram = TRUE;
			} else {
				JANUS_LOG(LOG_WARN, "Unknown type %s, assuming SOCK_SEQPACKET\n", type);
				type = "SOCK_SEQPACKET";
			}
			JANUS_LOG(LOG_INFO, "Configuring %s Unix Sockets server (Admin API)\n", type);
			admin_pfd = janus_pfunix_create_socket(pfname, admin_dgram);
		}
	}
	janus_config_destroy(config);
	config = NULL;
	if(pfd < 0 && admin_pfd < 0) {
		JANUS_LOG(LOG_FATAL, "No Unix Sockets server started, giving up...\n");
		return -1;	/* No point in keeping the plugin loaded */
	}

	/* Create a couple of hashtables for all clients */
	clients = g_hash_table_new(NULL, NULL);
	clients_by_fd = g_hash_table_new(NULL, NULL);
	clients_by_path = g_hash_table_new(g_str_hash, g_str_equal);
	janus_mutex_init(&clients_mutex);

	/* Start the Unix Sockets service thread */
	GError *error = NULL;
	pfunix_thread = g_thread_try_new("pfunix thread", &janus_pfunix_thread, NULL, &error);
	if(!pfunix_thread) {
		g_atomic_int_set(&initialized, 0);
		JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Unix Sockets thread...\n", error->code, error->message ? error->message : "??");
		return -1;
	}

	/* Done */
	g_atomic_int_set(&initialized, 1);
	JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_PFUNIX_NAME);
	return 0;
}