//-------------------------------------------------------------------------------------------------- le_result_t le_media_PlayDtmf ( le_audio_Stream_t* streamPtr, ///< [IN] Stream object const char* dtmfPtr, ///< [IN] The DTMFs to play. uint32_t duration, ///< [IN] The DTMF duration in milliseconds. uint32_t pause ///< [IN] The pause duration between tones in milliseconds. ) { le_result_t res; DtmfThreadCtx_t* threadCtxPtr = le_mem_ForceAlloc(DtmfThreadContextPool); memset(threadCtxPtr, 0, sizeof(DtmfThreadCtx_t)); streamPtr->samplePcmConfig.sampleRate = 16000; streamPtr->samplePcmConfig.bitsPerSample = 16; streamPtr->samplePcmConfig.channelsCount = 1; streamPtr->samplePcmConfig.fileSize = -1; streamPtr->samplePcmConfig.pcmFormat = PCM_RAW; threadCtxPtr->duration = duration; threadCtxPtr->pause = pause; threadCtxPtr->sampleRate = 16000; threadCtxPtr->dtmfPtr = dtmfPtr; if (pipe(threadCtxPtr->pipefd) == -1) { LE_ERROR("Failed to create the pipe"); le_mem_Release(threadCtxPtr); return LE_FAULT; } streamPtr->fd = threadCtxPtr->pipefd[0]; if ((res=pa_audio_PlaySamples(streamPtr->audioInterface, streamPtr->fd, &streamPtr->samplePcmConfig)) == LE_OK) { LE_INFO("Spawn DTMF thread"); if (DtmfTreadRef == NULL) { DtmfTreadRef = le_thread_Create("PlayDtmfs", PlayDtmfThread, threadCtxPtr); le_thread_AddChildDestructor(DtmfTreadRef, DestroyPlayDtmfThread, threadCtxPtr); le_thread_Start(DtmfTreadRef); } } else { le_mem_Release(threadCtxPtr); LE_ERROR("Cannot spawn DTMF thread!"); } return res; }
// ------------------------------------------------------------------------------------------------- static void SpawnChildren ( size_t depth, // Indicates what nesting level the thread is at. // 1 = children of the process main thread. void* completionObjPtr // Ptr to the object whose ref count is used to terminate the test. ) // ------------------------------------------------------------------------------------------------- { int i; char childName[32]; le_thread_Ref_t children[FAN_OUT]; // Create and start all the children. for (i = 0; i < FAN_OUT; i++) { le_thread_Ref_t threadRef; Context_t* contextPtr = le_mem_ForceAlloc(ContextPoolRef); contextPtr->depth = depth; contextPtr->completionObjPtr = completionObjPtr; le_mem_AddRef(completionObjPtr); snprintf(childName, sizeof(childName), "%s-%d", le_thread_GetMyName(), i + 1); LE_INFO("Spawning thread '%s'.", childName); threadRef = le_thread_Create(childName, ThreadMainFunction, contextPtr); LE_INFO("Thread '%s' created.", childName); // Create a thread destructor that will release the Context object and the // Test Completion Object that we are going to pass to the child. le_thread_AddChildDestructor(threadRef, ThreadDestructor, contextPtr); LE_INFO("Thread '%s' destructor added.", childName); // Make every third child thread non-joinable and the rest joinable. if (((i + 1) % 3) != 0) { le_thread_SetJoinable(threadRef); } LE_INFO("Thread '%s' joinability set.", childName); // Start the child thread. le_thread_Start(threadRef); LE_INFO("Thread '%s' started.", childName); // Remember the child's thread reference for later join attempt. children[i] = threadRef; } // Join with all the children. for (i = 0; i < FAN_OUT; i++) { void* threadReturnValue; snprintf(childName, sizeof(childName), "%s-%d", le_thread_GetMyName(), i + 1); LE_INFO("Joining with thread '%s'.", childName); le_result_t result = le_thread_Join(children[i], &threadReturnValue); if (result != LE_OK) { LE_INFO("Failed to join with thread '%s'.", childName); LE_FATAL_IF(((i + 1) % 3) != 0, "Failed to join with joinable thread '%s'!", childName); } else { LE_INFO("Successfully joined with thread '%s', which returned %p.", childName, threadReturnValue); LE_FATAL_IF(((i + 1) % 3) == 0, "Joined with non-joinable thread '%s'!", childName); LE_FATAL_IF(threadReturnValue != completionObjPtr, "Thread returned strange value %p. Expected %p.", threadReturnValue, completionObjPtr); } } }
// ------------------------------------------------------------------------------------------------- static void SpawnChildren ( size_t depth // Indicates what nesting level the thread is at. // 1 = children of the process main thread. ) // ------------------------------------------------------------------------------------------------- { int i, j, k; char childName[32]; le_thread_Ref_t children[FAN_OUT]; const char* threadName = le_thread_GetMyName(); if (depth == 2) { LE_ASSERT(sscanf(threadName, "%*[^-]-%d", &j) == 1); // switch to zero-based j--; LE_TEST_INFO("depth 2: j=%d", j); } else if (depth == 3) { LE_ASSERT(sscanf(threadName, "%*[^-]-%d-%d", &k, &j) == 2); // switch to zero based k--; j--; LE_TEST_INFO("depth 3: j=%d,k=%d", j, k); } // Create and start all the children. for (i = 0; i < FAN_OUT; i++) { le_thread_Ref_t threadRef; Context_t* contextPtr = le_mem_ForceAlloc(ContextPoolRef); contextPtr->depth = depth; int item = 0; if (depth == 1) { item = i*(FAN_OUT+1)*(FAN_OUT+1); } if (depth == 2) { item = (j*(FAN_OUT+1)+(i+1))*(FAN_OUT+1); } else if (depth == 3) { item = (k*(FAN_OUT+1) + (j+1))*(FAN_OUT+1) + (i+1); } if (item >= FAN_OUT*(FAN_OUT+1)*(FAN_OUT+1)) { LE_TEST_FATAL("Result index %d outside test result array size %d!", item, FAN_OUT*(FAN_OUT+1)*(FAN_OUT+1)); } snprintf(childName, sizeof(childName), "%s-%d", threadName, i + 1); LE_TEST_INFO("Spawning thread '%s' (item %d).", childName, item); threadRef = le_thread_Create(childName, ThreadMainFunction, contextPtr); TestResults[item].createOk = !!threadRef; // Create a thread destructor that will release the Context object and the // Test Completion Object that we are going to pass to the child. le_thread_AddChildDestructor(threadRef, ThreadDestructor, contextPtr); LE_TEST_INFO("Thread '%s' destructor added.", childName); // Make every third leaf thread non-joinable and the rest joinable. // Non-leaves must be joinable to ensure join if (IsThreadJoinable(depth, i)) { le_thread_SetJoinable(threadRef); LE_TEST_INFO("Thread '%s' joinability set.", childName); } // Start the child thread. le_thread_Start(threadRef); LE_TEST_INFO("Thread '%s' started.", childName); // Remember the child's thread reference for later join attempt. children[i] = threadRef; } // Join with all the children. for (i = 0; i < FAN_OUT; i++) { void* threadReturnValue; int item = 0; if (depth == 1) { item = i*(FAN_OUT+1)*(FAN_OUT+1); } if (depth == 2) { item = (j*(FAN_OUT+1)+(i+1))*(FAN_OUT+1); } else if (depth == 3) { item = (k*(FAN_OUT+1)+(j+1))*(FAN_OUT+1) + (i+1); } if (item >= FAN_OUT*(FAN_OUT+1)*(FAN_OUT+1)) { LE_TEST_FATAL("Result index %d outside test result array size %d!", item, FAN_OUT*(FAN_OUT+1)*(FAN_OUT+1)); } snprintf(childName, sizeof(childName), "%s-%d", le_thread_GetMyName(), i + 1); if (IsThreadJoinable(depth, i)) { le_result_t result = le_thread_Join(children[i], &threadReturnValue); TestResults[item].joinOk = (result == LE_OK); if (result != LE_OK) { LE_TEST_INFO("Failed to join with thread '%s'.", childName); } else { LE_TEST_INFO("Successfully joined with thread '%s', which returned %p.", childName, threadReturnValue); TestResults[item].expectedJoin = (void*)depth; TestResults[item].actualJoin = threadReturnValue; } } else { // Do not try to join non-joinable threads. Result is undefined as thread // could have exited in the meantime and been recycled. TestResults[item].joinOk = false; } } }